aboutsummaryrefslogtreecommitdiffstats
path: root/lib/syntax_tools
diff options
context:
space:
mode:
Diffstat (limited to 'lib/syntax_tools')
-rw-r--r--lib/syntax_tools/src/erl_syntax.erl28
-rw-r--r--lib/syntax_tools/test/syntax_tools_SUITE.erl4
2 files changed, 32 insertions, 0 deletions
diff --git a/lib/syntax_tools/src/erl_syntax.erl b/lib/syntax_tools/src/erl_syntax.erl
index 5da53113e0..40372a2106 100644
--- a/lib/syntax_tools/src/erl_syntax.erl
+++ b/lib/syntax_tools/src/erl_syntax.erl
@@ -669,6 +669,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;
@@ -6093,6 +6096,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) ->
@@ -6154,6 +6160,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),
@@ -6209,6 +6223,11 @@ 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));
_ ->
@@ -6221,6 +6240,15 @@ is_literal_binary_field(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
%% syntax tree, if possible. If `Tree' represents a
diff --git a/lib/syntax_tools/test/syntax_tools_SUITE.erl b/lib/syntax_tools/test/syntax_tools_SUITE.erl
index b4141956e6..721d1fd87c 100644
--- a/lib/syntax_tools/test/syntax_tools_SUITE.erl
+++ b/lib/syntax_tools/test/syntax_tools_SUITE.erl
@@ -136,6 +136,8 @@ t_abstract_type(Config) when is_list(Config) ->
{[$a,$b,$c],string},
{"hello world",string},
{<<1,2,3>>,binary},
+ {#{a=>1,"b"=>2},map_expr},
+ {#{#{i=>1}=>1,"b"=>#{v=>2}},map_expr},
{{a,b,c},tuple}]),
ok.
@@ -152,6 +154,7 @@ t_erl_parse_type(Config) when is_list(Config) ->
{"_", underscore,true},
{"[]", nil,true},
{"{}", tuple,true},
+ {"#{}",map_expr,true},
{"'some atom'", atom, true}]),
%% composite types
ok = validate(F,[{"case X of t -> t; f -> f end", case_expr,false},
@@ -175,6 +178,7 @@ t_erl_parse_type(Config) when is_list(Config) ->
{"[<<1>>,<<2>>,-2,<<>>,[more,list]]", list,false},
{"[1|[2|[3|[4|[]]]]]", list,false},
{"#{ a=>1, b=>2 }", map_expr,false},
+ {"#{3=>3}#{ a=>1, b=>2 }", map_expr,false},
{"#{ a:=1, b:=2 }", map_expr,false},
{"M#{ a=>1, b=>2 }", map_expr,false},
{"[V||V <- Vs]", list_comp,false},