2
0
Эх сурвалжийг харах

new way to use `vararg' parameters (with `...')

Roberto Ierusalimschy 21 жил өмнө
parent
commit
616438fe9a
13 өөрчлөгдсөн 192 нэмэгдсэн , 106 устгасан
  1. 21 7
      lcode.c
  2. 5 2
      lcode.h
  3. 10 3
      ldebug.c
  4. 43 23
      ldo.c
  5. 5 1
      lobject.h
  6. 4 2
      lopcodes.c
  7. 13 8
      lopcodes.h
  8. 31 29
      lparser.c
  9. 3 2
      lparser.h
  10. 2 1
      lstate.c
  11. 5 4
      lstate.h
  12. 23 14
      lua.c
  13. 27 10
      lvm.c

+ 21 - 7
lcode.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lcode.c,v 2.1 2003/12/10 12:13:36 roberto Exp roberto $
+** $Id: lcode.c,v 2.2 2004/04/30 20:13:38 roberto Exp roberto $
 ** Code generator for Lua
 ** See Copyright Notice in lua.h
 */
@@ -252,13 +252,26 @@ static int nil_constant (FuncState *fs) {
 }
 
 
-void luaK_setcallreturns (FuncState *fs, expdesc *e, int nresults) {
+void luaK_setreturns (FuncState *fs, expdesc *e, int nresults) {
   if (e->k == VCALL) {  /* expression is an open function call? */
     SETARG_C(getcode(fs, e), nresults+1);
-    if (nresults == 1) {  /* `regular' expression? */
-      e->k = VNONRELOC;
-      e->info = GETARG_A(getcode(fs, e));
-    }
+  }
+  else if (e->k == VVARARG) {
+    SETARG_B(getcode(fs, e), nresults+1);
+    SETARG_A(getcode(fs, e), fs->freereg);
+    luaK_reserveregs(fs, 1);
+  }
+}
+
+
+void luaK_setoneret (FuncState *fs, expdesc *e) {
+  if (e->k == VCALL) {  /* expression is an open function call? */
+    e->k = VNONRELOC;
+    e->info = GETARG_A(getcode(fs, e));
+  }
+  else if (e->k == VVARARG) {
+    SETARG_B(getcode(fs, e), 2);
+    e->k = VRELOCABLE;  /* can relocate its simple result */
   }
 }
 
@@ -286,8 +299,9 @@ void luaK_dischargevars (FuncState *fs, expdesc *e) {
       e->k = VRELOCABLE;
       break;
     }
+    case VVARARG:
     case VCALL: {
-      luaK_setcallreturns(fs, e, 1);
+      luaK_setoneret(fs, e);
       break;
     }
     default: break;  /* there is one value available (somewhere) */

+ 5 - 2
lcode.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lcode.h,v 1.37 2002/06/12 19:16:00 roberto Exp roberto $
+** $Id: lcode.h,v 1.38 2002/12/11 12:34:22 roberto Exp roberto $
 ** Code generator for Lua
 ** See Copyright Notice in lua.h
 */
@@ -41,6 +41,8 @@ typedef enum UnOpr { OPR_MINUS, OPR_NOT, OPR_NOUNOPR } UnOpr;
 
 #define luaK_codeAsBx(fs,o,A,sBx)	luaK_codeABx(fs,o,A,(sBx)+MAXARG_sBx)
 
+#define luaK_setmultret(fs,e)	luaK_setreturns(fs, e, LUA_MULTRET)
+
 int luaK_code (FuncState *fs, Instruction i, int line);
 int luaK_codeABx (FuncState *fs, OpCode o, int A, unsigned int Bx);
 int luaK_codeABC (FuncState *fs, OpCode o, int A, int B, int C);
@@ -60,7 +62,8 @@ void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k);
 void luaK_goiftrue (FuncState *fs, expdesc *e);
 void luaK_goiffalse (FuncState *fs, expdesc *e);
 void luaK_storevar (FuncState *fs, expdesc *var, expdesc *e);
-void luaK_setcallreturns (FuncState *fs, expdesc *var, int nresults);
+void luaK_setreturns (FuncState *fs, expdesc *e, int nresults);
+void luaK_setoneret (FuncState *fs, expdesc *e);
 int luaK_jump (FuncState *fs);
 void luaK_patchlist (FuncState *fs, int list, int target);
 void luaK_patchtohere (FuncState *fs, int list);

+ 10 - 3
ldebug.c

@@ -1,5 +1,5 @@
 /*
-** $Id: ldebug.c,v 2.3 2004/03/23 13:10:16 roberto Exp roberto $
+** $Id: ldebug.c,v 2.4 2004/04/30 20:13:38 roberto Exp roberto $
 ** Debug Interface
 ** See Copyright Notice in lua.h
 */
@@ -221,8 +221,8 @@ LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) {
   }
   else if (ar->i_ci != 0) {  /* no tail call? */
     CallInfo *ci = L->base_ci + ar->i_ci;
-    lua_assert(ttisfunction(ci->base - 1));
-    status = auxgetinfo(L, what, ar, ci->base - 1, ci);
+    lua_assert(ttisfunction(ci->func));
+    status = auxgetinfo(L, what, ar, ci->func, ci);
   }
   else
     info_tailcall(L, ar);
@@ -405,6 +405,13 @@ static Instruction luaG_symbexec (const Proto *pt, int lastpc, int reg) {
         }
         break;
       }
+      case OP_VARARG: {
+        check(pt->is_vararg & NEWSTYLEVARARG);
+        b--;
+        if (b == LUA_MULTRET) check(checkopenop(pt, pc));
+        checkreg(pt, a+b-1);
+        break;
+      }
       default: break;
     }
   }

+ 43 - 23
ldo.c

@@ -1,5 +1,5 @@
 /*
-** $Id: ldo.c,v 2.4 2004/05/10 17:50:51 roberto Exp roberto $
+** $Id: ldo.c,v 2.5 2004/05/14 19:25:09 roberto Exp roberto $
 ** Stack and Call structure of Lua
 ** See Copyright Notice in lua.h
 */
@@ -113,6 +113,7 @@ static void correctstack (lua_State *L, TValue *oldstack) {
   for (ci = L->base_ci; ci <= L->ci; ci++) {
     ci->top = (ci->top - oldstack) + L->stack;
     ci->base = (ci->base - oldstack) + L->stack;
+    ci->func = (ci->func - oldstack) + L->stack;
   }
   L->base = L->ci->base;
 }
@@ -181,26 +182,37 @@ void luaD_callhook (lua_State *L, int event, int line) {
 }
 
 
-static void adjust_varargs (lua_State *L, int nfixargs, StkId base) {
+static StkId adjust_varargs (lua_State *L, int nfixargs, int actual,
+                             int style) {
   int i;
-  Table *htab;
-  int actual = L->top - base;  /* actual number of arguments */
+  Table *htab = NULL;
+  StkId base, fixed;
   if (actual < nfixargs) {
-    luaD_checkstack(L, nfixargs - actual);
     for (; actual < nfixargs; ++actual)
       setnilvalue(L->top++);
   }
-  actual -= nfixargs;  /* number of extra arguments */
-  htab = luaH_new(L, actual, 1);  /* create `arg' table */
-  for (i=0; i<actual; i++)  /* put extra arguments into `arg' table */
-    setobj2n(L, luaH_setnum(L, htab, i+LUA_FIRSTINDEX), L->top - actual + i);
-  /* store counter in field `n' */
-  setnvalue(luaH_setstr(L, htab, luaS_newliteral(L, "n")),
-                                 cast(lua_Number, actual));
-  L->top -= actual;  /* remove extra elements from the stack */
-  sethvalue(L, L->top, htab);
-  lua_assert(iswhite(obj2gco(htab)));
-  incr_top(L);
+  if (style != NEWSTYLEVARARG) {  /* compatibility with old-style vararg */
+    int nvar = actual - nfixargs;  /* number of extra arguments */
+    htab = luaH_new(L, nvar, 1);  /* create `arg' table */
+    for (i=0; i<nvar; i++)  /* put extra arguments into `arg' table */
+      setobj2n(L, luaH_setnum(L, htab, i+LUA_FIRSTINDEX), L->top - nvar + i);
+    /* store counter in field `n' */
+    setnvalue(luaH_setstr(L, htab, luaS_newliteral(L, "n")),
+                                   cast(lua_Number, nvar));
+  }
+  /* move fixed parameters to final position */
+  fixed = L->top - actual;  /* first fixed argument */
+  base = L->top;  /* final position of first argument */
+  for (i=0; i<nfixargs; i++) {
+    setobjs2s(L, L->top++, fixed+i);
+    setnilvalue(fixed+i);
+  }
+  /* add `arg' parameter */
+  if (htab) {
+    sethvalue(L, L->top++, htab);
+    lua_assert(iswhite(obj2gco(htab)));
+  }
+  return base;
 }
 
 
@@ -221,21 +233,28 @@ static StkId tryfuncTM (lua_State *L, StkId func) {
 
 int luaD_precall (lua_State *L, StkId func, int nresults) {
   LClosure *cl;
-  ptrdiff_t funcr = savestack(L, func);
+  ptrdiff_t funcr;
   if (!ttisfunction(func)) /* `func' is not a function? */
     func = tryfuncTM(L, func);  /* check the `function' tag method */
+  funcr = savestack(L, func);
   if (L->ci + 1 == L->end_ci) luaD_growCI(L);
   else condhardstacktests(luaD_reallocCI(L, L->size_ci));
   cl = &clvalue(func)->l;
   if (!cl->isC) {  /* Lua function? prepare its call */
     CallInfo *ci;
-    StkId st;
+    StkId st, base;
     Proto *p = cl->p;
-    if (p->is_vararg)  /* varargs? */
-      adjust_varargs(L, p->numparams, func+1);
     luaD_checkstack(L, p->maxstacksize);
+    func = restorestack(L, funcr);
+    if (p->is_vararg) {  /* varargs? */
+      int nargs = L->top - func - 1;
+      base = adjust_varargs(L, p->numparams, nargs, p->is_vararg);
+    }
+    else
+      base = func + 1;
     ci = ++L->ci;  /* now `enter' new function */
-    L->base = L->ci->base = restorestack(L, funcr) + 1;
+    ci->func = func;
+    L->base = ci->base = base;
     ci->top = L->base + p->maxstacksize;
     ci->u.l.savedpc = p->code;  /* starting point */
     ci->u.l.tailcalls = 0;
@@ -250,7 +269,8 @@ int luaD_precall (lua_State *L, StkId func, int nresults) {
     int n;
     luaD_checkstack(L, LUA_MINSTACK);  /* ensure minimum stack size */
     ci = ++L->ci;  /* now `enter' new function */
-    L->base = L->ci->base = restorestack(L, funcr) + 1;
+    ci->func = restorestack(L, funcr);
+    L->base = ci->base = ci->func + 1;
     ci->top = L->top + LUA_MINSTACK;
     if (L->hookmask & LUA_MASKCALL)
       luaD_callhook(L, LUA_HOOKCALL, -1);
@@ -284,7 +304,7 @@ void luaD_poscall (lua_State *L, int wanted, StkId firstResult) {
   StkId res;
   if (L->hookmask & LUA_MASKRET)
     firstResult = callrethooks(L, firstResult);
-  res = L->base - 1;  /* res == final position of 1st result */
+  res = L->ci->func;  /* res == final position of 1st result */
   L->ci--;
   L->base = L->ci->base;  /* restore base */
   /* move results to correct place */

+ 5 - 1
lobject.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lobject.h,v 2.3 2004/02/20 16:01:05 roberto Exp roberto $
+** $Id: lobject.h,v 2.4 2004/03/15 21:04:33 roberto Exp roberto $
 ** Type definitions for Lua objects
 ** See Copyright Notice in lua.h
 */
@@ -249,6 +249,10 @@ typedef struct Proto {
 } Proto;
 
 
+/* mask for new-style vararg */
+#define NEWSTYLEVARARG		2
+
+
 typedef struct LocVar {
   TString *varname;
   int startpc;  /* first point where variable is active */

+ 4 - 2
lopcodes.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lopcodes.c,v 1.25 2003/05/14 21:09:53 roberto Exp roberto $
+** $Id: lopcodes.c,v 1.26 2004/04/30 20:13:38 roberto Exp roberto $
 ** See Copyright Notice in lua.h
 */
 
@@ -53,7 +53,8 @@ const char *const luaP_opnames[NUM_OPCODES] = {
   "SETLIST",
   "SETLISTO",
   "CLOSE",
-  "CLOSURE"
+  "CLOSURE",
+  "VARARG"
 };
 
 #endif
@@ -98,5 +99,6 @@ const lu_byte luaP_opmodes[NUM_OPCODES] = {
  ,opmode(0, 0, OpArgU, OpArgN, iABx)		/* OP_SETLISTO */
  ,opmode(0, 0, OpArgN, OpArgN, iABC)		/* OP_CLOSE */
  ,opmode(0, 1, OpArgU, OpArgN, iABx)		/* OP_CLOSURE */
+ ,opmode(0, 1, OpArgU, OpArgN, iABC)		/* OP_VARARG */
 };
 

+ 13 - 8
lopcodes.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lopcodes.h,v 1.107 2004/04/30 20:13:38 roberto Exp roberto $
+** $Id: lopcodes.h,v 1.108 2004/05/17 12:34:00 roberto Exp roberto $
 ** Opcodes for Lua virtual machine
 ** See Copyright Notice in lua.h
 */
@@ -79,7 +79,7 @@ enum OpMode {iABC, iABx, iAsBx};  /* basic instruction format */
 #define GET_OPCODE(i)	(cast(OpCode, (i)&MASK1(SIZE_OP,0)))
 #define SET_OPCODE(i,o)	((i) = (((i)&MASK0(SIZE_OP,0)) | cast(Instruction, o)))
 
-#define GETARG_A(i)	(cast(int, (i)>>POS_A) & MASK1(SIZE_A,0))
+#define GETARG_A(i)	(cast(int, ((i)>>POS_A) & MASK1(SIZE_A,0)))
 #define SETARG_A(i,u)	((i) = (((i)&MASK0(SIZE_A,POS_A)) | \
 		((cast(Instruction, u)<<POS_A)&MASK1(SIZE_A,POS_A))))
 
@@ -183,25 +183,30 @@ OP_SETLIST,/*	A Bx	R(A)[Bx-Bx%FPF+i] := R(A+i), 1 <= i <= Bx%FPF+1	*/
 OP_SETLISTO,/*	A Bx							*/
 
 OP_CLOSE,/*	A 	close all variables in the stack up to (>=) R(A)*/
-OP_CLOSURE/*	A Bx	R(A) := closure(KPROTO[Bx], R(A), ... ,R(A+n))	*/
+OP_CLOSURE,/*	A Bx	R(A) := closure(KPROTO[Bx], R(A), ... ,R(A+n))	*/
+
+OP_VARARG/*	A B	R(A), R(A+1), ..., R(A+B-1) = vararg		*/
 } OpCode;
 
 
-#define NUM_OPCODES	(cast(int, OP_CLOSURE+1))
+#define NUM_OPCODES	(cast(int, OP_VARARG+1))
 
 
 
 /*===========================================================================
   Notes:
-  (1) In OP_CALL, if (B == 0) then B = top. C is the number of returns - 1,
+  (*) In OP_CALL, if (B == 0) then B = top. C is the number of returns - 1,
       and can be 0: OP_CALL then sets `top' to last_result+1, so
       next open instruction (OP_CALL, OP_RETURN, OP_SETLIST) may use `top'.
 
-  (2) In OP_RETURN, if (B == 0) then return up to `top'
+  (*) In OP_VARARG, if (B == 0) then use actual number of varargs and
+      set top (like in OP_CALL).
+
+  (*) In OP_RETURN, if (B == 0) then return up to `top'
 
-  (3) For comparisons, B specifies what conditions the test should accept.
+  (*) For comparisons, B specifies what conditions the test should accept.
 
-  (4) All `skips' (pc++) assume that next instruction is a jump
+  (*) All `skips' (pc++) assume that next instruction is a jump
 ===========================================================================*/
 
 

+ 31 - 29
lparser.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lparser.c,v 2.3 2004/03/26 14:02:41 roberto Exp roberto $
+** $Id: lparser.c,v 2.4 2004/04/30 20:13:38 roberto Exp roberto $
 ** Lua Parser
 ** See Copyright Notice in lua.h
 */
@@ -27,6 +27,8 @@
 
 
 
+#define hasmultret(k)		((k) == VCALL || (k) == VVARARG)
+
 #define getlocvar(fs, i)	((fs)->f->locvars[(fs)->actvar[i]])
 
 #define luaY_checklimit(fs,v,l,m)	if ((v)>(l)) luaY_errorlimit(fs,l,m)
@@ -272,11 +274,11 @@ static TString *singlevar (LexState *ls, expdesc *var, int base) {
 static void adjust_assign (LexState *ls, int nvars, int nexps, expdesc *e) {
   FuncState *fs = ls->fs;
   int extra = nvars - nexps;
-  if (e->k == VCALL) {
+  if (hasmultret(e->k)) {
     extra++;  /* includes call itself */
-    if (extra <= 0) extra = 0;
-    else luaK_reserveregs(fs, extra-1);
-    luaK_setcallreturns(fs, e, extra);  /* call provides the difference */
+    if (extra < 0) extra = 0;
+    luaK_setreturns(fs, e, extra);  /* last exp. provides the difference */
+    if (extra > 1) luaK_reserveregs(fs, extra-1);
   }
   else {
     if (e->k != VVOID) luaK_exp2nextreg(fs, e);  /* close last expression */
@@ -392,6 +394,7 @@ Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, const char *name) {
   lexstate.nestlevel = 0;
   luaX_setinput(L, &lexstate, z, luaS_new(L, name));
   open_func(&lexstate, &funcstate);
+  funcstate.f->is_vararg = NEWSTYLEVARARG;
   next(&lexstate);  /* read first token */
   chunk(&lexstate);
   check_condition(&lexstate, (lexstate.t.token == TK_EOS), "<eof> expected");
@@ -481,8 +484,8 @@ static void closelistfield (FuncState *fs, struct ConsControl *cc) {
 
 static void lastlistfield (FuncState *fs, struct ConsControl *cc) {
   if (cc->tostore == 0) return;
-  if (cc->v.k == VCALL) {
-    luaK_setcallreturns(fs, &cc->v, LUA_MULTRET);
+  if (hasmultret(cc->v.k)) {
+    luaK_setmultret(fs, &cc->v);
     luaK_codeABx(fs, OP_SETLISTO, cc->t->info, cc->na-1);
     cc->na--;  /* do not count last expression (unknown number of elements) */
   }
@@ -558,12 +561,8 @@ static void parlist (LexState *ls) {
   if (ls->t.token != ')') {  /* is `parlist' not empty? */
     do {
       switch (ls->t.token) {
-        case TK_NAME: {  /* param -> NAME [ `=' `...' ] */
+        case TK_NAME: {  /* param -> NAME */
           new_localvar(ls, str_checkname(ls), nparams++);
-          if (testnext(ls, '=')) {
-            check(ls, TK_DOTS);
-            f->is_vararg = 1;
-          }
           break;
         }
         case TK_DOTS: {  /* param -> `...' */
@@ -629,7 +628,7 @@ static void funcargs (LexState *ls, expdesc *f) {
         args.k = VVOID;
       else {
         explist1(ls, &args);
-        luaK_setcallreturns(fs, &args, LUA_MULTRET);
+        luaK_setmultret(fs, &args);
       }
       check_match(ls, ')', '(', line);
       break;
@@ -650,7 +649,7 @@ static void funcargs (LexState *ls, expdesc *f) {
   }
   lua_assert(f->k == VNONRELOC);
   base = f->info;  /* base register for call */
-  if (args.k == VCALL)
+  if (hasmultret(args.k))
     nparams = LUA_MULTRET;  /* open call */
   else {
     if (args.k != VVOID)
@@ -739,43 +738,47 @@ static void simpleexp (LexState *ls, expdesc *v) {
   switch (ls->t.token) {
     case TK_NUMBER: {
       init_exp(v, VK, luaK_numberK(ls->fs, ls->t.seminfo.r));
-      next(ls);  /* must use `seminfo' before `next' */
       break;
     }
     case TK_STRING: {
       codestring(ls, v, ls->t.seminfo.ts);
-      next(ls);  /* must use `seminfo' before `next' */
       break;
     }
     case TK_NIL: {
       init_exp(v, VNIL, 0);
-      next(ls);
       break;
     }
     case TK_TRUE: {
       init_exp(v, VTRUE, 0);
-      next(ls);
       break;
     }
     case TK_FALSE: {
       init_exp(v, VFALSE, 0);
-      next(ls);
+      break;
+    }
+    case TK_DOTS: {  /* vararg */
+      FuncState *fs = ls->fs;
+      check_condition(ls, fs->f->is_vararg,
+                      "cannot use `...' outside a vararg function");
+      fs->f->is_vararg = NEWSTYLEVARARG;
+      init_exp(v, VVARARG, luaK_codeABC(fs, OP_VARARG, 0, 1, 0));
       break;
     }
     case '{': {  /* constructor */
       constructor(ls, v);
-      break;
+      return;
     }
     case TK_FUNCTION: {
       next(ls);
       body(ls, v, 0, ls->linenumber);
-      break;
+      return;
     }
     default: {
       primaryexp(ls, v);
-      break;
+      return;
     }
   }
+  next(ls);
 }
 
 
@@ -952,7 +955,7 @@ static void assignment (LexState *ls, struct LHS_assign *lh, int nvars) {
         ls->fs->freereg -= nexps - nvars;  /* remove extra values */
     }
     else {
-      luaK_setcallreturns(ls->fs, &e, 1);  /* close last expression */
+      luaK_setoneret(ls->fs, &e);  /* close last expression */
       luaK_storevar(ls->fs, &lh->v, &e);
       return;  /* avoid default */
     }
@@ -1236,9 +1239,8 @@ static void exprstat (LexState *ls) {
   FuncState *fs = ls->fs;
   struct LHS_assign v;
   primaryexp(ls, &v.v);
-  if (v.v.k == VCALL) {  /* stat -> func */
-    luaK_setcallreturns(fs, &v.v, 0);  /* call statement uses no results */
-  }
+  if (v.v.k == VCALL)  /* stat -> func */
+    SETARG_C(getcode(fs, &v.v), 1);  /* call statement uses no results */
   else {  /* stat -> assignment */
     v.prev = NULL;
     assignment(ls, &v, 1);
@@ -1256,9 +1258,9 @@ static void retstat (LexState *ls) {
     first = nret = 0;  /* return no values */
   else {
     nret = explist1(ls, &e);  /* optional return values */
-    if (e.k == VCALL) {
-      luaK_setcallreturns(fs, &e, LUA_MULTRET);
-      if (nret == 1) {  /* tail call? */
+    if (hasmultret(e.k)) {
+      luaK_setmultret(fs, &e);
+      if (e.k == VCALL && nret == 1) {  /* tail call? */
         SET_OPCODE(getcode(fs,&e), OP_TAILCALL);
         lua_assert(GETARG_A(getcode(fs,&e)) == fs->nactvar);
       }

+ 3 - 2
lparser.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lparser.h,v 1.49 2003/07/09 20:11:30 roberto Exp roberto $
+** $Id: lparser.h,v 1.50 2003/08/25 19:51:54 roberto Exp roberto $
 ** Lua Parser
 ** See Copyright Notice in lua.h
 */
@@ -30,7 +30,8 @@ typedef enum {
   VJMP,		/* info = instruction pc */
   VRELOCABLE,	/* info = instruction pc */
   VNONRELOC,	/* info = result register */
-  VCALL		/* info = result register */
+  VCALL,	/* info = instruction pc */
+  VVARARG	/* info = instruction pc */
 } expkind;
 
 typedef struct expdesc {

+ 2 - 1
lstate.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lstate.c,v 2.5 2004/03/23 12:57:12 roberto Exp roberto $
+** $Id: lstate.c,v 2.6 2004/04/30 20:13:38 roberto Exp roberto $
 ** Global State
 ** See Copyright Notice in lua.h
 */
@@ -57,6 +57,7 @@ static void stack_init (lua_State *L1, lua_State *L) {
   L1->stack_last = L1->stack+(L1->stacksize - EXTRA_STACK)-1;
   L1->base_ci = luaM_newvector(L, BASIC_CI_SIZE, CallInfo);
   L1->ci = L1->base_ci;
+  L1->ci->func = L1->top;
   setnilvalue(L1->top++);  /* `function' entry for this `ci' */
   L1->base = L1->ci->base = L1->top;
   L1->ci->top = L1->top + LUA_MINSTACK;

+ 5 - 4
lstate.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lstate.h,v 2.2 2004/03/23 17:02:58 roberto Exp roberto $
+** $Id: lstate.h,v 2.3 2004/05/14 19:25:09 roberto Exp roberto $
 ** Global State
 ** See Copyright Notice in lua.h
 */
@@ -71,6 +71,7 @@ typedef struct stringtable {
 */
 typedef struct CallInfo {
   StkId base;  /* base for this function */
+  StkId func;  /* function index in the stack */
   StkId	top;  /* top for this function */
   int nresults;  /* expected number of results from this function */
   union {
@@ -86,10 +87,10 @@ typedef struct CallInfo {
 
 
 
-#define curr_func(L)	(clvalue(L->base - 1))
-#define ci_func(ci)	(clvalue((ci)->base - 1))
+#define curr_func(L)	(clvalue(L->ci->func))
+#define ci_func(ci)	(clvalue((ci)->func))
 #define f_isLua(ci)	(!ci_func(ci)->c.isC)
-#define isLua(ci)	(ttisfunction((ci)->base - 1) && f_isLua(ci))
+#define isLua(ci)	(ttisfunction((ci)->func) && f_isLua(ci))
 
 
 /*

+ 23 - 14
lua.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lua.c,v 1.124 2003/10/23 18:06:22 roberto Exp roberto $
+** $Id: lua.c,v 1.125 2004/04/30 20:13:38 roberto Exp roberto $
 ** Lua stand-alone interpreter
 ** See Copyright Notice in lua.h
 */
@@ -113,30 +113,32 @@ static void print_version (void) {
 }
 
 
-static void getargs (char *argv[], int n) {
-  int i;
+static int getargs (char *argv[], int n) {
+  int i, narg;
+  for (i=n+1; argv[i]; i++) {
+    luaL_checkstack(L, 1, "too many arguments to script");
+    lua_pushstring(L, argv[i]);
+  }
+  narg = i-(n+1);  /* number of arguments to the script (not to `lua.c') */
   lua_newtable(L);
   for (i=0; argv[i]; i++) {
     lua_pushnumber(L, i - n);
     lua_pushstring(L, argv[i]);
     lua_rawset(L, -3);
   }
-}
-
-
-static int docall (int status) {
-  if (status == 0) status = lcall(0, 1);
-  return report(status);
+  return narg;
 }
 
 
 static int file_input (const char *name) {
-  return docall(luaL_loadfile(L, name));
+  int status = luaL_loadfile(L, name) || lcall(0, 1);
+  return report(status);
 }
 
 
 static int dostring (const char *s, const char *name) {
-  return docall(luaL_loadbuffer(L, s, strlen(s), name));
+  int status = luaL_loadbuffer(L, s, strlen(s), name) || lcall(0, 1);
+  return report(status);
 }
 
 
@@ -329,10 +331,17 @@ static int handle_argv (char *argv[], int *interactive) {
     } endloop:
     if (argv[i] != NULL) {
       const char *filename = argv[i];
-      getargs(argv, i);  /* collect arguments */
-      clearinteractive(interactive);
+      int narg = getargs(argv, i);  /* collect arguments */
+      int status;
       lua_setglobal(L, "arg");
-      return file_input(filename);  /* stop scanning arguments */
+      clearinteractive(interactive);
+      status = luaL_loadfile(L, filename);
+      lua_insert(L, -(narg+1));
+      if (status == 0)
+        status = lcall(narg, 0);
+      else
+        lua_pop(L, narg);      
+      return report(status);
     }
   }
   return 0;

+ 27 - 10
lvm.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lvm.c,v 2.5 2004/05/10 17:50:51 roberto Exp roberto $
+** $Id: lvm.c,v 2.6 2004/05/14 19:25:09 roberto Exp $
 ** Lua virtual machine
 ** See Copyright Notice in lua.h
 */
@@ -387,8 +387,8 @@ StkId luaV_execute (lua_State *L, int nexeccalls) {
     luaD_callhook(L, LUA_HOOKCALL, -1);
  retentry:  /* entry point when returning to old functions */
   pc = L->ci->u.l.savedpc;
+  cl = &clvalue(L->ci->func)->l;
   base = L->base;
-  cl = &clvalue(base - 1)->l;
   k = cl->p->k;
   /* main loop of interpreter */
   for (;;) {
@@ -615,17 +615,19 @@ StkId luaV_execute (lua_State *L, int nexeccalls) {
         pcr = luaD_precall(L, ra, LUA_MULTRET);
         if (pcr == PCRLUA) {
           /* tail call: put new frame in place of previous one */
+          CallInfo *ci = L->ci - 1;  /* previous frame */
           int aux;
-          base = (L->ci - 1)->base;  /* `luaD_precall' may change the stack */
-          ra = RA(i);
+          StkId func = ci->func;
+          StkId pfunc = (ci+1)->func;  /* previous function index */
+          base = ci->base = ci->func + ((ci+1)->base - pfunc);
+          L->base = base;
           if (L->openupval) luaF_close(L, base);
-          for (aux = 0; ra+aux < L->top; aux++)  /* move frame down */
-            setobjs2s(L, base+aux-1, ra+aux);
-          (L->ci - 1)->top = L->top = base+aux;  /* correct top */
-          (L->ci - 1)->u.l.savedpc = L->ci->u.l.savedpc;
-          (L->ci - 1)->u.l.tailcalls++;  /* one more call lost */
+          for (aux = 0; pfunc+aux < L->top; aux++)  /* move frame down */
+            setobjs2s(L, func+aux, pfunc+aux);
+          ci->top = L->top = base+aux;  /* correct top */
+          ci->u.l.savedpc = L->ci->u.l.savedpc;
+          ci->u.l.tailcalls++;  /* one more call lost */
           L->ci--;  /* remove new frame */
-          L->base = L->ci->base;
           goto callentry;
         }
         else if (pcr == PCRC) {
@@ -758,6 +760,21 @@ StkId luaV_execute (lua_State *L, int nexeccalls) {
         base = L->base;
         break;
       }
+      case OP_VARARG: {
+        int b = GETARG_B(i) - 1;
+        int j;
+        CallInfo *ci = L->ci;
+        int n = ci->base - ci->func - cl->p->numparams - 1;
+        if (b == LUA_MULTRET) {
+          b = n;
+          L->top = ra + n;
+        }
+        for (j=0; j<b && j<n; j++)
+          setobjs2s(L, ra+j, ci->base - n + j);
+        for (; j<b; j++)
+          setnilvalue(ra+j);
+        break;
+      }
     }
   }
 }