Vararg table
Not yet optimized nor documented.
This commit is contained in:
@@ -583,8 +583,10 @@ typedef struct AbsLineInfo {
|
|||||||
/*
|
/*
|
||||||
** Flags in Prototypes
|
** Flags in Prototypes
|
||||||
*/
|
*/
|
||||||
#define PF_ISVARARG 1
|
#define PF_ISVARARG 1 /* function is vararg */
|
||||||
#define PF_FIXED 2 /* prototype has parts in fixed memory */
|
#define PF_VATAB 2 /* function is vararg with table */
|
||||||
|
#define PF_VAPTAB 4 /* function is vararg with pseudo-table */
|
||||||
|
#define PF_FIXED 8 /* prototype has parts in fixed memory */
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -338,7 +338,7 @@ OP_CLOSURE,/* A Bx R[A] := closure(KPROTO[Bx]) */
|
|||||||
|
|
||||||
OP_VARARG,/* A C R[A], R[A+1], ..., R[A+C-2] = vararg */
|
OP_VARARG,/* A C R[A], R[A+1], ..., R[A+C-2] = vararg */
|
||||||
|
|
||||||
OP_VARARGPREP,/*A (adjust vararg parameters) */
|
OP_VARARGPREP,/* (adjust vararg parameters) */
|
||||||
|
|
||||||
OP_EXTRAARG/* Ax extra (larger) argument for previous opcode */
|
OP_EXTRAARG/* Ax extra (larger) argument for previous opcode */
|
||||||
} OpCode;
|
} OpCode;
|
||||||
|
|||||||
29
lparser.c
29
lparser.c
@@ -1041,9 +1041,10 @@ static void constructor (LexState *ls, expdesc *t) {
|
|||||||
/* }====================================================================== */
|
/* }====================================================================== */
|
||||||
|
|
||||||
|
|
||||||
static void setvararg (FuncState *fs, int nparams) {
|
static void setvararg (FuncState *fs, int kind) {
|
||||||
fs->f->flag |= PF_ISVARARG;
|
lua_assert(kind & PF_ISVARARG);
|
||||||
luaK_codeABC(fs, OP_VARARGPREP, nparams, 0, 0);
|
fs->f->flag |= cast_byte(kind);
|
||||||
|
luaK_codeABC(fs, OP_VARARGPREP, 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1052,7 +1053,7 @@ static void parlist (LexState *ls) {
|
|||||||
FuncState *fs = ls->fs;
|
FuncState *fs = ls->fs;
|
||||||
Proto *f = fs->f;
|
Proto *f = fs->f;
|
||||||
int nparams = 0;
|
int nparams = 0;
|
||||||
int isvararg = 0;
|
int varargk = 0;
|
||||||
if (ls->t.token != ')') { /* is 'parlist' not empty? */
|
if (ls->t.token != ')') { /* is 'parlist' not empty? */
|
||||||
do {
|
do {
|
||||||
switch (ls->t.token) {
|
switch (ls->t.token) {
|
||||||
@@ -1062,19 +1063,27 @@ static void parlist (LexState *ls) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TK_DOTS: {
|
case TK_DOTS: {
|
||||||
|
varargk |= PF_ISVARARG;
|
||||||
luaX_next(ls);
|
luaX_next(ls);
|
||||||
isvararg = 1;
|
if (testnext(ls, '=')) {
|
||||||
|
new_varkind(ls, str_checkname(ls), RDKVATAB);
|
||||||
|
varargk |= PF_VATAB;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: luaX_syntaxerror(ls, "<name> or '...' expected");
|
default: luaX_syntaxerror(ls, "<name> or '...' expected");
|
||||||
}
|
}
|
||||||
} while (!isvararg && testnext(ls, ','));
|
} while (!varargk && testnext(ls, ','));
|
||||||
}
|
}
|
||||||
adjustlocalvars(ls, nparams);
|
adjustlocalvars(ls, nparams);
|
||||||
f->numparams = cast_byte(fs->nactvar);
|
f->numparams = cast_byte(fs->nactvar);
|
||||||
if (isvararg)
|
if (varargk != 0) {
|
||||||
setvararg(fs, f->numparams); /* declared vararg */
|
setvararg(fs, varargk); /* declared vararg */
|
||||||
luaK_reserveregs(fs, fs->nactvar); /* reserve registers for parameters */
|
if (varargk & PF_VATAB)
|
||||||
|
adjustlocalvars(ls, 1); /* vararg table */
|
||||||
|
}
|
||||||
|
/* reserve registers for parameters (and vararg variable, if present) */
|
||||||
|
luaK_reserveregs(fs, fs->nactvar);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -2099,7 +2108,7 @@ static void mainfunc (LexState *ls, FuncState *fs) {
|
|||||||
BlockCnt bl;
|
BlockCnt bl;
|
||||||
Upvaldesc *env;
|
Upvaldesc *env;
|
||||||
open_func(ls, fs, &bl);
|
open_func(ls, fs, &bl);
|
||||||
setvararg(fs, 0); /* main function is always declared vararg */
|
setvararg(fs, PF_ISVARARG); /* main function is always vararg */
|
||||||
env = allocupvalue(fs); /* ...set environment upvalue */
|
env = allocupvalue(fs); /* ...set environment upvalue */
|
||||||
env->instack = 1;
|
env->instack = 1;
|
||||||
env->idx = 0;
|
env->idx = 0;
|
||||||
|
|||||||
@@ -97,10 +97,11 @@ typedef struct expdesc {
|
|||||||
/* kinds of variables */
|
/* kinds of variables */
|
||||||
#define VDKREG 0 /* regular local */
|
#define VDKREG 0 /* regular local */
|
||||||
#define RDKCONST 1 /* local constant */
|
#define RDKCONST 1 /* local constant */
|
||||||
#define RDKTOCLOSE 2 /* to-be-closed */
|
#define RDKVATAB 2 /* vararg table */
|
||||||
#define RDKCTC 3 /* local compile-time constant */
|
#define RDKTOCLOSE 3 /* to-be-closed */
|
||||||
#define GDKREG 4 /* regular global */
|
#define RDKCTC 4 /* local compile-time constant */
|
||||||
#define GDKCONST 5 /* global constant */
|
#define GDKREG 5 /* regular global */
|
||||||
|
#define GDKCONST 6 /* global constant */
|
||||||
|
|
||||||
/* variables that live in registers */
|
/* variables that live in registers */
|
||||||
#define varinreg(v) ((v)->vd.kind <= RDKTOCLOSE)
|
#define varinreg(v) ((v)->vd.kind <= RDKTOCLOSE)
|
||||||
|
|||||||
45
ltm.c
45
ltm.c
@@ -224,11 +224,38 @@ int luaT_callorderiTM (lua_State *L, const TValue *p1, int v2,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void luaT_adjustvarargs (lua_State *L, int nfixparams, CallInfo *ci,
|
/*
|
||||||
const Proto *p) {
|
** Create a vararg table at the top of the stack, with 'n' elements
|
||||||
|
** starting at 'f'.
|
||||||
|
*/
|
||||||
|
static void createvarargtab (lua_State *L, StkId f, int n) {
|
||||||
int i;
|
int i;
|
||||||
int actual = cast_int(L->top.p - ci->func.p) - 1; /* number of arguments */
|
TValue key, value;
|
||||||
int nextra = actual - nfixparams; /* number of extra arguments */
|
Table *t = luaH_new(L);
|
||||||
|
sethvalue(L, s2v(L->top.p), t);
|
||||||
|
L->top.p++;
|
||||||
|
luaH_resize(L, t, cast_uint(n), 1);
|
||||||
|
setsvalue(L, &key, luaS_new(L, "n")); /* key is "n" */
|
||||||
|
setivalue(&value, n); /* value is n */
|
||||||
|
/* No need to anchor the key: Due to the resize, the next operation
|
||||||
|
cannot trigger a garbage collection */
|
||||||
|
luaH_set(L, t, &key, &value); /* t.n = n */
|
||||||
|
for (i = 0; i < n; i++)
|
||||||
|
luaH_setint(L, t, i + 1, s2v(f + i));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** initial stack: func arg1 ... argn extra1 ...
|
||||||
|
** ^ ci->func ^ L->top
|
||||||
|
** final stack: func nil ... nil extra1 ... func arg1 ... argn
|
||||||
|
** ^ ci->func ^ L->top
|
||||||
|
*/
|
||||||
|
void luaT_adjustvarargs (lua_State *L, CallInfo *ci, const Proto *p) {
|
||||||
|
int i;
|
||||||
|
int totalargs = cast_int(L->top.p - ci->func.p) - 1;
|
||||||
|
int nfixparams = p->numparams;
|
||||||
|
int nextra = totalargs - nfixparams; /* number of extra arguments */
|
||||||
ci->u.l.nextraargs = nextra;
|
ci->u.l.nextraargs = nextra;
|
||||||
luaD_checkstack(L, p->maxstacksize + 1);
|
luaD_checkstack(L, p->maxstacksize + 1);
|
||||||
/* copy function to the top of the stack */
|
/* copy function to the top of the stack */
|
||||||
@@ -238,8 +265,14 @@ void luaT_adjustvarargs (lua_State *L, int nfixparams, CallInfo *ci,
|
|||||||
setobjs2s(L, L->top.p++, ci->func.p + i);
|
setobjs2s(L, L->top.p++, ci->func.p + i);
|
||||||
setnilvalue(s2v(ci->func.p + i)); /* erase original parameter (for GC) */
|
setnilvalue(s2v(ci->func.p + i)); /* erase original parameter (for GC) */
|
||||||
}
|
}
|
||||||
ci->func.p += actual + 1;
|
if (p->flag & (PF_VAPTAB | PF_VATAB)) { /* is there a vararg table? */
|
||||||
ci->top.p += actual + 1;
|
if (p->flag & PF_VAPTAB) /* is vararg table fake? */
|
||||||
|
setnilvalue(s2v(L->top.p)); /* initialize it */
|
||||||
|
else
|
||||||
|
createvarargtab(L, ci->func.p + nfixparams + 1, nextra);
|
||||||
|
}
|
||||||
|
ci->func.p += totalargs + 1;
|
||||||
|
ci->top.p += totalargs + 1;
|
||||||
lua_assert(L->top.p <= ci->top.p && ci->top.p <= L->stack_last.p);
|
lua_assert(L->top.p <= ci->top.p && ci->top.p <= L->stack_last.p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
4
ltm.h
4
ltm.h
@@ -95,8 +95,8 @@ LUAI_FUNC int luaT_callorderTM (lua_State *L, const TValue *p1,
|
|||||||
LUAI_FUNC int luaT_callorderiTM (lua_State *L, const TValue *p1, int v2,
|
LUAI_FUNC int luaT_callorderiTM (lua_State *L, const TValue *p1, int v2,
|
||||||
int inv, int isfloat, TMS event);
|
int inv, int isfloat, TMS event);
|
||||||
|
|
||||||
LUAI_FUNC void luaT_adjustvarargs (lua_State *L, int nfixparams,
|
LUAI_FUNC void luaT_adjustvarargs (lua_State *L, struct CallInfo *ci,
|
||||||
struct CallInfo *ci, const Proto *p);
|
const Proto *p);
|
||||||
LUAI_FUNC void luaT_getvarargs (lua_State *L, struct CallInfo *ci,
|
LUAI_FUNC void luaT_getvarargs (lua_State *L, struct CallInfo *ci,
|
||||||
StkId where, int wanted);
|
StkId where, int wanted);
|
||||||
|
|
||||||
|
|||||||
@@ -327,7 +327,8 @@ static void loadFunction (LoadState *S, Proto *f) {
|
|||||||
f->linedefined = loadInt(S);
|
f->linedefined = loadInt(S);
|
||||||
f->lastlinedefined = loadInt(S);
|
f->lastlinedefined = loadInt(S);
|
||||||
f->numparams = loadByte(S);
|
f->numparams = loadByte(S);
|
||||||
f->flag = loadByte(S) & PF_ISVARARG; /* get only the meaningful flags */
|
/* get only the meaningful flags */
|
||||||
|
f->flag = cast_byte(loadByte(S) & ~PF_FIXED);
|
||||||
if (S->fixed)
|
if (S->fixed)
|
||||||
f->flag |= PF_FIXED; /* signal that code is fixed */
|
f->flag |= PF_FIXED; /* signal that code is fixed */
|
||||||
f->maxstacksize = loadByte(S);
|
f->maxstacksize = loadByte(S);
|
||||||
|
|||||||
2
lvm.c
2
lvm.c
@@ -1927,7 +1927,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
|
|||||||
vmbreak;
|
vmbreak;
|
||||||
}
|
}
|
||||||
vmcase(OP_VARARGPREP) {
|
vmcase(OP_VARARGPREP) {
|
||||||
ProtectNT(luaT_adjustvarargs(L, GETARG_A(i), ci, cl->p));
|
ProtectNT(luaT_adjustvarargs(L, ci, cl->p));
|
||||||
if (l_unlikely(trap)) { /* previous "Protect" updated trap */
|
if (l_unlikely(trap)) { /* previous "Protect" updated trap */
|
||||||
luaD_hookcall(L, ci);
|
luaD_hookcall(L, ci);
|
||||||
L->oldpc = 1; /* next opcode will be seen as a "new" line */
|
L->oldpc = 1; /* next opcode will be seen as a "new" line */
|
||||||
|
|||||||
@@ -3,9 +3,12 @@
|
|||||||
|
|
||||||
print('testing vararg')
|
print('testing vararg')
|
||||||
|
|
||||||
local function f (a, ...)
|
local function f (a, ...=t)
|
||||||
local x = {n = select('#', ...), ...}
|
local x = {n = select('#', ...), ...}
|
||||||
for i = 1, x.n do assert(a[i] == x[i]) end
|
assert(x.n == t.n)
|
||||||
|
for i = 1, x.n do
|
||||||
|
assert(a[i] == x[i] and x[i] == t[i])
|
||||||
|
end
|
||||||
return x.n
|
return x.n
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -17,7 +20,7 @@ local function c12 (...)
|
|||||||
return res, 2
|
return res, 2
|
||||||
end
|
end
|
||||||
|
|
||||||
local function vararg (...) return {n = select('#', ...), ...} end
|
local function vararg (...=t) return t end
|
||||||
|
|
||||||
local call = function (f, args) return f(table.unpack(args, 1, args.n)) end
|
local call = function (f, args) return f(table.unpack(args, 1, args.n)) end
|
||||||
|
|
||||||
@@ -99,7 +102,7 @@ assert(a==nil and b==nil and c==nil and d==nil and e==nil)
|
|||||||
|
|
||||||
|
|
||||||
-- varargs for main chunks
|
-- varargs for main chunks
|
||||||
local f = load[[ return {...} ]]
|
local f = assert(load[[ return {...} ]])
|
||||||
local x = f(2,3)
|
local x = f(2,3)
|
||||||
assert(x[1] == 2 and x[2] == 3 and x[3] == undef)
|
assert(x[1] == 2 and x[2] == 3 and x[3] == undef)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user