1%% ===================================================================== 2%% Licensed under the Apache License, Version 2.0 (the "License"); you may 3%% not use this file except in compliance with the License. You may obtain 4%% a copy of the License at <http://www.apache.org/licenses/LICENSE-2.0> 5%% 6%% Unless required by applicable law or agreed to in writing, software 7%% distributed under the License is distributed on an "AS IS" BASIS, 8%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9%% See the License for the specific language governing permissions and 10%% limitations under the License. 11%% 12%% Alternatively, you may use this file under the terms of the GNU Lesser 13%% General Public License (the "LGPL") as published by the Free Software 14%% Foundation; either version 2.1, or (at your option) any later version. 15%% If you wish to allow use of your version of this file only under the 16%% terms of the LGPL, you should delete the provisions above and replace 17%% them with the notice and other provisions required by the LGPL; see 18%% <http://www.gnu.org/licenses/>. If you do not delete the provisions 19%% above, a recipient may use your version of this file under the terms of 20%% either the Apache License or the LGPL. 21%% 22%% @copyright 1997-2006 Richard Carlsson 23%% @author Richard Carlsson <carlsson.richard@gmail.com> 24%% @end 25%% ===================================================================== 26 27%% @doc Support library for abstract Erlang syntax trees. 28%% 29%% This module contains utility functions for working with the 30%% abstract data type defined in the module {@link erl_syntax}. 31%% 32%% @type syntaxTree() = erl_syntax:syntaxTree(). An abstract syntax 33%% tree. See the {@link erl_syntax} module for details. 34 35-module(erl_syntax_lib). 36 37-export([analyze_application/1, analyze_attribute/1, 38 analyze_export_attribute/1, analyze_file_attribute/1, 39 analyze_form/1, analyze_forms/1, analyze_function/1, 40 analyze_function_name/1, analyze_implicit_fun/1, 41 analyze_import_attribute/1, analyze_module_attribute/1, 42 analyze_record_attribute/1, analyze_record_expr/1, 43 analyze_record_field/1, analyze_wild_attribute/1, annotate_bindings/1, 44 analyze_type_application/1, analyze_type_name/1, 45 annotate_bindings/2, fold/3, fold_subtrees/3, foldl_listlist/3, 46 function_name_expansions/1, is_fail_expr/1, limit/2, limit/3, 47 map/2, map_subtrees/2, mapfold/3, mapfold_subtrees/3, 48 mapfoldl_listlist/3, new_variable_name/1, new_variable_name/2, 49 new_variable_names/2, new_variable_names/3, strip_comments/1, 50 to_comment/1, to_comment/2, to_comment/3, variables/1]). 51 52-export_type([info_pair/0]). 53 54%% ===================================================================== 55%% @spec map(Function, Tree::syntaxTree()) -> syntaxTree() 56%% 57%% Function = (syntaxTree()) -> syntaxTree() 58%% 59%% @doc Applies a function to each node of a syntax tree. The result of 60%% each application replaces the corresponding original node. The order 61%% of traversal is bottom-up. 62%% 63%% @see map_subtrees/2 64 65-spec map(fun((erl_syntax:syntaxTree()) -> erl_syntax:syntaxTree()), 66 erl_syntax:syntaxTree()) -> erl_syntax:syntaxTree(). 67 68map(F, Tree) -> 69 case erl_syntax:subtrees(Tree) of 70 [] -> 71 F(Tree); 72 Gs -> 73 Tree1 = erl_syntax:make_tree(erl_syntax:type(Tree), 74 [[map(F, T) || T <- G] 75 || G <- Gs]), 76 F(erl_syntax:copy_attrs(Tree, Tree1)) 77 end. 78 79 80%% ===================================================================== 81%% @spec map_subtrees(Function, syntaxTree()) -> syntaxTree() 82%% 83%% Function = (Tree) -> Tree1 84%% 85%% @doc Applies a function to each immediate subtree of a syntax tree. 86%% The result of each application replaces the corresponding original 87%% node. 88%% 89%% @see map/2 90 91-spec map_subtrees(fun((erl_syntax:syntaxTree()) -> erl_syntax:syntaxTree()), 92 erl_syntax:syntaxTree()) -> erl_syntax:syntaxTree(). 93 94map_subtrees(F, Tree) -> 95 case erl_syntax:subtrees(Tree) of 96 [] -> 97 Tree; 98 Gs -> 99 Tree1 = erl_syntax:make_tree(erl_syntax:type(Tree), 100 [[F(T) || T <- G] || G <- Gs]), 101 erl_syntax:copy_attrs(Tree, Tree1) 102 end. 103 104 105%% ===================================================================== 106%% @spec fold(Function, Start::term(), Tree::syntaxTree()) -> term() 107%% 108%% Function = (syntaxTree(), term()) -> term() 109%% 110%% @doc Folds a function over all nodes of a syntax tree. The result is 111%% the value of `Function(X1, Function(X2, ... Function(Xn, Start) 112%% ... ))', where `[X1, X2, ..., Xn]' are the nodes of 113%% `Tree' in a post-order traversal. 114%% 115%% @see fold_subtrees/3 116%% @see foldl_listlist/3 117 118-spec fold(fun((erl_syntax:syntaxTree(), term()) -> term()), 119 term(), erl_syntax:syntaxTree()) -> term(). 120 121fold(F, S, Tree) -> 122 case erl_syntax:subtrees(Tree) of 123 [] -> 124 F(Tree, S); 125 Gs -> 126 F(Tree, fold_1(F, S, Gs)) 127 end. 128 129fold_1(F, S, [L | Ls]) -> 130 fold_1(F, fold_2(F, S, L), Ls); 131fold_1(_, S, []) -> 132 S. 133 134fold_2(F, S, [T | Ts]) -> 135 fold_2(F, fold(F, S, T), Ts); 136fold_2(_, S, []) -> 137 S. 138 139 140%% ===================================================================== 141%% @spec fold_subtrees(Function, Start::term(), Tree::syntaxTree()) -> 142%% term() 143%% 144%% Function = (syntaxTree(), term()) -> term() 145%% 146%% @doc Folds a function over the immediate subtrees of a syntax tree. 147%% This is similar to `fold/3', but only on the immediate 148%% subtrees of `Tree', in left-to-right order; it does not 149%% include the root node of `Tree'. 150%% 151%% @see fold/3 152 153-spec fold_subtrees(fun((erl_syntax:syntaxTree(), term()) -> term()), 154 term(), erl_syntax:syntaxTree()) -> term(). 155 156fold_subtrees(F, S, Tree) -> 157 foldl_listlist(F, S, erl_syntax:subtrees(Tree)). 158 159 160%% ===================================================================== 161%% @spec foldl_listlist(Function, Start::term(), [[term()]]) -> term() 162%% 163%% Function = (term(), term()) -> term() 164%% 165%% @doc Like `lists:foldl/3', but over a list of lists. 166%% 167%% @see fold/3 168%% @see //stdlib/lists:foldl/3 169 170-spec foldl_listlist(fun((term(), term()) -> term()), 171 term(), [[term()]]) -> term(). 172 173foldl_listlist(F, S, [L | Ls]) -> 174 foldl_listlist(F, foldl(F, S, L), Ls); 175foldl_listlist(_, S, []) -> 176 S. 177 178foldl(F, S, [T | Ts]) -> 179 foldl(F, F(T, S), Ts); 180foldl(_, S, []) -> 181 S. 182 183 184%% ===================================================================== 185%% @spec mapfold(Function, Start::term(), Tree::syntaxTree()) -> 186%% {syntaxTree(), term()} 187%% 188%% Function = (syntaxTree(), term()) -> {syntaxTree(), term()} 189%% 190%% @doc Combines map and fold in a single operation. This is similar to 191%% `map/2', but also propagates an extra value from each 192%% application of the `Function' to the next, while doing a 193%% post-order traversal of the tree like `fold/3'. The value 194%% `Start' is passed to the first function application, and 195%% the final result is the result of the last application. 196%% 197%% @see map/2 198%% @see fold/3 199 200-spec mapfold(fun((erl_syntax:syntaxTree(), term()) -> {erl_syntax:syntaxTree(), term()}), 201 term(), erl_syntax:syntaxTree()) -> {erl_syntax:syntaxTree(), term()}. 202 203mapfold(F, S, Tree) -> 204 case erl_syntax:subtrees(Tree) of 205 [] -> 206 F(Tree, S); 207 Gs -> 208 {Gs1, S1} = mapfold_1(F, S, Gs), 209 Tree1 = erl_syntax:make_tree(erl_syntax:type(Tree), Gs1), 210 F(erl_syntax:copy_attrs(Tree, Tree1), S1) 211 end. 212 213mapfold_1(F, S, [L | Ls]) -> 214 {L1, S1} = mapfold_2(F, S, L), 215 {Ls1, S2} = mapfold_1(F, S1, Ls), 216 {[L1 | Ls1], S2}; 217mapfold_1(_, S, []) -> 218 {[], S}. 219 220mapfold_2(F, S, [T | Ts]) -> 221 {T1, S1} = mapfold(F, S, T), 222 {Ts1, S2} = mapfold_2(F, S1, Ts), 223 {[T1 | Ts1], S2}; 224mapfold_2(_, S, []) -> 225 {[], S}. 226 227 228%% ===================================================================== 229%% @spec mapfold_subtrees(Function, Start::term(), 230%% Tree::syntaxTree()) -> {syntaxTree(), term()} 231%% 232%% Function = (syntaxTree(), term()) -> {syntaxTree(), term()} 233%% 234%% @doc Does a mapfold operation over the immediate subtrees of a syntax 235%% tree. This is similar to `mapfold/3', but only on the 236%% immediate subtrees of `Tree', in left-to-right order; it 237%% does not include the root node of `Tree'. 238%% 239%% @see mapfold/3 240 241-spec mapfold_subtrees(fun((erl_syntax:syntaxTree(), term()) -> 242 {erl_syntax:syntaxTree(), term()}), 243 term(), erl_syntax:syntaxTree()) -> 244 {erl_syntax:syntaxTree(), term()}. 245 246mapfold_subtrees(F, S, Tree) -> 247 case erl_syntax:subtrees(Tree) of 248 [] -> 249 {Tree, S}; 250 Gs -> 251 {Gs1, S1} = mapfoldl_listlist(F, S, Gs), 252 Tree1 = erl_syntax:make_tree(erl_syntax:type(Tree), Gs1), 253 {erl_syntax:copy_attrs(Tree, Tree1), S1} 254 end. 255 256 257%% ===================================================================== 258%% @spec mapfoldl_listlist(Function, State, [[term()]]) -> 259%% {[[term()]], term()} 260%% 261%% Function = (term(), term()) -> {term(), term()} 262%% 263%% @doc Like `lists:mapfoldl/3', but over a list of lists. 264%% The list of lists in the result has the same structure as the given 265%% list of lists. 266 267-spec mapfoldl_listlist(fun((term(), term()) -> {term(), term()}), 268 term(), [[term()]]) -> {[[term()]], term()}. 269 270mapfoldl_listlist(F, S, [L | Ls]) -> 271 {L1, S1} = mapfoldl(F, S, L), 272 {Ls1, S2} = mapfoldl_listlist(F, S1, Ls), 273 {[L1 | Ls1], S2}; 274mapfoldl_listlist(_, S, []) -> 275 {[], S}. 276 277mapfoldl(F, S, [L | Ls]) -> 278 {L1, S1} = F(L, S), 279 {Ls1, S2} = mapfoldl(F, S1, Ls), 280 {[L1 | Ls1], S2}; 281mapfoldl(_, S, []) -> 282 {[], S}. 283 284 285%% ===================================================================== 286%% @spec variables(syntaxTree()) -> set(atom()) 287%% 288%% @type set(T) = //stdlib/sets:set(T) 289%% 290%% @doc Returns the names of variables occurring in a syntax tree, The 291%% result is a set of variable names represented by atoms. Macro names 292%% are not included. 293%% 294%% @see //stdlib/sets 295 296-spec variables(erl_syntax:syntaxTree()) -> sets:set(atom()). 297 298variables(Tree) -> 299 variables(Tree, sets:new()). 300 301variables(T, S) -> 302 case erl_syntax:type(T) of 303 variable -> 304 sets:add_element(erl_syntax:variable_name(T), S); 305 macro -> 306 %% macro names are ignored, even if represented by variables 307 case erl_syntax:macro_arguments(T) of 308 none -> S; 309 As -> 310 variables_2(As, S) 311 end; 312 _ -> 313 case erl_syntax:subtrees(T) of 314 [] -> 315 S; 316 Gs -> 317 variables_1(Gs, S) 318 end 319 end. 320 321variables_1([L | Ls], S) -> 322 variables_1(Ls, variables_2(L, S)); 323variables_1([], S) -> 324 S. 325 326variables_2([T | Ts], S) -> 327 variables_2(Ts, variables(T, S)); 328variables_2([], S) -> 329 S. 330 331 332-define(MINIMUM_RANGE, 100). 333-define(START_RANGE_FACTOR, 100). 334-define(MAX_RETRIES, 3). % retries before enlarging range 335-define(ENLARGE_ENUM, 8). % range enlargment enumerator 336-define(ENLARGE_DENOM, 1). % range enlargment denominator 337 338default_variable_name(N) -> 339 list_to_atom("V" ++ integer_to_list(N)). 340 341%% ===================================================================== 342%% @spec new_variable_name(Used::set(atom())) -> atom() 343%% 344%% @doc Returns an atom which is not already in the set `Used'. This is 345%% equivalent to `new_variable_name(Function, Used)', where `Function' 346%% maps a given integer `N' to the atom whose name consists of "`V'" 347%% followed by the numeral for `N'. 348%% 349%% @see new_variable_name/2 350 351-spec new_variable_name(sets:set(atom())) -> atom(). 352 353new_variable_name(S) -> 354 new_variable_name(fun default_variable_name/1, S). 355 356%% ===================================================================== 357%% @spec new_variable_name(Function, Used::set(atom())) -> atom() 358%% 359%% Function = (integer()) -> atom() 360%% 361%% @doc Returns a user-named atom which is not already in the set 362%% `Used'. The atom is generated by applying the given 363%% `Function' to a generated integer. Integers are generated 364%% using an algorithm which tries to keep the names randomly distributed 365%% within a reasonably small range relative to the number of elements in 366%% the set. 367%% 368%% This function uses the module `rand' to generate new 369%% keys. The seed it uses may be initialized by calling 370%% `rand:seed/1' or `rand:seed/2' before this 371%% function is first called. 372%% 373%% @see new_variable_name/1 374%% @see //stdlib/sets 375%% @see //stdlib/random 376 377-spec new_variable_name(fun((integer()) -> atom()), sets:set(atom())) -> atom(). 378 379new_variable_name(F, S) -> 380 R = start_range(S), 381 new_variable_name(R, F, S). 382 383new_variable_name(R, F, S) -> 384 new_variable_name(generate(R, R), R, 0, F, S). 385 386new_variable_name(N, R, T, F, S) when T < ?MAX_RETRIES -> 387 A = F(N), 388 case sets:is_element(A, S) of 389 true -> 390 new_variable_name(generate(N, R), R, T + 1, F, S); 391 false -> 392 A 393 end; 394new_variable_name(N, R, _T, F, S) -> 395 %% Too many retries - enlarge the range and start over. 396 R1 = (R * ?ENLARGE_ENUM) div ?ENLARGE_DENOM, 397 new_variable_name(generate(N, R1), R1, 0, F, S). 398 399%% Note that we assume that it is very cheap to take the size of 400%% the given set. This should be valid for the stdlib 401%% implementation of `sets'. 402 403start_range(S) -> 404 erlang:max(sets:size(S) * ?START_RANGE_FACTOR, ?MINIMUM_RANGE). 405 406%% The previous number might or might not be used to compute the 407%% next number to be tried. It is currently not used. 408%% 409%% It is important that this function does not generate values in 410%% order, but (pseudo-)randomly distributed over the range. 411 412generate(_Key, Range) -> 413 _ = case rand:export_seed() of 414 undefined -> 415 rand:seed(exsplus, {753,8,73}); 416 _ -> 417 ok 418 end, 419 rand:uniform(Range). % works well 420 421 422%% ===================================================================== 423%% @spec new_variable_names(N::integer(), Used::set(atom())) -> [atom()] 424%% 425%% @doc Like `new_variable_name/1', but generates a list of 426%% `N' new names. 427%% 428%% @see new_variable_name/1 429 430-spec new_variable_names(integer(), sets:set(atom())) -> [atom()]. 431 432new_variable_names(N, S) -> 433 new_variable_names(N, fun default_variable_name/1, S). 434 435%% ===================================================================== 436%% @spec new_variable_names(N::integer(), Function, 437%% Used::set(atom())) -> [atom()] 438%% 439%% Function = (integer()) -> atom() 440%% 441%% @doc Like `new_variable_name/2', but generates a list of 442%% `N' new names. 443%% 444%% @see new_variable_name/2 445 446-spec new_variable_names(integer(), fun((integer()) -> atom()), sets:set(atom())) -> 447 [atom()]. 448 449new_variable_names(N, F, S) when is_integer(N) -> 450 R = start_range(S), 451 new_variable_names(N, [], R, F, S). 452 453new_variable_names(N, Names, R, F, S) when N > 0 -> 454 Name = new_variable_name(R, F, S), 455 S1 = sets:add_element(Name, S), 456 new_variable_names(N - 1, [Name | Names], R, F, S1); 457new_variable_names(0, Names, _, _, _) -> 458 Names. 459 460 461%% ===================================================================== 462%% @spec annotate_bindings(Tree::syntaxTree(), 463%% Bindings::ordset(atom())) -> syntaxTree() 464%% 465%% @type ordset(T) = //stdlib/ordsets:ordset(T) 466%% 467%% @doc Adds or updates annotations on nodes in a syntax tree. 468%% `Bindings' specifies the set of bound variables in the 469%% environment of the top level node. The following annotations are 470%% affected: 471%% <ul> 472%% <li>`{env, Vars}', representing the input environment 473%% of the subtree.</li> 474%% 475%% <li>`{bound, Vars}', representing the variables that 476%% are bound in the subtree.</li> 477%% 478%% <li>`{free, Vars}', representing the free variables in 479%% the subtree.</li> 480%% </ul> 481%% `Bindings' and `Vars' are ordered-set lists 482%% (cf. module `ordsets') of atoms representing variable 483%% names. 484%% 485%% @see annotate_bindings/1 486%% @see //stdlib/ordsets 487 488-spec annotate_bindings(erl_syntax:syntaxTree(), ordsets:ordset(atom())) -> 489 erl_syntax:syntaxTree(). 490 491annotate_bindings(Tree, Env) -> 492 {Tree1, _, _} = vann(Tree, Env), 493 Tree1. 494 495%% ===================================================================== 496%% @spec annotate_bindings(Tree::syntaxTree()) -> syntaxTree() 497%% 498%% @doc Adds or updates annotations on nodes in a syntax tree. 499%% Equivalent to `annotate_bindings(Tree, Bindings)' where 500%% the top-level environment `Bindings' is taken from the 501%% annotation `{env, Bindings}' on the root node of 502%% `Tree'. An exception is thrown if no such annotation 503%% should exist. 504%% 505%% @see annotate_bindings/2 506 507-spec annotate_bindings(erl_syntax:syntaxTree()) -> erl_syntax:syntaxTree(). 508 509annotate_bindings(Tree) -> 510 As = erl_syntax:get_ann(Tree), 511 case lists:keyfind(env, 1, As) of 512 {env, InVars} -> 513 annotate_bindings(Tree, InVars); 514 _ -> 515 erlang:error(badarg) 516 end. 517 518vann(Tree, Env) -> 519 case erl_syntax:type(Tree) of 520 variable -> 521 %% Variable use 522 Bound = [], 523 Free = [erl_syntax:variable_name(Tree)], 524 {ann_bindings(Tree, Env, Bound, Free), Bound, Free}; 525 match_expr -> 526 vann_match_expr(Tree, Env); 527 case_expr -> 528 vann_case_expr(Tree, Env); 529 if_expr -> 530 vann_if_expr(Tree, Env); 531 receive_expr -> 532 vann_receive_expr(Tree, Env); 533 catch_expr -> 534 vann_catch_expr(Tree, Env); 535 try_expr -> 536 vann_try_expr(Tree, Env); 537 function -> 538 vann_function(Tree, Env); 539 fun_expr -> 540 vann_fun_expr(Tree, Env); 541 list_comp -> 542 vann_list_comp(Tree, Env); 543 binary_comp -> 544 vann_binary_comp(Tree, Env); 545 generator -> 546 vann_generator(Tree, Env); 547 binary_generator -> 548 vann_binary_generator(Tree, Env); 549 block_expr -> 550 vann_block_expr(Tree, Env); 551 macro -> 552 vann_macro(Tree, Env); 553 _Type -> 554 F = vann_list_join(Env), 555 {Tree1, {Bound, Free}} = mapfold_subtrees(F, {[], []}, 556 Tree), 557 {ann_bindings(Tree1, Env, Bound, Free), Bound, Free} 558 end. 559 560vann_list_join(Env) -> 561 fun (T, {Bound, Free}) -> 562 {T1, Bound1, Free1} = vann(T, Env), 563 {T1, {ordsets:union(Bound, Bound1), 564 ordsets:union(Free, Free1)}} 565 end. 566 567vann_list(Ts, Env) -> 568 lists:mapfoldl(vann_list_join(Env), {[], []}, Ts). 569 570vann_function(Tree, Env) -> 571 Cs = erl_syntax:function_clauses(Tree), 572 {Cs1, {_, Free}} = vann_clauses(Cs, Env), 573 N = erl_syntax:function_name(Tree), 574 {N1, _, _} = vann(N, Env), 575 Tree1 = rewrite(Tree, erl_syntax:function(N1, Cs1)), 576 Bound = [], 577 {ann_bindings(Tree1, Env, Bound, Free), Bound, Free}. 578 579vann_fun_expr(Tree, Env) -> 580 Cs = erl_syntax:fun_expr_clauses(Tree), 581 {Cs1, {_, Free}} = vann_clauses(Cs, Env), 582 Tree1 = rewrite(Tree, erl_syntax:fun_expr(Cs1)), 583 Bound = [], 584 {ann_bindings(Tree1, Env, Bound, Free), Bound, Free}. 585 586vann_match_expr(Tree, Env) -> 587 E = erl_syntax:match_expr_body(Tree), 588 {E1, Bound1, Free1} = vann(E, Env), 589 Env1 = ordsets:union(Env, Bound1), 590 P = erl_syntax:match_expr_pattern(Tree), 591 {P1, Bound2, Free2} = vann_pattern(P, Env1), 592 Bound = ordsets:union(Bound1, Bound2), 593 Free = ordsets:union(Free1, Free2), 594 Tree1 = rewrite(Tree, erl_syntax:match_expr(P1, E1)), 595 {ann_bindings(Tree1, Env, Bound, Free), Bound, Free}. 596 597vann_case_expr(Tree, Env) -> 598 E = erl_syntax:case_expr_argument(Tree), 599 {E1, Bound1, Free1} = vann(E, Env), 600 Env1 = ordsets:union(Env, Bound1), 601 Cs = erl_syntax:case_expr_clauses(Tree), 602 {Cs1, {Bound2, Free2}} = vann_clauses(Cs, Env1), 603 Bound = ordsets:union(Bound1, Bound2), 604 Free = ordsets:union(Free1, Free2), 605 Tree1 = rewrite(Tree, erl_syntax:case_expr(E1, Cs1)), 606 {ann_bindings(Tree1, Env, Bound, Free), Bound, Free}. 607 608vann_if_expr(Tree, Env) -> 609 Cs = erl_syntax:if_expr_clauses(Tree), 610 {Cs1, {Bound, Free}} = vann_clauses(Cs, Env), 611 Tree1 = rewrite(Tree, erl_syntax:if_expr(Cs1)), 612 {ann_bindings(Tree1, Env, Bound, Free), Bound, Free}. 613 614vann_catch_expr(Tree, Env) -> 615 E = erl_syntax:catch_expr_body(Tree), 616 {E1, _, Free} = vann(E, Env), 617 Tree1 = rewrite(Tree, erl_syntax:catch_expr(E1)), 618 Bound = [], 619 {ann_bindings(Tree1, Env, Bound, Free), Bound, Free}. 620 621vann_try_expr(Tree, Env) -> 622 Es = erl_syntax:try_expr_body(Tree), 623 {Es1, {Bound1, Free1}} = vann_body(Es, Env), 624 Cs = erl_syntax:try_expr_clauses(Tree), 625 %% bindings in the body should be available in the success case, 626 {Cs1, {_, Free2}} = vann_clauses(Cs, ordsets:union(Env, Bound1)), 627 Hs = erl_syntax:try_expr_handlers(Tree), 628 {Hs1, {_, Free3}} = vann_clauses(Hs, Env), 629 %% the after part does not export anything, yet; this might change 630 As = erl_syntax:try_expr_after(Tree), 631 {As1, {_, Free4}} = vann_body(As, Env), 632 Tree1 = rewrite(Tree, erl_syntax:try_expr(Es1, Cs1, Hs1, As1)), 633 Bound = [], 634 Free = ordsets:union(Free1, ordsets:union(Free2, ordsets:union(Free3, Free4))), 635 {ann_bindings(Tree1, Env, Bound, Free), Bound, Free}. 636 637vann_receive_expr(Tree, Env) -> 638 %% The timeout action is treated as an extra clause. 639 %% Bindings in the expiry expression are local only. 640 Cs = erl_syntax:receive_expr_clauses(Tree), 641 Es = erl_syntax:receive_expr_action(Tree), 642 C = erl_syntax:clause([], Es), 643 {[C1 | Cs1], {Bound, Free1}} = vann_clauses([C | Cs], Env), 644 Es1 = erl_syntax:clause_body(C1), 645 {T1, _, Free2} = case erl_syntax:receive_expr_timeout(Tree) of 646 none -> 647 {none, [], []}; 648 T -> 649 vann(T, Env) 650 end, 651 Free = ordsets:union(Free1, Free2), 652 Tree1 = rewrite(Tree, erl_syntax:receive_expr(Cs1, T1, Es1)), 653 {ann_bindings(Tree1, Env, Bound, Free), Bound, Free}. 654 655vann_list_comp(Tree, Env) -> 656 Es = erl_syntax:list_comp_body(Tree), 657 {Es1, {Bound1, Free1}} = vann_list_comp_body(Es, Env), 658 Env1 = ordsets:union(Env, Bound1), 659 T = erl_syntax:list_comp_template(Tree), 660 {T1, _, Free2} = vann(T, Env1), 661 Free = ordsets:union(Free1, ordsets:subtract(Free2, Bound1)), 662 Bound = [], 663 Tree1 = rewrite(Tree, erl_syntax:list_comp(T1, Es1)), 664 {ann_bindings(Tree1, Env, Bound, Free), Bound, Free}. 665 666vann_list_comp_body_join() -> 667 fun (T, {Env, Bound, Free}) -> 668 {T1, Bound1, Free1} = case erl_syntax:type(T) of 669 binary_generator -> 670 vann_binary_generator(T,Env); 671 generator -> 672 vann_generator(T, Env); 673 _ -> 674 %% Bindings in filters are not 675 %% exported to the rest of the 676 %% body. 677 {T2, _, Free2} = vann(T, Env), 678 {T2, [], Free2} 679 end, 680 Env1 = ordsets:union(Env, Bound1), 681 {T1, {Env1, ordsets:union(Bound, Bound1), 682 ordsets:union(Free, 683 ordsets:subtract(Free1, Bound))}} 684 end. 685 686vann_list_comp_body(Ts, Env) -> 687 F = vann_list_comp_body_join(), 688 {Ts1, {_, Bound, Free}} = lists:mapfoldl(F, {Env, [], []}, Ts), 689 {Ts1, {Bound, Free}}. 690 691vann_binary_comp(Tree, Env) -> 692 Es = erl_syntax:binary_comp_body(Tree), 693 {Es1, {Bound1, Free1}} = vann_binary_comp_body(Es, Env), 694 Env1 = ordsets:union(Env, Bound1), 695 T = erl_syntax:binary_comp_template(Tree), 696 {T1, _, Free2} = vann(T, Env1), 697 Free = ordsets:union(Free1, ordsets:subtract(Free2, Bound1)), 698 Bound = [], 699 Tree1 = rewrite(Tree, erl_syntax:binary_comp(T1, Es1)), 700 {ann_bindings(Tree1, Env, Bound, Free), Bound, Free}. 701 702vann_binary_comp_body_join() -> 703 fun (T, {Env, Bound, Free}) -> 704 {T1, Bound1, Free1} = case erl_syntax:type(T) of 705 binary_generator -> 706 vann_binary_generator(T, Env); 707 generator -> 708 vann_generator(T, Env); 709 _ -> 710 %% Bindings in filters are not 711 %% exported to the rest of the 712 %% body. 713 {T2, _, Free2} = vann(T, Env), 714 {T2, [], Free2} 715 end, 716 Env1 = ordsets:union(Env, Bound1), 717 {T1, {Env1, ordsets:union(Bound, Bound1), 718 ordsets:union(Free, 719 ordsets:subtract(Free1, Bound))}} 720 end. 721 722vann_binary_comp_body(Ts, Env) -> 723 F = vann_binary_comp_body_join(), 724 {Ts1, {_, Bound, Free}} = lists:mapfoldl(F, {Env, [], []}, Ts), 725 {Ts1, {Bound, Free}}. 726 727%% In list comprehension generators, the pattern variables are always 728%% viewed as new occurrences, shadowing whatever is in the input 729%% environment (thus, the pattern contains no variable uses, only 730%% bindings). Bindings in the generator body are not exported. 731 732vann_generator(Tree, Env) -> 733 P = erl_syntax:generator_pattern(Tree), 734 {P1, Bound, _} = vann_pattern(P, []), 735 E = erl_syntax:generator_body(Tree), 736 {E1, _, Free} = vann(E, Env), 737 Tree1 = rewrite(Tree, erl_syntax:generator(P1, E1)), 738 {ann_bindings(Tree1, Env, Bound, Free), Bound, Free}. 739 740vann_binary_generator(Tree, Env) -> 741 P = erl_syntax:binary_generator_pattern(Tree), 742 {P1, Bound, _} = vann_pattern(P, Env), 743 E = erl_syntax:binary_generator_body(Tree), 744 {E1, _, Free} = vann(E, Env), 745 Tree1 = rewrite(Tree, erl_syntax:binary_generator(P1, E1)), 746 {ann_bindings(Tree1, Env, Bound, Free), Bound, Free}. 747 748vann_block_expr(Tree, Env) -> 749 Es = erl_syntax:block_expr_body(Tree), 750 {Es1, {Bound, Free}} = vann_body(Es, Env), 751 Tree1 = rewrite(Tree, erl_syntax:block_expr(Es1)), 752 {ann_bindings(Tree1, Env, Bound, Free), Bound, Free}. 753 754vann_body_join() -> 755 fun (T, {Env, Bound, Free}) -> 756 {T1, Bound1, Free1} = vann(T, Env), 757 Env1 = ordsets:union(Env, Bound1), 758 {T1, {Env1, ordsets:union(Bound, Bound1), 759 ordsets:union(Free, 760 ordsets:subtract(Free1, Bound))}} 761 end. 762 763vann_body(Ts, Env) -> 764 {Ts1, {_, Bound, Free}} = lists:mapfoldl(vann_body_join(), 765 {Env, [], []}, Ts), 766 {Ts1, {Bound, Free}}. 767 768%% Macro names must be ignored even if they happen to be variables, 769%% lexically speaking. 770 771vann_macro(Tree, Env) -> 772 {As, {Bound, Free}} = case erl_syntax:macro_arguments(Tree) of 773 none -> 774 {none, {[], []}}; 775 As1 -> 776 vann_list(As1, Env) 777 end, 778 N = erl_syntax:macro_name(Tree), 779 Tree1 = rewrite(Tree, erl_syntax:macro(N, As)), 780 {ann_bindings(Tree1, Env, Bound, Free), Bound, Free}. 781 782vann_pattern(Tree, Env) -> 783 case erl_syntax:type(Tree) of 784 variable -> 785 V = erl_syntax:variable_name(Tree), 786 case ordsets:is_element(V, Env) of 787 true -> 788 %% Variable use 789 Bound = [], 790 Free = [V], 791 {ann_bindings(Tree, Env, Bound, Free), Bound, Free}; 792 false -> 793 %% Variable binding 794 Bound = [V], 795 Free = [], 796 {ann_bindings(Tree, Env, Bound, Free), Bound, Free} 797 end; 798 match_expr -> 799 %% Alias pattern 800 P = erl_syntax:match_expr_pattern(Tree), 801 {P1, Bound1, Free1} = vann_pattern(P, Env), 802 E = erl_syntax:match_expr_body(Tree), 803 {E1, Bound2, Free2} = vann_pattern(E, Env), 804 Bound = ordsets:union(Bound1, Bound2), 805 Free = ordsets:union(Free1, Free2), 806 Tree1 = rewrite(Tree, erl_syntax:match_expr(P1, E1)), 807 {ann_bindings(Tree1, Env, Bound, Free), Bound, Free}; 808 macro -> 809 %% The macro name must be ignored. The arguments are treated 810 %% as patterns. 811 {As, {Bound, Free}} = 812 case erl_syntax:macro_arguments(Tree) of 813 none -> 814 {none, {[], []}}; 815 As1 -> 816 vann_patterns(As1, Env) 817 end, 818 N = erl_syntax:macro_name(Tree), 819 Tree1 = rewrite(Tree, erl_syntax:macro(N, As)), 820 {ann_bindings(Tree1, Env, Bound, Free), Bound, Free}; 821 _Type -> 822 F = vann_patterns_join(Env), 823 {Tree1, {Bound, Free}} = mapfold_subtrees(F, {[], []}, 824 Tree), 825 {ann_bindings(Tree1, Env, Bound, Free), Bound, Free} 826 end. 827 828vann_patterns_join(Env) -> 829 fun (T, {Bound, Free}) -> 830 {T1, Bound1, Free1} = vann_pattern(T, Env), 831 {T1, {ordsets:union(Bound, Bound1), 832 ordsets:union(Free, Free1)}} 833 end. 834 835vann_patterns(Ps, Env) -> 836 lists:mapfoldl(vann_patterns_join(Env), {[], []}, Ps). 837 838vann_clause(C, Env) -> 839 {Ps, {Bound1, Free1}} = vann_patterns(erl_syntax:clause_patterns(C), 840 Env), 841 Env1 = ordsets:union(Env, Bound1), 842 %% Guards cannot add bindings 843 {G1, _, Free2} = case erl_syntax:clause_guard(C) of 844 none -> 845 {none, [], []}; 846 G -> 847 vann(G, Env1) 848 end, 849 {Es, {Bound2, Free3}} = vann_body(erl_syntax:clause_body(C), Env1), 850 Bound = ordsets:union(Bound1, Bound2), 851 Free = ordsets:union(Free1, 852 ordsets:subtract(ordsets:union(Free2, Free3), 853 Bound1)), 854 Tree1 = rewrite(C, erl_syntax:clause(Ps, G1, Es)), 855 {ann_bindings(Tree1, Env, Bound, Free), Bound, Free}. 856 857vann_clauses_join(Env) -> 858 fun (C, {Bound, Free}) -> 859 {C1, Bound1, Free1} = vann_clause(C, Env), 860 {C1, {ordsets:intersection(Bound, Bound1), 861 ordsets:union(Free, Free1)}} 862 end. 863 864vann_clauses([C | Cs], Env) -> 865 {C1, Bound, Free} = vann_clause(C, Env), 866 {Cs1, BF} = lists:mapfoldl(vann_clauses_join(Env), {Bound, Free}, Cs), 867 {[C1 | Cs1], BF}; 868vann_clauses([], _Env) -> 869 {[], {[], []}}. 870 871ann_bindings(Tree, Env, Bound, Free) -> 872 As0 = erl_syntax:get_ann(Tree), 873 As1 = [{env, Env}, 874 {bound, Bound}, 875 {free, Free} 876 | delete_binding_anns(As0)], 877 erl_syntax:set_ann(Tree, As1). 878 879delete_binding_anns([{env, _} | As]) -> 880 delete_binding_anns(As); 881delete_binding_anns([{bound, _} | As]) -> 882 delete_binding_anns(As); 883delete_binding_anns([{free, _} | As]) -> 884 delete_binding_anns(As); 885delete_binding_anns([A | As]) -> 886 [A | delete_binding_anns(As)]; 887delete_binding_anns([]) -> 888 []. 889 890 891%% ===================================================================== 892%% @spec is_fail_expr(Tree::syntaxTree()) -> boolean() 893%% 894%% @doc Returns `true' if `Tree' represents an 895%% expression which never terminates normally. Note that the reverse 896%% does not apply. Currently, the detected cases are calls to 897%% `exit/1', `throw/1', 898%% `erlang:error/1' and `erlang:error/2'. 899%% 900%% @see //erts/erlang:exit/1 901%% @see //erts/erlang:throw/1 902%% @see //erts/erlang:error/1 903%% @see //erts/erlang:error/2 904 905-spec is_fail_expr(erl_syntax:syntaxTree()) -> boolean(). 906 907is_fail_expr(E) -> 908 case erl_syntax:type(E) of 909 application -> 910 N = length(erl_syntax:application_arguments(E)), 911 F = erl_syntax:application_operator(E), 912 case catch {ok, analyze_function_name(F)} of 913 syntax_error -> 914 false; 915 {ok, exit} when N =:= 1 -> 916 true; 917 {ok, throw} when N =:= 1 -> 918 true; 919 {ok, {erlang, exit}} when N =:= 1 -> 920 true; 921 {ok, {erlang, throw}} when N =:= 1 -> 922 true; 923 {ok, {erlang, error}} when N =:= 1 -> 924 true; 925 {ok, {erlang, error}} when N =:= 2 -> 926 true; 927 {ok, {erlang, fault}} when N =:= 1 -> 928 true; 929 {ok, {erlang, fault}} when N =:= 2 -> 930 true; 931 _ -> 932 false 933 end; 934 _ -> 935 false 936 end. 937 938 939%% ===================================================================== 940%% @spec analyze_forms(Forms) -> [{Key, term()}] 941%% 942%% Forms = syntaxTree() | [syntaxTree()] 943%% Key = attributes | errors | exports | functions | imports 944%% | module | records | warnings 945%% 946%% @doc Analyzes a sequence of "program forms". The given 947%% `Forms' may be a single syntax tree of type 948%% `form_list', or a list of "program form" syntax trees. The 949%% returned value is a list of pairs `{Key, Info}', where 950%% each value of `Key' occurs at most once in the list; the 951%% absence of a particular key indicates that there is no well-defined 952%% value for that key. 953%% 954%% Each entry in the resulting list contains the following 955%% corresponding information about the program forms: 956%% <dl> 957%% <dt>`{attributes, Attributes}'</dt> 958%% <dd><ul> 959%% <li>`Attributes = [{atom(), term()}]'</li> 960%% </ul> 961%% `Attributes' is a list of pairs representing the 962%% names and corresponding values of all so-called "wild" 963%% attributes (as e.g. "`-compile(...)'") occurring in 964%% `Forms' (cf. `analyze_wild_attribute/1'). 965%% We do not guarantee that each name occurs at most once in the 966%% list. The order of listing is not defined.</dd> 967%% 968%% <dt>`{errors, Errors}'</dt> 969%% <dd><ul> 970%% <li>`Errors = [term()]'</li> 971%% </ul> 972%% `Errors' is the list of error descriptors of all 973%% `error_marker' nodes that occur in 974%% `Forms'. The order of listing is not defined.</dd> 975%% 976%% <dt>`{exports, Exports}'</dt> 977%% <dd><ul> 978%% <li>`Exports = [FunctionName]'</li> 979%% <li>`FunctionName = atom() 980%% | {atom(), integer()} 981%% | {ModuleName, FunctionName}'</li> 982%% <li>`ModuleName = atom()'</li> 983%% </ul> 984%% `Exports' is a list of representations of those 985%% function names that are listed by export declaration attributes 986%% in `Forms' (cf. 987%% `analyze_export_attribute/1'). We do not guarantee 988%% that each name occurs at most once in the list. The order of 989%% listing is not defined.</dd> 990%% 991%% <dt>`{functions, Functions}'</dt> 992%% <dd><ul> 993%% <li>`Functions = [{atom(), integer()}]'</li> 994%% </ul> 995%% `Functions' is a list of the names of the functions 996%% that are defined in `Forms' (cf. 997%% `analyze_function/1'). We do not guarantee that each 998%% name occurs at most once in the list. The order of listing is 999%% not defined.</dd> 1000%% 1001%% <dt>`{imports, Imports}'</dt> 1002%% <dd><ul> 1003%% <li>`Imports = [{Module, Names}]'</li> 1004%% <li>`Module = atom()'</li> 1005%% <li>`Names = [FunctionName]'</li> 1006%% <li>`FunctionName = atom() 1007%% | {atom(), integer()} 1008%% | {ModuleName, FunctionName}'</li> 1009%% <li>`ModuleName = atom()'</li> 1010%% </ul> 1011%% `Imports' is a list of pairs representing those 1012%% module names and corresponding function names that are listed 1013%% by import declaration attributes in `Forms' (cf. 1014%% `analyze_import_attribute/1'), where each 1015%% `Module' occurs at most once in 1016%% `Imports'. We do not guarantee that each name occurs 1017%% at most once in the lists of function names. The order of 1018%% listing is not defined.</dd> 1019%% 1020%% <dt>`{module, ModuleName}'</dt> 1021%% <dd><ul> 1022%% <li>`ModuleName = atom()'</li> 1023%% </ul> 1024%% `ModuleName' is the name declared by a module 1025%% attribute in `Forms'. If no module name is defined 1026%% in `Forms', the result will contain no entry for the 1027%% `module' key. If multiple module name declarations 1028%% should occur, all but the first will be ignored.</dd> 1029%% 1030%% <dt>`{records, Records}'</dt> 1031%% <dd><ul> 1032%% <li>`Records = [{atom(), Fields}]'</li> 1033%% <li>`Fields = [{atom(), {Default, Type}}]'</li> 1034%% <li>`Default = none | syntaxTree()'</li> 1035%% <li>`Type = none | syntaxTree()'</li> 1036%% </ul> 1037%% `Records' is a list of pairs representing the names 1038%% and corresponding field declarations of all record declaration 1039%% attributes occurring in `Forms'. For fields declared 1040%% without a default value, the corresponding value for 1041%% `Default' is the atom `none'. Similarly, for fields declared 1042%% without a type, the corresponding value for `Type' is the 1043%% atom `none' (cf. 1044%% `analyze_record_attribute/1'). We do not guarantee 1045%% that each record name occurs at most once in the list. The 1046%% order of listing is not defined.</dd> 1047%% 1048%% <dt>`{warnings, Warnings}'</dt> 1049%% <dd><ul> 1050%% <li>`Warnings = [term()]'</li> 1051%% </ul> 1052%% `Warnings' is the list of error descriptors of all 1053%% `warning_marker' nodes that occur in 1054%% `Forms'. The order of listing is not defined.</dd> 1055%% </dl> 1056%% 1057%% The evaluation throws `syntax_error' if an ill-formed 1058%% Erlang construct is encountered. 1059%% 1060%% @see analyze_wild_attribute/1 1061%% @see analyze_export_attribute/1 1062%% @see analyze_function/1 1063%% @see analyze_import_attribute/1 1064%% @see analyze_record_attribute/1 1065%% @see erl_syntax:error_marker_info/1 1066%% @see erl_syntax:warning_marker_info/1 1067 1068-type key() :: 'attributes' | 'errors' | 'exports' | 'functions' | 'imports' 1069 | 'module' | 'records' | 'warnings'. 1070-type info_pair() :: {key(), term()}. 1071 1072-spec analyze_forms(erl_syntax:forms()) -> [info_pair()]. 1073 1074analyze_forms(Forms) when is_list(Forms) -> 1075 finfo_to_list(lists:foldl(fun collect_form/2, new_finfo(), Forms)); 1076analyze_forms(Forms) -> 1077 analyze_forms( 1078 erl_syntax:form_list_elements( 1079 erl_syntax:flatten_form_list(Forms))). 1080 1081collect_form(Node, Info) -> 1082 case analyze_form(Node) of 1083 {attribute, {Name, Data}} -> 1084 collect_attribute(Name, Data, Info); 1085 {attribute, preprocessor} -> 1086 Info; 1087 {function, Name} -> 1088 finfo_add_function(Name, Info); 1089 {error_marker, Data} -> 1090 finfo_add_error(Data, Info); 1091 {warning_marker, Data} -> 1092 finfo_add_warning(Data, Info); 1093 _ -> 1094 Info 1095 end. 1096 1097collect_attribute(module, M, Info) -> 1098 finfo_set_module(M, Info); 1099collect_attribute(export, L, Info) -> 1100 finfo_add_exports(L, Info); 1101collect_attribute(import, {M, L}, Info) -> 1102 finfo_add_imports(M, L, Info); 1103collect_attribute(import, M, Info) -> 1104 finfo_add_module_import(M, Info); 1105collect_attribute(file, _, Info) -> 1106 Info; 1107collect_attribute(record, {R, L}, Info) -> 1108 finfo_add_record(R, L, Info); 1109collect_attribute(_, {N, V}, Info) -> 1110 finfo_add_attribute(N, V, Info). 1111 1112%% Abstract datatype for collecting module information. 1113 1114-record(forms, {module = none :: 'none' | {'value', atom()}, 1115 exports = [] :: [{atom(), arity()}], 1116 module_imports = [] :: [atom()], 1117 imports = [] :: [{atom(), [{atom(), arity()}]}], 1118 attributes = [] :: [{atom(), term()}], 1119 records = [] :: [{atom(), [{atom(), 1120 field_default(), 1121 field_type()}]}], 1122 errors = [] :: [term()], 1123 warnings = [] :: [term()], 1124 functions = [] :: [{atom(), arity()}]}). 1125 1126-type field_default() :: 'none' | erl_syntax:syntaxTree(). 1127-type field_type() :: 'none' | erl_syntax:syntaxTree(). 1128 1129new_finfo() -> 1130 #forms{}. 1131 1132finfo_set_module(Name, Info) -> 1133 case Info#forms.module of 1134 none -> 1135 Info#forms{module = {value, Name}}; 1136 {value, _} -> 1137 Info 1138 end. 1139 1140finfo_add_exports(L, Info) -> 1141 Info#forms{exports = L ++ Info#forms.exports}. 1142 1143finfo_add_module_import(M, Info) -> 1144 Info#forms{module_imports = [M | Info#forms.module_imports]}. 1145 1146finfo_add_imports(M, L, Info) -> 1147 Es = Info#forms.imports, 1148 case lists:keyfind(M, 1, Es) of 1149 {_, L1} -> 1150 Es1 = lists:keyreplace(M, 1, Es, {M, L ++ L1}), 1151 Info#forms{imports = Es1}; 1152 false -> 1153 Info#forms{imports = [{M, L} | Es]} 1154 end. 1155 1156finfo_add_attribute(Name, Val, Info) -> 1157 Info#forms{attributes = [{Name, Val} | Info#forms.attributes]}. 1158 1159finfo_add_record(R, L, Info) -> 1160 Info#forms{records = [{R, L} | Info#forms.records]}. 1161 1162finfo_add_error(R, Info) -> 1163 Info#forms{errors = [R | Info#forms.errors]}. 1164 1165finfo_add_warning(R, Info) -> 1166 Info#forms{warnings = [R | Info#forms.warnings]}. 1167 1168finfo_add_function(F, Info) -> 1169 Info#forms{functions = [F | Info#forms.functions]}. 1170 1171finfo_to_list(Info) -> 1172 [{Key, Value} 1173 || {Key, {value, Value}} <- 1174 [{module, Info#forms.module}, 1175 {exports, list_value(Info#forms.exports)}, 1176 {imports, list_value(Info#forms.imports)}, 1177 {module_imports, list_value(Info#forms.module_imports)}, 1178 {attributes, list_value(Info#forms.attributes)}, 1179 {records, list_value(Info#forms.records)}, 1180 {errors, list_value(Info#forms.errors)}, 1181 {warnings, list_value(Info#forms.warnings)}, 1182 {functions, list_value(Info#forms.functions)} 1183 ]]. 1184 1185list_value([]) -> 1186 none; 1187list_value(List) -> 1188 {value, List}. 1189 1190 1191%% ===================================================================== 1192%% @spec analyze_form(Node::syntaxTree()) -> {atom(), term()} | atom() 1193%% 1194%% @doc Analyzes a "source code form" node. If `Node' is a 1195%% "form" type (cf. `erl_syntax:is_form/1'), the returned 1196%% value is a tuple `{Type, Info}' where `Type' is 1197%% the node type and `Info' depends on `Type', as 1198%% follows: 1199%% <dl> 1200%% <dt>`{attribute, Info}'</dt> 1201%% 1202%% <dd>where `Info = analyze_attribute(Node)'.</dd> 1203%% 1204%% <dt>`{error_marker, Info}'</dt> 1205%% 1206%% <dd>where `Info = 1207%% erl_syntax:error_marker_info(Node)'.</dd> 1208%% 1209%% <dt>`{function, Info}'</dt> 1210%% 1211%% <dd>where `Info = analyze_function(Node)'.</dd> 1212%% 1213%% <dt>`{warning_marker, Info}'</dt> 1214%% 1215%% <dd>where `Info = 1216%% erl_syntax:warning_marker_info(Node)'.</dd> 1217%% </dl> 1218%% For other types of forms, only the node type is returned. 1219%% 1220%% The evaluation throws `syntax_error' if 1221%% `Node' is not well-formed. 1222%% 1223%% @see analyze_attribute/1 1224%% @see analyze_function/1 1225%% @see erl_syntax:is_form/1 1226%% @see erl_syntax:error_marker_info/1 1227%% @see erl_syntax:warning_marker_info/1 1228 1229-spec analyze_form(erl_syntax:syntaxTree()) -> {atom(), term()} | atom(). 1230 1231analyze_form(Node) -> 1232 case erl_syntax:type(Node) of 1233 attribute -> 1234 {attribute, analyze_attribute(Node)}; 1235 function -> 1236 {function, analyze_function(Node)}; 1237 error_marker -> 1238 {error_marker, erl_syntax:error_marker_info(Node)}; 1239 warning_marker -> 1240 {warning_marker, erl_syntax:warning_marker_info(Node)}; 1241 _ -> 1242 case erl_syntax:is_form(Node) of 1243 true -> 1244 erl_syntax:type(Node); 1245 false -> 1246 throw(syntax_error) 1247 end 1248 end. 1249 1250%% ===================================================================== 1251%% @spec analyze_attribute(Node::syntaxTree()) -> 1252%% preprocessor | {atom(), atom()} 1253%% 1254%% @doc Analyzes an attribute node. If `Node' represents a 1255%% preprocessor directive, the atom `preprocessor' is 1256%% returned. Otherwise, if `Node' represents a module 1257%% attribute "`-<em>Name</em>...'", a tuple `{Name, 1258%% Info}' is returned, where `Info' depends on 1259%% `Name', as follows: 1260%% <dl> 1261%% <dt>`{module, Info}'</dt> 1262%% 1263%% <dd>where `Info = 1264%% analyze_module_attribute(Node)'.</dd> 1265%% 1266%% <dt>`{export, Info}'</dt> 1267%% 1268%% <dd>where `Info = 1269%% analyze_export_attribute(Node)'.</dd> 1270%% 1271%% <dt>`{import, Info}'</dt> 1272%% 1273%% <dd>where `Info = 1274%% analyze_import_attribute(Node)'.</dd> 1275%% 1276%% <dt>`{file, Info}'</dt> 1277%% 1278%% <dd>where `Info = 1279%% analyze_file_attribute(Node)'.</dd> 1280%% 1281%% <dt>`{record, Info}'</dt> 1282%% 1283%% <dd>where `Info = 1284%% analyze_record_attribute(Node)'.</dd> 1285%% 1286%% <dt>`{Name, Info}'</dt> 1287%% 1288%% <dd>where `{Name, Info} = 1289%% analyze_wild_attribute(Node)'.</dd> 1290%% </dl> 1291%% The evaluation throws `syntax_error' if `Node' 1292%% does not represent a well-formed module attribute. 1293%% 1294%% @see analyze_module_attribute/1 1295%% @see analyze_export_attribute/1 1296%% @see analyze_import_attribute/1 1297%% @see analyze_file_attribute/1 1298%% @see analyze_record_attribute/1 1299%% @see analyze_wild_attribute/1 1300 1301-spec analyze_attribute(erl_syntax:syntaxTree()) -> 1302 'preprocessor' | {atom(), term()}. % XXX: underspecified 1303 1304analyze_attribute(Node) -> 1305 Name = erl_syntax:attribute_name(Node), 1306 case erl_syntax:type(Name) of 1307 atom -> 1308 case erl_syntax:atom_value(Name) of 1309 define -> preprocessor; 1310 undef -> preprocessor; 1311 include -> preprocessor; 1312 include_lib -> preprocessor; 1313 ifdef -> preprocessor; 1314 ifndef -> preprocessor; 1315 'if' -> preprocessor; 1316 elif -> preprocessor; 1317 else -> preprocessor; 1318 endif -> preprocessor; 1319 A -> 1320 {A, analyze_attribute(A, Node)} 1321 end; 1322 _ -> 1323 throw(syntax_error) 1324 end. 1325 1326analyze_attribute(module, Node) -> 1327 analyze_module_attribute(Node); 1328analyze_attribute(export, Node) -> 1329 analyze_export_attribute(Node); 1330analyze_attribute(import, Node) -> 1331 analyze_import_attribute(Node); 1332analyze_attribute(file, Node) -> 1333 analyze_file_attribute(Node); 1334analyze_attribute(record, Node) -> 1335 analyze_record_attribute(Node); 1336analyze_attribute(_, Node) -> 1337 %% A "wild" attribute (such as e.g. a `compile' directive). 1338 analyze_wild_attribute(Node). 1339 1340 1341%% ===================================================================== 1342%% @spec analyze_module_attribute(Node::syntaxTree()) -> 1343%% Name::atom() | {Name::atom(), Variables::[atom()]} 1344%% 1345%% @doc Returns the module name and possible parameters declared by a 1346%% module attribute. If the attribute is a plain module declaration such 1347%% as `-module(name)', the result is the module name. If the attribute 1348%% is a parameterized module declaration, the result is a tuple 1349%% containing the module name and a list of the parameter variable 1350%% names. 1351%% 1352%% The evaluation throws `syntax_error' if `Node' does not represent a 1353%% well-formed module attribute. 1354%% 1355%% @see analyze_attribute/1 1356 1357-spec analyze_module_attribute(erl_syntax:syntaxTree()) -> 1358 atom() | {atom(), [atom()]}. 1359 1360analyze_module_attribute(Node) -> 1361 case erl_syntax:type(Node) of 1362 attribute -> 1363 case erl_syntax:attribute_arguments(Node) of 1364 [M] -> 1365 module_name_to_atom(M); 1366 [M, L] -> 1367 M1 = module_name_to_atom(M), 1368 L1 = analyze_variable_list(L), 1369 {M1, L1}; 1370 _ -> 1371 throw(syntax_error) 1372 end; 1373 _ -> 1374 throw(syntax_error) 1375 end. 1376 1377analyze_variable_list(Node) -> 1378 case erl_syntax:is_proper_list(Node) of 1379 true -> 1380 [erl_syntax:variable_name(V) 1381 || V <- erl_syntax:list_elements(Node)]; 1382 false -> 1383 throw(syntax_error) 1384 end. 1385 1386 1387%% ===================================================================== 1388%% @spec analyze_export_attribute(Node::syntaxTree()) -> [FunctionName] 1389%% 1390%% FunctionName = atom() | {atom(), integer()} 1391%% | {ModuleName, FunctionName} 1392%% ModuleName = atom() 1393%% 1394%% @doc Returns the list of function names declared by an export 1395%% attribute. We do not guarantee that each name occurs at most once in 1396%% the list. The order of listing is not defined. 1397%% 1398%% The evaluation throws `syntax_error' if `Node' does not represent a 1399%% well-formed export attribute. 1400%% 1401%% @see analyze_attribute/1 1402 1403-type functionN() :: atom() | {atom(), arity()}. 1404-type functionName() :: functionN() | {atom(), functionN()}. 1405 1406-spec analyze_export_attribute(erl_syntax:syntaxTree()) -> [functionName()]. 1407 1408analyze_export_attribute(Node) -> 1409 case erl_syntax:type(Node) of 1410 attribute -> 1411 case erl_syntax:attribute_arguments(Node) of 1412 [L] -> 1413 analyze_function_name_list(L); 1414 _ -> 1415 throw(syntax_error) 1416 end; 1417 _ -> 1418 throw(syntax_error) 1419 end. 1420 1421analyze_function_name_list(Node) -> 1422 case erl_syntax:is_proper_list(Node) of 1423 true -> 1424 [analyze_function_name(F) 1425 || F <- erl_syntax:list_elements(Node)]; 1426 false -> 1427 throw(syntax_error) 1428 end. 1429 1430 1431%% ===================================================================== 1432%% @spec analyze_function_name(Node::syntaxTree()) -> FunctionName 1433%% 1434%% FunctionName = atom() | {atom(), integer()} 1435%% | {ModuleName, FunctionName} 1436%% ModuleName = atom() 1437%% 1438%% @doc Returns the function name represented by a syntax tree. If 1439%% `Node' represents a function name, such as 1440%% "`foo/1'" or "`bloggs:fred/2'", a uniform 1441%% representation of that name is returned. Different nestings of arity 1442%% and module name qualifiers in the syntax tree does not affect the 1443%% result. 1444%% 1445%% The evaluation throws `syntax_error' if 1446%% `Node' does not represent a well-formed function name. 1447 1448-spec analyze_function_name(erl_syntax:syntaxTree()) -> functionName(). 1449 1450analyze_function_name(Node) -> 1451 case erl_syntax:type(Node) of 1452 atom -> 1453 erl_syntax:atom_value(Node); 1454 arity_qualifier -> 1455 A = erl_syntax:arity_qualifier_argument(Node), 1456 case erl_syntax:type(A) of 1457 integer -> 1458 F = erl_syntax:arity_qualifier_body(Node), 1459 F1 = analyze_function_name(F), 1460 append_arity(erl_syntax:integer_value(A), F1); 1461 _ -> 1462 throw(syntax_error) 1463 end; 1464 module_qualifier -> 1465 M = erl_syntax:module_qualifier_argument(Node), 1466 case erl_syntax:type(M) of 1467 atom -> 1468 F = erl_syntax:module_qualifier_body(Node), 1469 F1 = analyze_function_name(F), 1470 {erl_syntax:atom_value(M), F1}; 1471 _ -> 1472 throw(syntax_error) 1473 end; 1474 _ -> 1475 throw(syntax_error) 1476 end. 1477 1478append_arity(A, {Module, Name}) -> 1479 {Module, append_arity(A, Name)}; 1480append_arity(A, Name) when is_atom(Name) -> 1481 {Name, A}; 1482append_arity(A, A) -> 1483 A; 1484append_arity(_A, Name) -> 1485 Name. % quietly drop extra arity in case of conflict 1486 1487 1488%% ===================================================================== 1489%% @spec analyze_import_attribute(Node::syntaxTree()) -> 1490%% {atom(), [FunctionName]} | atom() 1491%% 1492%% FunctionName = atom() | {atom(), integer()} 1493%% | {ModuleName, FunctionName} 1494%% ModuleName = atom() 1495%% 1496%% @doc Returns the module name and (if present) list of function names 1497%% declared by an import attribute. The returned value is an atom 1498%% `Module' or a pair `{Module, Names}', where 1499%% `Names' is a list of function names declared as imported 1500%% from the module named by `Module'. We do not guarantee 1501%% that each name occurs at most once in `Names'. The order 1502%% of listing is not defined. 1503%% 1504%% The evaluation throws `syntax_error' if `Node' does not represent a 1505%% well-formed import attribute. 1506%% 1507%% @see analyze_attribute/1 1508 1509-spec analyze_import_attribute(erl_syntax:syntaxTree()) -> 1510 {atom(), [functionName()]} | atom(). 1511 1512analyze_import_attribute(Node) -> 1513 case erl_syntax:type(Node) of 1514 attribute -> 1515 case erl_syntax:attribute_arguments(Node) of 1516 [M] -> 1517 module_name_to_atom(M); 1518 [M, L] -> 1519 M1 = module_name_to_atom(M), 1520 L1 = analyze_function_name_list(L), 1521 {M1, L1}; 1522 _ -> 1523 throw(syntax_error) 1524 end; 1525 _ -> 1526 throw(syntax_error) 1527 end. 1528 1529 1530%% ===================================================================== 1531%% @spec analyze_type_name(Node::syntaxTree()) -> TypeName 1532%% 1533%% TypeName = atom() 1534%% | {atom(), integer()} 1535%% | {ModuleName, {atom(), integer()}} 1536%% ModuleName = atom() 1537%% 1538%% @doc Returns the type name represented by a syntax tree. If 1539%% `Node' represents a type name, such as 1540%% "`foo/1'" or "`bloggs:fred/2'", a uniform 1541%% representation of that name is returned. 1542%% 1543%% The evaluation throws `syntax_error' if 1544%% `Node' does not represent a well-formed type name. 1545 1546-spec analyze_type_name(erl_syntax:syntaxTree()) -> typeName(). 1547 1548analyze_type_name(Node) -> 1549 case erl_syntax:type(Node) of 1550 atom -> 1551 erl_syntax:atom_value(Node); 1552 arity_qualifier -> 1553 A = erl_syntax:arity_qualifier_argument(Node), 1554 N = erl_syntax:arity_qualifier_body(Node), 1555 1556 case ((erl_syntax:type(A) =:= integer) 1557 and (erl_syntax:type(N) =:= atom)) 1558 of 1559 true -> 1560 append_arity(erl_syntax:integer_value(A), 1561 erl_syntax:atom_value(N)); 1562 _ -> 1563 throw(syntax_error) 1564 end; 1565 module_qualifier -> 1566 M = erl_syntax:module_qualifier_argument(Node), 1567 case erl_syntax:type(M) of 1568 atom -> 1569 N = erl_syntax:module_qualifier_body(Node), 1570 N1 = analyze_type_name(N), 1571 {erl_syntax:atom_value(M), N1}; 1572 _ -> 1573 throw(syntax_error) 1574 end; 1575 _ -> 1576 throw(syntax_error) 1577 end. 1578 1579%% ===================================================================== 1580%% @spec analyze_wild_attribute(Node::syntaxTree()) -> {atom(), term()} 1581%% 1582%% @doc Returns the name and value of a "wild" attribute. The result is 1583%% the pair `{Name, Value}', if `Node' represents "`-Name(Value)'". 1584%% 1585%% Note that no checking is done whether `Name' is a 1586%% reserved attribute name such as `module' or 1587%% `export': it is assumed that the attribute is "wild". 1588%% 1589%% The evaluation throws `syntax_error' if `Node' does not represent a 1590%% well-formed wild attribute. 1591%% 1592%% @see analyze_attribute/1 1593 1594-spec analyze_wild_attribute(erl_syntax:syntaxTree()) -> {atom(), term()}. 1595 1596analyze_wild_attribute(Node) -> 1597 case erl_syntax:type(Node) of 1598 attribute -> 1599 N = erl_syntax:attribute_name(Node), 1600 case erl_syntax:type(N) of 1601 atom -> 1602 case erl_syntax:attribute_arguments(Node) of 1603 [V] -> 1604 %% Note: does not work well with macros. 1605 case catch {ok, erl_syntax:concrete(V)} of 1606 {ok, Val} -> 1607 {erl_syntax:atom_value(N), Val}; 1608 _ -> 1609 throw(syntax_error) 1610 end; 1611 _ -> 1612 throw(syntax_error) 1613 end; 1614 _ -> 1615 throw(syntax_error) 1616 end; 1617 _ -> 1618 throw(syntax_error) 1619 end. 1620 1621 1622%% ===================================================================== 1623%% @spec analyze_record_attribute(Node::syntaxTree()) -> 1624%% {atom(), Fields} 1625%% 1626%% Fields = [{atom(), {Default, Type}}] 1627%% Default = none | syntaxTree() 1628%% Type = none | syntaxTree() 1629%% 1630%% @doc Returns the name and the list of fields of a record declaration 1631%% attribute. The result is a pair `{Name, Fields}', if 1632%% `Node' represents "`-record(Name, {...}).'", 1633%% where `Fields' is a list of pairs `{Label, 1634%% {Default, Type}}' for each field "`Label'", "`Label = 1635%% <em>Default</em>'", "`Label :: <em>Type</em>'", or 1636%% "`Label = <em>Default</em> :: <em>Type</em>'" in the declaration, 1637%% listed in left-to-right 1638%% order. If the field has no default-value declaration, the value for 1639%% `Default' will be the atom `none'. If the field has no type declaration, 1640%% the value for `Type' will be the atom `none'. We do not 1641%% guarantee that each label occurs at most once in the list. 1642%% 1643%% The evaluation throws `syntax_error' if 1644%% `Node' does not represent a well-formed record declaration 1645%% attribute. 1646%% 1647%% @see analyze_attribute/1 1648%% @see analyze_record_field/1 1649 1650-type field() :: {atom(), {field_default(), field_type()}}. 1651 1652-type fields() :: [field()]. 1653 1654-spec analyze_record_attribute(erl_syntax:syntaxTree()) -> {atom(), fields()}. 1655 1656analyze_record_attribute(Node) -> 1657 case erl_syntax:type(Node) of 1658 attribute -> 1659 case erl_syntax:attribute_arguments(Node) of 1660 [R, T] -> 1661 case erl_syntax:type(R) of 1662 atom -> 1663 Es = analyze_record_attribute_tuple(T), 1664 {erl_syntax:atom_value(R), Es}; 1665 _ -> 1666 throw(syntax_error) 1667 end; 1668 _ -> 1669 throw(syntax_error) 1670 end; 1671 _ -> 1672 throw(syntax_error) 1673 end. 1674 1675analyze_record_attribute_tuple(Node) -> 1676 case erl_syntax:type(Node) of 1677 tuple -> 1678 [analyze_record_field(F) 1679 || F <- erl_syntax:tuple_elements(Node)]; 1680 _ -> 1681 throw(syntax_error) 1682 end. 1683 1684 1685%% ===================================================================== 1686%% @spec analyze_record_expr(Node::syntaxTree()) -> 1687%% {atom(), Info} | atom() 1688%% 1689%% Info = {atom(), [{atom(), Value}]} | {atom(), atom()} | atom() 1690%% Value = syntaxTree() 1691%% 1692%% @doc Returns the record name and field name/names of a record 1693%% expression. If `Node' has type `record_expr', 1694%% `record_index_expr' or `record_access', a pair 1695%% `{Type, Info}' is returned, otherwise an atom 1696%% `Type' is returned. `Type' is the node type of 1697%% `Node', and `Info' depends on 1698%% `Type', as follows: 1699%% <dl> 1700%% <dt>`record_expr':</dt> 1701%% <dd>`{atom(), [{atom(), Value}]}'</dd> 1702%% <dt>`record_access':</dt> 1703%% <dd>`{atom(), atom()}'</dd> 1704%% <dt>`record_index_expr':</dt> 1705%% <dd>`{atom(), atom()}'</dd> 1706%% </dl> 1707%% 1708%% For a `record_expr' node, `Info' represents 1709%% the record name and the list of descriptors for the involved fields, 1710%% listed in the order they appear. A field descriptor is a pair 1711%% `{Label, Value}', if `Node' represents "`Label = <em>Value</em>'". 1712%% For a `record_access' node, 1713%% `Info' represents the record name and the field name. For a 1714%% `record_index_expr' node, `Info' represents the 1715%% record name and the name field name. 1716%% 1717%% The evaluation throws `syntax_error' if 1718%% `Node' represents a record expression that is not 1719%% well-formed. 1720%% 1721%% @see analyze_record_attribute/1 1722%% @see analyze_record_field/1 1723 1724-type info() :: {atom(), [{atom(), erl_syntax:syntaxTree()}]} 1725 | {atom(), atom()} | atom(). 1726 1727-spec analyze_record_expr(erl_syntax:syntaxTree()) -> {atom(), info()} | atom(). 1728 1729analyze_record_expr(Node) -> 1730 case erl_syntax:type(Node) of 1731 record_expr -> 1732 A = erl_syntax:record_expr_type(Node), 1733 case erl_syntax:type(A) of 1734 atom -> 1735 Fs0 = [analyze_record_field(F) 1736 || F <- erl_syntax:record_expr_fields(Node)], 1737 Fs = [{N, D} || {N, {D, _T}} <- Fs0], 1738 {record_expr, {erl_syntax:atom_value(A), Fs}}; 1739 _ -> 1740 throw(syntax_error) 1741 end; 1742 record_access -> 1743 F = erl_syntax:record_access_field(Node), 1744 case erl_syntax:type(F) of 1745 atom -> 1746 A = erl_syntax:record_access_type(Node), 1747 case erl_syntax:type(A) of 1748 atom -> 1749 {record_access, 1750 {erl_syntax:atom_value(A), 1751 erl_syntax:atom_value(F)}}; 1752 _ -> 1753 throw(syntax_error) 1754 end; 1755 _ -> 1756 throw(syntax_error) 1757 end; 1758 record_index_expr -> 1759 F = erl_syntax:record_index_expr_field(Node), 1760 case erl_syntax:type(F) of 1761 atom -> 1762 A = erl_syntax:record_index_expr_type(Node), 1763 case erl_syntax:type(A) of 1764 atom -> 1765 {record_index_expr, 1766 {erl_syntax:atom_value(A), 1767 erl_syntax:atom_value(F)}}; 1768 _ -> 1769 throw(syntax_error) 1770 end; 1771 _ -> 1772 throw(syntax_error) 1773 end; 1774 Type -> 1775 Type 1776 end. 1777 1778%% ===================================================================== 1779%% @spec analyze_record_field(Node::syntaxTree()) -> {atom(), {Default, Type}} 1780%% 1781%% Default = none | syntaxTree() 1782%% Type = none | syntaxTree() 1783%% 1784%% @doc Returns the label, value-expression, and type of a record field 1785%% specifier. The result is a pair `{Label, {Default, Type}}', if 1786%% `Node' represents "`Label'", "`Label = <em>Default</em>'", 1787%% "`Label :: <em>Type</em>'", or 1788%% "`Label = <em>Default</em> :: <em>Type</em>'". 1789%% If the field has no value-expression, the value for 1790%% `Default' will be the atom `none'. If the field has no type, 1791%% the value for `Type' will be the atom `none'. 1792%% 1793%% The evaluation throws `syntax_error' if 1794%% `Node' does not represent a well-formed record field 1795%% specifier. 1796%% 1797%% @see analyze_record_attribute/1 1798%% @see analyze_record_expr/1 1799 1800-spec analyze_record_field(erl_syntax:syntaxTree()) -> field(). 1801 1802analyze_record_field(Node) -> 1803 case erl_syntax:type(Node) of 1804 record_field -> 1805 A = erl_syntax:record_field_name(Node), 1806 case erl_syntax:type(A) of 1807 atom -> 1808 T = erl_syntax:record_field_value(Node), 1809 {erl_syntax:atom_value(A), {T, none}}; 1810 _ -> 1811 throw(syntax_error) 1812 end; 1813 typed_record_field -> 1814 F = erl_syntax:typed_record_field_body(Node), 1815 {N, {V, _none}} = analyze_record_field(F), 1816 T = erl_syntax:typed_record_field_type(Node), 1817 {N, {V, T}}; 1818 _ -> 1819 throw(syntax_error) 1820 end. 1821 1822 1823%% ===================================================================== 1824%% @spec analyze_file_attribute(Node::syntaxTree()) -> 1825%% {string(), integer()} 1826%% 1827%% @doc Returns the file name and line number of a `file' 1828%% attribute. The result is the pair `{File, Line}' if 1829%% `Node' represents "`-file(File, Line).'". 1830%% 1831%% The evaluation throws `syntax_error' if 1832%% `Node' does not represent a well-formed `file' 1833%% attribute. 1834%% 1835%% @see analyze_attribute/1 1836 1837-spec analyze_file_attribute(erl_syntax:syntaxTree()) -> {string(), integer()}. 1838 1839analyze_file_attribute(Node) -> 1840 case erl_syntax:type(Node) of 1841 attribute -> 1842 case erl_syntax:attribute_arguments(Node) of 1843 [F, N] -> 1844 case (erl_syntax:type(F) =:= string) 1845 and (erl_syntax:type(N) =:= integer) of 1846 true -> 1847 {erl_syntax:string_value(F), 1848 erl_syntax:integer_value(N)}; 1849 false -> 1850 throw(syntax_error) 1851 end; 1852 _ -> 1853 throw(syntax_error) 1854 end; 1855 _ -> 1856 throw(syntax_error) 1857 end. 1858 1859 1860%% ===================================================================== 1861%% @spec analyze_function(Node::syntaxTree()) -> {atom(), integer()} 1862%% 1863%% @doc Returns the name and arity of a function definition. The result 1864%% is a pair `{Name, A}' if `Node' represents a 1865%% function definition "`Name(<em>P_1</em>, ..., <em>P_A</em>) -> 1866%% ...'". 1867%% 1868%% The evaluation throws `syntax_error' if 1869%% `Node' does not represent a well-formed function 1870%% definition. 1871 1872-spec analyze_function(erl_syntax:syntaxTree()) -> {atom(), arity()}. 1873 1874analyze_function(Node) -> 1875 case erl_syntax:type(Node) of 1876 function -> 1877 N = erl_syntax:function_name(Node), 1878 case erl_syntax:type(N) of 1879 atom -> 1880 {erl_syntax:atom_value(N), 1881 erl_syntax:function_arity(Node)}; 1882 _ -> 1883 throw(syntax_error) 1884 end; 1885 _ -> 1886 throw(syntax_error) 1887 end. 1888 1889 1890%% ===================================================================== 1891%% @spec analyze_implicit_fun(Node::syntaxTree()) -> FunctionName 1892%% 1893%% FunctionName = atom() | {atom(), integer()} 1894%% | {ModuleName, FunctionName} 1895%% ModuleName = atom() 1896%% 1897%% @doc Returns the name of an implicit fun expression "`fun 1898%% <em>F</em>'". The result is a representation of the function 1899%% name `F'. (Cf. `analyze_function_name/1'.) 1900%% 1901%% The evaluation throws `syntax_error' if 1902%% `Node' does not represent a well-formed implicit fun. 1903%% 1904%% @see analyze_function_name/1 1905 1906-spec analyze_implicit_fun(erl_syntax:syntaxTree()) -> functionName(). 1907 1908analyze_implicit_fun(Node) -> 1909 case erl_syntax:type(Node) of 1910 implicit_fun -> 1911 analyze_function_name(erl_syntax:implicit_fun_name(Node)); 1912 _ -> 1913 throw(syntax_error) 1914 end. 1915 1916 1917%% ===================================================================== 1918%% @spec analyze_application(Node::syntaxTree()) -> FunctionName | Arity 1919%% 1920%% FunctionName = {atom(), Arity} 1921%% | {ModuleName, FunctionName} 1922%% Arity = integer() 1923%% ModuleName = atom() 1924%% 1925%% @doc Returns the name of a called function. The result is a 1926%% representation of the name of the applied function `F/A', 1927%% if `Node' represents a function application 1928%% "`<em>F</em>(<em>X_1</em>, ..., <em>X_A</em>)'". If the 1929%% function is not explicitly named (i.e., `F' is given by 1930%% some expression), only the arity `A' is returned. 1931%% 1932%% The evaluation throws `syntax_error' if `Node' does not represent a 1933%% well-formed application expression. 1934%% 1935%% @see analyze_function_name/1 1936 1937-type appFunName() :: {atom(), arity()} | {atom(), {atom(), arity()}}. 1938 1939-spec analyze_application(erl_syntax:syntaxTree()) -> appFunName() | arity(). 1940 1941analyze_application(Node) -> 1942 case erl_syntax:type(Node) of 1943 application -> 1944 A = length(erl_syntax:application_arguments(Node)), 1945 F = erl_syntax:application_operator(Node), 1946 case catch {ok, analyze_function_name(F)} of 1947 syntax_error -> 1948 A; 1949 {ok, N} -> 1950 append_arity(A, N); 1951 _ -> 1952 throw(syntax_error) 1953 end; 1954 _ -> 1955 throw(syntax_error) 1956 end. 1957 1958 1959%% ===================================================================== 1960%% @spec analyze_type_application(Node::syntaxTree()) -> TypeName 1961%% 1962%% TypeName = {atom(), integer()} 1963%% | {ModuleName, {atom(), integer()}} 1964%% ModuleName = atom() 1965%% 1966%% @doc Returns the name of a used type. The result is a 1967%% representation of the name of the used pre-defined or local type `N/A', 1968%% if `Node' represents a local (user) type application 1969%% "`<em>N</em>(<em>T_1</em>, ..., <em>T_A</em>)'", or 1970%% a representation of the name of the used remote type `M:N/A' 1971%% if `Node' represents a remote user type application 1972%% "`<em>M</em>:<em>N</em>(<em>T_1</em>, ..., <em>T_A</em>)'". 1973%% 1974%% The evaluation throws `syntax_error' if `Node' does not represent a 1975%% well-formed (user) type application expression. 1976%% 1977%% @see analyze_type_name/1 1978 1979-type typeName() :: atom() | {module(), {atom(), arity()}} | {atom(), arity()}. 1980 1981-spec analyze_type_application(erl_syntax:syntaxTree()) -> typeName(). 1982 1983analyze_type_application(Node) -> 1984 case erl_syntax:type(Node) of 1985 type_application -> 1986 A = length(erl_syntax:type_application_arguments(Node)), 1987 N = erl_syntax:type_application_name(Node), 1988 case catch {ok, analyze_type_name(N)} of 1989 {ok, TypeName} -> 1990 append_arity(A, TypeName); 1991 _ -> 1992 throw(syntax_error) 1993 end; 1994 user_type_application -> 1995 A = length(erl_syntax:user_type_application_arguments(Node)), 1996 N = erl_syntax:user_type_application_name(Node), 1997 case catch {ok, analyze_type_name(N)} of 1998 {ok, TypeName} -> 1999 append_arity(A, TypeName); 2000 _ -> 2001 throw(syntax_error) 2002 end; 2003 _ -> 2004 throw(syntax_error) 2005 end. 2006 2007 2008%% ===================================================================== 2009%% @spec function_name_expansions(Names::[Name]) -> [{ShortName, Name}] 2010%% 2011%% Name = ShortName | {atom(), Name} 2012%% ShortName = atom() | {atom(), integer()} 2013%% 2014%% @doc Creates a mapping from corresponding short names to full 2015%% function names. Names are represented by nested tuples of atoms and 2016%% integers (cf. `analyze_function_name/1'). The result is a 2017%% list containing a pair `{ShortName, Name}' for each 2018%% element `Name' in the given list, where the corresponding 2019%% `ShortName' is the rightmost-innermost part of 2020%% `Name'. The list thus represents a finite mapping from 2021%% unqualified names to the corresponding qualified names. 2022%% 2023%% Note: the resulting list can contain more than one tuple 2024%% `{ShortName, Name}' for the same `ShortName', 2025%% possibly with different values for `Name', depending on 2026%% the given list. 2027%% 2028%% @see analyze_function_name/1 2029 2030-type shortname() :: atom() | {atom(), arity()}. 2031-type name() :: shortname() | {atom(), shortname()}. 2032 2033-spec function_name_expansions([name()]) -> [{shortname(), name()}]. 2034 2035function_name_expansions(Fs) -> 2036 function_name_expansions(Fs, []). 2037 2038function_name_expansions([F | Fs], Ack) -> 2039 function_name_expansions(Fs, 2040 function_name_expansions(F, F, Ack)); 2041function_name_expansions([], Ack) -> 2042 Ack. 2043 2044function_name_expansions({A, N}, Name, Ack) when is_integer(N) -> 2045 [{{A, N}, Name} | Ack]; 2046function_name_expansions({_, N}, Name, Ack) -> 2047 function_name_expansions(N, Name, Ack); 2048function_name_expansions(A, Name, Ack) -> 2049 [{A, Name} | Ack]. 2050 2051 2052%% ===================================================================== 2053%% @spec strip_comments(Tree::syntaxTree()) -> syntaxTree() 2054%% 2055%% @doc Removes all comments from all nodes of a syntax tree. All other 2056%% attributes (such as position information) remain unchanged. 2057%% Standalone comments in form lists are removed; any other standalone 2058%% comments are changed into null-comments (no text, no indentation). 2059 2060-spec strip_comments(erl_syntax:syntaxTree()) -> erl_syntax:syntaxTree(). 2061 2062strip_comments(Tree) -> 2063 map(fun strip_comments_1/1, Tree). 2064 2065strip_comments_1(T) -> 2066 case erl_syntax:type(T) of 2067 form_list -> 2068 Es = erl_syntax:form_list_elements(T), 2069 Es1 = [E || E <- Es, erl_syntax:type(E) /= comment], 2070 T1 = erl_syntax:copy_attrs(T, erl_syntax:form_list(Es1)), 2071 erl_syntax:remove_comments(T1); 2072 comment -> 2073 erl_syntax:comment([]); 2074 _ -> 2075 erl_syntax:remove_comments(T) 2076 end. 2077 2078%% ===================================================================== 2079%% @spec to_comment(Tree) -> syntaxTree() 2080%% @equiv to_comment(Tree, "% ") 2081 2082-spec to_comment(erl_syntax:syntaxTree()) -> erl_syntax:syntaxTree(). 2083 2084to_comment(Tree) -> 2085 to_comment(Tree, "% "). 2086 2087%% ===================================================================== 2088%% @spec to_comment(Tree::syntaxTree(), Prefix::string()) -> 2089%% syntaxTree() 2090%% 2091%% @doc Equivalent to `to_comment(Tree, Prefix, F)' for a 2092%% default formatting function `F'. The default 2093%% `F' simply calls `erl_prettypr:format/1'. 2094%% 2095%% @see to_comment/3 2096%% @see erl_prettypr:format/1 2097 2098-spec to_comment(erl_syntax:syntaxTree(), string()) -> erl_syntax:syntaxTree(). 2099 2100to_comment(Tree, Prefix) -> 2101 F = fun (T) -> erl_prettypr:format(T) end, 2102 to_comment(Tree, Prefix, F). 2103 2104%% ===================================================================== 2105%% @spec to_comment(Tree::syntaxTree(), Prefix::string(), Printer) -> 2106%% syntaxTree() 2107%% 2108%% Printer = (syntaxTree()) -> string() 2109%% 2110%% @doc Transforms a syntax tree into an abstract comment. The lines of 2111%% the comment contain the text for `Node', as produced by 2112%% the given `Printer' function. Each line of the comment is 2113%% prefixed by the string `Prefix' (this does not include the 2114%% initial "`%'" character of the comment line). 2115%% 2116%% For example, the result of 2117%% `to_comment(erl_syntax:abstract([a,b,c]))' represents 2118%% <pre> 2119%% %% [a,b,c]</pre> 2120%% (cf. `to_comment/1'). 2121%% 2122%% Note: the text returned by the formatting function will be split 2123%% automatically into separate comment lines at each line break. No 2124%% extra work is needed. 2125%% 2126%% @see to_comment/1 2127%% @see to_comment/2 2128 2129-spec to_comment(erl_syntax:syntaxTree(), string(), 2130 fun((erl_syntax:syntaxTree()) -> string())) -> 2131 erl_syntax:syntaxTree(). 2132 2133to_comment(Tree, Prefix, F) -> 2134 erl_syntax:comment(split_lines(F(Tree), Prefix)). 2135 2136 2137%% ===================================================================== 2138%% @spec limit(Tree, Depth) -> syntaxTree() 2139%% 2140%% @doc Equivalent to `limit(Tree, Depth, Text)' using the 2141%% text `"..."' as default replacement. 2142%% 2143%% @see limit/3 2144%% @see erl_syntax:text/1 2145 2146-spec limit(erl_syntax:syntaxTree(), integer()) -> erl_syntax:syntaxTree(). 2147 2148limit(Tree, Depth) -> 2149 limit(Tree, Depth, erl_syntax:text("...")). 2150 2151%% ===================================================================== 2152%% @spec limit(Tree::syntaxTree(), Depth::integer(), 2153%% Node::syntaxTree()) -> syntaxTree() 2154%% 2155%% @doc Limits a syntax tree to a specified depth. Replaces all non-leaf 2156%% subtrees in `Tree' at the given `Depth' by 2157%% `Node'. If `Depth' is negative, the result is 2158%% always `Node', even if `Tree' has no subtrees. 2159%% 2160%% When a group of subtrees (as e.g., the argument list of an 2161%% `application' node) is at the specified depth, and there 2162%% are two or more subtrees in the group, these will be collectively 2163%% replaced by `Node' even if they are leaf nodes. Groups of 2164%% subtrees that are above the specified depth will be limited in size, 2165%% as if each subsequent tree in the group were one level deeper than 2166%% the previous. E.g., if `Tree' represents a list of 2167%% integers "`[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]'", the result 2168%% of `limit(Tree, 5)' will represent `[1, 2, 3, 4, 2169%% ...]'. 2170%% 2171%% The resulting syntax tree is typically only useful for 2172%% pretty-printing or similar visual formatting. 2173%% 2174%% @see limit/2 2175 2176-spec limit(erl_syntax:syntaxTree(), integer(), erl_syntax:syntaxTree()) -> 2177 erl_syntax:syntaxTree(). 2178 2179limit(_Tree, Depth, Node) when Depth < 0 -> 2180 Node; 2181limit(Tree, Depth, Node) -> 2182 limit_1(Tree, Depth, Node). 2183 2184limit_1(Tree, Depth, Node) -> 2185 %% Depth is nonnegative here. 2186 case erl_syntax:subtrees(Tree) of 2187 [] -> 2188 if Depth > 0 -> 2189 Tree; 2190 true -> 2191 case is_simple_leaf(Tree) of 2192 true -> 2193 Tree; 2194 false -> 2195 Node 2196 end 2197 end; 2198 Gs -> 2199 if Depth > 1 -> 2200 Gs1 = [[limit_1(T, Depth - 1, Node) 2201 || T <- limit_list(G, Depth, Node)] 2202 || G <- Gs], 2203 rewrite(Tree, 2204 erl_syntax:make_tree(erl_syntax:type(Tree), 2205 Gs1)); 2206 Depth =:= 0 -> 2207 %% Depth is zero, and this is not a leaf node 2208 %% so we always replace it. 2209 Node; 2210 true -> 2211 %% Depth is 1, so all subtrees are to be cut. 2212 %% This is done groupwise. 2213 Gs1 = [cut_group(G, Node) || G <- Gs], 2214 rewrite(Tree, 2215 erl_syntax:make_tree(erl_syntax:type(Tree), 2216 Gs1)) 2217 end 2218 end. 2219 2220cut_group([], _Node) -> 2221 []; 2222cut_group([T], Node) -> 2223 %% Only if the group contains a single subtree do we try to 2224 %% preserve it if suitable. 2225 [limit_1(T, 0, Node)]; 2226cut_group(_Ts, Node) -> 2227 [Node]. 2228 2229is_simple_leaf(Tree) -> 2230 case erl_syntax:type(Tree) of 2231 atom -> true; 2232 char -> true; 2233 float -> true; 2234 integer -> true; 2235 nil -> true; 2236 operator -> true; 2237 tuple -> true; 2238 underscore -> true; 2239 variable -> true; 2240 _ -> false 2241 end. 2242 2243%% If list has more than N elements, take the N - 1 first and 2244%% append Node; otherwise return list as is. 2245 2246limit_list(Ts, N, Node) -> 2247 if length(Ts) > N -> 2248 limit_list_1(Ts, N - 1, Node); 2249 true -> 2250 Ts 2251 end. 2252 2253limit_list_1([T | Ts], N, Node) -> 2254 if N > 0 -> 2255 [T | limit_list_1(Ts, N - 1, Node)]; 2256 true -> 2257 [Node] 2258 end; 2259limit_list_1([], _N, _Node) -> 2260 []. 2261 2262 2263%% ===================================================================== 2264%% Utility functions 2265 2266rewrite(Tree, Tree1) -> 2267 erl_syntax:copy_attrs(Tree, Tree1). 2268 2269module_name_to_atom(M) -> 2270 case erl_syntax:type(M) of 2271 atom -> 2272 erl_syntax:atom_value(M); 2273 _ -> 2274 throw(syntax_error) 2275 end. 2276 2277%% This splits lines at line terminators and expands tab characters to 2278%% spaces. The width of a tab is assumed to be 8. 2279 2280% split_lines(Cs) -> 2281% split_lines(Cs, ""). 2282 2283split_lines(Cs, Prefix) -> 2284 split_lines(Cs, Prefix, 0). 2285 2286split_lines(Cs, Prefix, N) -> 2287 lists:reverse(split_lines(Cs, N, [], [], Prefix)). 2288 2289split_lines([$\r, $\n | Cs], _N, Cs1, Ls, Prefix) -> 2290 split_lines_1(Cs, Cs1, Ls, Prefix); 2291split_lines([$\r | Cs], _N, Cs1, Ls, Prefix) -> 2292 split_lines_1(Cs, Cs1, Ls, Prefix); 2293split_lines([$\n | Cs], _N, Cs1, Ls, Prefix) -> 2294 split_lines_1(Cs, Cs1, Ls, Prefix); 2295split_lines([$\t | Cs], N, Cs1, Ls, Prefix) -> 2296 split_lines(Cs, 0, push(8 - (N rem 8), $\040, Cs1), Ls, 2297 Prefix); 2298split_lines([C | Cs], N, Cs1, Ls, Prefix) -> 2299 split_lines(Cs, N + 1, [C | Cs1], Ls, Prefix); 2300split_lines([], _, [], Ls, _) -> 2301 Ls; 2302split_lines([], _N, Cs, Ls, Prefix) -> 2303 [Prefix ++ lists:reverse(Cs) | Ls]. 2304 2305split_lines_1(Cs, Cs1, Ls, Prefix) -> 2306 split_lines(Cs, 0, [], [Prefix ++ lists:reverse(Cs1) | Ls], 2307 Prefix). 2308 2309push(N, C, Cs) when N > 0 -> 2310 push(N - 1, C, [C | Cs]); 2311push(0, _, Cs) -> 2312 Cs. 2313 2314