diff options
| -rw-r--r-- | lobject.h | 6 | ||||
| -rw-r--r-- | lopcodes.h | 2 | ||||
| -rw-r--r-- | lparser.c | 29 | ||||
| -rw-r--r-- | lparser.h | 9 | ||||
| -rw-r--r-- | ltm.c | 45 | ||||
| -rw-r--r-- | ltm.h | 4 | ||||
| -rw-r--r-- | lundump.c | 3 | ||||
| -rw-r--r-- | lvm.c | 2 | ||||
| -rw-r--r-- | testes/vararg.lua | 11 |
9 files changed, 80 insertions, 31 deletions
| @@ -583,8 +583,10 @@ typedef struct AbsLineInfo { | |||
| 583 | /* | 583 | /* |
| 584 | ** Flags in Prototypes | 584 | ** Flags in Prototypes |
| 585 | */ | 585 | */ |
| 586 | #define PF_ISVARARG 1 | 586 | #define PF_ISVARARG 1 /* function is vararg */ |
| 587 | #define PF_FIXED 2 /* prototype has parts in fixed memory */ | 587 | #define PF_VATAB 2 /* function is vararg with table */ |
| 588 | #define PF_VAPTAB 4 /* function is vararg with pseudo-table */ | ||
| 589 | #define PF_FIXED 8 /* prototype has parts in fixed memory */ | ||
| 588 | 590 | ||
| 589 | 591 | ||
| 590 | /* | 592 | /* |
| @@ -338,7 +338,7 @@ OP_CLOSURE,/* A Bx R[A] := closure(KPROTO[Bx]) */ | |||
| 338 | 338 | ||
| 339 | OP_VARARG,/* A C R[A], R[A+1], ..., R[A+C-2] = vararg */ | 339 | OP_VARARG,/* A C R[A], R[A+1], ..., R[A+C-2] = vararg */ |
| 340 | 340 | ||
| 341 | OP_VARARGPREP,/*A (adjust vararg parameters) */ | 341 | OP_VARARGPREP,/* (adjust vararg parameters) */ |
| 342 | 342 | ||
| 343 | OP_EXTRAARG/* Ax extra (larger) argument for previous opcode */ | 343 | OP_EXTRAARG/* Ax extra (larger) argument for previous opcode */ |
| 344 | } OpCode; | 344 | } OpCode; |
| @@ -1041,9 +1041,10 @@ static void constructor (LexState *ls, expdesc *t) { | |||
| 1041 | /* }====================================================================== */ | 1041 | /* }====================================================================== */ |
| 1042 | 1042 | ||
| 1043 | 1043 | ||
| 1044 | static void setvararg (FuncState *fs, int nparams) { | 1044 | static void setvararg (FuncState *fs, int kind) { |
| 1045 | fs->f->flag |= PF_ISVARARG; | 1045 | lua_assert(kind & PF_ISVARARG); |
| 1046 | luaK_codeABC(fs, OP_VARARGPREP, nparams, 0, 0); | 1046 | fs->f->flag |= cast_byte(kind); |
| 1047 | luaK_codeABC(fs, OP_VARARGPREP, 0, 0, 0); | ||
| 1047 | } | 1048 | } |
| 1048 | 1049 | ||
| 1049 | 1050 | ||
| @@ -1052,7 +1053,7 @@ static void parlist (LexState *ls) { | |||
| 1052 | FuncState *fs = ls->fs; | 1053 | FuncState *fs = ls->fs; |
| 1053 | Proto *f = fs->f; | 1054 | Proto *f = fs->f; |
| 1054 | int nparams = 0; | 1055 | int nparams = 0; |
| 1055 | int isvararg = 0; | 1056 | int varargk = 0; |
| 1056 | if (ls->t.token != ')') { /* is 'parlist' not empty? */ | 1057 | if (ls->t.token != ')') { /* is 'parlist' not empty? */ |
| 1057 | do { | 1058 | do { |
| 1058 | switch (ls->t.token) { | 1059 | switch (ls->t.token) { |
| @@ -1062,19 +1063,27 @@ static void parlist (LexState *ls) { | |||
| 1062 | break; | 1063 | break; |
| 1063 | } | 1064 | } |
| 1064 | case TK_DOTS: { | 1065 | case TK_DOTS: { |
| 1066 | varargk |= PF_ISVARARG; | ||
| 1065 | luaX_next(ls); | 1067 | luaX_next(ls); |
| 1066 | isvararg = 1; | 1068 | if (testnext(ls, '=')) { |
| 1069 | new_varkind(ls, str_checkname(ls), RDKVATAB); | ||
| 1070 | varargk |= PF_VATAB; | ||
| 1071 | } | ||
| 1067 | break; | 1072 | break; |
| 1068 | } | 1073 | } |
| 1069 | default: luaX_syntaxerror(ls, "<name> or '...' expected"); | 1074 | default: luaX_syntaxerror(ls, "<name> or '...' expected"); |
| 1070 | } | 1075 | } |
| 1071 | } while (!isvararg && testnext(ls, ',')); | 1076 | } while (!varargk && testnext(ls, ',')); |
| 1072 | } | 1077 | } |
| 1073 | adjustlocalvars(ls, nparams); | 1078 | adjustlocalvars(ls, nparams); |
| 1074 | f->numparams = cast_byte(fs->nactvar); | 1079 | f->numparams = cast_byte(fs->nactvar); |
| 1075 | if (isvararg) | 1080 | if (varargk != 0) { |
| 1076 | setvararg(fs, f->numparams); /* declared vararg */ | 1081 | setvararg(fs, varargk); /* declared vararg */ |
| 1077 | luaK_reserveregs(fs, fs->nactvar); /* reserve registers for parameters */ | 1082 | if (varargk & PF_VATAB) |
| 1083 | adjustlocalvars(ls, 1); /* vararg table */ | ||
| 1084 | } | ||
| 1085 | /* reserve registers for parameters (and vararg variable, if present) */ | ||
| 1086 | luaK_reserveregs(fs, fs->nactvar); | ||
| 1078 | } | 1087 | } |
| 1079 | 1088 | ||
| 1080 | 1089 | ||
| @@ -2099,7 +2108,7 @@ static void mainfunc (LexState *ls, FuncState *fs) { | |||
| 2099 | BlockCnt bl; | 2108 | BlockCnt bl; |
| 2100 | Upvaldesc *env; | 2109 | Upvaldesc *env; |
| 2101 | open_func(ls, fs, &bl); | 2110 | open_func(ls, fs, &bl); |
| 2102 | setvararg(fs, 0); /* main function is always declared vararg */ | 2111 | setvararg(fs, PF_ISVARARG); /* main function is always vararg */ |
| 2103 | env = allocupvalue(fs); /* ...set environment upvalue */ | 2112 | env = allocupvalue(fs); /* ...set environment upvalue */ |
| 2104 | env->instack = 1; | 2113 | env->instack = 1; |
| 2105 | env->idx = 0; | 2114 | env->idx = 0; |
| @@ -97,10 +97,11 @@ typedef struct expdesc { | |||
| 97 | /* kinds of variables */ | 97 | /* kinds of variables */ |
| 98 | #define VDKREG 0 /* regular local */ | 98 | #define VDKREG 0 /* regular local */ |
| 99 | #define RDKCONST 1 /* local constant */ | 99 | #define RDKCONST 1 /* local constant */ |
| 100 | #define RDKTOCLOSE 2 /* to-be-closed */ | 100 | #define RDKVATAB 2 /* vararg table */ |
| 101 | #define RDKCTC 3 /* local compile-time constant */ | 101 | #define RDKTOCLOSE 3 /* to-be-closed */ |
| 102 | #define GDKREG 4 /* regular global */ | 102 | #define RDKCTC 4 /* local compile-time constant */ |
| 103 | #define GDKCONST 5 /* global constant */ | 103 | #define GDKREG 5 /* regular global */ |
| 104 | #define GDKCONST 6 /* global constant */ | ||
| 104 | 105 | ||
| 105 | /* variables that live in registers */ | 106 | /* variables that live in registers */ |
| 106 | #define varinreg(v) ((v)->vd.kind <= RDKTOCLOSE) | 107 | #define varinreg(v) ((v)->vd.kind <= RDKTOCLOSE) |
| @@ -224,11 +224,38 @@ int luaT_callorderiTM (lua_State *L, const TValue *p1, int v2, | |||
| 224 | } | 224 | } |
| 225 | 225 | ||
| 226 | 226 | ||
| 227 | void luaT_adjustvarargs (lua_State *L, int nfixparams, CallInfo *ci, | 227 | /* |
| 228 | const Proto *p) { | 228 | ** Create a vararg table at the top of the stack, with 'n' elements |
| 229 | ** starting at 'f'. | ||
| 230 | */ | ||
| 231 | static void createvarargtab (lua_State *L, StkId f, int n) { | ||
| 229 | int i; | 232 | int i; |
| 230 | int actual = cast_int(L->top.p - ci->func.p) - 1; /* number of arguments */ | 233 | TValue key, value; |
| 231 | int nextra = actual - nfixparams; /* number of extra arguments */ | 234 | Table *t = luaH_new(L); |
| 235 | sethvalue(L, s2v(L->top.p), t); | ||
| 236 | L->top.p++; | ||
| 237 | luaH_resize(L, t, cast_uint(n), 1); | ||
| 238 | setsvalue(L, &key, luaS_new(L, "n")); /* key is "n" */ | ||
| 239 | setivalue(&value, n); /* value is n */ | ||
| 240 | /* No need to anchor the key: Due to the resize, the next operation | ||
| 241 | cannot trigger a garbage collection */ | ||
| 242 | luaH_set(L, t, &key, &value); /* t.n = n */ | ||
| 243 | for (i = 0; i < n; i++) | ||
| 244 | luaH_setint(L, t, i + 1, s2v(f + i)); | ||
| 245 | } | ||
| 246 | |||
| 247 | |||
| 248 | /* | ||
| 249 | ** initial stack: func arg1 ... argn extra1 ... | ||
| 250 | ** ^ ci->func ^ L->top | ||
| 251 | ** final stack: func nil ... nil extra1 ... func arg1 ... argn | ||
| 252 | ** ^ ci->func ^ L->top | ||
| 253 | */ | ||
| 254 | void luaT_adjustvarargs (lua_State *L, CallInfo *ci, const Proto *p) { | ||
| 255 | int i; | ||
| 256 | int totalargs = cast_int(L->top.p - ci->func.p) - 1; | ||
| 257 | int nfixparams = p->numparams; | ||
| 258 | int nextra = totalargs - nfixparams; /* number of extra arguments */ | ||
| 232 | ci->u.l.nextraargs = nextra; | 259 | ci->u.l.nextraargs = nextra; |
| 233 | luaD_checkstack(L, p->maxstacksize + 1); | 260 | luaD_checkstack(L, p->maxstacksize + 1); |
| 234 | /* copy function to the top of the stack */ | 261 | /* copy function to the top of the stack */ |
| @@ -238,8 +265,14 @@ void luaT_adjustvarargs (lua_State *L, int nfixparams, CallInfo *ci, | |||
| 238 | setobjs2s(L, L->top.p++, ci->func.p + i); | 265 | setobjs2s(L, L->top.p++, ci->func.p + i); |
| 239 | setnilvalue(s2v(ci->func.p + i)); /* erase original parameter (for GC) */ | 266 | setnilvalue(s2v(ci->func.p + i)); /* erase original parameter (for GC) */ |
| 240 | } | 267 | } |
| 241 | ci->func.p += actual + 1; | 268 | if (p->flag & (PF_VAPTAB | PF_VATAB)) { /* is there a vararg table? */ |
| 242 | ci->top.p += actual + 1; | 269 | if (p->flag & PF_VAPTAB) /* is vararg table fake? */ |
| 270 | setnilvalue(s2v(L->top.p)); /* initialize it */ | ||
| 271 | else | ||
| 272 | createvarargtab(L, ci->func.p + nfixparams + 1, nextra); | ||
| 273 | } | ||
| 274 | ci->func.p += totalargs + 1; | ||
| 275 | ci->top.p += totalargs + 1; | ||
| 243 | lua_assert(L->top.p <= ci->top.p && ci->top.p <= L->stack_last.p); | 276 | lua_assert(L->top.p <= ci->top.p && ci->top.p <= L->stack_last.p); |
| 244 | } | 277 | } |
| 245 | 278 | ||
| @@ -95,8 +95,8 @@ LUAI_FUNC int luaT_callorderTM (lua_State *L, const TValue *p1, | |||
| 95 | LUAI_FUNC int luaT_callorderiTM (lua_State *L, const TValue *p1, int v2, | 95 | LUAI_FUNC int luaT_callorderiTM (lua_State *L, const TValue *p1, int v2, |
| 96 | int inv, int isfloat, TMS event); | 96 | int inv, int isfloat, TMS event); |
| 97 | 97 | ||
| 98 | LUAI_FUNC void luaT_adjustvarargs (lua_State *L, int nfixparams, | 98 | LUAI_FUNC void luaT_adjustvarargs (lua_State *L, struct CallInfo *ci, |
| 99 | struct CallInfo *ci, const Proto *p); | 99 | const Proto *p); |
| 100 | LUAI_FUNC void luaT_getvarargs (lua_State *L, struct CallInfo *ci, | 100 | LUAI_FUNC void luaT_getvarargs (lua_State *L, struct CallInfo *ci, |
| 101 | StkId where, int wanted); | 101 | StkId where, int wanted); |
| 102 | 102 | ||
| @@ -327,7 +327,8 @@ static void loadFunction (LoadState *S, Proto *f) { | |||
| 327 | f->linedefined = loadInt(S); | 327 | f->linedefined = loadInt(S); |
| 328 | f->lastlinedefined = loadInt(S); | 328 | f->lastlinedefined = loadInt(S); |
| 329 | f->numparams = loadByte(S); | 329 | f->numparams = loadByte(S); |
| 330 | f->flag = loadByte(S) & PF_ISVARARG; /* get only the meaningful flags */ | 330 | /* get only the meaningful flags */ |
| 331 | f->flag = cast_byte(loadByte(S) & ~PF_FIXED); | ||
| 331 | if (S->fixed) | 332 | if (S->fixed) |
| 332 | f->flag |= PF_FIXED; /* signal that code is fixed */ | 333 | f->flag |= PF_FIXED; /* signal that code is fixed */ |
| 333 | f->maxstacksize = loadByte(S); | 334 | f->maxstacksize = loadByte(S); |
| @@ -1927,7 +1927,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) { | |||
| 1927 | vmbreak; | 1927 | vmbreak; |
| 1928 | } | 1928 | } |
| 1929 | vmcase(OP_VARARGPREP) { | 1929 | vmcase(OP_VARARGPREP) { |
| 1930 | ProtectNT(luaT_adjustvarargs(L, GETARG_A(i), ci, cl->p)); | 1930 | ProtectNT(luaT_adjustvarargs(L, ci, cl->p)); |
| 1931 | if (l_unlikely(trap)) { /* previous "Protect" updated trap */ | 1931 | if (l_unlikely(trap)) { /* previous "Protect" updated trap */ |
| 1932 | luaD_hookcall(L, ci); | 1932 | luaD_hookcall(L, ci); |
| 1933 | L->oldpc = 1; /* next opcode will be seen as a "new" line */ | 1933 | L->oldpc = 1; /* next opcode will be seen as a "new" line */ |
diff --git a/testes/vararg.lua b/testes/vararg.lua index 10553de2..4320684e 100644 --- a/testes/vararg.lua +++ b/testes/vararg.lua | |||
| @@ -3,9 +3,12 @@ | |||
| 3 | 3 | ||
| 4 | print('testing vararg') | 4 | print('testing vararg') |
| 5 | 5 | ||
| 6 | local function f (a, ...) | 6 | local function f (a, ...=t) |
| 7 | local x = {n = select('#', ...), ...} | 7 | local x = {n = select('#', ...), ...} |
| 8 | for i = 1, x.n do assert(a[i] == x[i]) end | 8 | assert(x.n == t.n) |
| 9 | for i = 1, x.n do | ||
| 10 | assert(a[i] == x[i] and x[i] == t[i]) | ||
| 11 | end | ||
| 9 | return x.n | 12 | return x.n |
| 10 | end | 13 | end |
| 11 | 14 | ||
| @@ -17,7 +20,7 @@ local function c12 (...) | |||
| 17 | return res, 2 | 20 | return res, 2 |
| 18 | end | 21 | end |
| 19 | 22 | ||
| 20 | local function vararg (...) return {n = select('#', ...), ...} end | 23 | local function vararg (...=t) return t end |
| 21 | 24 | ||
| 22 | local call = function (f, args) return f(table.unpack(args, 1, args.n)) end | 25 | local call = function (f, args) return f(table.unpack(args, 1, args.n)) end |
| 23 | 26 | ||
| @@ -99,7 +102,7 @@ assert(a==nil and b==nil and c==nil and d==nil and e==nil) | |||
| 99 | 102 | ||
| 100 | 103 | ||
| 101 | -- varargs for main chunks | 104 | -- varargs for main chunks |
| 102 | local f = load[[ return {...} ]] | 105 | local f = assert(load[[ return {...} ]]) |
| 103 | local x = f(2,3) | 106 | local x = f(2,3) |
| 104 | assert(x[1] == 2 and x[2] == 3 and x[3] == undef) | 107 | assert(x[1] == 2 and x[2] == 3 and x[3] == undef) |
| 105 | 108 | ||
