ex-scopes/lib/csys/program.ex

107 lines
2.6 KiB
Elixir

defmodule Scopes.CSys.Program do
import Scopes.CSys, only: [
neuron: 1, update_neuron: 1, synapse: 3,
syns: 1, env: 1
]
alias Scopes.Core.Actor
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(stages, stage) do
stages[stage] || stages[:default]
end
def get_proc(state) do
get_proc(elem(state.prog, 0), state.stage)
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, :create, :pred | _rest] -> create_pred(scope)
[:csys, :create, :succ | _rest] -> create_succ(scope)
#[:csys, :next | _rest] -> next(scope, meta)
#[:csys, :data | rest] -> process_data(rest, Shape.data(msg), scope)
#[:csys, action | rest] -> transition(action, scope)
_ -> forward(msg, scope) || notify(msg, scope)
end
end
def basic(msg, scope) do
forward(msg, scope) || notify(msg, scope)
end
# processor steps, helper functions
def notify(msg, scope) do
Actor.send(env(scope), msg)
end
def forward(msg, scope) do
Enum.reduce(syns(scope), false, fn s, _acc -> s.(msg); true end)
end
def restart({state, _proc, syns, env}) do
nstate = %{state | stage: :initial}
{nstate, get_proc(nstate), syns, env}
end
# step functions
# 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 create_pred(scope = {state, proc, _syns, env}) do
syn = synapse(self(), &Function.identity/1, 0)
new = neuron(restart({state, proc, [syn], env}))
notify({:created, new}, scope)
update_neuron(restart(scope))
end
def create_succ (scope = {state, proc, syns, env}) do
new = neuron(restart({state, proc, [], env}))
notify({:created, new}, scope)
syn = synapse(new, &Function.identity/1, 0)
update_neuron(restart({state, proc, [syn | syns], env}))
end
end