changeset 27736:bd80e14f268a

improve parse error message for @()x+=expr (bug #57255) * oct-parse.yy (anon_fcn_begin): New utility non-terminal to set both m_parsing_anon_fcn and m_at_beginning_of_statement lexer feedback flags. (anon_fcn_handle): Use it instead of stmt_begin. Reset m_parsing_anon_fcn after parsing expression. * lex.h (lexical_feedback::m_parsing_anon_fcn): New flag. (lexical_feedback::lexical_feedback: Initialize it. (lexical_feedback::reset): Reset it. (base_lexer::handle_identifier): Don't recognize identifier as a command when parsing anonymous function body.
author John W. Eaton <jwe@octave.org>
date Fri, 22 Nov 2019 12:18:21 -0600
parents 8600f5ea1ec1
children 527e25f7ee38
files libinterp/parse-tree/lex.h libinterp/parse-tree/lex.ll libinterp/parse-tree/oct-parse.yy
diffstat 3 files changed, 32 insertions(+), 10 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/parse-tree/lex.h	Thu Nov 21 19:23:20 2019 -0600
+++ b/libinterp/parse-tree/lex.h	Fri Nov 22 12:18:21 2019 -0600
@@ -272,6 +272,7 @@
         m_looking_at_matrix_or_assign_lhs (false),
         m_looking_for_object_index (false),
         m_looking_at_indirect_ref (false),
+        m_parsing_anon_fcn_body (false),
         m_parsing_class_method (false),
         m_parsing_classdef (false),
         m_parsing_classdef_decl (false),
@@ -387,6 +388,9 @@
     // structure element.
     bool m_looking_at_indirect_ref;
 
+    // true means we are parsing the body of an anonymous function.
+    bool m_parsing_anon_fcn_body;
+
     // true means we are parsing a class method in function or classdef file.
     bool m_parsing_class_method;
 
--- a/libinterp/parse-tree/lex.ll	Thu Nov 21 19:23:20 2019 -0600
+++ b/libinterp/parse-tree/lex.ll	Fri Nov 22 12:18:21 2019 -0600
@@ -2156,6 +2156,7 @@
     m_looking_at_matrix_or_assign_lhs = false;
     m_looking_for_object_index = false;
     m_looking_at_indirect_ref = false;
+    m_parsing_anon_fcn_body = false;
     m_parsing_class_method = false;
     m_parsing_classdef = false;
     m_parsing_classdef_decl = false;
@@ -3170,12 +3171,13 @@
     // function call with the argument "+1".
 
     if (m_at_beginning_of_statement
-        && (! (is_variable (ident, scope)
-               || ident == "e" || ident == "pi"
-               || ident == "I" || ident == "i"
-               || ident == "J" || ident == "j"
-               || ident == "Inf" || ident == "inf"
-               || ident == "NaN" || ident == "nan")))
+        && ! (m_parsing_anon_fcn_body
+              || is_variable (ident, scope)
+              || ident == "e" || ident == "pi"
+              || ident == "I" || ident == "i"
+              || ident == "J" || ident == "j"
+              || ident == "Inf" || ident == "inf"
+              || ident == "NaN" || ident == "nan"))
       tok->mark_may_be_command ();
 
     push_token (tok);
--- a/libinterp/parse-tree/oct-parse.yy	Thu Nov 21 19:23:20 2019 -0600
+++ b/libinterp/parse-tree/oct-parse.yy	Fri Nov 22 12:18:21 2019 -0600
@@ -229,8 +229,8 @@
 // Nonterminals we construct.
 %type <dummy_type> indirect_ref_op decl_param_init
 %type <dummy_type> push_fcn_symtab push_script_symtab begin_file
-%type <dummy_type> param_list_beg param_list_end stmt_begin parse_error
-%type <dummy_type> parsing_local_fcns
+%type <dummy_type> param_list_beg param_list_end stmt_begin anon_fcn_begin
+%type <dummy_type> parsing_local_fcns parse_error
 %type <comment_type> stash_comment
 %type <tok_val> function_beg classdef_beg
 %type <punct_type> sep_no_nl opt_sep_no_nl nl opt_nl sep opt_sep
@@ -604,7 +604,11 @@
                   { $$ = parser.make_fcn_handle ($1); }
                 ;
 
-anon_fcn_handle : '@' param_list stmt_begin expression
+// Note that we are deliberately not setting the beginning of statement
+// flag after recognizing the parameter list because we don't want to
+// accept word list commands in anonymous function bodies.
+
+anon_fcn_handle : '@' param_list anon_fcn_begin expression
                   {
                     $$ = parser.make_anon_fcn_handle ($2, $4);
                     if (! $$)
@@ -612,12 +616,16 @@
                         // make_anon_fcn_handle deleted $2 and $4.
                         YYABORT;
                       }
+
+                    lexer.m_parsing_anon_fcn_body = false;
                     lexer.m_nesting_level.remove ();
                   }
-                | '@' param_list stmt_begin error
+                | '@' param_list anon_fcn_begin error
                   {
                     YYUSE ($2);
 
+                    lexer.m_parsing_anon_fcn_body = false;
+
                     $$ = nullptr;
                     parser.bison_error ("anonymous function bodies must be single expressions");
                     YYABORT;
@@ -1975,6 +1983,14 @@
                   }
                 ;
 
+anon_fcn_begin  : // empty
+                  {
+                    $$ = 0;
+                    lexer.m_at_beginning_of_statement = true;
+                    lexer.m_parsing_anon_fcn_body = true;
+                  }
+                ;
+
 stash_comment   : // empty
                   { $$ = lexer.get_comment (); }
                 ;