ex-scopes/lib/csys/environ.ex

71 lines
1.8 KiB
Elixir

defmodule Scopes.CSys.Environ do
alias Scopes.CSys
alias Scopes.Shape
defmodule State do
defstruct [cells: %{}, init_seq: []]
end
def setup({state, proc}, init_seq, proc_env \\ &proc_env/2) do
env_scope = {%State{init_seq: init_seq}, proc_env, [], self()}
env = CSys.neuron(env_scope)
msg = Shape.create([:csys, :zero], data: %{addr: [:csys, :c00, {0, 0}]})
proc = {state, proc, [], env}
CSys.create(msg, proc)
env
end
def proc_env(msg, scope = {state, _proc, _syns, env}) do
case Shape.head(msg) do
{:exec, func} -> func.(state)
[:csys, :created | _rest] -> process_creation(msg, scope)
_ -> send(env, msg) # forward message to application
end
end
def process_creation(msg, {state, proc, syns, env}) do
data = Shape.data(msg)
new = data.new
addr = data[:addr]
cells = if addr do
[dom, cat, item] = addr
Map.update(state.cells, {dom, cat}, %{item => new},
fn x -> Map.put(x, item, new) end)
else
state.cells
end
{step, seq} = List.pop_at(state.init_seq, 0)
state1 = %State{cells: cells, init_seq: seq}
CSys.update({state1, proc, syns, env})
if step do
step.(state1)
end
end
# accessing cell registry via state.cells
def get_cell(state, [dom, cat, item]) do
get_in(state.cells, [{dom, cat}, item])
end
def send_message(state, addr, head, data) do
cell = get_cell(state, addr)
CSys.send_message(cell, head, data)
end
def connect(state, addr, target, op \\ []) do
send_message(state, addr, ~w(csys connect)a,
%{target: get_cell(state, target), op: op})
end
# delegating tasks to env
def delegate(env, func) do
CSys.send_message(env, {:exec, func})
end
def forward_value(env, addr, value) do
delegate(env, &send_message(&1, addr, ~w(csys data)a, %{value: value}))
end
end