aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHans Bolinder <[email protected]>2016-05-03 10:23:58 +0200
committerHans Bolinder <[email protected]>2016-05-09 08:27:22 +0200
commitdb39317ea85f7d8646b3da3d96f2f05954e16665 (patch)
tree46d145f6fe5cde5b4a0380cd12da33e7dc56404c
parenta73f32b54f5679a2badb48e080203e28f3b40af7 (diff)
downloadotp-db39317ea85f7d8646b3da3d96f2f05954e16665.tar.gz
otp-db39317ea85f7d8646b3da3d96f2f05954e16665.tar.bz2
otp-db39317ea85f7d8646b3da3d96f2f05954e16665.zip
syntax_tools: Add support for new map type syntax
The pretty-printing of `...' in map types is complex. The representation of `...' can be changed before OTP 19.
-rw-r--r--lib/syntax_tools/src/erl_prettypr.erl57
-rw-r--r--lib/syntax_tools/src/erl_syntax.erl167
-rw-r--r--lib/syntax_tools/test/syntax_tools_SUITE_data/type_specs.erl7
3 files changed, 167 insertions, 64 deletions
diff --git a/lib/syntax_tools/src/erl_prettypr.erl b/lib/syntax_tools/src/erl_prettypr.erl
index 9b6c5d977e..119d375746 100644
--- a/lib/syntax_tools/src/erl_prettypr.erl
+++ b/lib/syntax_tools/src/erl_prettypr.erl
@@ -27,8 +27,6 @@
-module(erl_prettypr).
--compile(export_all).
-
-export([format/1, format/2, best/1, best/2, layout/1, layout/2,
get_ctxt_precedence/1, set_ctxt_precedence/2,
get_ctxt_paperwidth/1, set_ctxt_paperwidth/2,
@@ -1133,20 +1131,25 @@ lay_2(Node, Ctxt) ->
text("map()");
Fs ->
{Prec, _PrecR} = type_preop_prec('#'),
- Es = seq(Fs,
- floating(text(",")), reset_prec(Ctxt),
- fun lay/2),
+ Es = lay_map_fields(Fs,
+ floating(text(",")),
+ reset_prec(Ctxt)),
D = beside(floating(text("#{")),
beside(par(Es),
floating(text("}")))),
maybe_parentheses(D, Prec, Ctxt)
end;
- map_type_pair ->
+ map_type_assoc ->
+ Name = erl_syntax:map_type_assoc_name(Node),
+ Value = erl_syntax:map_type_assoc_value(Node),
+ lay_type_assoc(Name, Value, Ctxt);
+
+ map_type_exact ->
Ctxt1 = reset_prec(Ctxt),
- D1 = lay(erl_syntax:map_type_pair_key(Node), Ctxt1),
- D2 = lay(erl_syntax:map_type_pair_value(Node), Ctxt1),
- par([D1, floating(text("=>")), D2], Ctxt1#ctxt.break_indent);
+ D1 = lay(erl_syntax:map_type_exact_name(Node), Ctxt1),
+ D2 = lay(erl_syntax:map_type_exact_value(Node), Ctxt1),
+ par([D1, floating(text(":=")), D2], Ctxt1#ctxt.break_indent);
integer_range_type ->
{PrecL, Prec, PrecR} = type_inop_prec('..'),
@@ -1397,6 +1400,42 @@ lay_error_info(T, Ctxt) ->
lay_concrete(T, Ctxt) ->
lay(erl_syntax:abstract(T), Ctxt).
+lay_map_fields([H | T], Separator, Ctxt) ->
+ case T of
+ [] ->
+ [case erl_syntax:type(H) of
+ map_type_assoc ->
+ lay_last_type_assoc(H, Ctxt);
+ _ ->
+ lay(H, Ctxt)
+ end];
+ _ ->
+ [maybe_append(Separator, lay(H, Ctxt))
+ | lay_map_fields(T, Separator, Ctxt)]
+ end;
+lay_map_fields([], _, _) ->
+ [empty()].
+
+lay_last_type_assoc(Node, Ctxt) ->
+ Name = erl_syntax:map_type_assoc_name(Node),
+ Value = erl_syntax:map_type_assoc_value(Node),
+ IsAny = fun({type,_,any,[]}) -> true;
+ %% ({var,_,'_'}) -> true;
+ (_) -> false
+ end,
+ case IsAny(Name) andalso IsAny(Value) of
+ true ->
+ text("...");
+ false ->
+ lay_type_assoc(Name, Value, Ctxt)
+ end.
+
+lay_type_assoc(Name, Value, Ctxt) ->
+ Ctxt1 = reset_prec(Ctxt),
+ D1 = lay(Name, Ctxt1),
+ D2 = lay(Value, Ctxt1),
+ par([D1, floating(text("=>")), D2], Ctxt1#ctxt.break_indent).
+
lay_type_application(Name, Arguments, Ctxt) ->
{PrecL, Prec} = func_prec(), %
D1 = lay(Name, set_prec(Ctxt, PrecL)),
diff --git a/lib/syntax_tools/src/erl_syntax.erl b/lib/syntax_tools/src/erl_syntax.erl
index 5c252dd749..f4cda814fc 100644
--- a/lib/syntax_tools/src/erl_syntax.erl
+++ b/lib/syntax_tools/src/erl_syntax.erl
@@ -253,9 +253,12 @@
map_type/0,
map_type/1,
map_type_fields/1,
- map_type_pair/2,
- map_type_pair_key/1,
- map_type_pair_value/1,
+ map_type_assoc/2,
+ map_type_assoc_name/1,
+ map_type_assoc_value/1,
+ map_type_exact/2,
+ map_type_exact_name/1,
+ map_type_exact_value/1,
match_expr/2,
match_expr_body/1,
match_expr_pattern/1,
@@ -509,7 +512,8 @@
%% <td>map_field_exact</td>
%% </tr><tr>
%% <td>map_type</td>
-%% <td>map_type_pair</td>
+%% <td>map_type_assoc</td>
+%% <td>map_type_exact</td>
%% <td>match_expr</td>
%% <td>module_qualifier</td>
%% </tr><tr>
@@ -596,7 +600,8 @@
%% @see map_field_exact/2
%% @see map_type/0
%% @see map_type/1
-%% @see map_type_pair/2
+%% @see map_type_assoc/2
+%% @see map_type_exact/2
%% @see match_expr/2
%% @see module_qualifier/2
%% @see named_fun_expr/2
@@ -697,7 +702,8 @@ type(Node) ->
{type, _, 'fun', []} -> fun_type;
{type, _, 'fun', [_, _]} -> function_type;
{type, _, map, _} -> map_type;
- {type, _, map_field_assoc, _} -> map_type_pair;
+ {type, _, map_field_assoc, _} -> map_type_assoc;
+ {type, _, map_field_exact, _} -> map_type_exact;
{type, _, record, _} -> record_type;
{type, _, field_type, _} -> record_type_field;
{type, _, range, _} -> integer_range_type;
@@ -5265,69 +5271,118 @@ constraint_body(Node) ->
%% =====================================================================
-%% @doc Creates an abstract type map assoc field. The result represents
-%% "<code><em>KeyType</em> => <em>ValueType</em></code>".
+%% @doc Creates an abstract map type assoc field. The result represents
+%% "<code><em>Name</em> => <em>Value</em></code>".
%%
-%% @see map_type_pair_key/1
-%% @see map_type_pair_value/1
+%% @see map_type_assoc_name/1
+%% @see map_type_assoc_value/1
+%% @see map_type/1
--record(map_type_pair, {key :: syntaxTree(),
- value :: syntaxTree()}).
+-record(map_type_assoc, {name :: syntaxTree(), value :: syntaxTree()}).
-%% type(Node) = map_type_pair
-%% data(Node) = #map_type_pair{key :: KeyType,
-%% value :: ValueType}
+%% `erl_parse' representation:
%%
-%% KeyType = syntaxTree()
-%% ValueType = syntaxTree()
+%% {type, Pos, map_field_assoc, [Name, Value]}
+
+-spec map_type_assoc(syntaxTree(), syntaxTree()) -> syntaxTree().
+
+map_type_assoc(Name, Value) ->
+ tree(map_type_assoc, #map_type_assoc{name = Name, value = Value}).
+
+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]}.
+
+
+%% =====================================================================
+%% @doc Returns the name subtree of a `map_type_assoc' node.
%%
-%% `erl_parse' representation:
+%% @see map_type_assoc/2
+
+-spec map_type_assoc_name(syntaxTree()) -> syntaxTree().
+
+map_type_assoc_name(Node) ->
+ case Node of
+ {type, _, map_field_assoc, [Name, _]} ->
+ Name;
+ _ ->
+ (data(Node))#map_type_assoc.name
+ end.
+
+
+%% =====================================================================
+%% @doc Returns the value subtree of a `map_type_assoc' node.
%%
-%% {type, Pos, map_field_assoc, [KeyType, ValueType]}
+%% @see map_type_assoc/2
+
+-spec map_type_assoc_value(syntaxTree()) -> syntaxTree().
+
+map_type_assoc_value(Node) ->
+ case Node of
+ {type, _, map_field_assoc, [_, Value]} ->
+ Value;
+ _ ->
+ (data(Node))#map_type_assoc.value
+ end.
+
+
+%% =====================================================================
+%% @doc Creates an abstract map type exact field. The result represents
+%% "<code><em>Name</em> := <em>Value</em></code>".
%%
-%% KeyType = erl_parse()
-%% ValueType = erl_parse()
+%% @see map_type_exact_name/1
+%% @see map_type_exact_value/1
+%% @see map_type/1
+
+-record(map_type_exact, {name :: syntaxTree(), value :: syntaxTree()}).
+
+%% `erl_parse' representation:
+%%
+%% {type, Pos, map_field_exact, [Name, Value]}
--spec map_type_pair(syntaxTree(), syntaxTree()) -> syntaxTree().
+-spec map_type_exact(syntaxTree(), syntaxTree()) -> syntaxTree().
-map_type_pair(KeyType, ValueType) ->
- tree(map_type_pair,
- #map_type_pair{key = KeyType, value = ValueType}).
+map_type_exact(Name, Value) ->
+ tree(map_type_exact, #map_type_exact{name = Name, value = Value}).
-revert_map_type_pair(Node) ->
+revert_map_type_exact(Node) ->
Pos = get_pos(Node),
- KeyType = map_type_pair_key(Node),
- ValueType = map_type_pair_value(Node),
- {type, Pos, map_field_assoc, [KeyType, ValueType]}.
+ Name = map_type_exact_name(Node),
+ Value = map_type_exact_value(Node),
+ {type, Pos, map_type_exact, [Name, Value]}.
+
%% =====================================================================
-%% @doc Returns the key type subtrees of a `map_type_pair' node.
+%% @doc Returns the name subtree of a `map_type_exact' node.
%%
-%% @see map_type_pair/2
+%% @see map_type_exact/2
--spec map_type_pair_key(syntaxTree()) -> syntaxTree().
+-spec map_type_exact_name(syntaxTree()) -> syntaxTree().
-map_type_pair_key(Node) ->
- case unwrap(Node) of
- {type, _, map_field_assoc, [KeyType, _]} ->
- KeyType;
- Node1 ->
- (data(Node1))#map_type_pair.key
+map_type_exact_name(Node) ->
+ case Node of
+ {type, _, map_field_exact, [Name, _]} ->
+ Name;
+ _ ->
+ (data(Node))#map_type_exact.name
end.
+
%% =====================================================================
-%% @doc Returns the value type subtrees of a `map_type_pair' node.
+%% @doc Returns the value subtree of a `map_type_exact' node.
%%
-%% @see map_type_pair/2
+%% @see map_type_exact/2
--spec map_type_pair_value(syntaxTree()) -> syntaxTree().
+-spec map_type_exact_value(syntaxTree()) -> syntaxTree().
-map_type_pair_value(Node) ->
- case unwrap(Node) of
- {type, _, map_field_assoc, [_, ValueType]} ->
- ValueType;
- Node1 ->
- (data(Node1))#map_type_pair.value
+map_type_exact_value(Node) ->
+ case Node of
+ {type, _, map_field_exact, [_, Value]} ->
+ Value;
+ _ ->
+ (data(Node))#map_type_exact.value
end.
@@ -7428,8 +7483,10 @@ revert_root(Node) ->
revert_map_field_exact(Node);
map_type ->
revert_map_type(Node);
- map_type_pair ->
- revert_map_type_pair(Node);
+ map_type_assoc ->
+ revert_map_type_assoc(Node);
+ map_type_exact ->
+ revert_map_type_exact(Node);
match_expr ->
revert_match_expr(Node);
module_qualifier ->
@@ -7721,9 +7778,12 @@ subtrees(T) ->
[map_field_exact_value(T)]];
map_type ->
[map_type_fields(T)];
- map_type_pair ->
- [[map_type_pair_key(T)],
- [map_type_pair_value(T)]];
+ map_type_assoc ->
+ [[map_type_assoc_name(T)],
+ [map_type_assoc_value(T)]];
+ map_type_exact ->
+ [[map_type_exact_name(T)],
+ [map_type_exact_value(T)]];
match_expr ->
[[match_expr_pattern(T)],
[match_expr_body(T)]];
@@ -7886,7 +7946,8 @@ 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(map_type, [Fs]) -> map_type(Fs);
-make_tree(map_type_pair, [[K],[V]]) -> map_type_pair(K, V);
+make_tree(map_type_assoc, [[N],[V]]) -> map_type_assoc(N, V);
+make_tree(map_type_exact, [[N],[V]]) -> map_type_exact(N, 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);
diff --git a/lib/syntax_tools/test/syntax_tools_SUITE_data/type_specs.erl b/lib/syntax_tools/test/syntax_tools_SUITE_data/type_specs.erl
index d5a9554f18..5621d3a293 100644
--- a/lib/syntax_tools/test/syntax_tools_SUITE_data/type_specs.erl
+++ b/lib/syntax_tools/test/syntax_tools_SUITE_data/type_specs.erl
@@ -47,8 +47,11 @@
-type r0() :: #r0{} | #r{f1 :: 3} | #r{f1 :: 3, f2 :: 'sju'}.
--type m1() :: #{}.
--type m2() :: #{a => m1(), b => #{} | fy:m2()}.
+-type m1() :: #{} | map().
+-type m2() :: #{a := m1(), b => #{} | fy:m2()}.
+-type m3() :: #{...}.
+-type m4() :: #{_ => _, ...}.
+-type m5() :: #{any() => any(), ...}. % Currently printed as `#{..., ...}'.
-type b1() :: B1 :: binary() | (BitString :: bitstring()).
-define(PAIR(A, B), {(A), (B)}).