aboutsummaryrefslogtreecommitdiffstats
path: root/lib/syntax_tools
diff options
context:
space:
mode:
Diffstat (limited to 'lib/syntax_tools')
-rw-r--r--lib/syntax_tools/doc/src/book.xml4
-rw-r--r--lib/syntax_tools/doc/src/fascicules.xml2
-rw-r--r--lib/syntax_tools/doc/src/notes.xml34
-rw-r--r--lib/syntax_tools/doc/src/part.xml4
-rw-r--r--lib/syntax_tools/doc/src/part_notes.xml4
-rw-r--r--lib/syntax_tools/doc/src/ref_man.xml4
-rw-r--r--lib/syntax_tools/src/erl_prettypr.erl34
-rw-r--r--lib/syntax_tools/src/erl_syntax.erl373
-rw-r--r--lib/syntax_tools/src/erl_tidy.erl23
-rw-r--r--lib/syntax_tools/test/syntax_tools_SUITE.erl31
-rw-r--r--lib/syntax_tools/vsn.mk2
11 files changed, 493 insertions, 22 deletions
diff --git a/lib/syntax_tools/doc/src/book.xml b/lib/syntax_tools/doc/src/book.xml
index 793b219ffb..6a8a3a3ca6 100644
--- a/lib/syntax_tools/doc/src/book.xml
+++ b/lib/syntax_tools/doc/src/book.xml
@@ -1,10 +1,10 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE book SYSTEM "book.dtd">
<book xmlns:xi="http://www.w3.org/2001/XInclude">
<header titlestyle="normal">
<copyright>
- <year>2006</year><year>2009</year>
+ <year>2006</year><year>2013</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/syntax_tools/doc/src/fascicules.xml b/lib/syntax_tools/doc/src/fascicules.xml
index 0678195e07..37feca543f 100644
--- a/lib/syntax_tools/doc/src/fascicules.xml
+++ b/lib/syntax_tools/doc/src/fascicules.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE fascicules SYSTEM "fascicules.dtd">
<fascicules>
diff --git a/lib/syntax_tools/doc/src/notes.xml b/lib/syntax_tools/doc/src/notes.xml
index c5a1baebdb..a9d3f68d1d 100644
--- a/lib/syntax_tools/doc/src/notes.xml
+++ b/lib/syntax_tools/doc/src/notes.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE chapter SYSTEM "chapter.dtd">
<chapter>
@@ -31,6 +31,38 @@
<p>This document describes the changes made to the Syntax_Tools
application.</p>
+<section><title>Syntax_Tools 1.6.13</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ In syntax_tools-1.6.12 (OTP R16B03) a bug was introduced
+ which broke reverting of local implicit funs. Implicit
+ funs were mistakenly thought to be using abstract terms
+ for their name and arity. This has now been corrected.
+ (Thanks to Anthony Ramine)</p>
+ <p>
+ Own Id: OTP-11576</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p> The default encoding of Erlang files has been changed
+ from ISO-8859-1 to UTF-8. </p> <p> The encoding of XML
+ files has also been changed to UTF-8. </p>
+ <p>
+ Own Id: OTP-10907</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Syntax_Tools 1.6.12</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/syntax_tools/doc/src/part.xml b/lib/syntax_tools/doc/src/part.xml
index 4a3bae29eb..ee8e796561 100644
--- a/lib/syntax_tools/doc/src/part.xml
+++ b/lib/syntax_tools/doc/src/part.xml
@@ -1,10 +1,10 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE part SYSTEM "part.dtd">
<part xmlns:xi="http://www.w3.org/2001/XInclude">
<header>
<copyright>
- <year>2006</year><year>2009</year>
+ <year>2006</year><year>2013</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/syntax_tools/doc/src/part_notes.xml b/lib/syntax_tools/doc/src/part_notes.xml
index 3656b3ddb6..6962145618 100644
--- a/lib/syntax_tools/doc/src/part_notes.xml
+++ b/lib/syntax_tools/doc/src/part_notes.xml
@@ -1,10 +1,10 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE part SYSTEM "part.dtd">
<part xmlns:xi="http://www.w3.org/2001/XInclude">
<header>
<copyright>
- <year>2007</year><year>2009</year>
+ <year>2007</year><year>2013</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/syntax_tools/doc/src/ref_man.xml b/lib/syntax_tools/doc/src/ref_man.xml
index 9249b42184..598f656011 100644
--- a/lib/syntax_tools/doc/src/ref_man.xml
+++ b/lib/syntax_tools/doc/src/ref_man.xml
@@ -1,10 +1,10 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE application SYSTEM "application.dtd">
<application xmlns:xi="http://www.w3.org/2001/XInclude">
<header>
<copyright>
- <year>2006</year><year>2009</year>
+ <year>2006</year><year>2013</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/syntax_tools/src/erl_prettypr.erl b/lib/syntax_tools/src/erl_prettypr.erl
index 1ffcf31134..877675772f 100644
--- a/lib/syntax_tools/src/erl_prettypr.erl
+++ b/lib/syntax_tools/src/erl_prettypr.erl
@@ -637,6 +637,14 @@ lay_2(Node, Ctxt) ->
sep([follow(text("fun"), D, Ctxt1#ctxt.sub_indent),
text("end")]);
+ named_fun_expr ->
+ Ctxt1 = reset_prec(Ctxt),
+ D1 = lay(erl_syntax:named_fun_expr_name(Node), Ctxt1),
+ D = lay_clauses(erl_syntax:named_fun_expr_clauses(Node),
+ {function,D1}, Ctxt1),
+ sep([follow(text("fun"), D, Ctxt1#ctxt.sub_indent),
+ text("end")]);
+
module_qualifier ->
{PrecL, _Prec, PrecR} = inop_prec(':'),
D1 = lay(erl_syntax:module_qualifier_argument(Node),
@@ -892,6 +900,32 @@ lay_2(Node, Ctxt) ->
beside(floating(text(".")), D2)),
maybe_parentheses(D3, Prec, Ctxt);
+ map_expr ->
+ {PrecL, Prec, _} = inop_prec('#'),
+ Ctxt1 = reset_prec(Ctxt),
+ D1 = par(seq(erl_syntax:map_expr_fields(Node),
+ floating(text(",")), Ctxt1, fun lay/2)),
+ D2 = beside(text("#{"), beside(D1, floating(text("}")))),
+ D3 = case erl_syntax:map_expr_argument(Node) of
+ none ->
+ D2;
+ A ->
+ beside(lay(A, set_prec(Ctxt, PrecL)), D2)
+ end,
+ maybe_parentheses(D3, Prec, Ctxt);
+
+ map_field_assoc ->
+ Ctxt1 = reset_prec(Ctxt),
+ D1 = lay(erl_syntax:map_field_assoc_name(Node), Ctxt1),
+ D2 = lay(erl_syntax:map_field_assoc_value(Node), Ctxt1),
+ par([D1, floating(text("=>")), D2], Ctxt1#ctxt.break_indent);
+
+ map_field_exact ->
+ Ctxt1 = reset_prec(Ctxt),
+ D1 = lay(erl_syntax:map_field_exact_name(Node), Ctxt1),
+ D2 = lay(erl_syntax:map_field_exact_value(Node), Ctxt1),
+ par([D1, floating(text(":=")), D2], Ctxt1#ctxt.break_indent);
+
rule ->
%% Comments on the name will be repeated; cf.
%% `function'.
diff --git a/lib/syntax_tools/src/erl_syntax.erl b/lib/syntax_tools/src/erl_syntax.erl
index 409805e95f..2f4c9ac309 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,
@@ -442,28 +456,30 @@
%% <td>match_expr</td>
%% <td>module_qualifier</td>
%% </tr><tr>
+%% <td>named_fun_expr</td>
%% <td>nil</td>
%% <td>operator</td>
%% <td>parentheses</td>
-%% <td>prefix_expr</td>
%% </tr><tr>
+%% <td>prefix_expr</td>
%% <td>receive_expr</td>
%% <td>record_access</td>
-%% </tr><tr>
%% <td>record_expr</td>
+%% </tr><tr>
%% <td>record_field</td>
%% <td>record_index_expr</td>
%% <td>rule</td>
-%% </tr><tr>
%% <td>size_qualifier</td>
+%% </tr><tr>
%% <td>string</td>
%% <td>text</td>
%% <td>try_expr</td>
-%% </tr><tr>
%% <td>tuple</td>
+%% </tr><tr>
%% <td>underscore</td>
%% <td>variable</td>
%% <td>warning_marker</td>
+%% <td></td>
%% </tr>
%% </table></center>
%%
@@ -506,6 +522,7 @@
%% @see macro/2
%% @see match_expr/2
%% @see module_qualifier/2
+%% @see named_fun_expr/2
%% @see nil/0
%% @see operator/1
%% @see parentheses/1
@@ -554,6 +571,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,6 +590,10 @@ 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;
@@ -1902,6 +1924,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/3
+
+-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/3
+
+-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/3
+
+-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.name
+ 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/3
+
+-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.name
+ end.
+
+
+%% =====================================================================
%% @doc Creates an abstract tuple. If `Elements' is
%% `[X1, ..., Xn]', the result represents
%% "<code>{<em>X1</em>, ..., <em>Xn</em>}</code>".
@@ -5485,7 +5709,13 @@ revert_implicit_fun(Node) ->
arity_qualifier ->
F = arity_qualifier_body(Name),
A = arity_qualifier_argument(Name),
- {'fun', Pos, {function, F, A}};
+ case {type(F), type(A)} of
+ {atom, integer} ->
+ {'fun', Pos,
+ {function, concrete(F), concrete(A)}};
+ _ ->
+ Node
+ end;
module_qualifier ->
M = module_qualifier_argument(Name),
Name1 = module_qualifier_body(Name),
@@ -5616,6 +5846,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.
@@ -5974,10 +6308,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 ->
@@ -6213,12 +6555,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 ->
@@ -6348,7 +6706,12 @@ 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);
diff --git a/lib/syntax_tools/src/erl_tidy.erl b/lib/syntax_tools/src/erl_tidy.erl
index 0c149634f6..7444d8dc67 100644
--- a/lib/syntax_tools/src/erl_tidy.erl
+++ b/lib/syntax_tools/src/erl_tidy.erl
@@ -269,6 +269,13 @@ file(Name) ->
%% is typically most useful if the `verbose' flag is enabled, to
%% generate reports about the program files without affecting
%% them. The default value is `false'.</dd>
+%%
+%% <dt>{stdout, boolean()}</dt>
+%%
+%% <dd>If the value is `true', instead of the file being written
+%% to disk it will be printed to stdout. The default value is
+%% `false'.</dd>
+%%
%% </dl>
%%
%% See the function `module/2' for further options.
@@ -309,9 +316,15 @@ file_2(Name, Opts) ->
true ->
ok;
false ->
- write_module(Tree, Name, Opts1),
- ok
- end.
+ case proplists:get_bool(stdout, Opts1) of
+ true ->
+ print_module(Tree, Opts1),
+ ok;
+ false ->
+ write_module(Tree, Name, Opts1),
+ ok
+ end
+ end.
read_module(Name, Opts) ->
verbose("reading module `~ts'.", [filename(Name)], Opts),
@@ -399,6 +412,10 @@ write_module(Tree, Name, Opts) ->
throw(R)
end.
+print_module(Tree, Opts) ->
+ Printer = proplists:get_value(printer, Opts),
+ io:format(Printer(Tree, Opts)).
+
output(FD, Printer, Tree, Opts) ->
io:put_chars(FD, Printer(Tree, Opts)),
io:nl(FD).
diff --git a/lib/syntax_tools/test/syntax_tools_SUITE.erl b/lib/syntax_tools/test/syntax_tools_SUITE.erl
index fd381f0b25..b673b70a95 100644
--- a/lib/syntax_tools/test/syntax_tools_SUITE.erl
+++ b/lib/syntax_tools/test/syntax_tools_SUITE.erl
@@ -24,12 +24,12 @@
init_per_group/2,end_per_group/2]).
%% Test cases
--export([smoke_test/1]).
+-export([smoke_test/1,revert/1]).
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- [smoke_test].
+ [smoke_test,revert].
groups() ->
[].
@@ -73,12 +73,37 @@ print_error_markers(F, File) ->
case erl_syntax:type(F) of
error_marker ->
{L,M,Info} = erl_syntax:error_marker_info(F),
- io:format("~s:~p: ~s", [File,L,M:format_error(Info)]);
+ io:format("~ts:~p: ~s", [File,L,M:format_error(Info)]);
_ ->
ok
end.
+%% Read with erl_parse, wrap and revert with erl_syntax and check for equality.
+revert(Config) when is_list(Config) ->
+ Dog = ?t:timetrap(?t:minutes(12)),
+ Wc = filename:join([code:lib_dir("stdlib"),"src","*.erl"]),
+ Fs = filelib:wildcard(Wc),
+ Path = [filename:join(code:lib_dir(stdlib), "include"),
+ filename:join(code:lib_dir(kernel), "include")],
+ io:format("~p files\n", [length(Fs)]),
+ case p_run(fun (File) -> revert_file(File, Path) end, Fs) of
+ 0 -> ok;
+ N -> ?line ?t:fail({N,errors})
+ end,
+ ?line ?t:timetrap_cancel(Dog).
+
+revert_file(File, Path) ->
+ case epp:parse_file(File, Path, []) of
+ {ok,Fs0} ->
+ Fs1 = erl_syntax:form_list(Fs0),
+ Fs2 = erl_syntax_lib:map(fun (Node) -> Node end, Fs1),
+ Fs3 = erl_syntax:form_list_elements(Fs2),
+ Fs4 = [ erl_syntax:revert(Form) || Form <- Fs3 ],
+ {ok,_} = compile:forms(Fs4, [report,strong_validation]),
+ ok
+ end.
+
p_run(Test, List) ->
N = erlang:system_info(schedulers),
p_run_loop(Test, List, N, [], 0).
diff --git a/lib/syntax_tools/vsn.mk b/lib/syntax_tools/vsn.mk
index 6cafc4dd55..26153a55f1 100644
--- a/lib/syntax_tools/vsn.mk
+++ b/lib/syntax_tools/vsn.mk
@@ -1 +1 @@
-SYNTAX_TOOLS_VSN = 1.6.12
+SYNTAX_TOOLS_VSN = 1.6.13