4
%% Copyright Ericsson AB 2000-2009. All Rights Reserved.
4
%% Copyright Ericsson AB 2000-2010. All Rights Reserved.
6
6
%% The contents of this file are subject to the Erlang Public License,
7
7
%% Version 1.1, (the "License"); you may not use this file except in
8
8
%% compliance with the License. You should have received a copy of the
9
9
%% Erlang Public License along with this software. If not, it can be
10
10
%% retrieved online at http://www.erlang.org/.
12
12
%% Software distributed under the License is distributed on an "AS IS"
13
13
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
14
14
%% the License for the specific language governing rights and limitations
15
15
%% under the License.
31
31
-define(CALL(F), ok).
34
%% Avoid warning for local function error/1 clashing with autoimported BIF.
35
-compile({no_auto_import,[error/1]}).
34
36
-export([compile/2]).
36
38
-export([update_graph_counter/3]).
38
40
-export([format_error/1]).
41
43
[concat/1, foldl/3, nthtail/2, reverse/1, sort/1, sublist/2]).
44
46
[composite/2, difference/2, empty_set/0, from_term/1,
45
47
intersection/2, is_empty_set/1, multiple_relative_product/2,
46
48
projection/2, relation/1, relation_to_family/1,
47
restriction/2, substitution/2, to_external/1, union/2,
49
restriction/2, specification/2, substitution/2,
50
to_external/1, union/2, union_of_family/1]).
51
53
%% Exported functions
75
77
{error, Info, Line} ->
76
78
error({parse_error, Line, Info})
79
81
format_error({error, Module, Error}) ->
80
82
Module:format_error(Error);
81
83
format_error({parse_error, Line, Error}) ->
115
117
throw_error({variable_reassigned, xref_parser:t2s(Stmt)});
117
119
{Type, OType, NewE} = t_expr(E, Table),
118
Val = #xref_var{name = Name, vtype = VarType,
120
Val = #xref_var{name = Name, vtype = VarType,
119
121
otype = OType, type = Type},
120
122
NewTable = dict:store(Name, Val, Table),
121
123
Stmts = if Stmts0 =:= [] -> [{variable, Name}]; true -> Stmts0 end,
128
130
E1 = un_familiarize(Type, OType, NewE),
129
131
NE = case {Type, OType} of
130
132
%% Edges with empty sets of line numbers are removed.
132
134
{relation_to_family, E1};
133
{_Type, edge_closure} ->
135
{_Type, edge_closure} ->
134
136
%% Fake a closure usage, just to make sure it is destroyed.
135
137
E2 = {fun graph_access/2, E1, E1},
136
138
{fun(_E) -> 'closure()' end, E2};
163
165
%%% Constant = atom() | {atom(), atom()} | MFA | {MFA, MFA}
164
166
%%% Call = atom() % function in the sofs module
166
%%% Type = {line, LineType} | function | module | application | release
168
%%% Type = {line, LineType} | function | module | application | release
168
170
%%% LineType = line | local_call | external_call | export_call | all_line_call
169
171
%%% VarType = predef | user | tmp
182
184
case dict:find(Name, Table) of
183
185
{ok, #xref_var{vtype = VarType, otype = OType, type = Type}} ->
184
186
V0 = {variable, {VarType, Name}},
185
V = case {VarType, Type, OType} of
187
V = case {VarType, Type, OType} of
186
188
{predef, release, _} -> V0;
187
189
{predef, application, _} -> V0;
188
190
{predef, module, _} -> V0;
212
214
{edge_set, domain} -> vertex_set;
213
215
{edge_set, weak} -> edge_set;
214
216
{edge_set, strict} -> edge_set;
216
218
throw_error({type_error, xref_parser:t2s(Expr)})
218
220
Op = set_op(SOp),
224
226
{line, _LineType} ->
225
227
throw_error({type_error, xref_parser:t2s(Expr)});
230
232
case {NOType, Op} of
231
233
{edge, components} -> vertex_set;
232
234
{edge, condensation} -> edge_set;
237
239
%% Neither need nor want these ones:
238
240
%% {edge_set, closure} -> edge_set_closure;
239
241
%% {edge_set, components} -> vertex_set_set;
241
243
throw_error({type_error, xref_parser:t2s(Expr)})
243
245
E2 = {convert, NOType, edge_closure, E1},
272
274
{expr, number, number, {call, ari_op(SOp), NE1, NE2}};
274
{Type, NewE1, NewE2} =
276
{Type, NewE1, NewE2} =
275
277
case {type_ord(Type1), type_ord(Type2)} of
276
278
{T1, T2} when T1 =:= T2 ->
277
%% Example: if Type1 = {line, line} and
279
%% Example: if Type1 = {line, line} and
278
280
%% Type2 = {line, export_line}, then this is not
279
281
%% correct, but works:
280
282
{Type1, NE1, NE2};
296
298
throw_error({type_error, xref_parser:t2s(Expr)});
297
299
{_Type1, {line, _LineType2}} ->
298
300
throw_error({type_error, xref_parser:t2s(Expr)});
302
304
case {OType1, OType2} of
307
309
{edge, vertex} ->
308
310
restriction(ROp, E1, Type1, NE1, Type2, NE2);
309
311
{edge_closure, vertex} when ROp =:= '|||' ->
311
313
closure_restriction('|', Type1, Type2, OType2, NE1, NE2),
313
315
closure_restriction('||', Type1, Type2, OType2, NE1, NE2),
314
316
{expr, Type1, edge, {call, intersection, R1, R2}};
315
{edge_closure, vertex} ->
317
{edge_closure, vertex} ->
316
318
closure_restriction(ROp, Type1, Type2, OType2, NE1, NE2);
318
320
throw_error({type_error, xref_parser:t2s(Expr)})
320
322
check_expr(Expr={path, E1, E2}, Table) ->
331
333
E2b = {convert, OType2, Type2, Type1, E2a},
332
334
{OType1, NE1} = path_arg(OType1a, E1a),
333
NE2 = case {OType1, OType2} of
335
NE2 = case {OType1, OType2} of
334
336
{path, edge} -> {convert, OType2, edge_closure, E2b};
335
337
{path, edge_closure} when Type1 =:= Type2 -> E2b;
336
338
_ -> throw_error({type_error, xref_parser:t2s(Expr)})
349
351
Var = {variable, {predef, V}},
350
Call = {call, fun(E, V2) -> xref_utils:regexpr(E, V2) end,
352
Call = {call, fun(E, V2) -> xref_utils:regexpr(E, V2) end,
351
353
{constants, RExpr}, Var},
352
354
{expr, Type, vertex, Call};
353
355
check_expr(C={constant, _Type, _OType, _C}, Table) ->
370
372
%% Allowed conversions.
371
conversions(_OType, {line, LineType}, {line, LineType}) -> ok;
373
conversions(_OType, {line, LineType}, {line, LineType}) -> ok;
372
374
conversions(edge, {line, _}, {line, all_line_call}) -> ok;
373
conversions(edge, From, {line, Line})
375
conversions(edge, From, {line, Line})
374
376
when is_atom(From), Line =/= all_line_call -> ok;
375
377
conversions(vertex, From, {line, line}) when is_atom(From) -> ok;
376
378
conversions(vertex, From, To) when is_atom(From), is_atom(To) -> ok;
377
379
conversions(edge, From, To) when is_atom(From), is_atom(To) -> ok;
379
conversions(edge, {line, Line}, To)
381
conversions(edge, {line, Line}, To)
380
382
when is_atom(To), Line =/= all_line_call -> ok;
381
383
conversions(vertex, {line, line}, To) when is_atom(To) -> ok;
382
384
conversions(_OType, _From, _To) -> not_ok.
400
402
restriction(ROp, E1, Type1, NE1, Type2, NE2) ->
401
403
{Column, _} = restr_op(ROp),
403
405
{call, union_of_family, _E} when ROp =:= '|' ->
404
406
restriction(Column, Type1, E1, Type2, NE2);
405
407
{call, union_of_family, _E} when ROp =:= '||' ->
455
457
E = function_vertices_to_family(Type, OType, {constants, S}),
456
458
{expr, Type, OType, E};
457
459
[{Type1, [C1|_]}, {Type2, [C2|_]} | _] ->
458
throw_error({type_mismatch,
459
make_vertex(Type1, C1),
460
throw_error({type_mismatch,
461
make_vertex(Type1, C1),
460
462
make_vertex(Type2, C2)})
467
469
check_mix(Cs, Type, OType, C);
468
470
check_mix([C | _], _Type0, _OType0, C0) ->
469
471
throw_error({type_mismatch, xref_parser:t2s(C0), xref_parser:t2s(C)});
470
check_mix([], _Type0, _OType0, _C0) ->
472
check_mix([], _Type0, _OType0, _C0) ->
473
475
split(Types, Cs, Table) ->
478
480
S0 = known_vertices(Type, Vs, Table),
479
481
S = difference(S0, AllSoFar),
480
482
case is_empty_set(S) of
482
484
split(Types, Vs, AllSoFar, Type, Table, L);
484
486
All = union(AllSoFar, S0),
485
split(Types, Vs, All, Type, Table,
487
split(Types, Vs, All, Type, Table,
486
488
[{Type, to_external(S)} | L])
488
490
split([], Vs, All, Type, _Table, L) ->
491
493
[C|_] -> throw_error({unknown_constant, make_vertex(Type, C)})
494
make_vertex(Type, C) ->
496
make_vertex(Type, C) ->
495
497
xref_parser:t2s({constant, Type, vertex, C}).
497
499
constant_vertices([{constant, _Type, edge, {A,B}} | Cs], L) ->
504
506
known_vertices('Fun', Cs, T) ->
505
507
M = projection(1, Cs),
506
508
F = union_of_family(restriction(fetch_value(v, T), M)),
509
union(bifs(Cs), intersection(Cs, F));
508
510
known_vertices('Mod', Cs, T) ->
509
511
intersection(Cs, fetch_value('M', T));
510
512
known_vertices('App', Cs, T) ->
512
514
known_vertices('Rel', Cs, T) ->
513
515
intersection(Cs, fetch_value('R', T)).
518
specification({external,
519
fun({M,F,A}) -> xref_utils:is_builtin(M, F, A) end},
515
522
function_vertices_to_family(function, vertex, E) ->
516
523
{call, partition_family, 1, E};
517
524
function_vertices_to_family(_Type, _OType, E) ->
568
575
general(_ObjectType, FromType, ToType, X) when FromType =:= ToType ->
570
general(edge, {line, _LineType}, ToType, LEs) ->
577
general(edge, {line, _LineType}, ToType, LEs) ->
571
578
VEs = {projection, ?Q({external, fun({V1V2,_Ls}) -> V1V2 end}), LEs},
572
579
general(edge, function, ToType, VEs);
573
580
general(edge, function, ToType, VEs) ->
575
582
?Q({external, fun({{M1,_,_},{M2,_,_}}) -> {M1,M2} end}),
577
584
general(edge, module, ToType, MEs);
580
587
general(edge, application, ToType, AEs);
581
588
general(edge, application, release, AEs) ->
582
589
{image, {get, ae}, AEs};
583
general(vertex, {line, _LineType}, ToType, L) ->
590
general(vertex, {line, _LineType}, ToType, L) ->
584
591
V = {partition_family, ?Q(1), {domain, L}},
585
592
general(vertex, function, ToType, V);
586
593
general(vertex, function, ToType, V) ->
595
602
special(_ObjectType, FromType, ToType, X) when FromType =:= ToType ->
597
604
special(edge, {line, _LineType}, {line, all_line_call}, Calls) ->
600
?Q({external, fun({{{M1,_,_},{M2,_,_}},_}) -> {M1,M2} end}),
607
?Q({external, fun({{{M1,_,_},{M2,_,_}},_}) -> {M1,M2} end}),
603
610
{union, {image, {get, def_at},
604
{union, {domain, {get, ?T(mods)}},
611
{union, {domain, {get, ?T(mods)}},
605
612
{range, {get, ?T(mods)}}}}},
606
613
{fun funs_to_lines/2,
607
614
{get, ?T(def_at)}, Calls}}};
608
615
special(edge, function, {line, LineType}, VEs) ->
610
617
LineType =:= line -> call_at;
611
618
LineType =:= export_call -> e_call_at;
612
619
LineType =:= local_call -> l_call_at;
615
622
line_edges(VEs, Var);
616
623
special(edge, module, ToType, MEs) ->
619
626
?Q({external, fun(FE={{M1,_,_},{M2,_,_}}) -> {{M1,M2},FE} end}),
621
628
{image, {get, e},
622
629
{projection, ?Q({external, fun({M1,_M2}) -> M1 end}), MEs}}}},
629
636
AEs = {inverse_image, {get, ae}, REs},
630
637
special(edge, application, ToType, AEs);
631
638
special(vertex, function, {line, _LineType}, V) ->
633
640
{union_of_family, {restriction, {get, def_at}, {domain, V}}},
634
641
{union_of_family, V}};
635
642
special(vertex, module, ToType, M) ->
643
650
special(vertex, application, ToType, A).
645
652
line_edges(VEs, CallAt) ->
648
{projection, ?Q({external, fun({{M1,_,_},_}) -> M1 end}),
655
{projection, ?Q({external, fun({{M1,_,_},_}) -> M1 end}),
650
657
{image, {projection, ?Q({external, fun(C={VV,_L}) -> {VV,C} end}),
651
658
{union, {image, {get, CallAt}, {get, ?T(m1)}}}},
652
659
{get, ?T(ves)}}}}.
654
%% {(((v1,l1),(v2,l2)),l) :
661
%% {(((v1,l1),(v2,l2)),l) :
655
662
%% (v1,l1) in DefAt and (v2,l2) in DefAt and ((v1,v2),L) in CallAt}
656
663
funs_to_lines(DefAt, CallAt) ->
657
664
T1 = multiple_relative_product({DefAt, DefAt}, projection(1, CallAt)),
766
773
%% Traverses the expression again, this time using more or less the
767
774
%% inverse of the table created by find_nodes. The first time a node
768
%% is visited, its children are traversed, the following times a
775
%% is visited, its children are traversed, the following times a
769
776
%% get instructions are inserted (using the saved value).
770
777
make_instructions(N, UserVars, D) ->
771
778
{D1, Is0} = make_instrs(N, D, []),
778
785
make_more_instrs([UV | UVs], D, Is) ->
779
786
case dict:find(UV, D) of
781
788
make_more_instrs(UVs, D, Is);
783
790
{ND, NIs} = make_instrs(UV, D, Is),
784
791
make_more_instrs(UVs, ND, [pop | NIs])
844
851
evaluate(P, T, [Val | S]);
845
852
evaluate([{get, Var} | P], T, S) when is_atom(Var) -> % predefined
846
853
Value = fetch_value(Var, T),
848
855
{R, _} -> R; % relation
849
856
_ -> Value % simple set
851
evaluate(P, T, [Val | S]);
858
evaluate(P, T, [Val | S]);
852
859
evaluate([{get, {inverse, Var}} | P], T, S) -> % predefined, inverse
853
860
{_, R} = fetch_value(Var, T),
854
evaluate(P, T, [R | S]);
861
evaluate(P, T, [R | S]);
855
862
evaluate([{get, {user, Var}} | P], T, S) ->
856
863
Val = fetch_value(Var, T),
857
evaluate(P, T, [Val | S]);
864
evaluate(P, T, [Val | S]);
858
865
evaluate([{get, Var} | P], T, S) -> % tmp
859
866
evaluate(P, T, [dict:fetch(Var, T) | S]);
860
867
evaluate([{save, Var={tmp, _}} | P], T, S=[Val | _]) ->
862
869
evaluate(P, dict:store(Var, Val, T1), S);
863
870
evaluate([{save, {user, Name}} | P], T, S=[Val | _]) ->
864
871
#xref_var{vtype = user, otype = OType, type = Type} = dict:fetch(Name, T),
865
NewVar = #xref_var{name = Name, value = Val,
872
NewVar = #xref_var{name = Name, value = Val,
866
873
vtype = user, otype = OType, type = Type},
867
874
T1 = update_graph_counter(Val, +1, T),
868
875
NT = dict:store(Name, NewVar, T1),