111 lines
2.8 KiB
Elixir
111 lines
2.8 KiB
Elixir
defmodule Scopes.Core.Environ do
|
|
@cell_registry __MODULE__.Cells
|
|
|
|
alias Scopes.Core
|
|
alias Scopes.Core.Actor
|
|
alias Scopes.Core.Shape
|
|
|
|
require Logger
|
|
|
|
defmodule State do
|
|
defstruct [cells: %{}, init_seq: []]
|
|
end
|
|
|
|
def cells(), do: @cell_registry
|
|
|
|
def child_spec(opts) do
|
|
%{id: __MODULE__,
|
|
start: {__MODULE__, :setup, opts}}
|
|
end
|
|
|
|
def setup({state, proc}, init_seq, proc_env \\ &proc_env/2) do
|
|
Registry.start_link(keys: :unique, name: cells())
|
|
env_scope = {%State{init_seq: init_seq}, proc_env, [], self()}
|
|
env = Core.neuron(env_scope)
|
|
Actor.register(env, cells(), {:env, :c00})
|
|
msg = Shape.create([:csys, :zero], data: %{addr: {:csys, :c00, "0-0"}})
|
|
scope = {state, proc, [], env}
|
|
Core.create(msg, scope)
|
|
#{:ok, env}
|
|
:ignore
|
|
end
|
|
|
|
def proc_env(msg, scope = {state, _proc, _syns, env}) do
|
|
case Shape.head(msg) do
|
|
{:exec, func} -> func.(state)
|
|
[:csys, :created | _rest] -> process_created(msg, scope)
|
|
_ -> send(env, msg) # forward message to application
|
|
end
|
|
end
|
|
|
|
def process_created(msg, {state, proc, syns, env}) do
|
|
data = Shape.data(msg)
|
|
new = data.new
|
|
addr = data[:addr]
|
|
cells = if addr do
|
|
Actor.register(new, cells(), addr)
|
|
{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}
|
|
Core.update({state1, proc, syns, env})
|
|
if step do
|
|
Process.sleep(1)
|
|
#step.(state1)
|
|
step.()
|
|
end
|
|
end
|
|
|
|
# accessing cell registry
|
|
|
|
def get_cell(addr) do
|
|
data = Registry.lookup(cells(), addr)
|
|
if data do
|
|
[{cell, _val}] = data
|
|
cell
|
|
else
|
|
Logger.warning "No cell found at address #{inspect(addr)}!"
|
|
nil
|
|
end
|
|
end
|
|
|
|
def send_message(addr, head, data) do
|
|
rcvr = get_cell(addr)
|
|
Core.send_message(rcvr, head, data)
|
|
end
|
|
|
|
def connect(addr = {dom, _cat, _item}, target, op \\ []) do
|
|
send_message(addr, [dom, :connect],
|
|
%{target: get_cell(target), op: op})
|
|
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)
|
|
Core.send_message(cell, head, data)
|
|
end
|
|
|
|
def connect_state(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
|
|
Core.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
|