defmodule Scopes.Core.Program do alias Scopes.Core alias Scopes.Core.Environ alias Scopes.Core.Shape alias Scopes.Util require Logger require Util defmodule State do defstruct [:value, :count, :stage, :prog] end def prepare(prog, args) do state = %State{ value: args[:bias] || 0, count: 0, stage: :initial, prog: prog } {state, get_proc(state)} end def get_proc(state) do get_proc(state.prog, state.stage) end defp get_proc(stages, stage) do stages[stage] || stages[:default] end # basic program def basic_prog(args) do default = basic_active(args) %{default: default, initial: basic_initial(args), active: default, retired: default } end def prepare_basic(args \\ []) do prepare(basic_prog(args), args) end # basic processors def basic_initial(args) do basic(args) end def basic_active(args) do basic(args) end def basic(args) do fn msg, scope -> case Shape.head(msg) do [:csys, :data | _rest] -> process_basic(msg, scope, args) #[:csys, :trigger | _rest] -> process_trigger(msg, scope) [:csys, :connect | _rest] -> Core.connect(msg, scope) [:csys, :create, :succ | _rest] -> create_succ(msg, scope) [:csys, :create, :pred | _rest] -> create_pred(msg, scope) [:csys, :create | _rest] -> create(msg, scope) #[:csys, :next | _rest] -> next(msg, scope) _ -> Core.forward(msg, scope) || Core.notify(msg, scope) end end end # message handlers // proc steps def process_basic(msg, scope, args) do threshold = args[:threshold] || 0 bias = args[:bias] || 0 limit = args[:limit] data = Shape.data(msg) state = Core.state(scope) Logger.debug(Util.show [data, state.value, threshold]) value_n = state.value + data.value if value_n >= threshold do value_out = limit && rem(value_n - 1, limit) + limit || value_n value_next = limit && max(value_n - limit, bias) || bias msg = Shape.create(Shape.head(msg), data: %{data | value: value_out}) Core.forward(msg, scope) || Core.notify(msg, scope) state_n = %{state | value: value_next} Core.update(put_elem(scope, 0, state_n)) else state_n = %{state | value: value_n} Core.update(put_elem(scope, 0, state_n)) end end def create_succ(msg, scope) do new = Core.create(msg, restart(scope)) data = Shape.data(msg) Core.send_message(self(), ~w(csys connect)a, Map.put(data, :target, new)) end def create_pred(msg, scope) do new = Core.create(msg, restart(scope)) data = Shape.data(msg) Core.send_message(new, ~w(csys connect)a, Map.put(data, :target, self())) end def create(msg, scope) do new = Core.create(msg, restart(scope)) data = Shape.data(msg) case data[:dir] do :succ -> Core.send_message(self(), ~w(csys connect)a, Map.put(data, :target, new)) :pred -> Core.send_message(new, ~w(csys connect)a, Map.put(data, :target, self())) _ -> nil end end # synapse operations def multiply(n) do fn msg -> value = Shape.data(msg)[:value] || 0 Shape.create(Shape.head(msg), data: %{Shape.data(msg) | value: n * value}) end end def negate(), do: multiply(-1) # helper functions def restart({state, _proc, syns, env}) do state_n = %{state | stage: :initial} {state_n, get_proc(state_n), syns, env} end # demo init sequences def init_seq_b1() do zero = [:csys, :c00, "0-0"] one = [:csys, :s01, "1-0"] two = [:csys, :c00, "1-1"] three = [:csys, :s01, "1-1"] [ &Environ.send_message(&1, zero, ~w(csys create pred)a, %{op: [Core.data_only(), negate()], addr: one}), &Environ.send_message(&1, one, ~w(csys create succ)a, %{op: Core.data_only(), addr: two}), &Environ.send_message(&1, two, ~w(csys create pred)a, %{addr: three}), &Environ.connect(&1, three, zero) ] end def init_recursive_1() do zero = [:csys, :c00, "0-0"] [ &Environ.send_message(&1, zero, ~w(csys create succ)a, %{}), &Environ.send_message(&1, zero, ~w(csys create pred)a, %{addr: [:csys, :s01, "1-1"]}), &Environ.connect(&1, zero, zero, negate()) ] end end