1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 2000-2015. All Rights Reserved.
5%%
6%% Licensed under the Apache License, Version 2.0 (the "License");
7%% you may not use this file except in compliance with the License.
8%% You may obtain a copy of the License at
9%%
10%%     http://www.apache.org/licenses/LICENSE-2.0
11%%
12%% Unless required by applicable law or agreed to in writing, software
13%% distributed under the License is distributed on an "AS IS" BASIS,
14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15%% See the License for the specific language governing permissions and
16%% limitations under the License.
17%%
18%% %CopyrightEnd%
19%%
20
21-module(xref_compiler).
22
23-include("xref.hrl").
24
25%-define(debug, true).
26
27-ifdef(debug).
28-define(FORMAT(P, A), io:format(P, A)).
29-define(CALL(F), F).
30-else.
31-define(FORMAT(P, A), ok).
32-define(CALL(F), ok).
33-endif.
34
35%% Avoid warning for local function error/1 clashing with autoimported BIF.
36-compile({no_auto_import,[error/1]}).
37-export([compile/2]).
38
39-export([update_graph_counter/3]).
40
41-export([format_error/1]).
42
43-import(lists,
44	[concat/1, foldl/3, nthtail/2, reverse/1, sort/1, sublist/2]).
45
46-import(sofs,
47	[composite/2, difference/2, empty_set/0, from_term/1,
48	 intersection/2, is_empty_set/1, multiple_relative_product/2,
49	 projection/2, relation/1, relation_to_family/1,
50	 restriction/2, specification/2, substitution/2,
51	 to_external/1, union/2, union_of_family/1]).
52
53%%
54%%  Exported functions
55%%
56
57compile(Chars, Table) ->
58    case xref_scanner:scan(Chars) of
59	{ok, Tokens}  ->
60	    case xref_parser:parse(Tokens) of
61		{ok, ParseTree} ->
62		    ?FORMAT("ParseTree ~p~n", [ParseTree]),
63		    case catch statements(ParseTree, Table) of
64			E={error, _, _} ->
65			    E;
66			{ok, UV, P} ->
67			    %% User variables to be.
68			    Table1 = user_vars(UV, Table),
69			    ?CALL(statistics(runtime)),
70			    Reply = i(P, Table1),
71			    ?CALL({_, Time} = statistics(runtime)),
72			    ?FORMAT("Result in ~p ms~n",[Time]),
73			    Reply
74		    end;
75		{error, {Line, _Module, Error}} ->
76		    error({parse_error, Line, Error})
77	    end;
78	{error, Info, Line} ->
79	    error({parse_error, Line, Info})
80    end.
81
82format_error({error, Module, Error}) ->
83    Module:format_error(Error);
84format_error({parse_error, Line, Error}) ->
85    format_parse_error(Error, format_line(Line));
86format_error({variable_reassigned, Expr}) ->
87    io_lib:format("Variable assigned more than once: ~ts~n", [Expr]);
88format_error({unknown_variable, Name}) ->
89    io_lib:format("Variable ~tp used before set~n", [Name]);
90format_error({type_error, Expr}) ->
91    io_lib:format("Operator applied to argument(s) of different or "
92		  "invalid type(s): ~ts~n", [Expr]);
93format_error({type_mismatch, Expr1, Expr2}) ->
94    io_lib:format("Constants of different types: ~ts, ~ts~n",
95		  [Expr1, Expr2]);
96format_error({unknown_constant, Constant}) ->
97    io_lib:format("Unknown constant ~ts~n", [Constant]);
98format_error(E) ->
99    io_lib:format("~tp~n", [E]).
100
101%%
102%%  Local functions
103%%
104
105user_vars([{{user,Name}, Val} | UV], Table) ->
106    user_vars(UV, dict:store(Name, Val, Table));
107user_vars([_V | UV], Table) ->
108    user_vars(UV, Table);
109user_vars([], Table) ->
110    Table.
111
112statements(Stmts, Table) ->
113    statements(Stmts, Table, [], []).
114
115statements([Stmt={assign, VarType, Name, E} | Stmts0], Table, L, UV) ->
116    case dict:find(Name, Table) of
117	{ok, _} ->
118	    throw_error({variable_reassigned, xref_parser:t2s(Stmt)});
119	error ->
120	    {Type, OType, NewE} = t_expr(E, Table),
121	    Val = #xref_var{name = Name, vtype = VarType,
122			    otype = OType, type = Type},
123	    NewTable = dict:store(Name, Val, Table),
124	    Stmts = if Stmts0 =:= [] -> [{variable, Name}]; true -> Stmts0 end,
125	    Variable = {VarType, Name},
126	    Put = {put, Variable, NewE},
127	    statements(Stmts, NewTable, [Put | L], [{Variable,Val} | UV])
128    end;
129statements([Expr], Table, L, UV) ->
130    {Type, OType, NewE} = t_expr(Expr, Table),
131    E1 = un_familiarize(Type, OType, NewE),
132    NE = case {Type, OType} of
133	     %% Edges with empty sets of line numbers are removed.
134	     {{line, _}, edge} ->
135		 {relation_to_family, E1};
136	     {_Type, edge_closure} ->
137		 %% Fake a closure usage, just to make sure it is destroyed.
138		 E2 = {fun graph_access/2, E1, E1},
139                 {fun(_E) -> 'closure()' end, E2};
140	     _Else -> E1
141	 end,
142    {ok, UV, stats(L, NE)}.
143
144stats([{put, V, X} | Ss], E) ->
145    stats(Ss, {put, V, X, E});
146stats([], E) ->
147    E.
148
149t_expr(E, Table) ->
150    {expr, Type, OType, E1} = check_expr(E, Table),
151    ?FORMAT("TExpr:~n~p~n",[E1]),
152    E2 = convert(E1),
153    ?FORMAT("After conversion:~n~p~n",[E2]),
154    {Type, OType, E2}.
155
156%%% check_expr/2 translates Expr in xref_parser.yrl into TExpr:
157%%%
158%%% TExpr = {expr, Type, ObjectType, Expr}
159%%% Expr = {constants, [Constant]}
160%%%      | {variable, {VarType, VarName}}
161%%%      | {call, Call, Expr}
162%%%      | {call, Call, Expr, Expr}
163%%%      | {call, restriction, integer(), Expr, Expr}
164%%%      | {convert, ObjectType, Type, Type}
165%%%      | {convert, Type, Type}
166%%% Constant = atom() | {atom(), atom()} | MFA | {MFA, MFA}
167%%% Call = atom() % function in the sofs module
168%%%      | fun()
169%%% Type = {line, LineType} | function | module | application | release
170%%%      | number
171%%% LineType = line | local_call | external_call | export_call | all_line_call
172%%% VarType = predef | user | tmp
173%%% ObjectType = vertex | vertex_set | edge | edge_set | edge_closure | path
174%%%            | number
175%%% MFA = {atom(), atom(), integer()}
176
177%% -> TExpr
178check_expr({list, L}, Table) ->
179    check_constants(L, Table);
180check_expr({tuple, L}, Table) ->
181    {expr, Type, vertex, _Consts} = check_constants(L, Table),
182    Cs = reverse(constant_vertices(L, [])),
183    {expr, Type, path, {constants, Cs}};
184check_expr({variable, Name}, Table) ->
185    case dict:find(Name, Table) of
186	{ok, #xref_var{vtype = VarType, otype = OType, type = Type}} ->
187	    V0 = {variable, {VarType, Name}},
188	    V = case {VarType, Type, OType} of
189		    {predef, release, _} -> V0;
190		    {predef, application, _} -> V0;
191		    {predef, module, _} -> V0;
192		    {predef, function, vertex} -> V0;
193		    {predef, function, edge} -> {call, union_of_family, V0};
194		    _Else  -> V0
195	    end,
196	    {expr, Type, OType, V};
197	error ->
198	    throw_error({unknown_variable, Name})
199    end;
200check_expr({type, {type, _Type}, E}, Table) ->
201    check_expr(E, Table);
202check_expr(Expr={type, {convert, NewType0}, E}, Table) ->
203    NewType = what_type(NewType0),
204    {expr, OldType, OType, NE} = check_expr(E, Table),
205    ok = check_conversion(OType, OldType, NewType, Expr),
206    {expr, NewType, OType, {convert, OType, OldType, NewType, NE}};
207check_expr(Expr={set, SOp, E}, Table) ->
208    {expr, Type, OType0, E1} = check_expr(E, Table),
209    OType = case {OType0, SOp} of
210		{edge, range} -> vertex;
211		{edge, domain} -> vertex;
212		{edge, weak} -> edge;
213		{edge, strict} -> edge;
214		{edge_set, range} -> vertex_set;
215		{edge_set, domain} -> vertex_set;
216		{edge_set, weak} -> edge_set;
217		{edge_set, strict} -> edge_set;
218		_ ->
219		    throw_error({type_error, xref_parser:t2s(Expr)})
220	    end,
221    Op = set_op(SOp),
222    NE = function_vertices_to_family(Type, OType, {call, Op, E1}),
223    {expr, Type, OType, NE};
224check_expr(Expr={graph, Op, E}, Table) ->
225    {expr, Type, NOType, E1} = check_expr(E, Table),
226    case Type of
227	{line, _LineType} ->
228	    throw_error({type_error, xref_parser:t2s(Expr)});
229	_Else ->
230	    ok
231    end,
232    OType =
233	case {NOType, Op} of
234	    {edge, components} -> vertex_set;
235	    {edge, condensation} -> edge_set;
236	    {edge, closure} -> edge_closure;
237	    {edge_closure, components} -> vertex_set;
238	    {edge_closure, condensation} -> edge_set;
239	    {edge_closure, closure} -> edge_closure;
240	    %% Neither need nor want these ones:
241	    %% {edge_set, closure} -> edge_set_closure;
242	    %% {edge_set, components} -> vertex_set_set;
243	    _ ->
244		throw_error({type_error, xref_parser:t2s(Expr)})
245	end,
246    E2 = {convert, NOType, edge_closure, E1},
247    NE = case Op of
248	     closure -> E2;
249	     _Op -> use_of_closure(Op, E2)
250	 end,
251    {expr, Type, OType, NE};
252check_expr(Expr={numeric, '#', E}, Table) ->
253    {expr, Type, OType, E1} = check_expr(E, Table),
254    case OType of
255	vertex -> ok;
256	vertex_set -> ok;
257	edge -> ok;
258	edge_set -> ok;
259	_Else -> throw_error({type_error, xref_parser:t2s(Expr)})
260    end,
261    NE = {convert, OType, Type, number, E1},
262    {expr, number, number, {call, no_elements, NE}};
263check_expr(Expr={set, SOp, E1, E2}, Table) ->
264    %% sets and numbers...
265    {expr, Type1, OType1, NE1} = check_expr(E1, Table),
266    {expr, Type2, OType2, NE2} = check_expr(E2, Table),
267    OType = case {OType1, OType2} of
268		{vertex, vertex} -> vertex;
269		{edge, edge} -> edge;
270		{number, number} -> number;
271		_ -> throw_error({type_error, xref_parser:t2s(Expr)})
272	    end,
273    case OType of
274	number ->
275	    {expr, number, number, {call, ari_op(SOp), NE1, NE2}};
276	_Else -> % set
277	    {Type, NewE1, NewE2} =
278		case {type_ord(Type1), type_ord(Type2)} of
279		    {T1, T2} when T1 =:= T2 ->
280			%% Example: if Type1 = {line, line} and
281			%% Type2 = {line, export_line}, then this is not
282			%% correct, but works:
283			{Type1, NE1, NE2};
284		    {T1, T2} when T1 < 2; T2 < 2 ->
285			throw_error({type_error, xref_parser:t2s(Expr)});
286		    {T1, T2} when T1 > T2 ->
287			{Type2, {convert, OType, Type1, Type2, NE1}, NE2};
288		    {T1, T2} when T1 < T2 ->
289			{Type1, NE1, {convert, OType, Type2, Type1, NE2}}
290		end,
291	    Op = set_op(SOp, Type, OType),
292	    {expr, Type, OType, {call, Op, NewE1, NewE2}}
293    end;
294check_expr(Expr={restr, ROp, E1, E2}, Table) ->
295    {expr, Type1, OType1, NE1} = check_expr(E1, Table),
296    {expr, Type2, OType2, NE2} = check_expr(E2, Table),
297    case {Type1, Type2} of
298	{{line, _LineType1}, _Type2} ->
299	    throw_error({type_error, xref_parser:t2s(Expr)});
300	{_Type1, {line, _LineType2}} ->
301	    throw_error({type_error, xref_parser:t2s(Expr)});
302	_ ->
303	    ok
304    end,
305    case {OType1, OType2} of
306	{edge, vertex} when ROp =:= '|||' ->
307	    {expr, _, _, R1} = restriction('|', E1, Type1, NE1, Type2, NE2),
308	    {expr, _, _, R2} = restriction('||', E1, Type1, NE1, Type2, NE2),
309	    {expr, Type1, edge, {call, intersection, R1, R2}};
310	{edge, vertex} ->
311	    restriction(ROp, E1, Type1, NE1, Type2, NE2);
312	{edge_closure, vertex} when ROp =:= '|||' ->
313	    {expr, _, _, R1} =
314		closure_restriction('|', Type1, Type2, OType2, NE1, NE2),
315	    {expr, _, _, R2} =
316		closure_restriction('||', Type1, Type2, OType2, NE1, NE2),
317	    {expr, Type1, edge, {call, intersection, R1, R2}};
318	{edge_closure, vertex} ->
319	    closure_restriction(ROp, Type1, Type2, OType2, NE1, NE2);
320	_ ->
321	    throw_error({type_error, xref_parser:t2s(Expr)})
322    end;
323check_expr(Expr={path, E1, E2}, Table) ->
324    {expr, Type1, OType1a, E1a} = check_expr(E1, Table),
325    {expr, Type2, OType2, E2a} = check_expr(E2, Table),
326    case {Type1, Type2} of
327	{{line, _LineType1}, _Type2} ->
328	    throw_error({type_error, xref_parser:t2s(Expr)});
329	{_Type1, {line, _LineType2}} ->
330	    throw_error({type_error, xref_parser:t2s(Expr)});
331	_Else ->
332	    ok
333    end,
334    E2b = {convert, OType2, Type2, Type1, E2a},
335    {OType1, NE1} = path_arg(OType1a, E1a),
336    NE2 = case {OType1, OType2} of
337	      {path, edge} -> {convert, OType2, edge_closure, E2b};
338	      {path, edge_closure} when Type1 =:= Type2 -> E2b;
339	      _ -> throw_error({type_error, xref_parser:t2s(Expr)})
340	  end,
341    {expr, Type1, path, use_of_closure(path, NE2, NE1)};
342check_expr({regexpr, RExpr, Type0}, _Table) ->
343    %% Using the "universal" variables is not optimal as regards speed,
344    %% but it is simple...
345    Type = what_type(Type0),
346    V = case Type of
347	    function -> v;
348	    module -> 'M';
349	    application -> 'A';
350	    release -> 'R'
351	end,
352    Var = {variable, {predef, V}},
353    Call = {call, fun(E, V2) -> xref_utils:regexpr(E, V2) end,
354	    {constants, RExpr}, Var},
355    {expr, Type, vertex, Call};
356check_expr(C={constant, _Type, _OType, _C}, Table) ->
357    check_constants([C], Table).
358
359path_arg(edge, E={constants, C}) ->
360    case to_external(C) of
361	[{V1,V2}] -> {path, {constants, [V1, V2]}};
362	_ -> {edge, E}
363    end;
364path_arg(OType, E) ->
365    {OType, E}.
366
367check_conversion(OType, Type1, Type2, Expr) ->
368    case conversions(OType, Type1, Type2) of
369	ok -> ok;
370	not_ok -> throw_error({type_error, xref_parser:t2s(Expr)})
371    end.
372
373%% Allowed conversions.
374conversions(_OType, {line, LineType}, {line, LineType}) -> ok;
375conversions(edge, {line, _}, {line, all_line_call}) -> ok;
376conversions(edge, From, {line, Line})
377                 when is_atom(From), Line =/= all_line_call -> ok;
378conversions(vertex, From, {line, line}) when is_atom(From) -> ok;
379conversions(vertex, From, To) when is_atom(From), is_atom(To) -> ok;
380conversions(edge, From, To) when is_atom(From), is_atom(To) -> ok;
381%% "Extra":
382conversions(edge, {line, Line}, To)
383                 when is_atom(To), Line =/= all_line_call -> ok;
384conversions(vertex, {line, line}, To) when is_atom(To) -> ok;
385conversions(_OType, _From, _To) -> not_ok.
386
387set_op(union, {line, _LineType}, edge) -> family_union;
388set_op(intersection, {line, _LineType}, edge) -> family_intersection;
389set_op(difference, {line, _LineType}, edge) -> family_difference;
390set_op(union, function, vertex) -> family_union;
391set_op(intersection, function, vertex) -> family_intersection;
392set_op(difference, function, vertex) -> family_difference;
393set_op(SOp, _Type, _OType) -> SOp.
394
395set_op(weak) -> weak_relation;
396set_op(strict) -> strict_relation;
397set_op(Op) -> Op.
398
399ari_op(union) -> fun(X, Y) -> X + Y end;
400ari_op(intersection) -> fun(X, Y) -> X * Y end;
401ari_op(difference) -> fun(X, Y) -> X - Y end.
402
403restriction(ROp, E1, Type1, NE1, Type2, NE2) ->
404    {Column, _} = restr_op(ROp),
405    case NE1 of
406	{call, union_of_family, _E} when ROp =:= '|' ->
407	    restriction(Column, Type1, E1, Type2, NE2);
408	{call, union_of_family, _E} when ROp =:= '||' ->
409	    E1p = {inverse, E1},
410	    restriction(Column, Type1, E1p, Type2, NE2);
411	_ ->
412	    NE2a = {convert, vertex, Type2, Type1, NE2},
413	    NE2b = family_to_function_vertices(Type1, vertex, NE2a),
414	    {expr, Type1, edge, {call, restriction, Column, NE1, NE2b}}
415    end.
416
417restriction(Column, Type1, VE, Type2, E2) when Type1 =:= function ->
418    M = {convert, vertex, Type2, module, E2},
419    Restr = {call, union_of_family, {call, restriction, VE, M}},
420    C = {convert, vertex, Type2, Type1, E2},
421    F = family_to_function_vertices(Type1, vertex, C),
422    {expr, Type1, edge, {call, restriction, Column, Restr, F}}.
423
424closure_restriction(Op, Type1, Type2, OType2, E1, E2) ->
425    {_, Fun} = restr_op(Op),
426    E2a = {convert, OType2, Type2, Type1, E2},
427    E2b = family_to_function_vertices(Type1, vertex, E2a),
428    {expr, Type1, edge, use_of_closure(Fun, E1, E2b)}.
429
430restr_op('|')  -> {1, call};
431restr_op('||') -> {2, use}.
432
433%% Closures (digraphs) must be deleted, but not too soon. A wrapper
434%% is inserted here for every use of a closure, to make sure that a
435%% 'save' and an 'unput' instruction are inserted for every digraph, in
436%% particular the temporary ones. The 'unput' instruction must occur
437%% _after_ the call to the function that uses the digraph (the default
438%% is that it is inserted _before_ the call).
439use_of_closure(Op, C) ->
440    access_of_closure(C, {call, fun(X) -> xref_utils:Op(X) end, C}).
441
442use_of_closure(Op, C, E) ->
443    access_of_closure(C, {call, fun(X, Y) -> xref_utils:Op(X, Y) end, C, E}).
444
445access_of_closure(C, E) ->
446    {call, fun graph_access/2, C, E}.
447
448check_constants(Cs=[C={constant, Type0, OType, _Con} | Cs1], Table) ->
449    check_mix(Cs1, Type0, OType, C),
450    Types = case Type0 of
451		unknown -> ['Rel', 'App', 'Mod'];
452		T -> [T]
453	    end,
454    case split(Types, Cs, Table) of
455	[{TypeToBe, _Cs}] ->
456            S = from_term([Con || {constant, _T, _OT, Con} <- Cs]),
457	    Type = what_type(TypeToBe),
458	    E = function_vertices_to_family(Type, OType, {constants, S}),
459	    {expr, Type, OType, E};
460	[{Type1, [C1|_]}, {Type2, [C2|_]} | _] ->
461	    throw_error({type_mismatch,
462			 make_vertex(Type1, C1),
463			 make_vertex(Type2, C2)})
464    end.
465
466check_mix([C={constant, 'Fun', OType, _Con} | Cs], 'Fun', OType, _C0) ->
467    check_mix(Cs, 'Fun', OType, C);
468check_mix([C={constant, Type, OType, _Con} | Cs], Type0, OType, _C0)
469         when Type =/= 'Fun', Type0 =/= 'Fun' ->
470    check_mix(Cs, Type, OType, C);
471check_mix([C | _], _Type0, _OType0, C0) ->
472    throw_error({type_mismatch, xref_parser:t2s(C0), xref_parser:t2s(C)});
473check_mix([], _Type0, _OType0, _C0) ->
474    ok.
475
476split(Types, Cs, Table) ->
477    Vs = from_term(constant_vertices(Cs, [])),
478    split(Types, Vs, empty_set(), unknown, Table, []).
479
480split([Type | Types], Vs, AllSoFar, _Type, Table, L) ->
481    S0 = known_vertices(Type, Vs, Table),
482    S = difference(S0, AllSoFar),
483    case is_empty_set(S) of
484	true ->
485	    split(Types, Vs, AllSoFar, Type, Table, L);
486	false ->
487	    All = union(AllSoFar, S0),
488	    split(Types, Vs, All, Type, Table,
489		  [{Type, to_external(S)} | L])
490    end;
491split([], Vs, All, Type, _Table, L) ->
492    case to_external(difference(Vs, All)) of
493	[] -> L;
494	[C|_] -> throw_error({unknown_constant, make_vertex(Type, C)})
495    end.
496
497make_vertex(Type, C) ->
498    xref_parser:t2s({constant, Type, vertex, C}).
499
500constant_vertices([{constant, _Type, edge, {A,B}} | Cs], L) ->
501    constant_vertices(Cs, [A, B | L]);
502constant_vertices([{constant, _Type, vertex, V} | Cs], L) ->
503    constant_vertices(Cs, [V | L]);
504constant_vertices([], L) ->
505    L.
506
507known_vertices('Fun', Cs, T) ->
508    M = projection(1, Cs),
509    F = union_of_family(restriction(fetch_value(v, T), M)),
510    union(bifs(Cs), intersection(Cs, F));
511known_vertices('Mod', Cs, T) ->
512    intersection(Cs, fetch_value('M', T));
513known_vertices('App', Cs, T) ->
514    intersection(Cs, fetch_value('A', T));
515known_vertices('Rel', Cs, T) ->
516    intersection(Cs, fetch_value('R', T)).
517
518bifs(Cs) ->
519    specification({external,
520                   fun({M,F,A}) -> xref_utils:is_builtin(M, F, A) end},
521                  Cs).
522
523function_vertices_to_family(function, vertex, E) ->
524    {call, partition_family, 1, E};
525function_vertices_to_family(_Type, _OType, E) ->
526    E.
527
528family_to_function_vertices(function, vertex, E) ->
529    {call, union_of_family, E};
530family_to_function_vertices(_Type, _OType, E) ->
531    E.
532
533-define(Q(E), {quote, E}).
534
535convert({inverse, {variable, Variable}}) ->
536    {get, {inverse, var_name(Variable)}};
537convert({variable, Variable}) ->
538    {get, var_name(Variable)};
539convert({convert, FromOType, ToOType, E}) ->
540    convert(convert(E), FromOType, ToOType);
541convert({convert, OType, FromType, ToType, E}) ->
542    convert(convert(E), OType, FromType, ToType);
543convert({call, Op, E}) ->
544    {Op, convert(E)};
545convert({call, Op, E1, E2}) ->
546    {Op, convert(E1), convert(E2)};
547convert({call, Op, E1, E2, E3}) ->
548    {Op, convert(E1), convert(E2), convert(E3)};
549convert({constants, Constants}) ->
550    ?Q(Constants);
551convert(I) when is_integer(I) ->
552    ?Q(I).
553
554var_name({predef, VarName}) -> VarName;
555var_name(Variable) -> Variable.
556
557convert(E, OType, OType) ->
558    E;
559convert(E, edge, edge_closure) ->
560    {fun(S) -> xref_utils:closure(S) end, E}.
561
562convert(E, OType, FromType, number) ->
563    un_familiarize(FromType, OType, E);
564convert(E, OType, FromType, ToType) ->
565    case {type_ord(FromType), type_ord(ToType)} of
566        {FT, To} when FT =:= To ->
567            E;
568	{FT, ToT} when FT > ToT ->
569            special(OType, FromType, ToType, E);
570	{FT, ToT} when FT < ToT ->
571            general(OType, FromType, ToType, E)
572    end.
573
574-define(T(V), {tmp, V}).
575
576general(_ObjectType, FromType, ToType, X) when FromType =:= ToType ->
577    X;
578general(edge, {line, _LineType}, ToType, LEs) ->
579    VEs = {projection, ?Q({external, fun({V1V2,_Ls}) -> V1V2 end}), LEs},
580    general(edge, function, ToType, VEs);
581general(edge, function, ToType, VEs) ->
582    MEs = {projection,
583	   ?Q({external, fun({{M1,_,_},{M2,_,_}}) -> {M1,M2} end}),
584	   VEs},
585    general(edge, module, ToType, MEs);
586general(edge, module, ToType, MEs) ->
587    AEs = {image, {get, me2ae}, MEs},
588    general(edge, application, ToType, AEs);
589general(edge, application, release, AEs) ->
590    {image, {get, ae}, AEs};
591general(vertex, {line, _LineType}, ToType, L) ->
592    V = {partition_family, ?Q(1), {domain, L}},
593    general(vertex, function, ToType, V);
594general(vertex, function, ToType, V) ->
595    M = {domain, V},
596    general(vertex, module, ToType, M);
597general(vertex, module, ToType, M) ->
598    A = {image, {get, m2a}, M},
599    general(vertex, application, ToType, A);
600general(vertex, application, release, A) ->
601    {image, {get, a2r}, A}.
602
603special(_ObjectType, FromType, ToType, X) when FromType =:= ToType ->
604    X;
605special(edge, {line, _LineType}, {line, all_line_call}, Calls) ->
606   {put, ?T(mods),
607       {projection,
608	?Q({external, fun({{{M1,_,_},{M2,_,_}},_}) -> {M1,M2} end}),
609	Calls},
610       {put, ?T(def_at),
611           {union, {image, {get, def_at},
612                           {union, {domain, {get, ?T(mods)}},
613                                   {range, {get, ?T(mods)}}}}},
614           {fun funs_to_lines/2,
615	           {get, ?T(def_at)}, Calls}}};
616special(edge, function, {line, LineType}, VEs) ->
617    Var = if
618	      LineType =:= line -> call_at;
619	      LineType =:= export_call -> e_call_at;
620	      LineType =:= local_call -> l_call_at;
621	      LineType =:= external_call -> x_call_at
622	  end,
623    line_edges(VEs, Var);
624special(edge, module, ToType, MEs) ->
625    VEs = {image,
626	   {projection,
627	    ?Q({external, fun(FE={{M1,_,_},{M2,_,_}}) -> {{M1,M2},FE} end}),
628	    {union,
629	     {image, {get, e},
630	      {projection, ?Q({external, fun({M1,_M2}) -> M1 end}), MEs}}}},
631	   MEs},
632    special(edge, function, ToType, VEs);
633special(edge, application, ToType, AEs) ->
634    MEs = {inverse_image, {get, me2ae}, AEs},
635    special(edge, module, ToType, MEs);
636special(edge, release, ToType, REs) ->
637    AEs = {inverse_image, {get, ae}, REs},
638    special(edge, application, ToType, AEs);
639special(vertex, function, {line, _LineType}, V) ->
640    {restriction,
641       {union_of_family, {restriction, {get, def_at}, {domain, V}}},
642       {union_of_family, V}};
643special(vertex, module, ToType, M) ->
644    V = {restriction, {get, v}, M},
645    special(vertex, function, ToType, V);
646special(vertex, application, ToType, A) ->
647    M = {inverse_image, {get, m2a}, A},
648    special(vertex, module, ToType, M);
649special(vertex, release, ToType, R) ->
650    A = {inverse_image, {get, a2r}, R},
651    special(vertex, application, ToType, A).
652
653line_edges(VEs, CallAt) ->
654    {put, ?T(ves), VEs,
655        {put, ?T(m1),
656             {projection, ?Q({external, fun({{M1,_,_},_}) -> M1 end}),
657	      {get, ?T(ves)}},
658	     {image, {projection, ?Q({external, fun(C={VV,_L}) -> {VV,C} end}),
659		      {union, {image, {get, CallAt}, {get, ?T(m1)}}}},
660		     {get, ?T(ves)}}}}.
661
662%% {(((v1,l1),(v2,l2)),l) :
663%%       (v1,l1) in DefAt and (v2,l2) in DefAt and ((v1,v2),L) in CallAt}
664funs_to_lines(DefAt, CallAt) ->
665    T1 = multiple_relative_product({DefAt, DefAt}, projection(1, CallAt)),
666    T2 = composite(substitution(1, T1), CallAt),
667    Fun = fun({{{V1,V2},{L1,L2}},Ls}) -> {{{V1,L1},{V2,L2}},Ls} end,
668    projection({external, Fun}, T2).
669
670what_type('Rel')         -> release;
671what_type('App')         -> application;
672what_type('Mod')         -> module;
673what_type('Fun')         -> function;
674what_type('Lin')         -> {line, line};
675what_type('LLin')        -> {line, local_call};
676what_type('XLin')        -> {line, external_call};
677what_type('ELin')        -> {line, export_call};
678what_type('XXL')         -> {line, all_line_call}.
679
680type_ord({line, all_line_call}) -> 0;
681type_ord({line, _LT})           -> 1;
682type_ord(function)              -> 2;
683type_ord(module)                -> 3;
684type_ord(application)           -> 4;
685type_ord(release)               -> 5.
686
687%% While evaluating, sets of vertices are represented as families.
688%% Sets of edges are not families, but plain sets (this might change).
689%% Calls (with line numbers) are "straightened" out here, but will be
690%% families again shortly, unless just counted.
691un_familiarize(function, vertex, E) ->
692    {union_of_family, E};
693un_familiarize({line, _}, edge, E) ->
694    {family_to_relation, E};
695un_familiarize(_Type, _OType, E) ->
696    E.
697
698%% Expressions are evaluated using a stack and tail recursion.
699%% Common subexpressions are evaluated once only, using a table for
700%% storing temporary results.
701%% (Using a table _and_ a stack is perhaps not a very good way of
702%% doing things.)
703i(E, Table) ->
704    Start = 1,
705    {N, _NE, _NI, NT} = find_nodes(E, Start, dict:new()),
706    {Vs, UVs0, L} = save_vars(dict:to_list(NT), NT, [], [], []),
707
708    VarsToSave = to_external(relation_to_family(relation(Vs))),
709    Fun = fun({NN,S}, D) ->
710		  dict:store(NN, {extra,S,dict:fetch(NN, D)}, D)
711	  end,
712    D = foldl(Fun, dict:from_list(L), VarsToSave),
713
714    UVs = reverse(sort(UVs0)),
715    {_D, Is0} = make_instructions(N, UVs, D),
716    Is = insert_unput(Is0),
717    ?FORMAT("Instructions:~n~p~n~n~n", [Is]),
718    %% Well, compiles _and_ evaluates...
719    evaluate(Is, Table, []).
720
721%% Traverses the expression tree in postorder, giving a unique number
722%% to each node. A table is created, and common subexpressions found.
723find_nodes(E={quote,_}, I, T) ->
724    find_node(E, I, T);
725find_nodes({get, Var}, I, T) ->
726    find_node({var,Var}, I, T);
727find_nodes({put, Var, E1, E2}, I, T) ->
728    {_NE1_N, NE1, I1, T1} = find_nodes(E1, I, T),
729    %% Now NE1 is considered used once, which is wrong. Fixed below.
730    NT = dict:store({var, Var}, NE1, T1),
731    find_nodes(E2, I1, NT);
732find_nodes(Tuple, I, T) when is_tuple(Tuple) ->
733    [Tag0 | L] = tuple_to_list(Tuple),
734    Fun = fun(A, {L0, I0, T0}) ->
735		  {NA, _E, NI, NT} = find_nodes(A, I0, T0),
736		  {[NA | L0], NI, NT}
737	  end,
738    {NL, NI, T1} = foldl(Fun, {[], I, T}, L),
739    Tag = case Tag0 of
740	      _ when is_function(Tag0) ->
741		  Tag0;
742	      _ when is_atom(Tag0) ->
743		  Arity = length(NL),
744		  fun sofs:Tag0/Arity
745	  end,
746    find_node({apply, Tag, NL}, NI, T1).
747
748find_node(E, I, T) ->
749    case dict:find(E, T) of
750        {ok, {reuse, N}} ->
751	    {N, E, I, T};
752	{ok, N} when is_integer(N) ->
753	    {N, E, I, dict:store(E, {reuse, N}, T)};
754	{ok, E1} ->
755	    find_node(E1, I, T);
756	error ->
757 	    {I, E, I+1, dict:store(E, I, T)}
758    end.
759
760%% Creates save instructions for those values (stored on the stack while
761%% evaluating) that are to be used after the result has been popped.
762save_vars([{I, {reuse,N}} | DL], D, Vs, UVs, L) ->
763    save_vars(DL, D, [{N, {save, {tmp, N}}} | Vs], UVs, [{N, I} | L]);
764save_vars([{I, N} | DL], D, Vs, UVs, L) when is_integer(N) ->
765    save_vars(DL, D, Vs, UVs, [{N, I} | L]);
766save_vars([{{var,V={user,_}}, I} | DL], D, Vs, UVs, L) ->
767    N = case dict:fetch(I, D) of
768	    {reuse, N0} -> N0;
769	    N0 -> N0
770	end,
771    save_vars(DL, D, [{N, {save, V}} | Vs], [N | UVs], L);
772save_vars([{{var,{tmp,_}}, _I} | DL], D, Vs, UVs, L) ->
773    save_vars(DL, D, Vs, UVs, L);
774save_vars([], _D, Vs, UVs, L) ->
775    {Vs, UVs, L}.
776
777%% Traverses the expression again, this time using more or less the
778%% inverse of the table created by find_nodes. The first time a node
779%% is visited, its children are traversed, the following times a
780%% get instructions are inserted (using the saved value).
781make_instructions(N, UserVars, D) ->
782    {D1, Is0} = make_instrs(N, D, []),
783    %% Assignments the results of which are not used by the final
784    %% expression are handled here. Instructions are created for user
785    %% variables only (assignment of a closure is handled properly
786    %% without further action).
787    make_more_instrs(UserVars, D1, Is0).
788
789make_more_instrs([UV | UVs], D, Is) ->
790    case dict:find(UV, D) of
791	error ->
792	    make_more_instrs(UVs, D, Is);
793	_Else ->
794	    {ND, NIs} = make_instrs(UV, D, Is),
795	    make_more_instrs(UVs, ND, [pop | NIs])
796    end;
797make_more_instrs([], D, Is) ->
798    {D, Is}.
799
800make_instrs(N, D, Is) ->
801    case dict:find(N, D) of
802	{ok, {extra, Save, Val}} ->
803	    {D1, Is1} = make_instr(Val, D, Is),
804	    {dict:erase(N, D1), Save ++ Is1};
805	{ok, Val} ->
806	    {D1, Is1} = make_instr(Val, D, Is),
807	    {dict:erase(N, D1), Is1};
808	error ->
809	    {D, [{get, {tmp, N}} | Is]}
810    end.
811
812make_instr({var, V}, D, Is) ->
813    {D, [{get, V} | Is]};
814make_instr(Q = {quote, _T}, D, Is) ->
815    {D, [Q | Is]};
816make_instr({apply, MF, Ns}, D, Is) ->
817    Fun = fun(N, {D0, Is0}) -> make_instrs(N, D0, Is0) end,
818    {D1, Is1} = foldl(Fun, {D, Is}, Ns),
819    {D1, [{apply, MF, length(Ns)} | Is1]}.
820
821%% Makes sure that temporary results are removed from the table as soon
822%% as they are no longer needed.
823%% Assignments may create extra save instructions, which are removed here.
824insert_unput(L) ->
825    insert_unput(L, dict:new(), []).
826
827insert_unput([I={get, V={tmp, _}} | Is], D, L) ->
828    case dict:find(V, D) of
829        {ok, _} -> insert_unput(Is, D, [I | L]);
830        error ->   insert_unput(Is, dict:store(V, [], D), [I,  {unput, V} | L])
831    end;
832insert_unput([I={save, V={tmp,_}} | Is], D, L) ->
833    case dict:find(V, D) of
834	{ok, _} ->
835	    insert_unput(Is, dict:erase(V, D), [I | L]);
836	error ->
837	    %% Extra save removed.
838	    insert_unput(Is, dict:erase(V, D), L)
839    end;
840insert_unput([I | Is], D, L) ->
841    insert_unput(Is, D, [I | L]);
842insert_unput([], _D, L) ->
843    L.
844
845graph_access(_G, V) ->
846    %% _G may have been deleted by an unput already
847    V.
848
849evaluate([{apply, MF, NoAs} | P], T, S) ->
850    Args = sublist(S, NoAs),
851    NewS = nthtail(NoAs, S),
852    ?FORMAT("Applying ~p/~p~n", [MF,NoAs]),
853    evaluate(P, T, [apply(MF, Args) | NewS]);
854evaluate([{quote, Val} | P], T, S) ->
855    evaluate(P, T, [Val | S]);
856evaluate([{get, Var} | P], T, S) when is_atom(Var) -> % predefined
857    Value = fetch_value(Var, T),
858    Val = case Value of
859	      {R, _} -> R; % relation
860	      _ -> Value   % simple set
861	  end,
862    evaluate(P, T, [Val | S]);
863evaluate([{get, {inverse, Var}} | P], T, S) -> % predefined, inverse
864    {_, R} = fetch_value(Var, T),
865    evaluate(P, T, [R | S]);
866evaluate([{get, {user, Var}} | P], T, S) ->
867    Val = fetch_value(Var, T),
868    evaluate(P, T, [Val | S]);
869evaluate([{get, Var} | P], T, S) -> % tmp
870    evaluate(P, T, [dict:fetch(Var, T) | S]);
871evaluate([{save, Var={tmp, _}} | P], T, S=[Val | _]) ->
872    T1 = update_graph_counter(Val, +1, T),
873    evaluate(P, dict:store(Var, Val, T1), S);
874evaluate([{save, {user, Name}} | P], T, S=[Val | _]) ->
875    #xref_var{vtype = user, otype = OType, type = Type} = dict:fetch(Name, T),
876    NewVar = #xref_var{name = Name, value = Val,
877		       vtype = user, otype = OType, type = Type},
878    T1 = update_graph_counter(Val, +1, T),
879    NT = dict:store(Name, NewVar, T1),
880    evaluate(P, NT, S);
881evaluate([{unput, Var} | P], T, S) ->
882    T1 = update_graph_counter(dict:fetch(Var, T), -1, T),
883    evaluate(P, dict:erase(Var, T1), S);
884evaluate([pop | P], T, [_ | S]) ->
885    evaluate(P, T, S);
886evaluate([], T, [R]) ->
887    {T, R}.
888
889%% (PossibleGraph, 1 | -1, dict:dict()) -> dict:dict()
890%% Use the same table for everything... Here: Reference counters for digraphs.
891update_graph_counter(Value, Inc, T) ->
892    case catch digraph:info(Value) of
893	Info when is_list(Info) ->
894	    case dict:find(Value, T) of
895		{ok, 1} when Inc =:= -1 ->
896		    true = digraph:delete(Value),
897		    dict:erase(Value, T);
898		{ok, C} ->
899		    dict:store(Value, C+Inc, T);
900		error when Inc =:= 1 ->
901		    dict:store(Value, 1, T)
902	    end;
903	_EXIT ->
904	    T
905    end.
906
907fetch_value(V, D) ->
908    #xref_var{value = Value} = dict:fetch(V, D),
909    Value.
910
911format_parse_error(["invalid_regexp", String, Error], Line) ->
912    io_lib:format("Invalid regular expression \"~ts\"~s: ~ts~n",
913		  [String, Line, lists:flatten(Error)]);
914format_parse_error(["invalid_regexp_variable", Var], Line) ->
915    io_lib:format("Invalid wildcard variable ~tp~s "
916		  "(only '_' is allowed)~n", [Var, Line]);
917format_parse_error(["missing_type", Expr], Line) ->
918    io_lib:format("Missing type of regular expression ~ts~s~n",
919		  [Expr, Line]);
920format_parse_error(["type_mismatch", Expr], Line) ->
921    io_lib:format("Type does not match structure of constant~s: ~ts~n",
922		  [Line, Expr]);
923format_parse_error(["invalid_operator", Op], Line) ->
924    io_lib:format("Invalid operator ~tp~s~n", [Op, Line]);
925format_parse_error(Error, Line) ->
926    io_lib:format("Parse error~s: ~ts~n", [Line, lists:flatten(Error)]).
927
928format_line(?XREF_END_LINE) ->
929    " at end of string";
930format_line(0) ->
931    "";
932format_line(Line) when is_integer(Line) ->
933    concat([" on line ", Line]).
934
935throw_error(Reason) ->
936    throw(error(Reason)).
937
938error(Reason) ->
939    {error, ?MODULE, Reason}.
940