From 8fb1af0e33cd8688f57cd0e3ab86420a8cfe99bd Mon Sep 17 00:00:00 2001 From: Roberto I Date: Wed, 17 Sep 2025 16:07:48 -0300 Subject: Varag parameter is a new kind of variable To allow some optimizations on its use. --- lcode.c | 12 ++++++++++++ lcode.h | 1 + lobject.h | 4 ++-- lparser.c | 26 +++++++++++++++++--------- lparser.h | 4 +++- ltm.c | 8 ++++---- testes/vararg.lua | 26 ++++++++++++++++++++++++++ 7 files changed, 65 insertions(+), 16 deletions(-) diff --git a/lcode.c b/lcode.c index cafe265e..f74223eb 100644 --- a/lcode.c +++ b/lcode.c @@ -785,6 +785,15 @@ void luaK_setoneret (FuncState *fs, expdesc *e) { } } +/* +** Change a vararg parameter into a regular local variable +*/ +void luaK_vapar2local (FuncState *fs, expdesc *var) { + fs->f->flag |= PF_VATAB; /* function will need a vararg table */ + /* now a vararg parameter is equivalent to a regular local variable */ + var->k = VLOCAL; +} + /* ** Ensure that expression 'e' is not a variable (nor a ). @@ -796,6 +805,9 @@ void luaK_dischargevars (FuncState *fs, expdesc *e) { const2exp(const2val(fs, e), e); break; } + case VVARGVAR: { + luaK_vapar2local(fs, e); /* turn it into a local variable */ + } /* FALLTHROUGH */ case VLOCAL: { /* already in a register */ int temp = e->u.var.ridx; e->u.info = temp; /* (can't do a direct assignment; values overlap) */ diff --git a/lcode.h b/lcode.h index 94fc2417..8c27bc92 100644 --- a/lcode.h +++ b/lcode.h @@ -71,6 +71,7 @@ LUAI_FUNC void luaK_nil (FuncState *fs, int from, int n); LUAI_FUNC void luaK_reserveregs (FuncState *fs, int n); LUAI_FUNC void luaK_checkstack (FuncState *fs, int n); LUAI_FUNC void luaK_int (FuncState *fs, int reg, lua_Integer n); +LUAI_FUNC void luaK_vapar2local (FuncState *fs, expdesc *var); LUAI_FUNC void luaK_dischargevars (FuncState *fs, expdesc *e); LUAI_FUNC int luaK_exp2anyreg (FuncState *fs, expdesc *e); LUAI_FUNC void luaK_exp2anyregup (FuncState *fs, expdesc *e); diff --git a/lobject.h b/lobject.h index a805dcbf..841ab5b9 100644 --- a/lobject.h +++ b/lobject.h @@ -584,8 +584,8 @@ typedef struct AbsLineInfo { ** Flags in Prototypes */ #define PF_ISVARARG 1 /* function is vararg */ -#define PF_VATAB 2 /* function is vararg with table */ -#define PF_VAPTAB 4 /* function is vararg with pseudo-table */ +#define PF_VAVAR 2 /* function has vararg parameter */ +#define PF_VATAB 4 /* function has vararg table */ #define PF_FIXED 8 /* prototype has parts in fixed memory */ diff --git a/lparser.c b/lparser.c index f7e78793..8b909f3d 100644 --- a/lparser.c +++ b/lparser.c @@ -289,7 +289,7 @@ static void check_readonly (LexState *ls, expdesc *e) { varname = ls->dyd->actvar.arr[e->u.info].vd.name; break; } - case VLOCAL: { + case VLOCAL: case VVARGVAR: { Vardesc *vardesc = getlocalvardesc(fs, e->u.var.vidx); if (vardesc->vd.kind != VDKREG) /* not a regular variable? */ varname = vardesc->vd.name; @@ -426,8 +426,11 @@ static int searchvar (FuncState *fs, TString *n, expdesc *var) { else if (eqstr(n, vd->vd.name)) { /* found? */ if (vd->vd.kind == RDKCTC) /* compile-time constant? */ init_exp(var, VCONST, fs->firstlocal + i); - else /* local variable */ + else { /* local variable */ init_var(fs, var, i); + if (vd->vd.kind == RDKVAVAR) /* vararg parameter? */ + var->k = VVARGVAR; + } return cast_int(var->k); } } @@ -467,8 +470,13 @@ static void marktobeclosed (FuncState *fs) { static void singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) { int v = searchvar(fs, n, var); /* look up variables at current level */ if (v >= 0) { /* found? */ - if (v == VLOCAL && !base) - markupval(fs, var->u.var.vidx); /* local will be used as an upval */ + if (!base) { + if (var->k == VVARGVAR) /* vararg parameter? */ + luaK_vapar2local(fs, var); /* change it to a regular local */ + if (var->k == VLOCAL) + markupval(fs, var->u.var.vidx); /* will be used as an upvalue */ + } + /* else nothing else to be done */ } else { /* not found at current level; try upvalues */ int idx = searchupvalue(fs, n); /* try existing upvalues */ @@ -1066,8 +1074,8 @@ static void parlist (LexState *ls) { varargk |= PF_ISVARARG; luaX_next(ls); if (testnext(ls, '=')) { - new_varkind(ls, str_checkname(ls), RDKVATAB); - varargk |= PF_VATAB; + new_varkind(ls, str_checkname(ls), RDKVAVAR); + varargk |= PF_VAVAR; } break; } @@ -1079,10 +1087,10 @@ static void parlist (LexState *ls) { f->numparams = cast_byte(fs->nactvar); if (varargk != 0) { setvararg(fs, varargk); /* declared vararg */ - if (varargk & PF_VATAB) - adjustlocalvars(ls, 1); /* vararg table */ + if (varargk & PF_VAVAR) + adjustlocalvars(ls, 1); /* vararg parameter */ } - /* reserve registers for parameters (and vararg variable, if present) */ + /* reserve registers for parameters (plus vararg parameter, if present) */ luaK_reserveregs(fs, fs->nactvar); } diff --git a/lparser.h b/lparser.h index e479905e..327170e3 100644 --- a/lparser.h +++ b/lparser.h @@ -37,6 +37,8 @@ typedef enum { info = result register */ VLOCAL, /* local variable; var.ridx = register index; var.vidx = relative index in 'actvar.arr' */ + VVARGVAR, /* vararg parameter; var.ridx = register index; + var.vidx = relative index in 'actvar.arr' */ VGLOBAL, /* global variable; info = relative index in 'actvar.arr' (or -1 for implicit declaration) */ @@ -97,7 +99,7 @@ typedef struct expdesc { /* kinds of variables */ #define VDKREG 0 /* regular local */ #define RDKCONST 1 /* local constant */ -#define RDKVATAB 2 /* vararg table */ +#define RDKVAVAR 2 /* vararg parameter */ #define RDKTOCLOSE 3 /* to-be-closed */ #define RDKCTC 4 /* local compile-time constant */ #define GDKREG 5 /* regular global */ diff --git a/ltm.c b/ltm.c index 619be59e..cc812e62 100644 --- a/ltm.c +++ b/ltm.c @@ -265,11 +265,11 @@ void luaT_adjustvarargs (lua_State *L, CallInfo *ci, const Proto *p) { setobjs2s(L, L->top.p++, ci->func.p + i); setnilvalue(s2v(ci->func.p + i)); /* erase original parameter (for GC) */ } - if (p->flag & (PF_VAPTAB | PF_VATAB)) { /* is there a vararg table? */ - if (p->flag & PF_VAPTAB) /* is vararg table fake? */ - setnilvalue(s2v(L->top.p)); /* initialize it */ - else + if (p->flag & PF_VAVAR) { /* is there a vararg parameter? */ + if (p->flag & PF_VATAB) /* does it need a vararg table? */ createvarargtab(L, ci->func.p + nfixparams + 1, nextra); + else /* no table; set parameter to nil */ + setnilvalue(s2v(L->top.p)); } ci->func.p += totalargs + 1; ci->top.p += totalargs + 1; diff --git a/testes/vararg.lua b/testes/vararg.lua index 4320684e..92f720cb 100644 --- a/testes/vararg.lua +++ b/testes/vararg.lua @@ -150,5 +150,31 @@ do local a, b = g() assert(a == nil and b == 2) end + + +do -- vararg parameter used in nested functions + local function foo (... = tab1) + return function (... = tab2) + return {tab1, tab2} + end + end + local f = foo(10, 20, 30) + local t = f("a", "b") + assert(t[1].n == 3 and t[1][1] == 10) + assert(t[2].n == 2 and t[2][1] == "a") +end + +do -- vararg parameter is read-only + local st, msg = load("return function (... = t) t = 10 end") + assert(string.find(msg, "const variable 't'")) + + local st, msg = load[[ + local function foo (... = extra) + return function (...) extra = nil end + end + ]] + assert(string.find(msg, "const variable 'extra'")) +end + print('OK') -- cgit v1.2.3-55-g6feb