|
@@ -0,0 +1,129 @@
|
|
|
+-module(ebb_run).
|
|
|
+-include("../include/ebb_prim.hrl").
|
|
|
+
|
|
|
+%%% Evaulation
|
|
|
+-export([linearize/1, run_linear/2, run_linear/1]).
|
|
|
+
|
|
|
+%%% Simplification
|
|
|
+-export([simpl/1]).
|
|
|
+
|
|
|
+%%%-----------------------------------------------------------------------------
|
|
|
+%%% Evaluation
|
|
|
+%%%-----------------------------------------------------------------------------
|
|
|
+
|
|
|
+linearize(Op) ->
|
|
|
+ fun(Args) -> run_linear(Op, Args) end.
|
|
|
+
|
|
|
+run_linear(Op) ->
|
|
|
+ run_linear(Op, []).
|
|
|
+
|
|
|
+run_linear(Op, Args) ->
|
|
|
+ case ebb_prim:is_operation(Op) andalso
|
|
|
+ ebb_prim:in_arity(Op) == length(Args) of
|
|
|
+ true -> do_run_linear(Op, Args);
|
|
|
+ false -> erlang:error(badargs, [Op, Args])
|
|
|
+ end.
|
|
|
+
|
|
|
+do_run_linear(#value{value=X}, []) ->
|
|
|
+ list_output(X);
|
|
|
+do_run_linear(#func{code=F}, Args) ->
|
|
|
+ list_output(apply(F, Args));
|
|
|
+do_run_linear(#pipe{ops=Ops}, Args) ->
|
|
|
+ lists:foldl(fun do_run_linear/2, Args, Ops);
|
|
|
+do_run_linear(#par{ops=Ops}, Args) ->
|
|
|
+ {Result, []} =
|
|
|
+ lists:foldl(
|
|
|
+ fun(Op, {Results, Remaining}) ->
|
|
|
+ {Args1, Rest} = lists:split(ebb_prim:in_arity(Op), Remaining),
|
|
|
+ {[do_run_linear(Op, Args1) | Results], Rest}
|
|
|
+ end,
|
|
|
+ {[], Args}, Ops),
|
|
|
+ lists:append(lists:reverse(Result));
|
|
|
+do_run_linear(#route{map=M}, Args) ->
|
|
|
+ [ lists:nth(I, Args) || I <- M ];
|
|
|
+do_run_linear(#sync{}, Args) ->
|
|
|
+ Args;
|
|
|
+do_run_linear(#split{}, Args) ->
|
|
|
+ Args;
|
|
|
+do_run_linear(#merge{}, Args) ->
|
|
|
+ Args;
|
|
|
+do_run_linear(#switch{map=M}, [Tag | Args]) ->
|
|
|
+ do_run_linear(element(2, lists:keyfind(Tag, 1, M)), Args).
|
|
|
+
|
|
|
+list_output(X) ->
|
|
|
+ if is_list(X) -> X;
|
|
|
+ is_tuple(X) -> tuple_to_list(X);
|
|
|
+ true -> [X]
|
|
|
+ end.
|
|
|
+
|
|
|
+%%%-----------------------------------------------------------------------------
|
|
|
+%%% Simplification
|
|
|
+%%%-----------------------------------------------------------------------------
|
|
|
+
|
|
|
+simpl(Op = #pipe{ops=Inside}) ->
|
|
|
+ flatten(Op#pipe{ops=simpl_pipe([ simpl(O) || O <- Inside ])});
|
|
|
+simpl(Op = #par{ops=Inside}) ->
|
|
|
+ flatten(Op#par{ops=simpl_par([ simpl(O) || O <- Inside ])});
|
|
|
+simpl(Op) ->
|
|
|
+ Op.
|
|
|
+
|
|
|
+simpl_pipe(Ops) ->
|
|
|
+ lists:reverse(lists:foldl(fun simpl_pipe/2, [], Ops)).
|
|
|
+
|
|
|
+simpl_pipe(#pipe{ops=Ops}, Acc) ->
|
|
|
+ lists:reverse(Ops, Acc);
|
|
|
+simpl_pipe(Par2 = #par{}, [Par1 = #par{} | Acc]) ->
|
|
|
+ lists:append(simpl_pipe_par(Par1, Par2), Acc);
|
|
|
+simpl_pipe(R2 = #route{in=N}, Acc) ->
|
|
|
+ case {R2 == ebb_flow:id(N), Acc} of
|
|
|
+ {true, _} -> Acc;
|
|
|
+ {false, [R1 = #route{} | Rest]} ->
|
|
|
+ [simpl_pipe_route(R1, R2) | Rest];
|
|
|
+ {false, _} -> [R2 | Acc]
|
|
|
+ end;
|
|
|
+simpl_pipe(#split{size=N}, [#merge{size=N} | Acc]) ->
|
|
|
+ Acc;
|
|
|
+simpl_pipe(#merge{size=N}, [#split{size=N} | Acc]) ->
|
|
|
+ Acc;
|
|
|
+simpl_pipe(Op, Acc) ->
|
|
|
+ [Op | Acc].
|
|
|
+
|
|
|
+simpl_pipe_par(Par1 = #par{in=In, ops=Ops1}, Par2 = #par{out=Out, ops=Ops2}) ->
|
|
|
+ ZOps = lists:zip(Ops1, Ops2),
|
|
|
+ Match = lists:all(fun({O1,O2}) -> ebb_prim:can_connect(O1, O2) end, ZOps),
|
|
|
+ case Match of
|
|
|
+ true -> [#par{in=In, out=Out,
|
|
|
+ ops=[ ebb_prim:pipe([O1,O2]) || {O1, O2} <- ZOps ]}];
|
|
|
+ false -> [Par1, Par2]
|
|
|
+ end.
|
|
|
+
|
|
|
+simpl_pipe_route(#route{in=In, map=M1}, #route{out=Out, map=M2}) ->
|
|
|
+ #route{in=In, out=Out, map=[ lists:nth(I, M1) || I <- M2 ]}.
|
|
|
+
|
|
|
+simpl_par(Ops) ->
|
|
|
+ lists:reverse(lists:foldl(fun simpl_par/2, [], Ops)).
|
|
|
+
|
|
|
+simpl_par(#par{ops=Ops}, Acc) ->
|
|
|
+ lists:reverse(Ops, Acc);
|
|
|
+simpl_par(#route{in=0, out=0, map=[]}, Acc) ->
|
|
|
+ Acc;
|
|
|
+simpl_par(R2 = #route{}, [R1 = #route{} | Acc]) ->
|
|
|
+ [simpl_par_route(R1, R2) | Acc];
|
|
|
+simpl_par(Op, Acc) ->
|
|
|
+ [Op | Acc].
|
|
|
+
|
|
|
+simpl_par_route(#route{in=In1, out=Out1, map=M1},
|
|
|
+ #route{in=In2, out=Out2, map=M2}) ->
|
|
|
+ #route{in=In1+In2, out=Out1+Out2,
|
|
|
+ map=lists:append(M1, [ S2+In1 || S2 <- M2 ])}.
|
|
|
+
|
|
|
+flatten(#pipe{in=N, out=N, ops=[]}) ->
|
|
|
+ ebb_flow:id(N);
|
|
|
+flatten(#pipe{ops=[Single]}) ->
|
|
|
+ Single;
|
|
|
+flatten(#par{in=N, out=N, ops=[]}) ->
|
|
|
+ ebb_flow:id(N);
|
|
|
+flatten(#par{ops=[Single]}) ->
|
|
|
+ Single;
|
|
|
+flatten(Op) ->
|
|
|
+ Op.
|