diff options
Diffstat (limited to 'lib/syntax_tools/src/erl_syntax.erl')
-rw-r--r-- | lib/syntax_tools/src/erl_syntax.erl | 632 |
1 files changed, 443 insertions, 189 deletions
diff --git a/lib/syntax_tools/src/erl_syntax.erl b/lib/syntax_tools/src/erl_syntax.erl index 775b2cc109..3f2a3e05dd 100644 --- a/lib/syntax_tools/src/erl_syntax.erl +++ b/lib/syntax_tools/src/erl_syntax.erl @@ -220,12 +220,26 @@ macro/2, macro_arguments/1, macro_name/1, + map_expr/1, + map_expr/2, + map_expr_argument/1, + map_expr_fields/1, + map_field_assoc/2, + map_field_assoc_name/1, + map_field_assoc_value/1, + map_field_exact/2, + map_field_exact_name/1, + map_field_exact_value/1, match_expr/2, match_expr_body/1, match_expr_pattern/1, module_qualifier/2, module_qualifier_argument/1, module_qualifier_body/1, + named_fun_expr/2, + named_fun_expr_arity/1, + named_fun_expr_clauses/1, + named_fun_expr_name/1, nil/0, operator/1, operator_literal/1, @@ -240,7 +254,6 @@ receive_expr_action/1, receive_expr_clauses/1, receive_expr_timeout/1, - record_access/2, record_access/3, record_access_argument/1, record_access_field/1, @@ -257,10 +270,6 @@ record_index_expr/2, record_index_expr_field/1, record_index_expr_type/1, - rule/2, - rule_arity/1, - rule_clauses/1, - rule_name/1, size_qualifier/2, size_qualifier_argument/1, size_qualifier_body/1, @@ -439,8 +448,13 @@ %% </tr><tr> %% <td>list_comp</td> %% <td>macro</td> +%% <td>map_expr</td> +%% <td>map_field_assoc</td> +%% </tr><tr> +%% <td>map_field_exact</td> %% <td>match_expr</td> %% <td>module_qualifier</td> +%% <td>named_fun_expr</td> %% </tr><tr> %% <td>nil</td> %% <td>operator</td> @@ -449,20 +463,19 @@ %% </tr><tr> %% <td>receive_expr</td> %% <td>record_access</td> -%% </tr><tr> %% <td>record_expr</td> %% <td>record_field</td> -%% <td>record_index_expr</td> -%% <td>rule</td> %% </tr><tr> +%% <td>record_index_expr</td> %% <td>size_qualifier</td> %% <td>string</td> %% <td>text</td> -%% <td>try_expr</td> %% </tr><tr> +%% <td>try_expr</td> %% <td>tuple</td> %% <td>underscore</td> %% <td>variable</td> +%% </tr><tr> %% <td>warning_marker</td> %% </tr> %% </table></center> @@ -504,8 +517,12 @@ %% @see list/2 %% @see list_comp/2 %% @see macro/2 +%% @see map_expr/2 +%% @see map_field_assoc/2 +%% @see map_field_exact/2 %% @see match_expr/2 %% @see module_qualifier/2 +%% @see named_fun_expr/2 %% @see nil/0 %% @see operator/1 %% @see parentheses/1 @@ -515,7 +532,6 @@ %% @see record_expr/2 %% @see record_field/2 %% @see record_index_expr/2 -%% @see rule/2 %% @see size_qualifier/2 %% @see string/1 %% @see text/1 @@ -554,6 +570,7 @@ type(Node) -> {'catch', _, _} -> catch_expr; {'cond', _, _} -> cond_expr; {'fun', _, {clauses, _}} -> fun_expr; + {named_fun, _, _, _} -> named_fun_expr; {'fun', _, {function, _, _}} -> implicit_fun; {'fun', _, {function, _, _, _}} -> implicit_fun; {'if', _, _} -> if_expr; @@ -572,15 +589,17 @@ type(Node) -> {lc, _, _, _} -> list_comp; {bc, _, _, _} -> binary_comp; {match, _, _, _} -> match_expr; + {map, _, _, _} -> map_expr; + {map, _, _} -> map_expr; + {map_field_assoc, _, _, _} -> map_field_assoc; + {map_field_exact, _, _, _} -> map_field_exact; {op, _, _, _, _} -> infix_expr; {op, _, _, _} -> prefix_expr; {record, _, _, _, _} -> record_expr; {record, _, _, _} -> record_expr; {record_field, _, _, _, _} -> record_access; - {record_field, _, _, _} -> record_access; {record_index, _, _, _} -> record_index_expr; {remote, _, _, _} -> module_qualifier; - {rule, _, _, _, _} -> rule; {'try', _, _, _, _, _} -> try_expr; {tuple, _, _} -> tuple; _ -> @@ -639,6 +658,9 @@ is_leaf(Node) -> operator -> true; % nonstandard type string -> true; text -> true; % nonstandard type + map_expr -> + map_expr_fields(Node) =:= [] andalso + map_expr_argument(Node) =:= none; tuple -> tuple_elements(Node) =:= []; underscore -> true; variable -> true; @@ -660,10 +682,9 @@ is_leaf(Node) -> %% <td>`comment'</td> %% <td>`error_marker'</td> %% <td>`eof_marker'</td> -%% <td>`form_list'</td> %% </tr><tr> +%% <td>`form_list'</td> %% <td>`function'</td> -%% <td>`rule'</td> %% <td>`warning_marker'</td> %% <td>`text'</td> %% </tr> @@ -676,7 +697,6 @@ is_leaf(Node) -> %% @see error_marker/1 %% @see form_list/1 %% @see function/2 -%% @see rule/2 %% @see warning_marker/1 -spec is_form(syntaxTree()) -> boolean(). @@ -689,7 +709,6 @@ is_form(Node) -> eof_marker -> true; error_marker -> true; form_list -> true; - rule -> true; warning_marker -> true; text -> true; _ -> false @@ -1902,6 +1921,208 @@ atom_literal(Node) -> %% ===================================================================== +%% @equiv map_expr(none, Fields) + +-spec map_expr([syntaxTree()]) -> syntaxTree(). + +map_expr(Fields) -> + map_expr(none, Fields). + + +%% ===================================================================== +%% @doc Creates an abstract map expression. If `Fields' is +%% `[F1, ..., Fn]', then if `Argument' is `none', the result represents +%% "<code>#{<em>F1</em>, ..., <em>Fn</em>}</code>", +%% otherwise it represents +%% "<code><em>Argument</em>#{<em>F1</em>, ..., <em>Fn</em>}</code>". +%% +%% @see map_expr/1 +%% @see map_expr_argument/1 +%% @see map_expr_fields/1 +%% @see map_field_assoc/2 +%% @see map_field_exact/2 + +-record(map_expr, {argument :: 'none' | syntaxTree(), + fields :: [syntaxTree()]}). + +%% `erl_parse' representation: +%% +%% {map, Pos, Fields} +%% {map, Pos, Argument, Fields} + +-spec map_expr('none' | syntaxTree(), [syntaxTree()]) -> syntaxTree(). + +map_expr(Argument, Fields) -> + tree(map_expr, #map_expr{argument = Argument, fields = Fields}). + +revert_map_expr(Node) -> + Pos = get_pos(Node), + Argument = map_expr_argument(Node), + Fields = map_expr_fields(Node), + case Argument of + none -> + {map, Pos, Fields}; + _ -> + {map, Pos, Argument, Fields} + end. + + +%% ===================================================================== +%% @doc Returns the argument subtree of a `map_expr' node, if any. If `Node' +%% represents "<code>#{...}</code>", `none' is returned. +%% Otherwise, if `Node' represents "<code><em>Argument</em>#{...}</code>", +%% `Argument' is returned. +%% +%% @see map_expr/2 + +-spec map_expr_argument(syntaxTree()) -> 'none' | syntaxTree(). + +map_expr_argument(Node) -> + case unwrap(Node) of + {map, _, _} -> + none; + {map, _, Argument, _} -> + Argument; + Node1 -> + (data(Node1))#map_expr.argument + end. + + +%% ===================================================================== +%% @doc Returns the list of field subtrees of a `map_expr' node. +%% +%% @see map_expr/2 + +-spec map_expr_fields(syntaxTree()) -> [syntaxTree()]. + +map_expr_fields(Node) -> + case unwrap(Node) of + {map, _, Fields} -> + Fields; + {map, _, _, Fields} -> + Fields; + Node1 -> + (data(Node1))#map_expr.fields + end. + + +%% ===================================================================== +%% @doc Creates an abstract map assoc field. The result represents +%% "<code><em>Name</em> => <em>Value</em></code>". +%% +%% @see map_field_assoc_name/1 +%% @see map_field_assoc_value/1 +%% @see map_expr/2 + +-record(map_field_assoc, {name :: syntaxTree(), value :: syntaxTree()}). + +%% `erl_parse' representation: +%% +%% {map_field_assoc, Pos, Name, Value} + +-spec map_field_assoc(syntaxTree(), syntaxTree()) -> syntaxTree(). + +map_field_assoc(Name, Value) -> + tree(map_field_assoc, #map_field_assoc{name = Name, value = Value}). + +revert_map_field_assoc(Node) -> + Pos = get_pos(Node), + Name = map_field_assoc_name(Node), + Value = map_field_assoc_value(Node), + {map_field_assoc, Pos, Name, Value}. + + +%% ===================================================================== +%% @doc Returns the name subtree of a `map_field_assoc' node. +%% +%% @see map_field_assoc/2 + +-spec map_field_assoc_name(syntaxTree()) -> syntaxTree(). + +map_field_assoc_name(Node) -> + case Node of + {map_field_assoc, _, Name, _} -> + Name; + _ -> + (data(Node))#map_field_assoc.name + end. + + +%% ===================================================================== +%% @doc Returns the value subtree of a `map_field_assoc' node. +%% +%% @see map_field_assoc/2 + +-spec map_field_assoc_value(syntaxTree()) -> syntaxTree(). + +map_field_assoc_value(Node) -> + case Node of + {map_field_assoc, _, _, Value} -> + Value; + _ -> + (data(Node))#map_field_assoc.value + end. + + +%% ===================================================================== +%% @doc Creates an abstract map exact field. The result represents +%% "<code><em>Name</em> := <em>Value</em></code>". +%% +%% @see map_field_exact_name/1 +%% @see map_field_exact_value/1 +%% @see map_expr/2 + +-record(map_field_exact, {name :: syntaxTree(), value :: syntaxTree()}). + +%% `erl_parse' representation: +%% +%% {map_field_exact, Pos, Name, Value} + +-spec map_field_exact(syntaxTree(), syntaxTree()) -> syntaxTree(). + +map_field_exact(Name, Value) -> + tree(map_field_exact, #map_field_exact{name = Name, value = Value}). + +revert_map_field_exact(Node) -> + Pos = get_pos(Node), + Name = map_field_exact_name(Node), + Value = map_field_exact_value(Node), + {map_field_exact, Pos, Name, Value}. + + +%% ===================================================================== +%% @doc Returns the name subtree of a `map_field_exact' node. +%% +%% @see map_field_exact/2 + +-spec map_field_exact_name(syntaxTree()) -> syntaxTree(). + +map_field_exact_name(Node) -> + case Node of + {map_field_exact, _, Name, _} -> + Name; + _ -> + (data(Node))#map_field_exact.name + end. + + +%% ===================================================================== +%% @doc Returns the value subtree of a `map_field_exact' node. +%% +%% @see map_field_exact/2 + +-spec map_field_exact_value(syntaxTree()) -> syntaxTree(). + +map_field_exact_value(Node) -> + case Node of + {map_field_exact, _, _, Value} -> + Value; + _ -> + (data(Node))#map_field_exact.value + end. + + +%% ===================================================================== %% @doc Creates an abstract tuple. If `Elements' is %% `[X1, ..., Xn]', the result represents %% "<code>{<em>X1</em>, ..., <em>Xn</em>}</code>". @@ -3088,6 +3309,11 @@ attribute_arguments(Node) -> [set_pos( list(unfold_function_names(Data, Pos)), Pos)]; + optional_callbacks -> + D = try list(unfold_function_names(Data, Pos)) + catch _:_ -> abstract(Data) + end, + [set_pos(D, Pos)]; import -> {Module, Imports} = Data, [set_pos(atom(Module), Pos), @@ -3240,7 +3466,6 @@ module_qualifier_body(Node) -> %% @see function_clauses/1 %% @see function_arity/1 %% @see is_form/1 -%% @see rule/2 %% Don't use the name 'function' for this record, to avoid confusion with %% the tuples on the form {function,Name,Arity} used by erl_parse. @@ -4070,49 +4295,32 @@ record_index_expr_field(Node) -> %% ===================================================================== -%% @equiv record_access(Argument, none, Field) - --spec record_access(syntaxTree(), syntaxTree()) -> syntaxTree(). - -record_access(Argument, Field) -> - record_access(Argument, none, Field). - - -%% ===================================================================== -%% @doc Creates an abstract record field access expression. If -%% `Type' is not `none', the result represents -%% "<code><em>Argument</em>#<em>Type</em>.<em>Field</em></code>". -%% -%% If `Type' is `none', the result represents -%% "<code><em>Argument</em>.<em>Field</em></code>". This is a special -%% form only allowed within Mnemosyne queries. +%% @doc Creates an abstract record field access expression. The result +%% represents "<code><em>Argument</em>#<em>Type</em>.<em>Field</em></code>". %% -%% @see record_access/2 %% @see record_access_argument/1 %% @see record_access_type/1 %% @see record_access_field/1 %% @see record_expr/3 -record(record_access, {argument :: syntaxTree(), - type :: 'none' | syntaxTree(), + type :: syntaxTree(), field :: syntaxTree()}). %% type(Node) = record_access %% data(Node) = #record_access{argument :: Argument, type :: Type, %% field :: Field} %% -%% Argument = Field = syntaxTree() -%% Type = none | syntaxTree() +%% Argument = Type = Field = syntaxTree() %% %% `erl_parse' representation: %% %% {record_field, Pos, Argument, Type, Field} -%% {record_field, Pos, Argument, Field} %% %% Argument = Field = erl_parse() %% Type = atom() --spec record_access(syntaxTree(), 'none' | syntaxTree(), syntaxTree()) -> +-spec record_access(syntaxTree(), syntaxTree(), syntaxTree()) -> syntaxTree(). record_access(Argument, Type, Field) -> @@ -4125,16 +4333,11 @@ revert_record_access(Node) -> Argument = record_access_argument(Node), Type = record_access_type(Node), Field = record_access_field(Node), - if Type =:= none -> - {record_field, Pos, Argument, Field}; - true -> - case type(Type) of - atom -> - {record_field, Pos, - Argument, concrete(Type), Field}; - _ -> - Node - end + case type(Type) of + atom -> + {record_field, Pos, Argument, concrete(Type), Field}; + _ -> + Node end. @@ -4147,8 +4350,6 @@ revert_record_access(Node) -> record_access_argument(Node) -> case unwrap(Node) of - {record_field, _, Argument, _} -> - Argument; {record_field, _, Argument, _, _} -> Argument; Node1 -> @@ -4157,21 +4358,14 @@ record_access_argument(Node) -> %% ===================================================================== -%% @doc Returns the type subtree of a `record_access' node, -%% if any. If `Node' represents -%% "<code><em>Argument</em>.<em>Field</em></code>", `none' -%% is returned, otherwise if `Node' represents -%% "<code><em>Argument</em>#<em>Type</em>.<em>Field</em></code>", -%% `Type' is returned. +%% @doc Returns the type subtree of a `record_access' node. %% %% @see record_access/3 --spec record_access_type(syntaxTree()) -> 'none' | syntaxTree(). +-spec record_access_type(syntaxTree()) -> syntaxTree(). record_access_type(Node) -> case unwrap(Node) of - {record_field, _, _, _} -> - none; {record_field, Pos, _, Type, _} -> set_pos(atom(Type), Pos); Node1 -> @@ -4188,8 +4382,6 @@ record_access_type(Node) -> record_access_field(Node) -> case unwrap(Node) of - {record_field, _, _, Field} -> - Field; {record_field, _, _, _, Field} -> Field; Node1 -> @@ -4568,117 +4760,6 @@ binary_comp_body(Node) -> %% ===================================================================== -%% @doc Creates an abstract Mnemosyne rule. If `Clauses' is -%% `[C1, ..., Cn]', the results represents -%% "<code><em>Name</em> <em>C1</em>; ...; <em>Name</em> -%% <em>Cn</em>.</code>". More exactly, if each `Ci' -%% represents "<code>(<em>Pi1</em>, ..., <em>Pim</em>) <em>Gi</em> -> -%% <em>Bi</em></code>", then the result represents -%% "<code><em>Name</em>(<em>P11</em>, ..., <em>P1m</em>) <em>G1</em> :- -%% <em>B1</em>; ...; <em>Name</em>(<em>Pn1</em>, ..., <em>Pnm</em>) -%% <em>Gn</em> :- <em>Bn</em>.</code>". Rules are source code forms. -%% -%% @see rule_name/1 -%% @see rule_clauses/1 -%% @see rule_arity/1 -%% @see is_form/1 -%% @see function/2 - --record(rule, {name :: syntaxTree(), clauses :: [syntaxTree()]}). - -%% type(Node) = rule -%% data(Node) = #rule{name :: Name, clauses :: Clauses} -%% -%% Name = syntaxTree() -%% Clauses = [syntaxTree()] -%% -%% (See `function' for notes on why the arity is not stored.) -%% -%% `erl_parse' representation: -%% -%% {rule, Pos, Name, Arity, Clauses} -%% -%% Name = atom() -%% Arity = integer() -%% Clauses = [Clause] \ [] -%% Clause = {clause, ...} -%% -%% where the number of patterns in each clause should be equal to -%% the integer `Arity'; see `clause' for documentation on -%% `erl_parse' clauses. - --spec rule(syntaxTree(), [syntaxTree()]) -> syntaxTree(). - -rule(Name, Clauses) -> - tree(rule, #rule{name = Name, clauses = Clauses}). - -revert_rule(Node) -> - Name = rule_name(Node), - Clauses = [revert_clause(C) || C <- rule_clauses(Node)], - Pos = get_pos(Node), - case type(Name) of - atom -> - A = rule_arity(Node), - {rule, Pos, concrete(Name), A, Clauses}; - _ -> - Node - end. - - -%% ===================================================================== -%% @doc Returns the name subtree of a `rule' node. -%% -%% @see rule/2 - --spec rule_name(syntaxTree()) -> syntaxTree(). - -rule_name(Node) -> - case unwrap(Node) of - {rule, Pos, Name, _, _} -> - set_pos(atom(Name), Pos); - Node1 -> - (data(Node1))#rule.name - end. - -%% ===================================================================== -%% @doc Returns the list of clause subtrees of a `rule' node. -%% -%% @see rule/2 - --spec rule_clauses(syntaxTree()) -> [syntaxTree()]. - -rule_clauses(Node) -> - case unwrap(Node) of - {rule, _, _, _, Clauses} -> - Clauses; - Node1 -> - (data(Node1))#rule.clauses - end. - -%% ===================================================================== -%% @doc Returns the arity of a `rule' node. The result is the -%% number of parameter patterns in the first clause of the rule; -%% subsequent clauses are ignored. -%% -%% An exception is thrown if `rule_clauses(Node)' returns -%% an empty list, or if the first element of that list is not a syntax -%% tree `C' of type `clause' such that -%% `clause_patterns(C)' is a nonempty list. -%% -%% @see rule/2 -%% @see rule_clauses/1 -%% @see clause/3 -%% @see clause_patterns/1 - --spec rule_arity(syntaxTree()) -> arity(). - -rule_arity(Node) -> - %% Note that this never accesses the arity field of - %% `erl_parse' rule nodes. - length(clause_patterns(hd(rule_clauses(Node)))). - - -%% ===================================================================== %% @doc Creates an abstract generator. The result represents %% "<code><em>Pattern</em> <- <em>Body</em></code>". %% @@ -5622,6 +5703,110 @@ fun_expr_arity(Node) -> %% ===================================================================== +%% @doc Creates an abstract named fun-expression. If `Clauses' is +%% `[C1, ..., Cn]', the result represents "<code>fun +%% <em>Name</em> <em>C1</em>; ...; <em>Name</em> <em>Cn</em> end</code>". +%% More exactly, if each `Ci' represents +%% "<code>(<em>Pi1</em>, ..., <em>Pim</em>) <em>Gi</em> -> <em>Bi</em></code>", +%% then the result represents +%% "<code>fun <em>Name</em>(<em>P11</em>, ..., <em>P1m</em>) <em>G1</em> -> +%% <em>B1</em>; ...; <em>Name</em>(<em>Pn1</em>, ..., <em>Pnm</em>) +%% <em>Gn</em> -> <em>Bn</em> end</code>". +%% +%% @see named_fun_expr_name/1 +%% @see named_fun_expr_clauses/1 +%% @see named_fun_expr_arity/1 + +-record(named_fun_expr, {name :: syntaxTree(), clauses :: [syntaxTree()]}). + +%% type(Node) = named_fun_expr +%% data(Node) = #named_fun_expr{name :: Name, clauses :: Clauses} +%% +%% Name = syntaxTree() +%% Clauses = [syntaxTree()] +%% +%% (See `function' for notes; e.g. why the arity is not stored.) +%% +%% `erl_parse' representation: +%% +%% {named_fun, Pos, Name, Clauses} +%% +%% Clauses = [Clause] \ [] +%% Clause = {clause, ...} +%% +%% See `clause' for documentation on `erl_parse' clauses. + +-spec named_fun_expr(syntaxTree(), [syntaxTree()]) -> syntaxTree(). + +named_fun_expr(Name, Clauses) -> + tree(named_fun_expr, #named_fun_expr{name = Name, clauses = Clauses}). + +revert_named_fun_expr(Node) -> + Pos = get_pos(Node), + Name = named_fun_expr_name(Node), + Clauses = [revert_clause(C) || C <- named_fun_expr_clauses(Node)], + case type(Name) of + variable -> + {named_fun, Pos, variable_name(Name), Clauses}; + _ -> + Node + end. + + +%% ===================================================================== +%% @doc Returns the name subtree of a `named_fun_expr' node. +%% +%% @see named_fun_expr/2 + +-spec named_fun_expr_name(syntaxTree()) -> syntaxTree(). + +named_fun_expr_name(Node) -> + case unwrap(Node) of + {named_fun, Pos, Name, _} -> + set_pos(variable(Name), Pos); + Node1 -> + (data(Node1))#named_fun_expr.name + end. + + +%% ===================================================================== +%% @doc Returns the list of clause subtrees of a `named_fun_expr' node. +%% +%% @see named_fun_expr/2 + +-spec named_fun_expr_clauses(syntaxTree()) -> [syntaxTree()]. + +named_fun_expr_clauses(Node) -> + case unwrap(Node) of + {named_fun, _, _, Clauses} -> + Clauses; + Node1 -> + (data(Node1))#named_fun_expr.clauses + end. + + +%% ===================================================================== +%% @doc Returns the arity of a `named_fun_expr' node. The result is +%% the number of parameter patterns in the first clause of the +%% named fun-expression; subsequent clauses are ignored. +%% +%% An exception is thrown if `named_fun_expr_clauses(Node)' +%% returns an empty list, or if the first element of that list is not a +%% syntax tree `C' of type `clause' such that +%% `clause_patterns(C)' is a nonempty list. +%% +%% @see named_fun_expr/2 +%% @see named_fun_expr_clauses/1 +%% @see clause/3 +%% @see clause_patterns/1 + +-spec named_fun_expr_arity(syntaxTree()) -> arity(). + +named_fun_expr_arity(Node) -> + length(clause_patterns(hd(named_fun_expr_clauses(Node)))). + + +%% ===================================================================== %% @doc Creates an abstract parenthesised expression. The result %% represents "<code>(<em>Body</em>)</code>", independently of the %% context. @@ -5757,6 +5942,9 @@ abstract([]) -> nil(); abstract(T) when is_tuple(T) -> tuple(abstract_list(tuple_to_list(T))); +abstract(T) when is_map(T) -> + map_expr([map_field_assoc(abstract(Key),abstract(Value)) + || {Key,Value} <- maps:to_list(T)]); abstract(T) when is_binary(T) -> binary([binary_field(integer(B)) || B <- binary_to_list(T)]); abstract(T) -> @@ -5793,6 +5981,13 @@ abstract_tail(H, T) -> %% {@link char/1} function to explicitly create an abstract %% character.) %% +%% Note: `arity_qualifier' nodes are recognized. This is to follow The +%% Erlang Parser when it comes to wild attributes: both {F, A} and F/A +%% are recognized, which makes it possible to turn wild attributes +%% into recognized attributes without at the same time making it +%% impossible to compile files using the new syntax with the old +%% version of the Erlang Compiler. +%% %% @see abstract/1 %% @see is_literal/1 %% @see char/1 @@ -5818,6 +6013,14 @@ concrete(Node) -> | concrete(list_tail(Node))]; tuple -> list_to_tuple(concrete_list(tuple_elements(Node))); + map_expr -> + As = [tuple([map_field_assoc_name(F), + map_field_assoc_value(F)]) || F <- map_expr_fields(Node)], + M0 = maps:from_list(concrete_list(As)), + case map_expr_argument(Node) of + none -> M0; + Node0 -> maps:merge(concrete(Node0),M0) + end; binary -> Fs = [revert_binary_field( binary_field(binary_field_body(F), @@ -5834,6 +6037,20 @@ concrete(Node) -> {value, concrete(F), []} end, [], true), B; + arity_qualifier -> + A = erl_syntax:arity_qualifier_argument(Node), + case erl_syntax:type(A) of + integer -> + F = erl_syntax:arity_qualifier_body(Node), + case erl_syntax:type(F) of + atom -> + {F, A}; + _ -> + erlang:error({badarg, Node}) + end; + _ -> + erlang:error({badarg, Node}) + end; _ -> erlang:error({badarg, Node}) end. @@ -5873,10 +6090,31 @@ is_literal(T) -> is_literal(list_head(T)) andalso is_literal(list_tail(T)); tuple -> lists:all(fun is_literal/1, tuple_elements(T)); + map_expr -> + case map_expr_argument(T) of + none -> true; + Arg -> is_literal(Arg) + end andalso lists:all(fun is_literal_map_field/1, map_expr_fields(T)); + binary -> + lists:all(fun is_literal_binary_field/1, binary_fields(T)); _ -> false end. +is_literal_binary_field(F) -> + case binary_field_types(F) of + [] -> is_literal(binary_field_body(F)); + _ -> false + end. + +is_literal_map_field(F) -> + case type(F) of + map_field_assoc -> + is_literal(map_field_assoc_name(F)) andalso + is_literal(map_field_assoc_value(F)); + map_field_exact -> + false + end. %% ===================================================================== %% @doc Returns an `erl_parse'-compatible representation of a @@ -5980,10 +6218,18 @@ revert_root(Node) -> revert_list(Node); list_comp -> revert_list_comp(Node); + map_expr -> + revert_map_expr(Node); + map_field_assoc -> + revert_map_field_assoc(Node); + map_field_exact -> + revert_map_field_exact(Node); match_expr -> revert_match_expr(Node); module_qualifier -> revert_module_qualifier(Node); + named_fun_expr -> + revert_named_fun_expr(Node); nil -> revert_nil(Node); parentheses -> @@ -5998,8 +6244,6 @@ revert_root(Node) -> revert_record_expr(Node); record_index_expr -> revert_record_index_expr(Node); - rule -> - revert_rule(Node); string -> revert_string(Node); try_expr -> @@ -6219,12 +6463,28 @@ subtrees(T) -> As -> [[macro_name(T)], As] end; + map_expr -> + case map_expr_argument(T) of + none -> + [map_expr_fields(T)]; + V -> + [[V], map_expr_fields(T)] + end; + map_field_assoc -> + [[map_field_assoc_name(T)], + [map_field_assoc_value(T)]]; + map_field_exact -> + [[map_field_exact_name(T)], + [map_field_exact_value(T)]]; match_expr -> [[match_expr_pattern(T)], [match_expr_body(T)]]; module_qualifier -> [[module_qualifier_argument(T)], [module_qualifier_body(T)]]; + named_fun_expr -> + [[named_fun_expr_name(T)], + named_fun_expr_clauses(T)]; parentheses -> [[parentheses_body(T)]]; prefix_expr -> @@ -6240,15 +6500,9 @@ subtrees(T) -> receive_expr_action(T)] end; record_access -> - case record_access_type(T) of - none -> - [[record_access_argument(T)], - [record_access_field(T)]]; - R -> - [[record_access_argument(T)], - [R], - [record_access_field(T)]] - end; + [[record_access_argument(T)], + [record_access_type(T)], + [record_access_field(T)]]; record_expr -> case record_expr_argument(T) of none -> @@ -6269,8 +6523,6 @@ subtrees(T) -> record_index_expr -> [[record_index_expr_type(T)], [record_index_expr_field(T)]]; - rule -> - [[rule_name(T)], rule_clauses(T)]; size_qualifier -> [[size_qualifier_body(T)], [size_qualifier_argument(T)]]; @@ -6354,14 +6606,17 @@ make_tree(list, [P, [S]]) -> list(P, S); make_tree(list_comp, [[T], B]) -> list_comp(T, B); make_tree(macro, [[N]]) -> macro(N); make_tree(macro, [[N], A]) -> macro(N, A); +make_tree(map_expr, [Fs]) -> map_expr(Fs); +make_tree(map_expr, [[E], Fs]) -> map_expr(E, Fs); +make_tree(map_field_assoc, [[K], [V]]) -> map_field_assoc(K, V); +make_tree(map_field_exact, [[K], [V]]) -> map_field_exact(K, V); make_tree(match_expr, [[P], [E]]) -> match_expr(P, E); +make_tree(named_fun_expr, [[N], C]) -> named_fun_expr(N, C); make_tree(module_qualifier, [[M], [N]]) -> module_qualifier(M, N); make_tree(parentheses, [[E]]) -> parentheses(E); make_tree(prefix_expr, [[F], [A]]) -> prefix_expr(F, A); make_tree(receive_expr, [C]) -> receive_expr(C); make_tree(receive_expr, [C, [E], A]) -> receive_expr(C, E, A); -make_tree(record_access, [[E], [F]]) -> - record_access(E, F); make_tree(record_access, [[E], [T], [F]]) -> record_access(E, T, F); make_tree(record_expr, [[T], F]) -> record_expr(T, F); @@ -6370,7 +6625,6 @@ make_tree(record_field, [[N]]) -> record_field(N); make_tree(record_field, [[N], [E]]) -> record_field(N, E); make_tree(record_index_expr, [[T], [F]]) -> record_index_expr(T, F); -make_tree(rule, [[N], C]) -> rule(N, C); make_tree(size_qualifier, [[N], [A]]) -> size_qualifier(N, A); make_tree(try_expr, [B, C, H, A]) -> try_expr(B, C, H, A); make_tree(tuple, [E]) -> tuple(E). |