lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


One last (I hope) fix for this. I don’t totally grok the finer points between the expkind VINDEX* cases and where we do or don’t need to tuck intermediate values in registers, but I came up with code that produces each and confirmed that the += operator generates the same bytecode (or close enough) as doing it long form. I also added an error if the compound operator appears after a tuple, because I don’t want to touch that.

Let me know if it’s helpful! Or hurtful!

-Dave


diff -urN lua-5.4.0-beta/src/llex.c lua-5.4-test/src/llex.c
--- lua-5.4.0-beta/src/llex.c 2019-09-30 18:52:15.000000000 -0500
+++ lua-5.4-test/src/llex.c 2020-01-03 22:39:27.000000000 -0600
@@ -44,7 +44,8 @@
     "return", "then", "true", "until", "while",
     "//", "..", "...", "==", ">=", "<=", "~=",
     "<<", ">>", "::", "<eof>",
-    "<number>", "<integer>", "<name>", "<string>"
+    "<number>", "<integer>", "<name>", "<string>",
+    "+=", "-=", "*=", "/=", "<<=", ">>=", "&=", "|=", "^="
 };
 
 
@@ -453,6 +454,7 @@
       }
       case '-': {  /* '-' or '--' (comment) */
         next(ls);
+        if (check_next1(ls, '=')) return TK_MINUSEQ;
         if (ls->current != '-') return '-';
         /* else is a comment */
         next(ls);
@@ -488,20 +490,52 @@
       case '<': {
         next(ls);
         if (check_next1(ls, '=')) return TK_LE;
-        else if (check_next1(ls, '<')) return TK_SHL;
+        else if (check_next1(ls, '<')) {
+          if (check_next1(ls, '=')) return TK_SHLEQ;
+          else return TK_SHL;
+        }
         else return '<';
       }
       case '>': {
         next(ls);
         if (check_next1(ls, '=')) return TK_GE;
-        else if (check_next1(ls, '>')) return TK_SHR;
+        else if (check_next1(ls, '>')) {
+          if (check_next1(ls, '=')) return TK_SHREQ;
+          else return TK_SHR;
+        }
         else return '>';
       }
       case '/': {
         next(ls);
         if (check_next1(ls, '/')) return TK_IDIV;
+        if (check_next1(ls, '=')) return TK_DIVEQ;
         else return '/';
       }
+      case '+': {
+        next(ls);
+        if (check_next1(ls, '=')) return TK_PLUSEQ;
+        else return '+';
+      }
+      case '*': {
+        next(ls);
+        if (check_next1(ls, '=')) return TK_MULTEQ;
+        else return '*';
+      }
+      case '&': {
+        next(ls);
+        if (check_next1(ls, '=')) return TK_BANDEQ;
+        else return '*';
+      }
+      case '|': {
+        next(ls);
+        if (check_next1(ls, '=')) return TK_BOREQ;
+        else return '|';
+      }
+      case '^': {
+        next(ls);
+        if (check_next1(ls, '=')) return TK_BXOREQ;
+        else return '^';
+      }
       case '~': {
         next(ls);
         if (check_next1(ls, '=')) return TK_NE;
diff -urN lua-5.4.0-beta/src/llex.h lua-5.4-test/src/llex.h
--- lua-5.4.0-beta/src/llex.h 2019-09-30 18:52:15.000000000 -0500
+++ lua-5.4-test/src/llex.h 2019-12-26 18:33:52.000000000 -0600
@@ -33,7 +33,8 @@
   TK_IDIV, TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE,
   TK_SHL, TK_SHR,
   TK_DBCOLON, TK_EOS,
-  TK_FLT, TK_INT, TK_NAME, TK_STRING
+  TK_FLT, TK_INT, TK_NAME, TK_STRING,
+  TK_PLUSEQ, TK_MINUSEQ, TK_MULTEQ, TK_DIVEQ, TK_SHLEQ, TK_SHREQ, TK_BANDEQ, TK_BOREQ, TK_BXOREQ
 };
 
 /* number of reserved words */
diff -urN lua-5.4.0-beta/src/lparser.c lua-5.4-test/src/lparser.c
--- lua-5.4.0-beta/src/lparser.c 2019-10-08 05:18:16.000000000 -0500
+++ lua-5.4-test/src/lparser.c 2020-01-03 22:46:21.000000000 -0600
@@ -1206,6 +1206,15 @@
     case TK_GE: return OPR_GE;
     case TK_AND: return OPR_AND;
     case TK_OR: return OPR_OR;
+    case TK_PLUSEQ: return OPR_ADD;
+    case TK_MINUSEQ: return OPR_SUB;
+    case TK_MULTEQ: return OPR_MUL;
+    case TK_DIVEQ: return OPR_DIV;
+    case TK_SHLEQ: return OPR_SHL;
+    case TK_SHREQ: return OPR_SHR;
+    case TK_BANDEQ: return OPR_BAND;
+    case TK_BOREQ: return OPR_BOR;
+    case TK_BXOREQ: return OPR_BXOR;
     default: return OPR_NOBINOPR;
   }
 }
@@ -1345,12 +1354,55 @@
   }
 }
 
+
+static void compound_assignment(LexState *ls, expdesc* v) {
+  BinOpr op = getbinopr(ls->t.token);
+  FuncState * fs=ls->fs;
+  int tolevel=fs->nactvar;
+  int old_free=fs->freereg;
+  expdesc e,infix;
+  int line=ls->linenumber;
+  int nextra, i;
+  luaX_next(ls);
+
+  /* create temporary local variables to lock up any registers needed
+     by indexed lvalues. */
+  lu_byte top=fs->nactvar;
+  /* protect both the table and index result registers,
+  ** ensuring that they won't be overwritten prior to the
+  ** storevar calls. */
+  if (vkisindexed(v->k)) {
+    if (v->u.ind.t>=top)
+      top = v->u.ind.t+1;
+    if (v->k == VINDEXED && v->u.ind.idx >= top)
+      top = v->u.ind.idx+1;
+  }
+  nextra=top-fs->nactvar;
+  if(nextra) {
+    for(i=0;i<nextra;i++) {
+      new_localvarliteral(ls,"(temp)");
+    }
+    adjustlocalvars(ls,nextra);
+  }
+
+  infix = *v;
+  luaK_infix(fs,op,&infix);
+  expr(ls, &e);
+  luaK_posfix(fs, op, &infix, &e, line);
+  luaK_storevar(fs, v, &infix);
+  removevars(fs,tolevel);
+
+  if(old_free<fs->freereg) {
+    fs->freereg=old_free;
+  }
+}
+
 /*
 ** Parse and compile a multiple assignment. The first "variable"
 ** (a 'suffixedexp') was already read by the caller.
 **
 ** assignment -> suffixedexp restassign
-** restassign -> ',' suffixedexp restassign | '=' explist
+** restassign -> ',' suffixedexp restassign | '=' explist | opeq expr
 */
 static void restassign (LexState *ls, struct LHS_assign *lh, int nvars) {
   expdesc e;
@@ -1366,10 +1418,8 @@
     restassign(ls, &nv, nvars+1);
     leavelevel(ls);
   }
-  else {  /* restassign -> '=' explist */
-    int nexps;
-    checknext(ls, '=');
-    nexps = explist(ls, &e);
+  else if (testnext(ls, '=')) {  /* restassign -> '=' explist */
+    int nexps = explist(ls, &e);
     if (nexps != nvars)
       adjust_assign(ls, nvars, nexps, &e);
     else {
@@ -1378,6 +1428,11 @@
       return;  /* avoid default */
     }
   }
+  else if ( ls->t.token >= TK_PLUSEQ && ls->t.token <= TK_BXOREQ ) { /* restassign -> opeq expr */
+   check_condition(ls, nvars == 1, "compound assignment not allowed on tuples");
+   compound_assignment(ls,&lh->v);
+      return;
+  }
   init_exp(&e, VNONRELOC, ls->fs->freereg-1);  /* default assignment */
   luaK_storevar(ls->fs, &lh->v, &e);
 }
@@ -1816,7 +1871,7 @@
   FuncState *fs = ls->fs;
   struct LHS_assign v;
   suffixedexp(ls, &v.v);
-  if (ls->t.token == '=' || ls->t.token == ',') { /* stat -> assignment ? */
+  if (ls->t.token == '=' || ls->t.token == ',' || (ls->t.token >= TK_PLUSEQ && ls->t.token <= TK_BXOREQ) ) { /* stat -> assignment ? */
     v.prev = NULL;
     restassign(ls, &v, 1);
   }