diff options
Diffstat (limited to 'lib/syntax_tools/src')
-rw-r--r-- | lib/syntax_tools/src/Makefile | 2 | ||||
-rw-r--r-- | lib/syntax_tools/src/epp_dodger.erl | 36 | ||||
-rw-r--r-- | lib/syntax_tools/src/erl_comment_scan.erl | 2 | ||||
-rw-r--r-- | lib/syntax_tools/src/erl_prettypr.erl | 25 | ||||
-rw-r--r-- | lib/syntax_tools/src/erl_syntax.erl | 114 | ||||
-rw-r--r-- | lib/syntax_tools/src/erl_syntax_lib.erl | 4 | ||||
-rw-r--r-- | lib/syntax_tools/src/merl_transform.erl | 2 |
7 files changed, 149 insertions, 36 deletions
diff --git a/lib/syntax_tools/src/Makefile b/lib/syntax_tools/src/Makefile index 8325db45a8..c21d2f49c8 100644 --- a/lib/syntax_tools/src/Makefile +++ b/lib/syntax_tools/src/Makefile @@ -75,7 +75,7 @@ $(EBIN)/%.$(EMULATOR):%.erl # special rules and dependencies to apply the transform to itself $(EBIN)/merl_transform.beam: $(EBIN)/merl.beam ./merl_transform.beam \ - ../include/merl.hrl \ + ../include/merl.hrl $(EBIN)/erl_comment_scan.beam \ $(EBIN)/erl_syntax.beam $(EBIN)/erl_syntax_lib.beam ./merl_transform.beam: ./merl_transform.erl $(EBIN)/merl.beam \ ../include/merl.hrl diff --git a/lib/syntax_tools/src/epp_dodger.erl b/lib/syntax_tools/src/epp_dodger.erl index 0a12e8fd8b..7e741cc649 100644 --- a/lib/syntax_tools/src/epp_dodger.erl +++ b/lib/syntax_tools/src/epp_dodger.erl @@ -502,6 +502,10 @@ quickscan_form([{'-', _L}, {atom, La, ifdef} | _Ts]) -> kill_form(La); quickscan_form([{'-', _L}, {atom, La, ifndef} | _Ts]) -> kill_form(La); +quickscan_form([{'-', _L}, {'if', La} | _Ts]) -> + kill_form(La); +quickscan_form([{'-', _L}, {atom, La, elif} | _Ts]) -> + kill_form(La); quickscan_form([{'-', _L}, {atom, La, else} | _Ts]) -> kill_form(La); quickscan_form([{'-', _L}, {atom, La, endif} | _Ts]) -> @@ -615,8 +619,13 @@ filter_form(T) -> %% --------------------------------------------------------------------- %% Normal parsing - try to preserve all information -normal_parser(Ts, Opt) -> - rewrite_form(parse_tokens(scan_form(Ts, Opt))). +normal_parser(Ts0, Opt) -> + case scan_form(Ts0, Opt) of + Ts when is_list(Ts) -> + rewrite_form(parse_tokens(Ts)); + Node -> + Node + end. scan_form([{'-', _L}, {atom, La, define} | Ts], Opt) -> [{atom, La, ?pp_form}, {'(', La}, {')', La}, {'->', La}, @@ -636,12 +645,26 @@ scan_form([{'-', _L}, {atom, La, ifdef} | Ts], Opt) -> scan_form([{'-', _L}, {atom, La, ifndef} | Ts], Opt) -> [{atom, La, ?pp_form}, {'(', La}, {')', La}, {'->', La}, {atom, La, ifndef} | scan_macros(Ts, Opt)]; +scan_form([{'-', _L}, {'if', La} | Ts], Opt) -> + [{atom, La, ?pp_form}, {'(', La}, {')', La}, {'->', La}, + {atom, La, 'if'} | scan_macros(Ts, Opt)]; +scan_form([{'-', _L}, {atom, La, elif} | Ts], Opt) -> + [{atom, La, ?pp_form}, {'(', La}, {')', La}, {'->', La}, + {atom, La, 'elif'} | scan_macros(Ts, Opt)]; scan_form([{'-', _L}, {atom, La, else} | Ts], Opt) -> [{atom, La, ?pp_form}, {'(', La}, {')', La}, {'->', La}, {atom, La, else} | scan_macros(Ts, Opt)]; scan_form([{'-', _L}, {atom, La, endif} | Ts], Opt) -> [{atom, La, ?pp_form}, {'(', La}, {')', La}, {'->', La}, {atom, La, endif} | scan_macros(Ts, Opt)]; +scan_form([{'-', _L}, {atom, La, error} | Ts], _Opt) -> + Desc = build_info_string("-error", Ts), + ErrorInfo = {La, ?MODULE, {error, Desc}}, + erl_syntax:error_marker(ErrorInfo); +scan_form([{'-', _L}, {atom, La, warning} | Ts], _Opt) -> + Desc = build_info_string("-warning", Ts), + ErrorInfo = {La, ?MODULE, {warning, Desc}}, + erl_syntax:error_marker(ErrorInfo); scan_form([{'-', L}, {'?', L1}, {Type, _, _}=N | [{'(', _} | _]=Ts], Opt) when Type =:= atom; Type =:= var -> %% minus, macro and open parenthesis at start of form - assume that @@ -657,6 +680,11 @@ scan_form([{'?', L}, {Type, _, _}=N | [{'(', _} | _]=Ts], Opt) scan_form(Ts, Opt) -> scan_macros(Ts, Opt). +build_info_string(Prefix, Ts0) -> + Ts = lists:droplast(Ts0), + String = lists:droplast(tokens_to_string(Ts)), + Prefix ++ " " ++ String ++ ".". + scan_macros(Ts, Opt) -> scan_macros(Ts, [], Opt). @@ -865,6 +893,10 @@ tokens_to_string([]) -> format_error(macro_args) -> errormsg("macro call missing end parenthesis"); +format_error({error, Error}) -> + Error; +format_error({warning, Error}) -> + Error; format_error({unknown, Reason}) -> errormsg(io_lib:format("unknown error: ~tP", [Reason, 15])). diff --git a/lib/syntax_tools/src/erl_comment_scan.erl b/lib/syntax_tools/src/erl_comment_scan.erl index 07e501e553..e3eb95b819 100644 --- a/lib/syntax_tools/src/erl_comment_scan.erl +++ b/lib/syntax_tools/src/erl_comment_scan.erl @@ -208,7 +208,7 @@ scan_comment([], Cs1, L, Col, M, Ack) -> seen_comment(Cs, Cs1, L, Col, M, Ack) -> %% Compute indentation and strip trailing spaces N = Col - M, - Text = lists:reverse(string:strip(Cs1, left)), + Text = lists:reverse(string:trim(Cs1, leading)), Ack1 = [{L, Col + 1, N, Text} | Ack], scan_lines(Cs, L + 1, 0, 0, Ack1). diff --git a/lib/syntax_tools/src/erl_prettypr.erl b/lib/syntax_tools/src/erl_prettypr.erl index 40ddd2b22a..6ad9bec2e6 100644 --- a/lib/syntax_tools/src/erl_prettypr.erl +++ b/lib/syntax_tools/src/erl_prettypr.erl @@ -675,7 +675,12 @@ lay_2(Node, Ctxt) -> %% attribute name, without following parentheses. Ctxt1 = reset_prec(Ctxt), Args = erl_syntax:attribute_arguments(Node), - N = erl_syntax:attribute_name(Node), + N = case erl_syntax:attribute_name(Node) of + {atom, _, 'if'} -> + erl_syntax:variable('if'); + N0 -> + N0 + end, D = case attribute_type(Node) of spec -> [SpecTuple] = Args, @@ -774,9 +779,16 @@ lay_2(Node, Ctxt) -> class_qualifier -> Ctxt1 = set_prec(Ctxt, max_prec()), D1 = lay(erl_syntax:class_qualifier_argument(Node), Ctxt1), - D2 = lay(erl_syntax:class_qualifier_body(Node), Ctxt1), - beside(D1, beside(text(":"), D2)); - + D2 = lay(erl_syntax:class_qualifier_body(Node), Ctxt1), + Stacktrace = erl_syntax:class_qualifier_stacktrace(Node), + case erl_syntax:variable_name(Stacktrace) of + '_' -> + beside(D1, beside(text(":"), D2)); + _ -> + D3 = lay(Stacktrace, Ctxt1), + beside(D1, beside(beside(text(":"), D2), + beside(text(":"), D3))) + end; comment -> D = stack_comment_lines( erl_syntax:comment_text(Node)), @@ -1089,8 +1101,9 @@ lay_2(Node, Ctxt) -> Ctxt1 = reset_prec(Ctxt), D1 = lay(erl_syntax:constrained_function_type_body(Node), Ctxt1), + Ctxt2 = Ctxt1#ctxt{clause = undefined}, D2 = lay(erl_syntax:constrained_function_type_argument(Node), - Ctxt1), + Ctxt2), beside(D1, beside(floating(text(" when ")), D2)); @@ -1101,7 +1114,7 @@ lay_2(Node, Ctxt) -> _ -> {"fun(", ")"} end, - Ctxt1 = reset_prec(Ctxt), + Ctxt1 = (reset_prec(Ctxt))#ctxt{clause = undefined}, D1 = case erl_syntax:function_type_arguments(Node) of any_arity -> text("(...)"); diff --git a/lib/syntax_tools/src/erl_syntax.erl b/lib/syntax_tools/src/erl_syntax.erl index 9b2b503762..1be644c620 100644 --- a/lib/syntax_tools/src/erl_syntax.erl +++ b/lib/syntax_tools/src/erl_syntax.erl @@ -342,8 +342,10 @@ typed_record_field_body/1, typed_record_field_type/1, class_qualifier/2, + class_qualifier/3, class_qualifier_argument/1, class_qualifier_body/1, + class_qualifier_stacktrace/1, tuple/1, tuple_elements/1, tuple_size/1, @@ -3884,7 +3886,7 @@ fold_try_clause({clause, Pos, [P], Guard, Body}) -> class_qualifier -> {tuple, Pos, [class_qualifier_argument(P), class_qualifier_body(P), - {var, Pos, '_'}]}; + class_qualifier_stacktrace(P)]}; _ -> {tuple, Pos, [{atom, Pos, throw}, P, {var, Pos, '_'}]} end, @@ -3893,12 +3895,14 @@ fold_try_clause({clause, Pos, [P], Guard, Body}) -> unfold_try_clauses(Cs) -> [unfold_try_clause(C) || C <- Cs]. -unfold_try_clause({clause, Pos, [{tuple, _, [{atom, _, throw}, V, _]}], +unfold_try_clause({clause, Pos, [{tuple, _, [{atom, _, throw}, + V, + {var, _, '_'}]}], Guard, Body}) -> {clause, Pos, [V], Guard, Body}; -unfold_try_clause({clause, Pos, [{tuple, _, [C, V, _]}], +unfold_try_clause({clause, Pos, [{tuple, _, [C, V, Stacktrace]}], Guard, Body}) -> - {clause, Pos, [class_qualifier(C, V)], Guard, Body}. + {clause, Pos, [class_qualifier(C, V, Stacktrace)], Guard, Body}. %% ===================================================================== @@ -5324,7 +5328,7 @@ revert_map_type_assoc(Node) -> Pos = get_pos(Node), Name = map_type_assoc_name(Node), Value = map_type_assoc_value(Node), - {type, Pos, map_type_assoc, [Name, Value]}. + {type, Pos, map_field_assoc, [Name, Value]}. %% ===================================================================== @@ -5382,7 +5386,7 @@ revert_map_type_exact(Node) -> Pos = get_pos(Node), Name = map_type_exact_name(Node), Value = map_type_exact_value(Node), - {type, Pos, map_type_exact, [Name, Value]}. + {type, Pos, map_field_exact, [Name, Value]}. %% ===================================================================== @@ -5451,8 +5455,12 @@ map_type(Fields) -> revert_map_type(Node) -> Pos = get_pos(Node), - {type, Pos, map, map_type_fields(Node)}. - + case map_type_fields(Node) of + any_size -> + {type, Pos, map, any}; + Fields -> + {type, Pos, map, Fields} + end. %% ===================================================================== %% @doc Returns the list of field subtrees of a `map_type' node. @@ -5710,7 +5718,12 @@ tuple_type(Elements) -> revert_tuple_type(Node) -> Pos = get_pos(Node), - {type, Pos, tuple, tuple_type_elements(Node)}. + case tuple_type_elements(Node) of + any_size -> + {type, Pos, tuple, any}; + TypeElements -> + {type, Pos, tuple, TypeElements} + end. %% ===================================================================== @@ -6725,9 +6738,12 @@ try_expr_after(Node) -> %% %% @see class_qualifier_argument/1 %% @see class_qualifier_body/1 +%% @see class_qualifier_stacktrace/1 %% @see try_expr/4 --record(class_qualifier, {class :: syntaxTree(), body :: syntaxTree()}). +-record(class_qualifier, {class :: syntaxTree(), + body :: syntaxTree(), + stacktrace :: syntaxTree()}). %% type(Node) = class_qualifier %% data(Node) = #class_qualifier{class :: Class, body :: Body} @@ -6737,8 +6753,27 @@ try_expr_after(Node) -> -spec class_qualifier(syntaxTree(), syntaxTree()) -> syntaxTree(). class_qualifier(Class, Body) -> + Underscore = {var, get_pos(Body), '_'}, tree(class_qualifier, - #class_qualifier{class = Class, body = Body}). + #class_qualifier{class = Class, body = Body, + stacktrace = Underscore}). + +%% ===================================================================== +%% @doc Creates an abstract class qualifier. The result represents +%% "<code><em>Class</em>:<em>Body</em>:<em>Stacktrace</em></code>". +%% +%% @see class_qualifier_argument/1 +%% @see class_qualifier_body/1 +%% @see try_expr/4 + +-spec class_qualifier(syntaxTree(), syntaxTree(), syntaxTree()) -> + syntaxTree(). + +class_qualifier(Class, Body, Stacktrace) -> + tree(class_qualifier, + #class_qualifier{class = Class, + body = Body, + stacktrace = Stacktrace}). %% ===================================================================== @@ -6763,6 +6798,16 @@ class_qualifier_argument(Node) -> class_qualifier_body(Node) -> (data(Node))#class_qualifier.body. +%% ===================================================================== +%% @doc Returns the stacktrace subtree of a `class_qualifier' node. +%% +%% @see class_qualifier/2 + +-spec class_qualifier_stacktrace(syntaxTree()) -> syntaxTree(). + +class_qualifier_stacktrace(Node) -> + (data(Node))#class_qualifier.stacktrace. + %% ===================================================================== %% @doc Creates an abstract "implicit fun" expression. If @@ -7187,7 +7232,7 @@ macro_arguments(Node) -> %% @doc Returns the syntax tree corresponding to an Erlang term. %% `Term' must be a literal term, i.e., one that can be %% represented as a source code literal. Thus, it may not contain a -%% process identifier, port, reference, binary or function value as a +%% process identifier, port, reference or function value as a %% subterm. The function recognises printable strings, in order to get a %% compact and readable representation. Evaluation fails with reason %% `badarg' if `Term' is not a literal term. @@ -7221,6 +7266,13 @@ abstract(T) when is_map(T) -> || {Key,Value} <- maps:to_list(T)]); abstract(T) when is_binary(T) -> binary([binary_field(integer(B)) || B <- binary_to_list(T)]); +abstract(T) when is_bitstring(T) -> + S = bit_size(T), + ByteS = S div 8, + BitS = S rem 8, + <<Bin:ByteS/binary, I:BitS>> = T, + binary([binary_field(integer(B)) || B <- binary_to_list(Bin)] + ++ [binary_field(integer(I), integer(BitS), [])]); abstract(T) -> erlang:error({badarg, T}). @@ -7296,15 +7348,20 @@ concrete(Node) -> Node0 -> maps:merge(concrete(Node0),M0) end; binary -> - Fs = [revert_binary_field( - binary_field(binary_field_body(F), - case binary_field_size(F) of - none -> none; - S -> - revert(S) - end, - binary_field_types(F))) - || F <- binary_fields(Node)], + Fs = [begin + B = binary_field_body(F), + {Body, Size} = + case type(B) of + size_qualifier -> + {size_qualifier_body(B), + size_qualifier_argument(B)}; + _ -> + {B, none} + end, + revert_binary_field( + binary_field(Body, Size, binary_field_types(F))) + end + || F <- binary_fields(Node)], {value, B, _} = eval_bits:expr_grp(Fs, [], fun(F, _) -> @@ -7377,7 +7434,14 @@ is_literal(T) -> is_literal_binary_field(F) -> case binary_field_types(F) of - [] -> is_literal(binary_field_body(F)); + [] -> B = binary_field_body(F), + case type(B) of + size_qualifier -> + is_literal(size_qualifier_body(B)) andalso + is_literal(size_qualifier_argument(B)); + _ -> + is_literal(B) + end; _ -> false end. @@ -7727,8 +7791,9 @@ subtrees(T) -> catch_expr -> [[catch_expr_body(T)]]; class_qualifier -> - [[class_qualifier_argument(T)], - [class_qualifier_body(T)]]; + [[class_qualifier_argument(T)], + [class_qualifier_body(T)], + [class_qualifier_stacktrace(T)]]; clause -> case clause_guard(T) of none -> @@ -7949,6 +8014,7 @@ make_tree(block_expr, [B]) -> block_expr(B); make_tree(case_expr, [[A], C]) -> case_expr(A, C); make_tree(catch_expr, [[B]]) -> catch_expr(B); make_tree(class_qualifier, [[A], [B]]) -> class_qualifier(A, B); +make_tree(class_qualifier, [[A], [B], [C]]) -> class_qualifier(A, B, C); make_tree(clause, [P, B]) -> clause(P, none, B); make_tree(clause, [P, [G], B]) -> clause(P, G, B); make_tree(cond_expr, [C]) -> cond_expr(C); diff --git a/lib/syntax_tools/src/erl_syntax_lib.erl b/lib/syntax_tools/src/erl_syntax_lib.erl index c7f477c4d2..352165893f 100644 --- a/lib/syntax_tools/src/erl_syntax_lib.erl +++ b/lib/syntax_tools/src/erl_syntax_lib.erl @@ -1317,6 +1317,8 @@ analyze_attribute(Node) -> include_lib -> preprocessor; ifdef -> preprocessor; ifndef -> preprocessor; + 'if' -> preprocessor; + elif -> preprocessor; else -> preprocessor; endif -> preprocessor; A -> @@ -1979,7 +1981,7 @@ analyze_application(Node) -> %% %% @see analyze_type_name/1 --type typeName() :: atom() | {module(), atom(), arity()} | {atom(), arity()}. +-type typeName() :: atom() | {module(), {atom(), arity()}} | {atom(), arity()}. -spec analyze_type_application(erl_syntax:syntaxTree()) -> typeName(). diff --git a/lib/syntax_tools/src/merl_transform.erl b/lib/syntax_tools/src/merl_transform.erl index b298bc407f..571d7e4d86 100644 --- a/lib/syntax_tools/src/merl_transform.erl +++ b/lib/syntax_tools/src/merl_transform.erl @@ -196,7 +196,7 @@ var_name(V) -> V. var_to_tag(V) when is_integer(V) -> V; var_to_tag(V) -> - list_to_atom(string:to_lower(atom_to_list(V))). + list_to_atom(string:lowercase(atom_to_list(V))). pre_expand_case(Expr, Clauses, Line) -> merl:qquote(Line, "merl:switch(_@expr, _@clauses)", |