lua-users home
lua-l archive

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


The old patch from Sven Olsen for compound assignment broke in 5.4.0 beta, so I pieced together something that seems to be working. I moved the operator+equals parsing to the lexer and took out the tuple handling to simplify things. (Now that it’s [maybe] working I might take a stab at adding it back in, though I doubt I’d ever use it.) I know there’s no interest in adding compound assignment to Standard Lua, but I understand it’s a pretty popular patch. I’d certainly have a hard time without it..

Hopefully this is useful to others, and please let me know what I did wrong! :)

Thanks,
-Dave


diff -r -u 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 2019-12-26 18:33:48.000000000 -0600
@@ -453,6 +453,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 +489,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 -r -u 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 -r -u 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 2019-12-26 18:33:55.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,58 @@
   }
 }
 
+
+static void compound_assignment(LexState *ls, expdesc* v, int nvars) {
+  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 VINDEXED 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(v->k==VINDEXED) {
+    if( /*!ISK( v->u.ind.t ) &&*/ v->u.ind.t >= top) {
+      top= v->u.ind.t+1;
+    }
+    if( /*!ISK( v->u.ind.idx ) &&*/ 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;
@@ -1365,21 +1420,21 @@
     enterlevel(ls);  /* control recursion depth */
     restassign(ls, &nv, nvars+1);
     leavelevel(ls);
+    init_exp(&e, VNONRELOC, ls->fs->freereg-1);  /* default assignment */
+    luaK_storevar(ls->fs, &lh->v, &e);
   }
-  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 {
       luaK_setoneret(ls->fs, &e);  /* close last _expression_ */
       luaK_storevar(ls->fs, &lh->v, &e);
-      return;  /* avoid default */
     }
   }
-  init_exp(&e, VNONRELOC, ls->fs->freereg-1);  /* default assignment */
-  luaK_storevar(ls->fs, &lh->v, &e);
+  else if ( ls->t.token >= TK_PLUSEQ && ls->t.token <= TK_BXOREQ ) { /* restassign -> opeq expr */
+   compound_assignment(ls,&lh->v,nvars);
+  }
 }
 
 
@@ -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);
   }