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

openSUSE Build Service is sponsored by