ex-scopes/lib/core/environ.ex

93 lines
2.2 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 [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) do
case Shape.head(msg) do
{:exec, func} -> func.()
[:csys, :created | _rest] -> process_created(msg, scope)
_ -> send(Core.env(scope), 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]
if addr do
Actor.register(new, cells(), addr)
end
{step, seq} = List.pop_at(state.init_seq, 0)
state1 = %State{init_seq: seq}
Core.update({state1, proc, syns, env})
if step do
Process.sleep(1)
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 send_value(addr, value) do
send_message(addr, ~w(csys data)a, %{value: value})
end
def connect(addr = {dom, _cat, _item}, target, op \\ []) do
send_message(addr, [dom, :connect],
%{target: get_cell(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, fn -> send_message(addr, ~w(csys data)a, %{value: value}) end)
end
end