Просмотр исходного кода

Added module for basic control flow graph structure.

Paul Downen 14 лет назад
Родитель
Сommit
5c3fa050ad
1 измененных файлов с 164 добавлено и 0 удалено
  1. 164 0
      src/flow_graph.erl

+ 164 - 0
src/flow_graph.erl

@@ -0,0 +1,164 @@
+-module(flow_graph).
+
+% Vertex construction
+-export([hole/0, value/1, void/0, split/0, merge/0, switch/2, select/2]).
+% Edge construction
+-export([flow/2, func/3, index/3, range/4, tagged/3, dynamic/2]).
+% Graph construction
+-export([singleton/1, from_list/3]).
+% Graph manipulation
+-export([append/2, out_edges/2]).
+% Checks for validity
+-export([valid_edge/1, valid_edge_list/1, valid_graph/1]).
+
+% Use the orddict module for clarity, and the dict module for speed.
+-define(DICT, dict).
+
+% flow_graph ::= {in    : vertex,
+%                 out   : vertex,
+%                 graph : dict(vertex, [edge])}
+-record(flow_graph, {in, out, graph}).
+
+% vertex ::= {ref, node}
+-record(vertex, {ref, node}).
+
+% node ::= hole | value | void | split | merge | switch | select | delayed
+% value ::= term
+% switch ::= {fun(A, State) -> {Tag, State}, State}
+% select ::= {fun(A, State) -> {select, State} | {block, State}, State}
+-record(value, {value}).
+-record(switch, {switch, state}).
+-record(select, {select, state}).
+
+% edge ::= {from : vertex, to : vertex, through : link
+-record(edge, {from, to, through}).
+
+% link ::= flow | func | range | tagged | dynamic
+% func ::= fun(A) -> B
+% range ::= {int, int}
+% tagged ::= Tag
+% dyanmic ::= fun(A) -> flow_graph
+-record(func, {func}).
+-record(range, {from, to}).
+-record(tagged, {tag}).
+-record(dynamic, {code}).
+
+%% Vertex construction
+make_vertex(N) ->
+    #vertex{ref=make_ref(), node=N}.
+
+hole() ->
+    make_vertex(hole).
+
+value(X) ->
+    make_vertex(#value{value=X}).
+
+void() ->
+    make_vertex(void).
+
+split() ->
+    make_vertex(split).
+
+merge() ->
+    make_vertex(merge).
+
+switch(Switch, Init) when is_function(Switch) ->
+    make_vertex(#switch{switch=Switch, state=Init}).
+
+select(Select, Init) when is_function(Select) ->
+    make_vertex(#select{select=Select, state=Init}).
+
+delayed() ->
+    make_vertex(delayed).
+
+%% Edge construction
+
+make_edge(From, To, Through) ->
+    #edge{from=From, to=To, through=Through}.
+
+flow(From, To) ->
+    make_edge(From, To, flow).
+
+func(From, To, Func) ->
+    make_edge(From, To, #func{func=Func}).
+
+index(From, To, N) when is_number(N) ->
+    range(From, To, N, N).
+
+range(From, To, Low, High) when is_number(Low), is_number(High), Low =< High->
+    make_edge(From, To, #range{from=Low, to=High}).
+
+tagged(From, To, Tag) ->
+    make_edge(From, To, #tagged{tag=Tag}).
+
+dynamic(From, Code) ->
+    make_edge(From, delayed(), #dynamic{code=Code}).
+
+%% Graph constructon
+
+singleton(V = #vertex{}) ->
+    #flow_graph{in=V, out=V, graph=orddict:store(V, [], ?DICT:new())}.
+
+from_list(In = #vertex{}, Out = #vertex{}, Edges) ->
+    G = lists:fold(fun(E, G) -> add_edge(G, E) end, ?DICT:new(), Edges),
+    #flow_graph{in=In, out=Out, graph=G}.
+
+%% Graph manipulation
+
+append(FG1 = #flow_graph{in=In1, out=Out1},
+       FG2 = #flow_graph{in=In2, out=Out2}) ->
+    G = ?DICT:merge(fun(_, E1, E2) -> lists:append(E1,E2) end,
+		      FG1#flow_graph.graph,
+		      FG2#flow_graph.graph),
+    add_edge(#flow_graph{in=In1, out=Out2, graph=G},
+	     flow(Out1, In2)).
+
+out_edges(#flow_graph{graph=G}, #vertex{ref=R}) ->
+    ?DICT:find(R, G).
+
+add_edge(FG = #flow_graph{graph=G}, E = #edge{from=From}) ->
+    Add = fun(Edges) -> [E|Edges] end,
+    FG#flow_graph{graph=?DICT:update(From, Add, [], G)}.
+
+% Checks for validity
+valid_edge(#edge{from=From, to=To, through=Through}) ->
+    IsNeutral = fun(flow)       -> true;
+		   (#func{})    -> true;
+		   (#dynamic{}) -> true;
+		   (_)          -> false
+		end,
+    Left = case {From, Through, To} of
+	       {delayed,   _,          _}        -> false;
+	       {hole,      _,          _}        -> IsNeutral(Through);
+	       {#value{},  _,          _}        -> IsNeutral(Through);
+	       {void,      flow,       #value{}} -> true;
+	       {void,      #dynamic{}, delayed}  -> true;
+	       {void,      _,          _}        -> false;
+	       {split,     #range{},   _}        -> true;
+	       {split,     _,          _}        -> false;
+	       {merge,     _,          _}        -> IsNeutral(Through);
+	       {#switch{}, #tagged{},  _}        -> true;
+	       {#switch{}, _,          _}        -> false;
+	       {#select{}, _,          _}        -> IsNeutral(Through);
+	       _                                 -> false
+	   end,
+    Right = case {From, Through, To} of
+		{_,    dynamic,  delayed}   -> true;
+		{_,    dynamic,  _}         -> false;
+		{_,    _,        hole}      -> true;
+		{void, flow,     #value{}}  -> true;
+		{_,    _,        #value{}}  -> false;
+		{_,    _,        split}     -> true;
+		{_,    #range{}, merge}     -> true;
+		{_,    _,        merge}     -> false;
+		{_,    _, 	 #switch{}} -> true;
+		{_,    _, 	 #select{}} -> true
+	    end,
+    Left and Right.
+
+valid_edge_list(Edges) ->
+    lists:all(fun valid_edge/1, Edges).
+
+valid_graph(#flow_graph{graph=G}) ->
+    lists:all(fun({_, Es}) -> valid_edge_list(Es) end,
+	      ?DICT:to_list(G)).