Browse Source

generic for (with any number of control variables)

Roberto Ierusalimschy 23 years ago
parent
commit
bd8b9c94b3
7 changed files with 98 additions and 68 deletions
  1. 19 8
      lcode.c
  2. 3 1
      lcode.h
  3. 17 4
      ldebug.c
  4. 3 2
      lopcodes.c
  5. 6 4
      lopcodes.h
  6. 44 40
      lparser.c
  7. 6 9
      lvm.c

+ 19 - 8
lcode.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lcode.c,v 1.89 2002/02/05 22:39:12 roberto Exp roberto $
+** $Id: lcode.c,v 1.90 2002/03/05 12:42:47 roberto Exp roberto $
 ** Code generator for Lua
 ** See Copyright Notice in lua.h
 */
@@ -158,6 +158,11 @@ void luaK_patchlist (FuncState *fs, int list, int target) {
 }
 
 
+void luaK_patchtohere (FuncState *fs, int list) {
+  luaK_patchlist(fs, list, luaK_getlabel(fs));
+}
+
+
 void luaK_concat (FuncState *fs, int *l1, int l2) {
   if (*l1 == NO_JUMP)
     *l1 = l2;
@@ -171,16 +176,22 @@ void luaK_concat (FuncState *fs, int *l1, int l2) {
 }
 
 
-void luaK_reserveregs (FuncState *fs, int n) {
-  fs->freereg += n;
-  if (fs->freereg > fs->f->maxstacksize) {
-    if (fs->freereg >= MAXSTACK)
+void luaK_checkstack (FuncState *fs, int n) {
+  int newstack = fs->freereg + n;
+  if (newstack > fs->f->maxstacksize) {
+    if (newstack >= MAXSTACK)
       luaK_error(fs->ls, "function or expression too complex");
-    fs->f->maxstacksize = cast(lu_byte, fs->freereg);
+    fs->f->maxstacksize = cast(lu_byte, newstack);
   }
 }
 
 
+void luaK_reserveregs (FuncState *fs, int n) {
+  luaK_checkstack(fs, n);
+  fs->freereg += n;
+}
+
+
 static void freereg (FuncState *fs, int reg) {
   if (reg >= fs->nactloc && reg < MAXSTACK) {
     fs->freereg--;
@@ -533,7 +544,7 @@ void luaK_goiftrue (FuncState *fs, expdesc *e) {
     }
   }
   luaK_concat(fs, &e->f, pc);  /* insert last jump in `f' list */
-  luaK_patchlist(fs, e->t, luaK_getlabel(fs));
+  luaK_patchtohere(fs, e->t);
   e->t = NO_JUMP;
 }
 
@@ -560,7 +571,7 @@ static void luaK_goiffalse (FuncState *fs, expdesc *e) {
     }
   }
   luaK_concat(fs, &e->t, pc);  /* insert last jump in `t' list */
-  luaK_patchlist(fs, e->f, luaK_getlabel(fs));
+  luaK_patchtohere(fs, e->f);
   e->f = NO_JUMP;
 }
 

+ 3 - 1
lcode.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lcode.h,v 1.1 2001/11/29 22:14:34 rieru Exp rieru $
+** $Id: lcode.h,v 1.27 2002/02/05 22:39:12 roberto Exp roberto $
 ** Code generator for Lua
 ** See Copyright Notice in lua.h
 */
@@ -42,6 +42,7 @@ void luaK_error (LexState *ls, const char *msg);
 int luaK_codeABc (FuncState *fs, OpCode o, int A, unsigned int Bc);
 int luaK_codeABC (FuncState *fs, OpCode o, int A, int B, int C);
 void luaK_nil (FuncState *fs, int from, int n);
+void luaK_checkstack (FuncState *fs, int n);
 void luaK_reserveregs (FuncState *fs, int n);
 int luaK_stringK (FuncState *fs, TString *s);
 int luaK_numberK (FuncState *fs, lua_Number r);
@@ -57,6 +58,7 @@ void luaK_storevar (FuncState *fs, expdesc *var, expdesc *e);
 void luaK_setcallreturns (FuncState *fs, expdesc *var, int nresults);
 int luaK_jump (FuncState *fs);
 void luaK_patchlist (FuncState *fs, int list, int target);
+void luaK_patchtohere (FuncState *fs, int list);
 void luaK_concat (FuncState *fs, int *l1, int l2);
 int luaK_getlabel (FuncState *fs);
 void luaK_prefix (FuncState *fs, UnOpr op, expdesc *v);

+ 17 - 4
ldebug.c

@@ -1,5 +1,5 @@
 /*
-** $Id: ldebug.c,v 1.97 2002/01/09 22:02:47 roberto Exp $
+** $Id: ldebug.c,v 1.100 2002/02/05 22:39:12 roberto Exp $
 ** Debug Interface
 ** See Copyright Notice in lua.h
 */
@@ -375,9 +375,10 @@ static Instruction luaG_symbexec (const Proto *pt, int lastpc, int reg) {
         check(c < MAXSTACK && b < c);
         break;
       }
-      case OP_JMP:
       case OP_FORLOOP:
-      case OP_TFORLOOP: {
+        checkreg(pt, a+2);
+        /* go through */
+      case OP_JMP: {
         int dest = pc+1+b;
 	check(0 <= dest && dest < pt->sizecode);
         /* not full check and jump is forward and do not skip `lastpc'? */
@@ -385,6 +386,12 @@ static Instruction luaG_symbexec (const Proto *pt, int lastpc, int reg) {
           pc += b;  /* do the jump */
         break;
       }
+      case OP_TFORLOOP: {
+        checkreg(pt, a+c);
+        checkreg(pt, a+2);  /* at least 2 for table generators */
+        check(pc+2 < pt->sizecode);  /* check skip */
+        break;
+      }
       case OP_CALL: {
         if (b != 0) {
           checkreg(pt, a+b-1);
@@ -408,8 +415,14 @@ static Instruction luaG_symbexec (const Proto *pt, int lastpc, int reg) {
         break;
       }
       case OP_CLOSURE: {
+        int nup;
         check(b < pt->sizep);
-        check(pc + pt->p[b]->nupvalues < pt->sizecode);
+        nup = pt->p[b]->nupvalues;
+        check(pc + nup < pt->sizecode);
+        for (; nup>0; nup--) {
+          OpCode op1 = GET_OPCODE(pt->code[pc+nup]);
+          check(op1 == OP_GETUPVAL || op1 == OP_MOVE);
+        }
         break;
       }
       default: break;

+ 3 - 2
lopcodes.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lopcodes.c,v 1.8 2001/12/11 22:48:44 roberto Exp $
+** $Id: lopcodes.c,v 1.11 2002/02/05 22:39:12 roberto Exp roberto $
 ** extracted automatically from lopcodes.h by mkprint.lua
 ** DO NOT EDIT
 ** See Copyright Notice in lua.h
@@ -60,6 +60,7 @@ const char *const luaP_opnames[] = {
    ((b)<<OpModeBreg) | ((c)<<OpModeCreg) | \
    ((sa)<<OpModesetA) | ((k)<<OpModeK) | (x)<<OpModeNoTrace | (m))
 
+
 const lu_byte luaP_opmodes[NUM_OPCODES] = {
 /*       T n B C sA K mode		   opcode    */
   opmode(0,0,1,0, 1,0,iABC)		/* OP_MOVE */
@@ -94,7 +95,7 @@ const lu_byte luaP_opmodes[NUM_OPCODES] = {
  ,opmode(0,0,0,0, 0,0,iABC)		/* OP_CALL */
  ,opmode(0,0,0,0, 0,0,iABC)		/* OP_RETURN */
  ,opmode(0,1,0,0, 0,0,iAsBc)		/* OP_FORLOOP */
- ,opmode(0,1,0,0, 0,0,iAsBc)		/* OP_TFORLOOP */
+ ,opmode(0,0,0,0, 0,0,iABC)		/* OP_TFORLOOP */
  ,opmode(0,0,0,0, 0,0,iABc)		/* OP_SETLIST */
  ,opmode(0,0,0,0, 0,0,iABc)		/* OP_SETLISTO */
  ,opmode(0,0,0,0, 0,0,iABC)		/* OP_CLOSE */

+ 6 - 4
lopcodes.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lopcodes.h,v 1.85 2002/01/09 22:02:47 roberto Exp $
+** $Id: lopcodes.h,v 1.89 2002/02/14 21:43:01 roberto Exp roberto $
 ** Opcodes for Lua virtual machine
 ** See Copyright Notice in lua.h
 */
@@ -166,11 +166,13 @@ OP_TESTGE,/*	A C	if not (R(A) >= R/K(C)) then pc++		*/
 OP_TESTT,/*	A B	if (R(B)) then R(A) := R(B) else pc++		*/ 
 OP_TESTF,/*	A B	if not (R(B)) then R(A) := R(B) else pc++	*/ 
 
-OP_CALL,/*	A B C	R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1))*/
+OP_CALL,/*	A B C	R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) */
 OP_RETURN,/*	A B	return R(A), ... ,R(A+B-2)	(see (3))	*/
 
-OP_FORLOOP,/*	A sBc							*/
-OP_TFORLOOP,/*	A sBc							*/
+OP_FORLOOP,/*	A sBc	R(A)+=R(A+2); if R(A) <?= R(A+1) then PC+= sBc	*/
+
+OP_TFORLOOP,/*	A C	R(A+1), ... ,R(A+C) := R(A)(); 
+                        if R(A+1) ~= nil then pc++			*/
 
 OP_SETLIST,/*	A Bc	R(A)[Bc-Bc%FPF+i] := R(A+i), 1 <= i <= Bc%FPF+1	*/
 OP_SETLISTO,/*	A Bc							*/

+ 44 - 40
lparser.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lparser.c,v 1.1 2001/11/29 22:14:34 rieru Exp rieru $
+** $Id: lparser.c,v 1.167 2002/02/14 21:46:58 roberto Exp $
 ** Lua Parser
 ** See Copyright Notice in lua.h
 */
@@ -247,12 +247,12 @@ static void adjust_assign (LexState *ls, int nvars, int nexps, expdesc *e) {
 }
 
 
-static void code_params (LexState *ls, int nparams, short dots) {
+static void code_params (LexState *ls, int nparams, int dots) {
   FuncState *fs = ls->fs;
   adjustlocalvars(ls, nparams);
   luaX_checklimit(ls, fs->nactloc, MAXPARAMS, "parameters");
-  fs->f->numparams = cast(short, fs->nactloc);  /* `self' could be there already */
-  fs->f->is_vararg = dots;
+  fs->f->numparams = cast(lu_byte, fs->nactloc);
+  fs->f->is_vararg = cast(lu_byte, dots);
   if (dots) {
     new_localvarstr(ls, "arg", 0);
     adjustlocalvars(ls, 1);
@@ -271,7 +271,7 @@ static void enterbreak (FuncState *fs, Breaklabel *bl) {
 
 static void leavebreak (FuncState *fs, Breaklabel *bl) {
   fs->bl = bl->previous;
-  luaK_patchlist(fs, bl->breaklist, luaK_getlabel(fs));
+  luaK_patchtohere(fs, bl->breaklist);
   lua_assert(bl->nactloc == fs->nactloc);
 }
 
@@ -471,8 +471,11 @@ static void recfield (LexState *ls, struct ConsControl *cc) {
   FuncState *fs = ls->fs;
   int reg = ls->fs->freereg;
   expdesc key, val;
-  if (ls->t.token == TK_NAME)
+  if (ls->t.token == TK_NAME) {
+    luaX_checklimit(ls, cc->nh, MAX_INT, "items in a constructor");
+    cc->nh++;
     checkname(ls, &key);
+  }
   else  /* ls->t.token == '[' */
     luaY_index(ls, &key);
   check(ls, '=');
@@ -481,8 +484,6 @@ static void recfield (LexState *ls, struct ConsControl *cc) {
   luaK_exp2anyreg(fs, &val);
   luaK_codeABC(fs, OP_SETTABLE, val.info, cc->t->info, luaK_exp2RK(fs, &key));
   fs->freereg = reg;  /* free registers */
-  luaX_checklimit(ls, cc->nh, MAX_INT, "items in a constructor");
-  cc->nh++;
 }
 
 
@@ -893,7 +894,7 @@ static void whilestat (LexState *ls, int line) {
   check(ls, TK_DO);
   block(ls);
   luaK_patchlist(fs, luaK_jump(fs), while_init);
-  luaK_patchlist(fs, v.f, luaK_getlabel(fs));
+  luaK_patchtohere(fs, v.f);
   check_match(ls, TK_END, TK_WHILE, line);
   leavebreak(fs, &bl);
 }
@@ -922,24 +923,11 @@ static void exp1 (LexState *ls) {
 }
 
 
-static void forbody (LexState *ls, OpCode loopfor) {
-  /* forbody -> DO block END */
-  FuncState *fs = ls->fs;
-  int basereg = fs->freereg - 3;
-  int prep = luaK_jump(fs);
-  int blockinit = luaK_getlabel(fs);
-  check(ls, TK_DO);
-  adjustlocalvars(ls, 3);  /* scope for control variables */
-  block(ls);
-  luaK_patchlist(fs, prep, luaK_getlabel(fs));
-  luaK_patchlist(fs, luaK_codeAsBc(fs, loopfor, basereg, NO_JUMP), blockinit);
-  removelocalvars(ls, 3, 1);
-}
-
-
 static void fornum (LexState *ls, TString *varname) {
-  /* fornum -> NAME = exp1,exp1[,exp1] forbody */
+  /* fornum -> NAME = exp1,exp1[,exp1] DO body */
   FuncState *fs = ls->fs;
+  int prep;
+  int base = fs->freereg;
   new_localvar(ls, varname, 0);
   new_localvarstr(ls, "(limit)", 1);
   new_localvarstr(ls, "(step)", 2);
@@ -954,26 +942,42 @@ static void fornum (LexState *ls, TString *varname) {
     luaK_reserveregs(fs, 1);
   }
   luaK_codeABC(fs, OP_SUB, fs->freereg - 3, fs->freereg - 3, fs->freereg - 1);
-  forbody(ls, OP_FORLOOP);
+  luaK_jump(fs);
+  prep = luaK_getlabel(fs);
+  check(ls, TK_DO);
+  adjustlocalvars(ls, 3);  /* scope for control variables */
+  block(ls);
+  luaK_patchtohere(fs, prep-1);
+  luaK_patchlist(fs, luaK_codeAsBc(fs, OP_FORLOOP, base, NO_JUMP), prep);
+  removelocalvars(ls, 3, 1);
 }
 
 
 static void forlist (LexState *ls, TString *indexname) {
-  /* forlist -> NAME,NAME IN exp1 forbody */
+  /* forlist -> NAME {,NAME} IN exp1 DO body */
   FuncState *fs = ls->fs;
+  int nvars = 0;
+  int prep;
+  int base = fs->freereg;
   new_localvarstr(ls, "(table)", 0);
-  new_localvar(ls, indexname, 1);
-  if (optional(ls, ',')) {
-    new_localvar(ls, str_checkname(ls), 2);
-    next(ls);  /* skip var name */
+  new_localvar(ls, indexname, ++nvars);
+  while (optional(ls, ',')) {
+    new_localvar(ls, str_checkname(ls), ++nvars);
+    next(ls);
   }
-  else
-    new_localvarstr(ls, "(val)", 2);
   check(ls, TK_IN);
   exp1(ls);  /* table */
-  luaK_reserveregs(fs, 2);  /* registers for index and val */
-  luaK_codeABC(fs, OP_LOADNIL, fs->freereg - 2, fs->freereg - 1, 0);
-  forbody(ls, OP_TFORLOOP);
+  luaK_checkstack(fs, 2);  /* at least two slots, to traverse tables */
+  luaK_reserveregs(fs, nvars);  /* registers for vars */
+  luaK_codeABC(fs, OP_LOADNIL, base+1, base+nvars, 0);
+  adjustlocalvars(ls, nvars+1);  /* scope for control variables */
+  luaK_codeABC(fs, OP_TFORLOOP, base, 0, nvars);
+  prep = luaK_jump(fs);
+  check(ls, TK_DO);
+  block(ls);
+  luaK_patchlist(fs, luaK_jump(fs), prep-1);
+  luaK_patchtohere(fs, prep);
+  removelocalvars(ls, nvars+1, 1);
 }
 
 
@@ -1013,18 +1017,18 @@ static void ifstat (LexState *ls, int line) {
   test_then_block(ls, &v);  /* IF cond THEN block */
   while (ls->t.token == TK_ELSEIF) {
     luaK_concat(fs, &escapelist, luaK_jump(fs));
-    luaK_patchlist(fs, v.f, luaK_getlabel(fs));
+    luaK_patchtohere(fs, v.f);
     test_then_block(ls, &v);  /* ELSEIF cond THEN block */
   }
   if (ls->t.token == TK_ELSE) {
     luaK_concat(fs, &escapelist, luaK_jump(fs));
-    luaK_patchlist(fs, v.f, luaK_getlabel(fs));
+    luaK_patchtohere(fs, v.f);
     next(ls);  /* skip ELSE */
     block(ls);  /* `else' part */
   }
   else
     luaK_concat(fs, &escapelist, v.f);
-  luaK_patchlist(fs, escapelist, luaK_getlabel(fs));
+  luaK_patchtohere(fs, escapelist);
   check_match(ls, TK_END, TK_IF, line);
 }
 
@@ -1182,7 +1186,7 @@ static int statement (LexState *ls) {
 static void parlist (LexState *ls) {
   /* parlist -> [ param { `,' param } ] */
   int nparams = 0;
-  short dots = 0;
+  int dots = 0;
   if (ls->t.token != ')') {  /* is `parlist' not empty? */
     do {
       switch (ls->t.token) {

+ 6 - 9
lvm.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lvm.c,v 1.217 2002/03/04 15:40:04 roberto Exp roberto $
+** $Id: lvm.c,v 1.218 2002/03/04 21:33:09 roberto Exp roberto $
 ** Lua virtual machine
 ** See Copyright Notice in lua.h
 */
@@ -560,24 +560,21 @@ StkId luaV_execute (lua_State *L) {
         break;
       }
       case OP_TFORLOOP: {
-        int j = GETARG_sBc(i);
-        int loop = 0;
-        pc += j;  /* jump back before tests (for error messages) */
         if (ttype(ra) == LUA_TTABLE) {
           Table *t = hvalue(ra);
-          loop = luaH_next(L, t, ra+1);
+          if (luaH_next(L, t, ra+1))
+            pc++;  /* skip jump (keep looping) */
         }
         else if (ttype(ra) == LUA_TFUNCTION) {
           setobj(ra+1, ra);
           L->top = ra+2;  /* no arguments */
-          luaD_call(L, ra+1, 2);
+          luaD_call(L, ra+1, GETARG_C(i));
           L->top = L->ci->top;
-          loop = (ttype(ra+1) != LUA_TNIL);
+          if (ttype(ra+1) != LUA_TNIL)
+            pc++;  /* skip jump (keep looping) */
         }
         else
           luaD_error(L, "`for' generator must be a table or function");
-        if (!loop)
-          pc -= j;  /* undo jump */
         break;
       }
       case OP_SETLIST: