getop = fn (state, x) ->
try do
String.to_integer(x)
rescue
_ -> Map.get(state, x, 0)
end
end
setop = fn (state, x, y) -> Map.put(state, x, y) end
opadd = fn (state, x, y) -> getop.(state, x) + getop.(state, y) end
opmul = fn (state, x, y) -> getop.(state, x) * getop.(state, y) end
opmod = fn (state, x, y) -> rem(getop.(state, x), getop.(state, y)) end
execute = fn (state, pc, inst) ->
# inst |> IO.inspect
{ op, x, y } = inst
new =
case op do
"add" -> setop.(state, x, opadd.(state, x, y))
"mul" -> setop.(state, x, opmul.(state, x, y))
"mod" -> setop.(state, x, opmod.(state, x, y))
"set" -> setop.(state, x, getop.(state, y))
end
{ new, pc + 1 }
end
execute_and_next = fn {state, pc, prog} ->
inst = Enum.at(prog, pc)
{ state, pc } =
case inst do
nil -> { state, nil }
_ -> execute.(state, pc, Enum.at(prog, pc))
end
{ state, pc, prog }
end
runner = fn (state, prog, stop) ->
gen = Stream.resource(
fn -> { state, 0, prog } end,
fn x ->
case stop.(x) do
:halt -> {:halt, x }
x ->
n = execute_and_next.(x)
{ [n], n }
end
end,
fn x -> x end)
|> Stream.take(-1)
|> Enum.to_list
elem(Enum.at(gen, 0), 0)
end
stop = fn { state, pc, prog } ->
case Enum.at(prog, pc) do
nil -> :halt
_ -> { state, pc, prog }
end
end
thread = fn ->
receive do x ->
send x.parent,
%{ child: x.state["p"],
state: runner.(x.state, x.prog, stop) }
end
end
#prog = [ {"set", "a", "1" }, { "add", "a", "2" }, { "set", "b", "a"} ]
prog = :stdio
|> IO.read(:all)
|> String.split("\n")
|> Enum.map(&(String.trim(&1)))
|> Enum.filter(&(&1 != ""))
|> Enum.map(&(List.to_tuple(String.split(&1, " "))))
prog |> IO.inspect
pid0 = spawn_link thread
pid1 = spawn_link thread
send pid0, %{ parent: self(), state: %{"p" => 0}, prog: prog}
send pid1, %{ parent: self(), state: %{"p" => 1}, prog: prog}
receive do x -> x end
|> IO.inspect
receive do x -> x end
|> IO.inspect