defmodule Scopes.CSys.Program do import Scopes.CSys, only: [ neuron: 1, update_neuron: 1, synapse: 3 ] alias Scopes.CSys alias Scopes.Shape defmodule State do defstruct [:value, :stage, :prog] end def prepare(prog, value \\ []) do state = %State{value: value, stage: :initial, prog: prog} {state, get_proc(state)} end def get_proc(state) do get_proc(elem(state.prog, 0), state.stage) end defp get_proc(stages, stage) do stages[stage] || stages[:default] end # basic program def basic_prog() do default = &basic_active/2 stages = %{ default: default, initial: &basic_initial/2, active: default, retired: default } transitions = %{ restart: :initial, retire: :retired, next: [initial: :active, active: :retired] } {stages, transitions} end def prepare_basic(value \\ []) do prepare(basic_prog(), value) end # basic processors def basic_initial(msg, scope) do basic(msg, scope) end def basic_active(msg, scope) do basic(msg, scope) end def basic(msg = {head, _info}, scope) do case head do [:csys, :connect, :succ | _rest] -> connect_succ(msg, scope) [:csys, :create, :succ | _rest] -> create_succ(msg, scope) [:csys, :create, :pred | _rest] -> create_pred(msg, scope) #[:csys, :next | _rest] -> next(scope, meta) #[:csys, :data | rest] -> process_data(rest, Shape.data(msg), scope) #[:csys, action | rest] -> transition(action, scope) _ -> CSys.forward(msg, scope) || CSys.notify(msg, scope) end end def basic(msg, scope) do CSys.forward(msg, scope) || CSys.notify(msg, scope) end # helper functions def restart({state, _proc, syns, env}) do nstate = %{state | stage: :initial} {nstate, get_proc(nstate), syns, env} end # step functions # connect, create_... steps # todo: provide parameters for initial state, proc / stage, op, # depending on state and stage (proc) of self, as well as message, env, ... def connect_succ(msg, {state, proc, syns, env}) do data = Shape.data(msg) op = data[:op] || CSys.noop() succ = data[:succ] syn = synapse(succ, op, 0) update_neuron({state, proc, [syn | syns], env}) end def create_succ(msg, scope = {state, proc, syns, env}) do op = Shape.data(msg)[:op] || CSys.noop() new = neuron(restart({state, proc, [], env})) CSys.notify({:created, new}, scope) syn = synapse(new, op, 0) update_neuron(restart({state, proc, [syn | syns], env})) end def create_pred(msg, scope = {state, proc, _syns, env}) do op = Shape.data(msg)[:op] || CSys.noop() syn = synapse(self(), op, 0) new = neuron(restart({state, proc, [syn], env})) CSys.notify({:created, new}, scope) update_neuron(restart(scope)) end end