aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoberto I <roberto@inf.puc-rio.br>2025-09-16 13:26:24 -0300
committerRoberto I <roberto@inf.puc-rio.br>2025-09-16 13:26:24 -0300
commit140b672e2ee2ac842661ece4b48e1a64f0cd11ea (patch)
treeb925cd1e40712ab09a75ef2c0e30095aac0af0aa
parent9ea06e61f20ae34974226074fc6123dbb54a07c2 (diff)
downloadlua-140b672e2ee2ac842661ece4b48e1a64f0cd11ea.tar.gz
lua-140b672e2ee2ac842661ece4b48e1a64f0cd11ea.tar.bz2
lua-140b672e2ee2ac842661ece4b48e1a64f0cd11ea.zip
Vararg table
Not yet optimized nor documented.
-rw-r--r--lobject.h6
-rw-r--r--lopcodes.h2
-rw-r--r--lparser.c29
-rw-r--r--lparser.h9
-rw-r--r--ltm.c45
-rw-r--r--ltm.h4
-rw-r--r--lundump.c3
-rw-r--r--lvm.c2
-rw-r--r--testes/vararg.lua11
9 files changed, 80 insertions, 31 deletions
diff --git a/lobject.h b/lobject.h
index cc3dd370..a805dcbf 100644
--- a/lobject.h
+++ b/lobject.h
@@ -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/*
diff --git a/lopcodes.h b/lopcodes.h
index 9ad21021..c3f7f64d 100644
--- a/lopcodes.h
+++ b/lopcodes.h
@@ -338,7 +338,7 @@ OP_CLOSURE,/* A Bx R[A] := closure(KPROTO[Bx]) */
338 338
339OP_VARARG,/* A C R[A], R[A+1], ..., R[A+C-2] = vararg */ 339OP_VARARG,/* A C R[A], R[A+1], ..., R[A+C-2] = vararg */
340 340
341OP_VARARGPREP,/*A (adjust vararg parameters) */ 341OP_VARARGPREP,/* (adjust vararg parameters) */
342 342
343OP_EXTRAARG/* Ax extra (larger) argument for previous opcode */ 343OP_EXTRAARG/* Ax extra (larger) argument for previous opcode */
344} OpCode; 344} OpCode;
diff --git a/lparser.c b/lparser.c
index 5abcd407..f7e78793 100644
--- a/lparser.c
+++ b/lparser.c
@@ -1041,9 +1041,10 @@ static void constructor (LexState *ls, expdesc *t) {
1041/* }====================================================================== */ 1041/* }====================================================================== */
1042 1042
1043 1043
1044static void setvararg (FuncState *fs, int nparams) { 1044static 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;
diff --git a/lparser.h b/lparser.h
index fdbb9b8a..e479905e 100644
--- a/lparser.h
+++ b/lparser.h
@@ -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)
diff --git a/ltm.c b/ltm.c
index d1a61a62..619be59e 100644
--- a/ltm.c
+++ b/ltm.c
@@ -224,11 +224,38 @@ int luaT_callorderiTM (lua_State *L, const TValue *p1, int v2,
224} 224}
225 225
226 226
227void 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*/
231static 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*/
254void 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
diff --git a/ltm.h b/ltm.h
index ba2e4760..ed479bb4 100644
--- a/ltm.h
+++ b/ltm.h
@@ -95,8 +95,8 @@ LUAI_FUNC int luaT_callorderTM (lua_State *L, const TValue *p1,
95LUAI_FUNC int luaT_callorderiTM (lua_State *L, const TValue *p1, int v2, 95LUAI_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
98LUAI_FUNC void luaT_adjustvarargs (lua_State *L, int nfixparams, 98LUAI_FUNC void luaT_adjustvarargs (lua_State *L, struct CallInfo *ci,
99 struct CallInfo *ci, const Proto *p); 99 const Proto *p);
100LUAI_FUNC void luaT_getvarargs (lua_State *L, struct CallInfo *ci, 100LUAI_FUNC void luaT_getvarargs (lua_State *L, struct CallInfo *ci,
101 StkId where, int wanted); 101 StkId where, int wanted);
102 102
diff --git a/lundump.c b/lundump.c
index 76f0ddc1..74839af8 100644
--- a/lundump.c
+++ b/lundump.c
@@ -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);
diff --git a/lvm.c b/lvm.c
index d0a1c05d..d88a80d1 100644
--- a/lvm.c
+++ b/lvm.c
@@ -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
4print('testing vararg') 4print('testing vararg')
5 5
6local function f (a, ...) 6local 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
10end 13end
11 14
@@ -17,7 +20,7 @@ local function c12 (...)
17 return res, 2 20 return res, 2
18end 21end
19 22
20local function vararg (...) return {n = select('#', ...), ...} end 23local function vararg (...=t) return t end
21 24
22local call = function (f, args) return f(table.unpack(args, 1, args.n)) end 25local 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
102local f = load[[ return {...} ]] 105local f = assert(load[[ return {...} ]])
103local x = f(2,3) 106local x = f(2,3)
104assert(x[1] == 2 and x[2] == 3 and x[3] == undef) 107assert(x[1] == 2 and x[2] == 3 and x[3] == undef)
105 108