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