From 616438fe9ab5e3ae7d73e9ad838e9b7bdea1ea59 Mon Sep 17 00:00:00 2001 From: Roberto Ierusalimschy Date: Mon, 31 May 2004 15:51:50 -0300 Subject: new way to use `vararg' parameters (with `...') --- lcode.c | 28 +++++++++++++++++++------- lcode.h | 7 +++++-- ldebug.c | 13 ++++++++++--- ldo.c | 66 ++++++++++++++++++++++++++++++++++++++++---------------------- lobject.h | 6 +++++- lopcodes.c | 6 ++++-- lopcodes.h | 21 ++++++++++++-------- lparser.c | 60 +++++++++++++++++++++++++++++--------------------------- lparser.h | 5 +++-- lstate.c | 3 ++- lstate.h | 9 +++++---- lua.c | 37 ++++++++++++++++++++++------------- lvm.c | 37 +++++++++++++++++++++++++---------- 13 files changed, 192 insertions(+), 106 deletions(-) diff --git a/lcode.c b/lcode.c index e9bcb5f1..8ea811d8 100644 --- a/lcode.c +++ b/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) */ diff --git a/lcode.h b/lcode.h index 8a0eece9..65dea30e 100644 --- a/lcode.h +++ b/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); diff --git a/ldebug.c b/ldebug.c index 3a1509f0..044eb57f 100644 --- a/ldebug.c +++ b/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; } } diff --git a/ldo.c b/ldo.c index fc1caa7f..293e66a3 100644 --- a/ldo.c +++ b/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; itop - 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; itop - 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; itop++, 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 */ diff --git a/lobject.h b/lobject.h index ee23f3db..ada627fd 100644 --- a/lobject.h +++ b/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 */ diff --git a/lopcodes.c b/lopcodes.c index d84f402e..d0a3dcf1 100644 --- a/lopcodes.c +++ b/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 */ }; diff --git a/lopcodes.h b/lopcodes.h index be5bde30..8fdaf6b1 100644 --- a/lopcodes.h +++ b/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)<=) 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 ===========================================================================*/ diff --git a/lparser.c b/lparser.c index d9f6cbd4..06fd8951 100644 --- a/lparser.c +++ b/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), " 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); } diff --git a/lparser.h b/lparser.h index 42d46783..f4398ccc 100644 --- a/lparser.h +++ b/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 { diff --git a/lstate.c b/lstate.c index 4ee1c743..890d1d77 100644 --- a/lstate.c +++ b/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; diff --git a/lstate.h b/lstate.h index 3a1eb329..0ac69529 100644 --- a/lstate.h +++ b/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)) /* diff --git a/lua.c b/lua.c index 05ffc88e..cabc5592 100644 --- a/lua.c +++ b/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; diff --git a/lvm.c b/lvm.c index 4c5a7ec7..5363ebef 100644 --- a/lvm.c +++ b/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; jbase - n + j); + for (; j