diff options
-rw-r--r-- | lbaselib.c | 81 | ||||
-rw-r--r-- | lcode.c | 3 | ||||
-rw-r--r-- | ldebug.c | 15 | ||||
-rw-r--r-- | ldo.c | 126 | ||||
-rw-r--r-- | lopcodes.h | 19 | ||||
-rw-r--r-- | lparser.c | 10 | ||||
-rw-r--r-- | lstate.c | 1 | ||||
-rw-r--r-- | lstate.h | 6 | ||||
-rw-r--r-- | lua.h | 17 | ||||
-rw-r--r-- | lvm.c | 86 | ||||
-rw-r--r-- | lvm.h | 2 |
11 files changed, 229 insertions, 137 deletions
@@ -148,30 +148,6 @@ static int luaB_eventtable (lua_State *L) { } -static int luaB_weakmode (lua_State *L) { - const char *mode = luaL_check_string(L, 2); - luaL_check_type(L, 1, LUA_TTABLE); - if (*mode == '?') { - char buff[3]; - char *s = buff; - int imode = lua_getweakmode(L, 1); - if (imode & LUA_WEAK_KEY) *s++ = 'k'; - if (imode & LUA_WEAK_VALUE) *s++ = 'v'; - *s = '\0'; - lua_pushstring(L, buff); - return 1; - } - else { - int imode = 0; - if (strchr(mode, 'k')) imode |= LUA_WEAK_KEY; - if (strchr(mode, 'v')) imode |= LUA_WEAK_VALUE; - lua_pushvalue(L, 1); /* push table */ - lua_setweakmode(L, imode); - return 1; /* return the table */ - } -} - - static int luaB_globals (lua_State *L) { lua_getglobals(L); /* value to be returned */ if (!lua_isnone(L, 1)) { @@ -287,6 +263,14 @@ static int luaB_loadfile (lua_State *L) { } +static int luaB_assert (lua_State *L) { + luaL_check_any(L, 1); + if (!lua_istrue(L, 1)) + luaL_verror(L, "assertion failed! %.90s", luaL_opt_string(L, 2, "")); + lua_settop(L, 1); + return 1; +} + #define LUA_PATH "LUA_PATH" @@ -428,6 +412,40 @@ static int luaB_tostring (lua_State *L) { } +static int luaB_resume (lua_State *L) { + lua_State *co = (lua_State *)lua_touserdata(L, lua_upvalueindex(1)); + lua_resume(L, co); + return 0; +} + + +static int luaB_coroutine (lua_State *L) { + lua_State *NL; + int ref; + luaL_check_type(L, 1, LUA_TFUNCTION); + NL = lua_newthread(L, 0); + if (NL == NULL) lua_error(L, "unable to create new thread"); + /* move function from L to NL */ + ref = lua_ref(L, 1); + lua_getref(NL, ref); + lua_unref(L, ref); + lua_cobegin(NL, 0); + lua_newuserdatabox(L, NL); + lua_pushcclosure(L, luaB_resume, 1); + return 1; +} + + +static int luaB_yield (lua_State *L) { + return lua_yield(L, 0); +} + + +/* +** {====================================================== +** Auxiliar table-related functions +*/ + static int luaB_foreachi (lua_State *L) { int n, i; luaL_check_type(L, 1, LUA_TTABLE); @@ -464,15 +482,6 @@ static int luaB_foreach (lua_State *L) { } -static int luaB_assert (lua_State *L) { - luaL_check_any(L, 1); - if (!lua_istrue(L, 1)) - luaL_verror(L, "assertion failed! %.90s", luaL_opt_string(L, 2, "")); - lua_settop(L, 1); - return 1; -} - - static int luaB_getn (lua_State *L) { luaL_check_type(L, 1, LUA_TTABLE); lua_pushnumber(L, lua_getn(L, 1)); @@ -521,7 +530,6 @@ static int luaB_tremove (lua_State *L) { - /* ** {====================================================== ** Quicksort @@ -627,6 +635,8 @@ static int luaB_sort (lua_State *L) { /* }====================================================== */ +/* }====================================================== */ + static const luaL_reg base_funcs[] = { @@ -634,6 +644,7 @@ static const luaL_reg base_funcs[] = { {LUA_ERRORMESSAGE, luaB__ERRORMESSAGE}, {"call", luaB_call}, {"collectgarbage", luaB_collectgarbage}, + {"coroutine", luaB_coroutine}, {"dofile", luaB_dofile}, {"dostring", luaB_dostring}, {"error", luaB_error}, @@ -659,7 +670,7 @@ static const luaL_reg base_funcs[] = { {"tinsert", luaB_tinsert}, {"tremove", luaB_tremove}, {"unpack", luaB_unpack}, - {"weakmode", luaB_weakmode} + {"yield", luaB_yield} }; @@ -264,8 +264,7 @@ static int nil_constant (FuncState *fs) { void luaK_setcallreturns (FuncState *fs, expdesc *e, int nresults) { if (e->k == VCALL) { /* expression is an open function call? */ - if (nresults == LUA_MULTRET) nresults = NO_REG; - SETARG_C(getcode(fs, e), nresults); + SETARG_C(getcode(fs, e), nresults+1); if (nresults == 1) { /* `regular' expression? */ e->k = VNONRELOC; e->u.i.info = GETARG_A(getcode(fs, e)); @@ -1,5 +1,5 @@ /* -** $Id: ldebug.c,v 1.1 2001/11/29 22:14:34 rieru Exp rieru $ +** $Id: ldebug.c,v 1.96 2001/12/18 20:52:30 roberto Exp $ ** Debug Interface ** See Copyright Notice in lua.h */ @@ -303,7 +303,7 @@ static int checkopenop (const Proto *pt, int pc) { switch (GET_OPCODE(i)) { case OP_CALL: case OP_RETURN: { - check(GETARG_B(i) == NO_REG); + check(GETARG_B(i) == 0); return 1; } case OP_SETLISTO: return 1; @@ -391,10 +391,11 @@ static Instruction luaG_symbexec (const Proto *pt, int lastpc, int reg) { break; } case OP_CALL: { - if (b != NO_REG) { - checkreg(pt, a+b); + if (b != 0) { + checkreg(pt, a+b-1); } - if (c == NO_REG) { + c--; /* c = num. returns */ + if (c == LUA_MULTRET) { check(checkopenop(pt, pc)); } else if (c != 0) @@ -403,8 +404,8 @@ static Instruction luaG_symbexec (const Proto *pt, int lastpc, int reg) { break; } case OP_RETURN: { - if (b != NO_REG && b != 0) - checkreg(pt, a+b-1); + b--; /* b = num. returns */ + if (b > 0) checkreg(pt, a+b-1); break; } case OP_FORPREP: @@ -18,6 +18,7 @@ #include "lgc.h" #include "lmem.h" #include "lobject.h" +#include "lopcodes.h" #include "lparser.h" #include "lstate.h" #include "lstring.h" @@ -112,8 +113,6 @@ void luaD_callHook (lua_State *L, lua_Hook callhook, const char *event) { } -#define newci(L) ((++L->ci == L->end_ci) ? growci(L) : L->ci) - static CallInfo *growci (lua_State *L) { lua_assert(L->ci == L->end_ci); luaM_reallocvector(L, L->base_ci, L->size_ci, 2*L->size_ci, CallInfo); @@ -124,9 +123,32 @@ static CallInfo *growci (lua_State *L) { } +static void adjust_varargs (lua_State *L, StkId base, int nfixargs) { + int i; + Table *htab; + TObject n, nname; + StkId firstvar = base + nfixargs; /* position of first vararg */ + if (L->top < firstvar) { + luaD_checkstack(L, firstvar - L->top); + while (L->top < firstvar) + setnilvalue(L->top++); + } + htab = luaH_new(L, 0, 0); + for (i=0; firstvar+i<L->top; i++) + luaH_setnum(L, htab, i+1, firstvar+i); + /* store counter in field `n' */ + setnvalue(&n, i); + setsvalue(&nname, luaS_newliteral(L, "n")); + luaH_set(L, htab, &nname, &n); + L->top = firstvar; /* remove elements from the stack */ + sethvalue(L->top, htab); + incr_top; +} + + StkId luaD_precall (lua_State *L, StkId func) { CallInfo *ci; - int n; + LClosure *cl; if (ttype(func) != LUA_TFUNCTION) { /* `func' is not a function; check the `function' tag method */ const TObject *tm = luaT_gettmbyobj(L, func, TM_CALL); @@ -135,21 +157,39 @@ StkId luaD_precall (lua_State *L, StkId func) { luaD_openstack(L, func); setobj(func, tm); /* tag method is the new function to be called */ } - ci = newci(L); + ci = ++L->ci; + if (L->ci == L->end_ci) ci = growci(L); ci->base = func+1; - ci->savedpc = NULL; if (L->callhook) luaD_callHook(L, L->callhook, "call"); - if (!clvalue(func)->c.isC) return NULL; - /* if is a C function, call it */ - luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ - lua_unlock(L); + cl = &clvalue(func)->l; + if (!cl->isC) { /* Lua function? prepare its call */ + StkId base = func+1; + Proto *p = cl->p; + ci->linehook = L->linehook; + ci->savedpc = p->code; /* starting point */ + if (p->is_vararg) /* varargs? */ + adjust_varargs(L, base, p->numparams); + if (base > L->stack_last - p->maxstacksize) + luaD_stackerror(L); + ci->top = base + p->maxstacksize; + while (L->top < ci->top) + setnilvalue(L->top++); + L->top = ci->top; + return NULL; + } + else { /* if is a C function, call it */ + int n; + ci->savedpc = NULL; + luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ + lua_unlock(L); #if LUA_COMPATUPVALUES - lua_pushupvalues(L); + lua_pushupvalues(L); #endif - n = (*clvalue(func)->c.f)(L); /* do the actual call */ - lua_lock(L); - return L->top - n; + n = (*clvalue(func)->c.f)(L); /* do the actual call */ + lua_lock(L); + return L->top - n; + } } @@ -179,12 +219,60 @@ void luaD_poscall (lua_State *L, int wanted, StkId firstResult) { */ void luaD_call (lua_State *L, StkId func, int nResults) { StkId firstResult = luaD_precall(L, func); - if (firstResult == NULL) /* is a Lua function? */ - firstResult = luaV_execute(L, &clvalue(func)->l, func+1); /* call it */ + if (firstResult == NULL) { /* is a Lua function? */ + firstResult = luaV_execute(L); /* call it */ + if (firstResult == NULL) { + luaD_poscall(L, 0, L->top); + luaD_error(L, "attempt to `yield' across tag-method/C-call boundary"); + } + } luaD_poscall(L, nResults, firstResult); } +LUA_API void lua_cobegin (lua_State *L, int nargs) { + StkId func; + lua_lock(L); + func = L->top - (nargs+1); /* coroutine main function */ + if (luaD_precall(L, func) != NULL) + luaD_error(L, "coroutine started with a C function"); + lua_unlock(L); +} + + +LUA_API void lua_resume (lua_State *L, lua_State *co) { + StkId firstResult; + lua_lock(L); + if (co->ci->savedpc == NULL) /* no activation record? */ + luaD_error(L, "thread is dead - cannot be resumed"); + lua_assert(co->errorJmp == NULL); + co->errorJmp = L->errorJmp; + firstResult = luaV_execute(co); + if (firstResult != NULL) /* `return'? */ + luaD_poscall(co, LUA_MULTRET, firstResult); /* ends this coroutine */ + else { /* `yield' */ + int nresults = GETARG_C(*((co->ci-1)->savedpc - 1)) - 1; + luaD_poscall(co, nresults, co->top); /* complete it */ + if (nresults >= 0) co->top = co->ci->top; + } + co->errorJmp = NULL; + lua_unlock(L); +} + + +LUA_API int lua_yield (lua_State *L, int nresults) { + CallInfo *ci; + int ibase; + lua_lock(L); + ci = L->ci - 1; /* call info of calling function */ + if (ci->pc == NULL) + luaD_error(L, "cannot `yield' a C function"); + ibase = L->top - ci->base; + lua_unlock(L); + return ibase; +} + + /* ** Execute a protected call. */ @@ -330,7 +418,13 @@ static void message (lua_State *L, const char *s) { ** Reports an error, and jumps up to the available recovery label */ void luaD_error (lua_State *L, const char *s) { - if (s) message(L, s); + if (s) { + if (L->ci->savedpc) { /* error in Lua function preamble? */ + L->ci->savedpc = NULL; /* pretend function was already running */ + L->ci->pc = NULL; + } + message(L, s); + } luaD_breakrun(L, LUA_ERRRUN); } @@ -168,8 +168,8 @@ OP_TESTGE,/* A C test := (R(A) >= R/K(C)) */ OP_TESTT,/* A B test := R(B); if (test) R(A) := R(B) */ OP_TESTF,/* A B test := not R(B); if (test) R(A) := R(B) */ -OP_CALL,/* A B C R(A), ... ,R(A+C-1) := R(A)(R(A+1), ... ,R(A+B))*/ -OP_RETURN,/* A B return R(A), ... ,R(A+B-1) (see (3)) */ +OP_CALL,/* A B C R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1))*/ +OP_RETURN,/* A B return R(A), ... ,R(A+B-2) (see (3)) */ OP_FORPREP,/* A sBc */ OP_FORLOOP,/* A sBc */ @@ -182,6 +182,9 @@ OP_SETLISTO,/* A Bc */ OP_CLOSE,/* A close all variables in the stack up to (>=) R(A)*/ OP_CLOSURE /* A Bc R(A) := closure(KPROTO[Bc], R(A), ... ,R(A+n)) */ +/*---------------------------------------------------------------------- +pseudo-instructions (interruptions): cannot occur in regular code +------------------------------------------------------------------------*/ } OpCode; @@ -194,11 +197,11 @@ OP_CLOSURE /* A Bc R(A) := closure(KPROTO[Bc], R(A), ... ,R(A+n)) */ (1) In the current implementation there is no `test' variable; instructions OP_TEST* and OP_CJMP must always occur together. - (2) In OP_CALL, if (B == NO_REG) then B = top. C is the number of returns, - and can be NO_REG. OP_CALL can set `top' to last_result+1, so + (2) 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'. - (3) In OP_RETURN, if (B == NO_REG) then return up to `top' + (3) In OP_RETURN, if (B == 0) then return up to `top' ===========================================================================*/ @@ -221,6 +224,12 @@ extern const lu_byte luaP_opmodes[NUM_OPCODES]; /* +** constant instructions +*/ + +extern const Instruction luaP_yieldop; + +/* ** opcode names (only included when compiled with LUA_OPNAMES) */ extern const char *const luaP_opnames[]; @@ -335,7 +335,7 @@ static void close_func (LexState *ls) { FuncState *fs = ls->fs; Proto *f = fs->f; removelocalvars(ls, fs->nactloc, 0); - luaK_codeABC(fs, OP_RETURN, 0, 0, 0); /* final return */ + luaK_codeABC(fs, OP_RETURN, 0, 1, 0); /* final return */ luaK_getlabel(fs); /* close eventual list of pending jumps */ lua_assert(G(L)->roottable == fs->h); G(L)->roottable = fs->h->next; @@ -449,13 +449,13 @@ static void funcargs (LexState *ls, expdesc *f) { lua_assert(f->k == VNONRELOC); base = f->u.i.info; /* base register for call */ if (args.k == VCALL) - nparams = NO_REG; /* open call */ + nparams = LUA_MULTRET; /* open call */ else { if (args.k != VVOID) luaK_exp2nextreg(fs, &args); /* close last argument */ nparams = fs->freereg - (base+1); } - init_exp(f, VCALL, luaK_codeABC(fs, OP_CALL, base, nparams, 1)); + init_exp(f, VCALL, luaK_codeABC(fs, OP_CALL, base, nparams+1, 2)); fs->freereg = base+1; /* call remove function and arguments and leaves (unless changed) one result */ } @@ -1136,7 +1136,7 @@ static void retstat (LexState *ls) { if (e.k == VCALL) { luaK_setcallreturns(fs, &e, LUA_MULTRET); first = fs->nactloc; - nret = NO_REG; /* return all values */ + nret = LUA_MULTRET; /* return all values */ } else { luaK_exp2nextreg(fs, &e); /* values must go to the `stack' */ @@ -1144,7 +1144,7 @@ static void retstat (LexState *ls) { nret = fs->freereg - first; /* return all `active' values */ } } - luaK_codeABC(fs, OP_RETURN, first, nret, 0); + luaK_codeABC(fs, OP_RETURN, first, nret+1, 0); fs->freereg = fs->nactloc; /* removes all temp values */ } @@ -104,6 +104,7 @@ LUA_API lua_State *lua_newthread (lua_State *OL, int stacksize) { } } if (OL) lua_unlock(OL); + lua_userstateopen(L); return L; } @@ -39,6 +39,10 @@ #define LUA_USERSTATE #endif +#ifndef lua_userstateopen +#define lua_userstateopen(l) +#endif + struct lua_longjmp; /* defined in ldo.c */ @@ -77,8 +81,8 @@ typedef struct CallInfo { const Instruction *savedpc; lua_Hook linehook; StkId top; /* top for this function (when it's a Lua function) */ - /* extra information for debugging */ const Instruction **pc; + /* extra information for line tracing */ int lastpc; /* last pc traced */ int line; /* current line */ int refi; /* current index in `lineinfo' */ @@ -45,10 +45,6 @@ #define LUA_ERRMEM 4 #define LUA_ERRERR 5 -/* weak-table modes */ -#define LUA_WEAK_KEY 1 -#define LUA_WEAK_VALUE 2 - typedef struct lua_State lua_State; @@ -182,6 +178,14 @@ LUA_API int lua_loadbuffer (lua_State *L, const char *buff, size_t size, LUA_API int lua_dobuffer (lua_State *L, const char *buff, size_t size, const char *name); + +/* +** coroutine functions +*/ +LUA_API void lua_cobegin (lua_State *L, int nargs); +LUA_API int lua_yield (lua_State *L, int nresults); +LUA_API void lua_resume (lua_State *L, lua_State *co); + /* ** Garbage-collection functions */ @@ -203,9 +207,6 @@ LUA_API void lua_concat (lua_State *L, int n); LUA_API void *lua_newuserdata (lua_State *L, size_t size); LUA_API void lua_newuserdatabox (lua_State *L, void *u); -LUA_API void lua_setweakmode (lua_State *L, int mode); -LUA_API int lua_getweakmode (lua_State *L, int index); - /* @@ -242,7 +243,7 @@ LUA_API int lua_getweakmode (lua_State *L, int index); ** compatibility macros and functions */ -LUA_API void lua_pushupvalues (lua_State *L); +LUA_API int lua_pushupvalues (lua_State *L); #define lua_isnull lua_isnone @@ -254,29 +254,6 @@ void luaV_strconc (lua_State *L, int total, StkId top) { } -static void adjust_varargs (lua_State *L, StkId base, int nfixargs) { - int i; - Table *htab; - TObject n, nname; - StkId firstvar = base + nfixargs; /* position of first vararg */ - if (L->top < firstvar) { - luaD_checkstack(L, firstvar - L->top); - while (L->top < firstvar) - setnilvalue(L->top++); - } - htab = luaH_new(L, 0, 0); - for (i=0; firstvar+i<L->top; i++) - luaH_setnum(L, htab, i+1, firstvar+i); - /* store counter in field `n' */ - setnvalue(&n, i); - setsvalue(&nname, luaS_newliteral(L, "n")); - luaH_set(L, htab, &nname, &n); - L->top = firstvar; /* remove elements from the stack */ - sethvalue(L->top, htab); - incr_top; -} - - static void powOp (lua_State *L, StkId ra, StkId rb, StkId rc) { const TObject *b = rb; const TObject *c = rc; @@ -307,8 +284,8 @@ static void powOp (lua_State *L, StkId ra, StkId rb, StkId rc) { #define RC(i) (base+GETARG_C(i)) #define RKC(i) ((GETARG_C(i) < MAXSTACK) ? \ base+GETARG_C(i) : \ - cl->p->k+GETARG_C(i)-MAXSTACK) -#define KBc(i) (cl->p->k+GETARG_Bc(i)) + k+GETARG_C(i)-MAXSTACK) +#define KBc(i) (k+GETARG_Bc(i)) #define Arith(op, optm) { \ const TObject *b = RB(i); const TObject *c = RKC(i); \ @@ -321,38 +298,26 @@ static void powOp (lua_State *L, StkId ra, StkId rb, StkId rc) { } -#define luaV_poscall(L,c,f,ci) \ - if (c != NO_REG) { \ - luaD_poscall(L, c, f); \ - L->top = ci->top; \ - } \ - else { \ - luaD_poscall(L, LUA_MULTRET, f); \ - } - - #define dojump(pc, i) ((pc) += GETARG_sBc(i)) /* -** Executes the given Lua function. Parameters are between [base,top). +** Executes current Lua function. Parameters are between [base,top). ** Returns n such that the results are between [n,top). */ -StkId luaV_execute (lua_State *L, const LClosure *cl, StkId base) { +StkId luaV_execute (lua_State *L) { + StkId base; + LClosure *cl; + TObject *k; const Instruction *pc; lua_Hook linehook; reinit: - lua_assert(L->ci->savedpc == NULL); + base = L->ci->base; + cl = &clvalue(base - 1)->l; + k = cl->p->k; + linehook = L->ci->linehook; L->ci->pc = &pc; - L->ci->top = base + cl->p->maxstacksize; - if (cl->p->is_vararg) /* varargs? */ - adjust_varargs(L, base, cl->p->numparams); - if (base > L->stack_last - cl->p->maxstacksize) - luaD_stackerror(L); - while (L->top < L->ci->top) - setnilvalue(L->top++); - L->top = L->ci->top; - linehook = L->ci->linehook = L->linehook; - pc = cl->p->code; + pc = L->ci->savedpc; + L->ci->savedpc = NULL; /* main loop of interpreter */ for (;;) { const Instruction i = *pc++; @@ -535,18 +500,21 @@ StkId luaV_execute (lua_State *L, const LClosure *cl, StkId base) { case OP_CALL: { StkId firstResult; int b = GETARG_B(i); - if (b != NO_REG) L->top = ra+b+1; - /* else previous instruction set top */ + int nresults; + if (b != 0) L->top = ra+b; /* else previous instruction set top */ + nresults = GETARG_C(i) - 1; firstResult = luaD_precall(L, ra); if (firstResult) { + if (firstResult == base) { /* yield?? */ + (L->ci-1)->savedpc = pc; + return NULL; + } /* it was a C function (`precall' called it); adjust results */ - luaV_poscall(L, GETARG_C(i), firstResult, L->ci); + luaD_poscall(L, nresults, firstResult); + if (nresults >= 0) L->top = L->ci->top; } else { /* it is a Lua function: `call' it */ - CallInfo *ci = L->ci; - (ci-1)->savedpc = pc; - base = ci->base; - cl = &clvalue(base - 1)->l; + (L->ci-1)->savedpc = pc; goto reinit; } break; @@ -556,19 +524,23 @@ StkId luaV_execute (lua_State *L, const LClosure *cl, StkId base) { int b; if (L->openupval) luaF_close(L, base); b = GETARG_B(i); - if (b != NO_REG) L->top = ra+b; + if (b != 0) L->top = ra+b-1; ci = L->ci - 1; if (ci->savedpc == NULL) return ra; else { /* previous function is Lua: continue its execution */ + int nresults; lua_assert(ttype(ci->base-1) == LUA_TFUNCTION); base = ci->base; /* restore previous values */ linehook = ci->linehook; cl = &clvalue(base - 1)->l; + k = cl->p->k; pc = ci->savedpc; ci->savedpc = NULL; lua_assert(GET_OPCODE(*(pc-1)) == OP_CALL); - luaV_poscall(L, GETARG_C(*(pc-1)), ra, ci); + nresults = GETARG_C(*(pc-1)) - 1; + luaD_poscall(L, nresults, ra); + if (nresults >= 0) L->top = L->ci->top; } break; } @@ -20,7 +20,7 @@ const TObject *luaV_tonumber (const TObject *obj, TObject *n); int luaV_tostring (lua_State *L, TObject *obj); void luaV_gettable (lua_State *L, StkId t, TObject *key, StkId res); void luaV_settable (lua_State *L, StkId t, TObject *key, StkId val); -StkId luaV_execute (lua_State *L, const LClosure *cl, StkId base); +StkId luaV_execute (lua_State *L); int luaV_lessthan (lua_State *L, const TObject *l, const TObject *r); void luaV_strconc (lua_State *L, int total, StkId top); |