changeset 29900:da6e5914ddaf

handle all binary operators the same when detecting command syntax (bug #60882) This change breaks Matlab compatibility when parsing things like x += 2 Matlab will handle this as a command-style function call with two arguments '+=' and '2'. Octave will now treat this as a computed assignment (the variable X incremented by 2). Octave will still handle x +=2 as a command-style function call when parsing this statement inside a function. At the command line, Octave will recognize this statement as a computed assignment expression if X is already defined to be a variable. Note that command lines are parsed completely before executing anything, so in octave> clear x octave> x = 1; x +=2 the "x +=2" statement will be parsed as a command-style function call because the parser does not find a definition for X as a variable when that portion of the command line is parsed. * lex.ll (CMD_OR_COMPUTED_ASSIGN_OP): Delete macro. Change all uses to CMD_OR_OP instead. (base_lexer::handle_identifier): Don't call mark_may_be_command for token if we are at the top level and the identifier has already been recognized as a variable. * parser.tst: Update test.
author John W. Eaton <jwe@octave.org>
date Wed, 21 Jul 2021 09:49:09 -0400
parents 853e4b7ae0d5
children ee84485289ce
files libinterp/parse-tree/lex.ll test/parser.tst
diffstat 2 files changed, 25 insertions(+), 52 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/parse-tree/lex.ll	Wed Jul 21 14:45:32 2021 +0200
+++ b/libinterp/parse-tree/lex.ll	Wed Jul 21 09:49:09 2021 -0400
@@ -183,38 +183,6 @@
      }                                                                  \
    while (0)
 
-#if 0
-// Use the following to handle computed assignment operators
-// (+=, -=, etc.) in word list commands in a way that is compatible
-// with Matlab.  However, that will also make it impossible to use
-// these operators with a space before them:
-//
-//   x = 1;
-//   x+=2;   ## ok
-//   x+= 2;  ## ok
-//   x +=2;  ## error: invalid use of symbol as both variable and command
-//   x += 2; ## error: invalid use of symbol as both variable and command
-//
-#  define CMD_OR_COMPUTED_ASSIGN_OP(PATTERN, TOK)                       \
-   do                                                                   \
-     {                                                                  \
-       curr_lexer->lexer_debug (PATTERN);                               \
-                                                                        \
-       if (curr_lexer->previous_token_may_be_command ()                 \
-           && curr_lexer->space_follows_previous_token ())              \
-         {                                                              \
-           yyless (0);                                                  \
-           curr_lexer->push_start_state (COMMAND_START);                \
-         }                                                              \
-       else                                                             \
-         return curr_lexer->handle_op (TOK, false, false);              \
-     }                                                                  \
-   while (0)
-#else
-#  define CMD_OR_COMPUTED_ASSIGN_OP(PATTERN, TOK)                       \
-   return curr_lexer->handle_op (TOK, false, false)
-#endif
-
 #define CMD_OR_UNARY_OP(PATTERN, TOK, COMPAT)                           \
    do                                                                   \
      {                                                                  \
@@ -1836,22 +1804,22 @@
     return curr_lexer->handle_op ('=');
   }
 
-"+="   { CMD_OR_COMPUTED_ASSIGN_OP ("+=", ADD_EQ); }
-"-="   { CMD_OR_COMPUTED_ASSIGN_OP ("-=", SUB_EQ); }
-"*="   { CMD_OR_COMPUTED_ASSIGN_OP ("*=", MUL_EQ); }
-"/="   { CMD_OR_COMPUTED_ASSIGN_OP ("/=", DIV_EQ); }
-"\\="  { CMD_OR_COMPUTED_ASSIGN_OP ("\\=", LEFTDIV_EQ); }
-".+="  { CMD_OR_COMPUTED_ASSIGN_OP (".+=", ADD_EQ); }
-".-="  { CMD_OR_COMPUTED_ASSIGN_OP (".-=", SUB_EQ); }
-".*="  { CMD_OR_COMPUTED_ASSIGN_OP (".*=", EMUL_EQ); }
-"./="  { CMD_OR_COMPUTED_ASSIGN_OP ("./=", EDIV_EQ); }
-".\\=" { CMD_OR_COMPUTED_ASSIGN_OP (".\\=", ELEFTDIV_EQ); }
-"^="   { CMD_OR_COMPUTED_ASSIGN_OP ("^=", POW_EQ); }
-"**="  { CMD_OR_COMPUTED_ASSIGN_OP ("^=", POW_EQ); }
-".^="  { CMD_OR_COMPUTED_ASSIGN_OP (".^=", EPOW_EQ); }
-".**=" { CMD_OR_COMPUTED_ASSIGN_OP (".^=", EPOW_EQ); }
-"&="   { CMD_OR_COMPUTED_ASSIGN_OP ("&=", AND_EQ); }
-"|="   { CMD_OR_COMPUTED_ASSIGN_OP ("|=", OR_EQ); }
+"+="   { CMD_OR_OP ("+=", ADD_EQ, false); }
+"-="   { CMD_OR_OP ("-=", SUB_EQ, false); }
+"*="   { CMD_OR_OP ("*=", MUL_EQ, false); }
+"/="   { CMD_OR_OP ("/=", DIV_EQ, false); }
+"\\="  { CMD_OR_OP ("\\=", LEFTDIV_EQ, false); }
+".+="  { CMD_OR_OP (".+=", ADD_EQ, false); }
+".-="  { CMD_OR_OP (".-=", SUB_EQ, false); }
+".*="  { CMD_OR_OP (".*=", EMUL_EQ, false); }
+"./="  { CMD_OR_OP ("./=", EDIV_EQ, false); }
+".\\=" { CMD_OR_OP (".\\=", ELEFTDIV_EQ, false); }
+"^="   { CMD_OR_OP ("^=", POW_EQ, false); }
+"**="  { CMD_OR_OP ("^=", POW_EQ, false); }
+".^="  { CMD_OR_OP (".^=", EPOW_EQ, false); }
+".**=" { CMD_OR_OP (".^=", EPOW_EQ, false); }
+"&="   { CMD_OR_OP ("&=", AND_EQ, false); }
+"|="   { CMD_OR_OP ("|=", OR_EQ, false); }
 
 %{
 // In Matlab, '{' may also trigger command syntax.
@@ -3584,12 +3552,15 @@
 
     token *tok = new token (NAME, ident, m_tok_beg, m_tok_end);
 
-    // The following symbols are handled specially so that things like
+    // For compatibility with Matlab, the following symbols are
+    // handled specially so that things like
     //
     //   pi +1
     //
     // are parsed as an addition expression instead of as a command-style
-    // function call with the argument "+1".
+    // function call with the argument "+1".  Also for compatibility with
+    // Matlab, if we are at the top level workspace, do not consider IDENT
+    // as a possible command if it is already known to be a variable.
 
     if (m_at_beginning_of_statement
         && ! (m_parsing_anon_fcn_body
@@ -3597,7 +3568,9 @@
               || ident == "I" || ident == "i"
               || ident == "J" || ident == "j"
               || ident == "Inf" || ident == "inf"
-              || ident == "NaN" || ident == "nan"))
+              || ident == "NaN" || ident == "nan"
+              || (m_interpreter.at_top_level ()
+                  && m_interpreter.is_variable (ident))))
       tok->mark_may_be_command ();
 
     push_token (tok);
--- a/test/parser.tst	Wed Jul 21 14:45:32 2021 +0200
+++ b/test/parser.tst	Wed Jul 21 09:49:09 2021 -0400
@@ -91,7 +91,7 @@
 %! assert (1 && a ++, false);
 %! assert (0 || a --, true);
 %! a = 5; b = 2;
-%! b +=a ++;
+%! b += a ++;
 %! assert (b, 7);
 
 ## Level 11 (transpose and exponentiation)