File 3508-syntax_tools-Implement-support-for-maybe-.-end.patch of Package erlang
From 0793709fa4bc4a4c975086a2125e6931ba5d97a4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= <bjorn@erlang.org>
Date: Tue, 9 Nov 2021 13:16:45 +0100
Subject: [PATCH 08/12] syntax_tools: Implement support for maybe ... end
---
lib/syntax_tools/src/epp_dodger.erl | 23 +-
lib/syntax_tools/src/erl_prettypr.erl | 36 ++-
lib/syntax_tools/src/erl_syntax.erl | 243 +++++++++++++++++-
lib/syntax_tools/src/erl_syntax_lib.erl | 2 +-
lib/syntax_tools/test/syntax_tools_SUITE.erl | 22 +-
.../syntax_tools_SUITE_test_module.erl | 43 ++++
6 files changed, 350 insertions(+), 19 deletions(-)
diff --git a/lib/syntax_tools/src/epp_dodger.erl b/lib/syntax_tools/src/epp_dodger.erl
index eacfbc5d6b..edf092bfcd 100644
--- a/lib/syntax_tools/src/epp_dodger.erl
+++ b/lib/syntax_tools/src/epp_dodger.erl
@@ -430,7 +430,17 @@ quick_parse_form(Dev, L0, Options) ->
parse_form(Dev, L0, Parser, Options) ->
NoFail = proplists:get_bool(no_fail, Options),
Opt = #opt{clever = proplists:get_bool(clever, Options)},
- case io:scan_erl_form(Dev, "", L0) of
+
+ %% FIXME: This should not be hard-coded. Either all keywords from
+ %% all features should be retrieved here, or there should be an option
+ %% to passes in either the keywords or the feature names.
+ ResWordFun =
+ fun('maybe') -> true;
+ ('else') -> true;
+ (Other) -> erl_scan:reserved_word(Other)
+ end,
+
+ case io:scan_erl_form(Dev, "", L0, [{reserved_word_fun,ResWordFun}]) of
{ok, Ts, L1} ->
case catch {ok, Parser(Ts, Opt)} of
{'EXIT', Term} ->
@@ -504,7 +514,9 @@ quickscan_form([{'-', _Anno}, {'if', AnnoA} | _Ts]) ->
kill_form(AnnoA);
quickscan_form([{'-', _Anno}, {atom, AnnoA, elif} | _Ts]) ->
kill_form(AnnoA);
-quickscan_form([{'-', _Anno}, {atom, AnnoA, else} | _Ts]) ->
+quickscan_form([{'-', _Anno}, {atom, AnnoA, 'else'} | _Ts]) ->
+ kill_form(AnnoA);
+quickscan_form([{'-', _Anno}, {'else', AnnoA} | _Ts]) ->
kill_form(AnnoA);
quickscan_form([{'-', _Anno}, {atom, AnnoA, endif} | _Ts]) ->
kill_form(AnnoA);
@@ -648,9 +660,12 @@ scan_form([{'-', _Anno}, {'if', AnnoA} | Ts], Opt) ->
scan_form([{'-', _Anno}, {atom, AnnoA, elif} | Ts], Opt) ->
[{atom, AnnoA, ?pp_form}, {'(', AnnoA}, {')', AnnoA}, {'->', AnnoA},
{atom, AnnoA, 'elif'} | scan_macros(Ts, Opt)];
-scan_form([{'-', _Anno}, {atom, AnnoA, else} | Ts], Opt) ->
+scan_form([{'-', _Anno}, {atom, AnnoA, 'else'} | Ts], Opt) ->
+ [{atom, AnnoA, ?pp_form}, {'(', AnnoA}, {')', AnnoA}, {'->', AnnoA},
+ {atom, AnnoA, 'else'} | scan_macros(Ts, Opt)];
+scan_form([{'-', _Anno}, {'else', AnnoA} | Ts], Opt) ->
[{atom, AnnoA, ?pp_form}, {'(', AnnoA}, {')', AnnoA}, {'->', AnnoA},
- {atom, AnnoA, else} | scan_macros(Ts, Opt)];
+ {atom, AnnoA, 'else'} | scan_macros(Ts, Opt)];
scan_form([{'-', _Anno}, {atom, AnnoA, endif} | Ts], Opt) ->
[{atom, AnnoA, ?pp_form}, {'(', AnnoA}, {')', AnnoA}, {'->', AnnoA},
{atom, AnnoA, endif} | scan_macros(Ts, Opt)];
diff --git a/lib/syntax_tools/src/erl_prettypr.erl b/lib/syntax_tools/src/erl_prettypr.erl
index af1f2b4d11..d6c1c1e005 100644
--- a/lib/syntax_tools/src/erl_prettypr.erl
+++ b/lib/syntax_tools/src/erl_prettypr.erl
@@ -54,7 +54,7 @@
-type hook() :: 'none'
| fun((syntaxTree(), _, _) -> prettypr:document()).
-type clause_t() :: 'case_expr' | 'fun_expr'
- | 'if_expr' | 'receive_expr' | 'try_expr'
+ | 'if_expr' | 'maybe_expr' | 'receive_expr' | 'try_expr'
| {'function', prettypr:document()}
| 'spec'.
@@ -588,6 +588,8 @@ lay_2(Node, Ctxt) ->
make_if_clause(D1, D2, D3, Ctxt);
case_expr ->
make_case_clause(D1, D2, D3, Ctxt);
+ maybe_expr ->
+ make_case_clause(D1, D2, D3, Ctxt);
receive_expr ->
make_case_clause(D1, D2, D3, Ctxt);
try_expr ->
@@ -648,6 +650,34 @@ lay_2(Node, Ctxt) ->
set_prec(Ctxt, PrecR)),
beside(D1, beside(text(":"), D2));
+ maybe_expr ->
+ Ctxt1 = reset_prec(Ctxt),
+ D1 = vertical(seq(erl_syntax:maybe_expr_body(Node),
+ floating(text(",")), Ctxt1, fun lay/2)),
+ Es0 = [text("end")],
+ Es1 = case erl_syntax:maybe_expr_else(Node) of
+ none -> Es0;
+ ElseNode ->
+ ElseCs = erl_syntax:else_expr_clauses(ElseNode),
+ D3 = lay_clauses(ElseCs, maybe_expr, Ctxt1),
+ [text("else"),
+ nest(Ctxt1#ctxt.break_indent, D3)
+ | Es0]
+ end,
+ sep([par([text("maybe"), nest(Ctxt1#ctxt.break_indent, D1),
+ hd(Es1)]) | tl(Es1)]);
+
+ maybe_match_expr ->
+ {PrecL, Prec, PrecR} = inop_prec('='),
+ D1 = lay(erl_syntax:maybe_match_expr_pattern(Node),
+ set_prec(Ctxt, PrecL)),
+ D2 = lay(erl_syntax:maybe_match_expr_body(Node),
+ set_prec(Ctxt, PrecR)),
+ D3 = follow(beside(D1, floating(text(" ?="))), D2,
+ Ctxt#ctxt.break_indent),
+ maybe_parentheses(D3, Prec, Ctxt);
+
+
%%
%% The rest is in alphabetical order (except map and types)
%%
@@ -759,7 +789,7 @@ lay_2(Node, Ctxt) ->
nest(Ctxt1#ctxt.break_indent, sep(Es)),
text("end")]);
- catch_expr ->
+ 'catch_expr' -> %Quoted to help Emacs.
{Prec, PrecR} = preop_prec('catch'),
D = lay(erl_syntax:catch_expr_body(Node),
set_prec(Ctxt, PrecR)),
@@ -801,7 +831,7 @@ lay_2(Node, Ctxt) ->
sep(seq(erl_syntax:disjunction_body(Node),
floating(text(";")), reset_prec(Ctxt),
fun lay/2));
-
+
error_marker ->
E = erl_syntax:error_marker_info(Node),
beside(text("** "),
diff --git a/lib/syntax_tools/src/erl_syntax.erl b/lib/syntax_tools/src/erl_syntax.erl
index f62cfb4108..4da1635aec 100644
--- a/lib/syntax_tools/src/erl_syntax.erl
+++ b/lib/syntax_tools/src/erl_syntax.erl
@@ -193,6 +193,8 @@
constraint_body/1,
disjunction/1,
disjunction_body/1,
+ else_expr/1,
+ else_expr_clauses/1,
eof_marker/0,
error_marker/1,
error_marker_info/1,
@@ -266,6 +268,13 @@
match_expr/2,
match_expr_body/1,
match_expr_pattern/1,
+ maybe_expr/1,
+ maybe_expr/2,
+ maybe_expr_body/1,
+ maybe_expr_else/1,
+ maybe_match_expr/2,
+ maybe_match_expr_pattern/1,
+ maybe_match_expr_body/1,
module_qualifier/2,
module_qualifier_argument/1,
module_qualifier_body/1,
@@ -505,13 +514,14 @@
%% <td>constrained_function_type</td>
%% <td>constraint</td>
%% <td>disjunction</td>
-%% <td>eof_marker</td>
%% </tr><tr>
+%% <td>else_expr</td>
+%% <td>eof_marker</td>
%% <td>error_marker</td>
+%% </tr><tr>
%% <td>float</td>
%% <td>form_list</td>
%% <td>fun_expr</td>
-%% </tr><tr>
%% <td>fun_type</td>
%% <td>function</td>
%% <td>function_type</td>
@@ -535,6 +545,9 @@
%% <td>map_type_assoc</td>
%% <td>map_type_exact</td>
%% <td>match_expr</td>
+%% </tr><tr>
+%% <td>maybe_expr</td>
+%% <td>maybe_match_expr</td>
%% <td>module_qualifier</td>
%% </tr><tr>
%% <td>named_fun_expr</td>
@@ -597,6 +610,7 @@
%% @see constrained_function_type/2
%% @see constraint/2
%% @see disjunction/1
+%% @see else_expr/1
%% @see eof_marker/0
%% @see error_marker/1
%% @see float/1
@@ -623,6 +637,9 @@
%% @see map_type_assoc/2
%% @see map_type_exact/2
%% @see match_expr/2
+%% @see maybe_expr/1
+%% @see maybe_expr/2
+%% @see maybe_match_expr/2
%% @see module_qualifier/2
%% @see named_fun_expr/2
%% @see nil/0
@@ -683,6 +700,9 @@ type(Node) ->
{'fun', _, {function, _, _}} -> implicit_fun;
{'fun', _, {function, _, _, _}} -> implicit_fun;
{'if', _, _} -> if_expr;
+ {'maybe', _, _} -> maybe_expr;
+ {'maybe', _, _, _} -> maybe_expr;
+ {'else', _, _} -> else_expr;
{'receive', _, _, _, _} -> receive_expr;
{'receive', _, _} -> receive_expr;
{attribute, _, _, _} -> attribute;
@@ -702,6 +722,7 @@ type(Node) ->
{map, _, _} -> map_expr;
{map_field_assoc, _, _, _} -> map_field_assoc;
{map_field_exact, _, _, _} -> map_field_exact;
+ {maybe_match, _, _, _} -> maybe_match_expr;
{op, _, _, _, _} -> infix_expr;
{op, _, _, _} -> prefix_expr;
{record, _, _, _, _} -> record_expr;
@@ -4134,6 +4155,71 @@ match_expr_body(Node) ->
end.
+%% =====================================================================
+%% @doc Creates an abstract maybe-expression, as used in <code>maybe</code>
+%% blocks. The result represents
+%% "<code><em>Pattern</em> ?= <em>Body</em></code>".
+%%
+%% @see maybe_match_expr_pattern/1
+%% @see maybe_match_expr_body/1
+%% @see maybe_expr/2
+
+-record(maybe_match_expr, {pattern :: syntaxTree(), body :: syntaxTree()}).
+
+%% type(Node) = maybe_expr
+%% data(Node) = #maybe_expr{pattern :: Pattern, body :: Body}
+%%
+%% Pattern = Body = syntaxTree()
+%%
+%% `erl_parse' representation:
+%%
+%% {maybe_match, Pos, Pattern, Body}
+%%
+%% Pattern = Body = erl_parse()
+%%
+
+-spec maybe_match_expr(syntaxTree(), syntaxTree()) -> syntaxTree().
+
+maybe_match_expr(Pattern, Body) ->
+ tree(maybe_match_expr, #maybe_match_expr{pattern = Pattern, body = Body}).
+
+revert_maybe_match_expr(Node) ->
+ Pos = get_pos(Node),
+ Pattern = maybe_match_expr_pattern(Node),
+ Body = maybe_match_expr_body(Node),
+ {maybe_match, Pos, Pattern, Body}.
+
+%% =====================================================================
+%% @doc Returns the pattern subtree of a `maybe_expr' node.
+%%
+%% @see maybe_match_expr/2
+
+-spec maybe_match_expr_pattern(syntaxTree()) -> syntaxTree().
+
+maybe_match_expr_pattern(Node) ->
+ case unwrap(Node) of
+ {maybe_match, _, Pattern, _} ->
+ Pattern;
+ Node1 ->
+ (data(Node1))#maybe_match_expr.pattern
+ end.
+
+
+%% =====================================================================
+%% @doc Returns the body subtree of a `maybe_expr' node.
+%%
+%% @see maybe_match_expr/2
+
+-spec maybe_match_expr_body(syntaxTree()) -> syntaxTree().
+
+maybe_match_expr_body(Node) ->
+ case unwrap(Node) of
+ {maybe_match, _, _, Body} ->
+ Body;
+ Node1 ->
+ (data(Node1))#maybe_match_expr.body
+ end.
+
%% =====================================================================
%% @doc Creates an abstract operator. The name of the operator is the
%% character sequence represented by `Name'. This is
@@ -6361,6 +6447,130 @@ case_expr_clauses(Node) ->
(data(Node1))#case_expr.clauses
end.
+%% =====================================================================
+%% @doc Creates an abstract else-expression. If `Clauses' is `[C1,
+%% ..., Cn]', the result represents "<code>else <em>C1</em>; ...; <em>Cn</em>
+%% end</code>". More exactly, if each `Ci' represents
+%% "<code>(<em>Pi</em>) <em>Gi</em> -> <em>Bi</em></code>", then the
+%% result represents "<code>else <em>G1</em> -> <em>B1</em>; ...;
+%% <em>Pn</em> <em>Gn</em> -> <em>Bn</em> end</code>".
+%%
+%% @see maybe_expr/2
+%% @see else_expr_clauses/1
+%% @see clause/3
+
+else_expr(Clauses) ->
+ tree(else_expr, Clauses).
+
+revert_else_expr(Node) ->
+ Pos = get_pos(Node),
+ Clauses = else_expr_clauses(Node),
+ {'else', Pos, Clauses}.
+
+%% =====================================================================
+%% @doc Returns the list of clause subtrees of an `else_expr' node.
+%%
+%% @see else_expr/1
+
+-spec else_expr_clauses(syntaxTree()) -> [syntaxTree()].
+
+else_expr_clauses(Node) ->
+ case unwrap(Node) of
+ {'else', _, Clauses} ->
+ Clauses;
+ Node1 ->
+ data(Node1)
+ end.
+
+%% =====================================================================
+%% @equiv maybe_expr(Body, none)
+
+-spec maybe_expr([syntaxTree()]) -> syntaxTree().
+
+maybe_expr(Body) ->
+ maybe_expr(Body, none).
+
+%% =====================================================================
+%% @doc Creates an abstract maybe-expression. If `Body' is `[B1, ...,
+%% Bn]', and `OptionalElse' is `none', the result represents
+%% "<code>maybe <em>B1</em>, ..., <em>Bn</em> end</code>". If `Body'
+%% is `[B1, ..., Bn]', and `OptionalElse' reprsents an `else_expr' node
+%% with clauses `[C1, ..., Cn]', the result represents "<code>maybe
+%% <em>B1</em>, ..., <em>Bn</em> else <em>C1</em>; ..., <em>Cn</em>
+%% end</code>".
+%%
+%% See `clause' for documentation on `erl_parse' clauses.
+%%
+%% @see maybe_expr_body/1
+%% @see maybe_expr_else/1
+
+-record(maybe_expr, {body :: [syntaxTree()],
+ 'else' = none :: 'none' | syntaxTree()}).
+
+%% type(Node) = maybe_expr
+%% data(Node) = #maybe_expr{body :: Body, 'else' :: 'none' | Else}
+%%
+%% Body = [syntaxTree()]
+%% Else = syntaxTree()
+%%
+%% `erl_parse' representation:
+%%
+%% {block, Pos, Body}
+%% {block, Pos, Body, Else}
+%%
+%% Body = [erl_parse()] \ []
+%% Else = {'else', Pos, Clauses}
+%% Clauses = [Clause] \ []
+%% Clause = {clause, ...}
+
+-spec maybe_expr([syntaxTree()], 'none' | syntaxTree()) -> syntaxTree().
+
+maybe_expr(Body, OptionalElse) ->
+ tree(maybe_expr, #maybe_expr{body = Body,
+ 'else' = OptionalElse}).
+revert_maybe_expr(Node) ->
+ Pos = get_pos(Node),
+ Body = maybe_expr_body(Node),
+ case maybe_expr_else(Node) of
+ none ->
+ {'maybe', Pos, Body};
+ Else ->
+ {'maybe', Pos, Body, Else}
+ end.
+
+%% =====================================================================
+%% @doc Returns the list of body subtrees of a `maybe_expr' node.
+%%
+%% @see maybe_expr/2
+
+-spec maybe_expr_body(syntaxTree()) -> [syntaxTree()].
+
+maybe_expr_body(Node) ->
+ case unwrap(Node) of
+ {'maybe', _, Body} ->
+ Body;
+ {'maybe', _, Body, _Else} ->
+ Body;
+ Node1 ->
+ (data(Node1))#maybe_expr.body
+ end.
+
+%% =====================================================================
+%% @doc Returns the else subtree of a `maybe_expr' node.
+%%
+%% @see maybe_expr/2
+
+-spec maybe_expr_else(syntaxTree()) -> 'none' | syntaxTree().
+
+maybe_expr_else(Node) ->
+ case unwrap(Node) of
+ {'maybe', _, _Body} ->
+ none;
+ {'maybe', _, _Body, Else} ->
+ Else;
+ Node1 ->
+ (data(Node1))#maybe_expr.'else'
+ end.
%% =====================================================================
%% @equiv receive_expr(Clauses, none, [])
@@ -7470,9 +7680,9 @@ revert_root(Node) ->
revert_bitstring_type(Node);
block_expr ->
revert_block_expr(Node);
- case_expr ->
+ 'case_expr' -> %Quoted to help Emacs.
revert_case_expr(Node);
- catch_expr ->
+ 'catch_expr' -> %Quoted to help Emacs.
revert_catch_expr(Node);
char ->
revert_char(Node);
@@ -7482,6 +7692,8 @@ revert_root(Node) ->
revert_constrained_function_type(Node);
constraint ->
revert_constraint(Node);
+ else_expr ->
+ revert_else_expr(Node);
eof_marker ->
revert_eof_marker(Node);
error_marker ->
@@ -7526,6 +7738,10 @@ revert_root(Node) ->
revert_map_type_exact(Node);
match_expr ->
revert_match_expr(Node);
+ maybe_match_expr ->
+ revert_maybe_match_expr(Node);
+ maybe_expr ->
+ revert_maybe_expr(Node);
module_qualifier ->
revert_module_qualifier(Node);
named_fun_expr ->
@@ -7730,7 +7946,7 @@ subtrees(T) ->
case_expr ->
[[case_expr_argument(T)],
case_expr_clauses(T)];
- catch_expr ->
+ 'catch_expr' -> %Quoted to help Emacs.
[[catch_expr_body(T)]];
class_qualifier ->
[[class_qualifier_argument(T)],
@@ -7755,6 +7971,8 @@ subtrees(T) ->
constraint_body(T)];
disjunction ->
[disjunction_body(T)];
+ else_expr ->
+ [else_expr_clauses(T)];
form_list ->
[form_list_elements(T)];
fun_expr ->
@@ -7823,6 +8041,17 @@ subtrees(T) ->
match_expr ->
[[match_expr_pattern(T)],
[match_expr_body(T)]];
+ maybe_expr ->
+ case maybe_expr_else(T) of
+ none ->
+ [maybe_expr_body(T)];
+ E ->
+ [maybe_expr_body(T),
+ [E]]
+ end;
+ maybe_match_expr ->
+ [[maybe_match_expr_pattern(T)],
+ [maybe_match_expr_body(T)]];
module_qualifier ->
[[module_qualifier_argument(T)],
[module_qualifier_body(T)]];
@@ -7962,6 +8191,7 @@ make_tree(constrained_function_type, [[F],C]) ->
constrained_function_type(F, C);
make_tree(constraint, [[N], Ts]) -> constraint(N, Ts);
make_tree(disjunction, [E]) -> disjunction(E);
+make_tree(else_expr, [E]) -> else_expr(E);
make_tree(form_list, [E]) -> form_list(E);
make_tree(fun_expr, [C]) -> fun_expr(C);
make_tree(function, [[N], C]) -> function(N, C);
@@ -7985,6 +8215,9 @@ make_tree(map_type, [Fs]) -> map_type(Fs);
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(maybe_expr, [Body]) -> maybe_expr(Body);
+make_tree(maybe_expr, [Body, [Else]]) -> maybe_expr(Body, Else);
+make_tree(maybe_match_expr, [[P], [E]]) -> maybe_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);
diff --git a/lib/syntax_tools/src/erl_syntax_lib.erl b/lib/syntax_tools/src/erl_syntax_lib.erl
index b2d31be4f5..78c7ab9e46 100644
--- a/lib/syntax_tools/src/erl_syntax_lib.erl
+++ b/lib/syntax_tools/src/erl_syntax_lib.erl
@@ -1314,7 +1314,7 @@ analyze_attribute(Node) ->
ifndef -> preprocessor;
'if' -> preprocessor;
elif -> preprocessor;
- else -> preprocessor;
+ 'else' -> preprocessor;
endif -> preprocessor;
A ->
{A, analyze_attribute(A, Node)}
diff --git a/lib/syntax_tools/test/syntax_tools_SUITE.erl b/lib/syntax_tools/test/syntax_tools_SUITE.erl
index 3246ce7010..2ffec12740 100644
--- a/lib/syntax_tools/test/syntax_tools_SUITE.erl
+++ b/lib/syntax_tools/test/syntax_tools_SUITE.erl
@@ -106,7 +106,8 @@ revert(Config) when is_list(Config) ->
test_server:timetrap_cancel(Dog).
revert_file(File, Path) ->
- case epp:parse_file(File, Path, []) of
+ case epp:parse_file(File, [{includes,Path},
+ res_word_option()]) of
{ok,Fs0} ->
Fs1 = erl_syntax:form_list(Fs0),
Fs2 = erl_syntax_lib:map(fun (Node) -> Node end, Fs1),
@@ -350,8 +351,7 @@ t_comment_scan(Config) when is_list(Config) ->
t_prettypr(Config) when is_list(Config) ->
DataDir = ?config(data_dir, Config),
PrivDir = ?config(priv_dir, Config),
- Filenames = ["type_specs.erl",
- "specs_and_funs.erl"],
+ Filenames = test_files(),
ok = test_prettypr(Filenames,DataDir,PrivDir),
ok.
@@ -391,15 +391,16 @@ test_comment_scan([File|Files],DataDir) ->
test_prettypr([],_,_) -> ok;
test_prettypr([File|Files],DataDir,PrivDir) ->
Filename = filename:join(DataDir,File),
+ Options = [res_word_option()],
io:format("Parsing ~p~n", [Filename]),
- {ok, Fs0} = epp:parse_file(Filename, [], []),
+ {ok, Fs0} = epp:parse_file(Filename, Options),
Fs = erl_syntax:form_list(Fs0),
PP = erl_prettypr:format(Fs, [{paper, 120}, {ribbon, 110}]),
io:put_chars(PP),
OutFile = filename:join(PrivDir, File),
ok = file:write_file(OutFile,unicode:characters_to_binary(PP)),
io:format("Parsing OutFile: ~ts~n", [OutFile]),
- {ok, Fs2} = epp:parse_file(OutFile, [], []),
+ {ok, Fs2} = epp:parse_file(OutFile, Options),
case [Error || {error, _} = Error <- Fs2] of
[] ->
ok;
@@ -408,7 +409,6 @@ test_prettypr([File|Files],DataDir,PrivDir) ->
end,
test_prettypr(Files,DataDir,PrivDir).
-
test_epp_dodger([], _, _) -> ok;
test_epp_dodger([Filename|Files],DataDir,PrivDir) ->
io:format("Parsing ~p~n", [Filename]),
@@ -617,3 +617,13 @@ p_run_loop(Test, List, N, Refs0, Errors0) ->
Refs = Refs0 -- [Ref],
p_run_loop(Test, List, N, Refs, Errors)
end.
+
+res_word_option() ->
+ %% FIXME: When the experimental features EEP has been implemented, we should
+ %% dig out all keywords defined in all features.
+ ResWordFun =
+ fun('maybe') -> true;
+ ('else') -> true;
+ (Other) -> erl_scan:reserved_word(Other)
+ end,
+ {reserved_word_fun, ResWordFun}.
diff --git a/lib/syntax_tools/test/syntax_tools_SUITE_data/syntax_tools_SUITE_test_module.erl b/lib/syntax_tools/test/syntax_tools_SUITE_data/syntax_tools_SUITE_test_module.erl
index 95afffa7f6..9035139fea 100644
--- a/lib/syntax_tools/test/syntax_tools_SUITE_data/syntax_tools_SUITE_test_module.erl
+++ b/lib/syntax_tools/test/syntax_tools_SUITE_data/syntax_tools_SUITE_test_module.erl
@@ -8,6 +8,7 @@
sub_word/2,sub_word/3,left/2,left/3,right/2,right/3,
sub_string/2,sub_string/3,centre/2,centre/3, join/2]).
-export([to_upper/1, to_lower/1]).
+-export([eep49/0]).
-import(lists,[reverse/1,member/2]).
@@ -538,3 +539,45 @@ join([], Sep) when is_list(Sep) ->
[];
join([H|T], Sep) ->
H ++ lists:append([Sep ++ X || X <- T]).
+
+eep49() ->
+ maybe ok ?= ok end,
+
+ {a,b} =
+ maybe
+ {ok,A} ?= {ok,a},
+ {ok,B} ?= {ok,b},
+ {A,B}
+ end,
+
+ maybe
+ ok ?= {ok,x}
+ else
+ error -> error;
+ {error,_} -> error
+ end,
+
+ maybe
+ ok ?= {ok,x}
+ else
+ error -> error
+ end,
+
+ maybe
+ {ok,X} ?= {ok,x},
+ {ok,Y} ?= {ok,y},
+ {X,Y}
+ else
+ error -> error;
+ {error,_} -> error
+ end,
+
+ maybe
+ {ok,X2} ?= {ok,x},
+ {ok,Y2} ?= {ok,y},
+ {X2,Y2}
+ else
+ error -> error
+ end,
+
+ ok.
--
2.34.1