diff --git a/lapi.c b/lapi.c index 8bc2ddd1..769eba13 100644 --- a/lapi.c +++ b/lapi.c @@ -187,7 +187,7 @@ LUA_API void lua_settop (lua_State *L, int idx) { api_check(L, idx <= ci->top.p - (func + 1), "new top too large"); diff = ((func + 1) + idx) - L->top.p; for (; diff > 0; diff--) - setnilvalue2s(L->top.p++); /* clear new slots */ + setnilvalue(s2v(L->top.p++)); /* clear new slots */ } else { api_check(L, -(idx+1) <= (L->top.p - (func + 1)), "invalid new top"); @@ -210,7 +210,7 @@ LUA_API void lua_closeslot (lua_State *L, int idx) { api_check(L, (L->ci->callstatus & CIST_TBC) && (L->tbclist.p == level), "no variable to close at given level"); level = luaF_close(L, level, CLOSEKTOP, 0); - setnilvalue2s(level); + setnilvalue(s2v(level)); lua_unlock(L); } @@ -366,7 +366,7 @@ LUA_API int lua_compare (lua_State *L, int index1, int index2, int op) { } -LUA_API unsigned lua_numbertocstring (lua_State *L, int idx, char *buff) { +LUA_API unsigned (lua_numbertocstring) (lua_State *L, int idx, char *buff) { const TValue *o = index2value(L, idx); if (ttisnumber(o)) { unsigned len = luaO_tostringbuff(o, buff); @@ -440,13 +440,7 @@ LUA_API lua_Unsigned lua_rawlen (lua_State *L, int idx) { case LUA_VSHRSTR: return cast(lua_Unsigned, tsvalue(o)->shrlen); case LUA_VLNGSTR: return cast(lua_Unsigned, tsvalue(o)->u.lnglen); case LUA_VUSERDATA: return cast(lua_Unsigned, uvalue(o)->len); - case LUA_VTABLE: { - lua_Unsigned res; - lua_lock(L); - res = luaH_getn(L, hvalue(o)); - lua_unlock(L); - return res; - } + case LUA_VTABLE: return luaH_getn(hvalue(o)); default: return 0; } } @@ -484,7 +478,7 @@ LUA_API lua_State *lua_tothread (lua_State *L, int idx) { /* ** Returns a pointer to the internal representation of an object. -** Note that ISO C does not allow the conversion of a pointer to +** Note that ANSI C does not allow the conversion of a pointer to ** function to a 'void*', so the conversion here goes through ** a 'size_t'. (As the returned pointer is only informative, this ** conversion should not be a problem.) @@ -513,7 +507,7 @@ LUA_API const void *lua_topointer (lua_State *L, int idx) { LUA_API void lua_pushnil (lua_State *L) { lua_lock(L); - setnilvalue2s(L->top.p); + setnilvalue(s2v(L->top.p)); api_incr_top(L); lua_unlock(L); } @@ -570,7 +564,7 @@ LUA_API const char *lua_pushexternalstring (lua_State *L, LUA_API const char *lua_pushstring (lua_State *L, const char *s) { lua_lock(L); if (s == NULL) - setnilvalue2s(L->top.p); + setnilvalue(s2v(L->top.p)); else { TString *ts; ts = luaS_new(L, s); @@ -685,7 +679,7 @@ static int auxgetstr (lua_State *L, const TValue *t, const char *k) { /* ** The following function assumes that the registry cannot be a weak -** table; so, an emergency collection while using the global table +** table, so that en mergency collection while using the global table ** cannot collect it. */ static void getGlobalTable (lua_State *L, TValue *gt) { @@ -743,7 +737,7 @@ LUA_API int lua_geti (lua_State *L, int idx, lua_Integer n) { static int finishrawget (lua_State *L, lu_byte tag) { if (tagisempty(tag)) /* avoid copying empty items to the stack */ - setnilvalue2s(L->top.p); + setnilvalue(s2v(L->top.p)); api_incr_top(L); lua_unlock(L); return novariant(tag); @@ -836,7 +830,7 @@ LUA_API int lua_getiuservalue (lua_State *L, int idx, int n) { o = index2value(L, idx); api_check(L, ttisfulluserdata(o), "full userdata expected"); if (n <= 0 || n > uvalue(o)->nuvalue) { - setnilvalue2s(L->top.p); + setnilvalue(s2v(L->top.p)); t = LUA_TNONE; } else { @@ -1122,7 +1116,6 @@ LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data, ZIO z; TStatus status; lua_lock(L); - luaC_checkGC(L); if (!chunkname) chunkname = "?"; luaZ_init(L, &z, reader, data); status = luaD_protectedparser(L, &z, chunkname, mode); @@ -1202,16 +1195,11 @@ LUA_API int lua_gc (lua_State *L, int what, ...) { case LUA_GCSTEP: { lu_byte oldstp = g->gcstp; l_mem n = cast(l_mem, va_arg(argp, size_t)); - l_mem newdebt; int work = 0; /* true if GC did some work */ g->gcstp = 0; /* allow GC to run (other bits must be zero here) */ if (n <= 0) - newdebt = 0; /* force to run one basic step */ - else if (g->GCdebt >= n - MAX_LMEM) /* no overflow? */ - newdebt = g->GCdebt - n; - else /* overflow */ - newdebt = -MAX_LMEM; /* set debt to mininum value */ - luaE_setdebt(g, newdebt); + n = g->GCdebt; /* force to run one basic step */ + luaE_setdebt(g, g->GCdebt - n); luaC_condGC(L, (void)0, work = 1); if (work && g->gcstate == GCSpause) /* end of cycle? */ res = 1; /* signal it */ @@ -1299,8 +1287,8 @@ LUA_API void lua_toclose (lua_State *L, int idx) { LUA_API void lua_concat (lua_State *L, int n) { lua_lock(L); + api_checknelems(L, n); if (n > 0) { - api_checkpop(L, n); luaV_concat(L, n); luaC_checkGC(L); } @@ -1418,7 +1406,7 @@ LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) { TValue *fi; lua_lock(L); fi = index2value(L, funcindex); - api_checkpop(L, 1); + api_checknelems(L, 1); name = aux_upvalue(fi, n, &val, &owner); if (name) { L->top.p--; diff --git a/lauxlib.c b/lauxlib.c index 8620c8b3..7f33f0ad 100644 --- a/lauxlib.c +++ b/lauxlib.c @@ -513,25 +513,12 @@ static const luaL_Reg boxmt[] = { /* box metamethods */ }; -/* -** Get/create metatable (MT) for boxes -*/ -static void getBoxMT (lua_State *L) { - const char *BOXMT = "_UBOX*"; /* key for the metatable */ - if (luaL_getmetatable(L, BOXMT) == LUA_TNIL) { /* MT not created yet? */ - luaL_newlibtable(L, boxmt); /* create it */ - luaL_setfuncs(L, boxmt, 0); /* initialize it */ - lua_copy(L, -1, -2); /* change stack from nil,MT to MT,MT */ - lua_setfield(L, LUA_REGISTRYINDEX, BOXMT); /* store MT in the registry */ - } -} - - static void newbox (lua_State *L) { UBox *box = (UBox *)lua_newuserdatauv(L, sizeof(UBox), 0); box->box = NULL; box->bsize = 0; - getBoxMT(L); + if (luaL_newmetatable(L, "_UBOX*")) /* creating metatable? */ + luaL_setfuncs(L, boxmt, 0); /* set its metamethods */ lua_setmetatable(L, -2); } @@ -755,7 +742,7 @@ typedef struct LoadF { static const char *getF (lua_State *L, void *ud, size_t *size) { LoadF *lf = (LoadF *)ud; - UNUSED(L); + (void)L; /* not used */ if (lf->n > 0) { /* are there pre-read characters to be read? */ *size = lf->n; /* return them (chars already in buffer) */ lf->n = 0; /* no more pre-read characters */ @@ -869,7 +856,7 @@ typedef struct LoadS { static const char *getS (lua_State *L, void *ud, size_t *size) { LoadS *ls = (LoadS *)ud; - UNUSED(L); + (void)L; /* not used */ if (ls->size == 0) return NULL; *size = ls->size; ls->size = 0; @@ -887,7 +874,7 @@ LUALIB_API int luaL_loadbufferx (lua_State *L, const char *buff, size_t size, LUALIB_API int luaL_loadstring (lua_State *L, const char *s) { - return luaL_loadbufferx(L, s, strlen(s), s, "t"); + return luaL_loadbuffer(L, s, strlen(s), s); } /* }====================================================== */ @@ -1059,8 +1046,8 @@ LUALIB_API const char *luaL_gsub (lua_State *L, const char *s, } -void *luaL_alloc (void *ud, void *ptr, size_t osize, size_t nsize) { - UNUSED(ud); UNUSED(osize); +static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) { + (void)ud; (void)osize; /* not used */ if (nsize == 0) { free(ptr); return NULL; @@ -1185,20 +1172,16 @@ static unsigned int luai_makeseed (void) { LUALIB_API unsigned int luaL_makeseed (lua_State *L) { - UNUSED(L); + (void)L; /* unused */ return luai_makeseed(); } -/* -** Use the name with parentheses so that headers can redefine it -** as a macro. -*/ -LUALIB_API lua_State *(luaL_newstate) (void) { - lua_State *L = lua_newstate(luaL_alloc, NULL, luaL_makeseed(NULL)); +LUALIB_API lua_State *luaL_newstate (void) { + lua_State *L = lua_newstate(l_alloc, NULL, luai_makeseed()); if (l_likely(L)) { lua_atpanic(L, &panic); - lua_setwarnf(L, warnfon, L); + lua_setwarnf(L, warnfoff, L); /* default is warnings off */ } return L; } diff --git a/lauxlib.h b/lauxlib.h index 2d015362..d8522098 100644 --- a/lauxlib.h +++ b/lauxlib.h @@ -81,9 +81,6 @@ LUALIB_API int (luaL_checkoption) (lua_State *L, int arg, const char *def, LUALIB_API int (luaL_fileresult) (lua_State *L, int stat, const char *fname); LUALIB_API int (luaL_execresult) (lua_State *L, int stat); -LUALIB_API void *(luaL_alloc) (void *ud, void *ptr, size_t osize, - size_t nsize); - /* predefined references */ #define LUA_NOREF (-2) @@ -103,7 +100,7 @@ LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s); LUALIB_API lua_State *(luaL_newstate) (void); -LUALIB_API unsigned (luaL_makeseed) (lua_State *L); +LUALIB_API unsigned luaL_makeseed (lua_State *L); LUALIB_API lua_Integer (luaL_len) (lua_State *L, int idx); diff --git a/lbaselib.c b/lbaselib.c index 3962ea53..b296c4b7 100644 --- a/lbaselib.c +++ b/lbaselib.c @@ -279,22 +279,21 @@ static int luaB_next (lua_State *L) { static int pairscont (lua_State *L, int status, lua_KContext k) { (void)L; (void)status; (void)k; /* unused */ - return 4; /* __pairs did all the work, just return its results */ + return 3; } static int luaB_pairs (lua_State *L) { luaL_checkany(L, 1); if (luaL_getmetafield(L, 1, "__pairs") == LUA_TNIL) { /* no metamethod? */ - lua_pushcfunction(L, luaB_next); /* will return generator and */ - lua_pushvalue(L, 1); /* state */ - lua_pushnil(L); /* initial value */ - lua_pushnil(L); /* to-be-closed object */ + lua_pushcfunction(L, luaB_next); /* will return generator, */ + lua_pushvalue(L, 1); /* state, */ + lua_pushnil(L); /* and initial value */ } else { lua_pushvalue(L, 1); /* argument 'self' to metamethod */ - lua_callk(L, 1, 4, 0, pairscont); /* get 4 values from metamethod */ + lua_callk(L, 1, 3, 0, pairscont); /* get 3 values from metamethod */ } - return 4; + return 3; } @@ -340,11 +339,9 @@ static int load_aux (lua_State *L, int status, int envidx) { static const char *getMode (lua_State *L, int idx) { - const char *mode = luaL_optstring(L, idx, NULL); - if (mode != NULL && strchr(mode, 'B') != NULL) { - /* Lua code cannot use fixed buffers */ + const char *mode = luaL_optstring(L, idx, "bt"); + if (strchr(mode, 'B') != NULL) /* Lua code cannot use fixed buffers */ luaL_argerror(L, idx, "invalid mode"); - } return mode; } @@ -366,24 +363,33 @@ static int luaB_loadfile (lua_State *L) { /* -** Reader for generic 'load' function. +** reserved slot, above all arguments, to hold a copy of the returned +** string to avoid it being collected while parsed. 'load' has four +** optional arguments (chunk, source name, mode, and environment). +*/ +#define RESERVEDSLOT 5 + + +/* +** Reader for generic 'load' function: 'lua_load' uses the +** stack for internal stuff, so the reader cannot change the +** stack top. Instead, it keeps its resulting string in a +** reserved slot inside the stack. */ static const char *generic_reader (lua_State *L, void *ud, size_t *size) { - int *firstcall = cast(int *, ud); + (void)(ud); /* not used */ luaL_checkstack(L, 2, "too many nested functions"); - if (*firstcall) - *firstcall = 0; - else - lua_pop(L, 1); /* remove previous result */ lua_pushvalue(L, 1); /* get function */ lua_call(L, 0, 1); /* call it */ if (lua_isnil(L, -1)) { + lua_pop(L, 1); /* pop result */ *size = 0; return NULL; } else if (l_unlikely(!lua_isstring(L, -1))) luaL_error(L, "reader function must return a string"); - return lua_tolstring(L, -1, size); + lua_replace(L, RESERVEDSLOT); /* save string in reserved slot */ + return lua_tolstring(L, RESERVEDSLOT, size); } @@ -398,10 +404,10 @@ static int luaB_load (lua_State *L) { status = luaL_loadbufferx(L, s, l, chunkname, mode); } else { /* loading from a reader function */ - int firstcall = 1; /* userdata for generic_reader */ const char *chunkname = luaL_optstring(L, 2, "=(load)"); luaL_checktype(L, 1, LUA_TFUNCTION); - status = lua_load(L, generic_reader, &firstcall, chunkname, mode); + lua_settop(L, RESERVEDSLOT); /* create reserved slot */ + status = lua_load(L, generic_reader, NULL, chunkname, mode); } return load_aux(L, status, env); } @@ -418,7 +424,7 @@ static int dofilecont (lua_State *L, int d1, lua_KContext d2) { static int luaB_dofile (lua_State *L) { const char *fname = luaL_optstring(L, 1, NULL); lua_settop(L, 1); - if (l_unlikely(luaL_loadfilex(L, fname, "bt") != LUA_OK)) + if (l_unlikely(luaL_loadfile(L, fname) != LUA_OK)) return lua_error(L); lua_callk(L, 0, LUA_MULTRET, 0, dofilecont); return dofilecont(L, 0, 0); diff --git a/lcode.c b/lcode.c index 8b61d5de..7ca895f1 100644 --- a/lcode.c +++ b/lcode.c @@ -45,7 +45,6 @@ l_noret luaK_semerror (LexState *ls, const char *fmt, ...) { va_list argp; pushvfstring(ls->L, argp, fmt, msg); ls->t.token = 0; /* remove "near " from final message */ - ls->linenumber = ls->lastline; /* back to line of last used token */ luaX_syntaxerror(ls, msg); } @@ -566,20 +565,20 @@ static int k2proto (FuncState *fs, TValue *key, TValue *v) { TValue val; Proto *f = fs->f; int tag = luaH_get(fs->kcache, key, &val); /* query scanner table */ + int k; if (!tagisempty(tag)) { /* is there an index there? */ - int k = cast_int(ivalue(&val)); + k = cast_int(ivalue(&val)); /* collisions can happen only for float keys */ lua_assert(ttisfloat(key) || luaV_rawequalobj(&f->k[k], v)); return k; /* reuse index */ } - else { /* constant not found; create a new entry */ - int k = addk(fs, f, v); - /* cache it for reuse; numerical value does not need GC barrier; - table is not a metatable, so it does not need to invalidate cache */ - setivalue(&val, k); - luaH_set(fs->ls->L, fs->kcache, key, &val); - return k; - } + /* constant not found; create a new entry */ + k = addk(fs, f, v); + /* cache it for reuse; numerical value does not need GC barrier; + table is not a metatable, so it does not need to invalidate cache */ + setivalue(&val, k); + luaH_set(fs->ls->L, fs->kcache, key, &val); + return k; } @@ -605,14 +604,13 @@ static int luaK_intK (FuncState *fs, lua_Integer n) { /* ** Add a float to list of constants and return its index. Floats ** with integral values need a different key, to avoid collision -** with actual integers. To that end, we add to the number its smaller +** with actual integers. To that, we add to the number its smaller ** power-of-two fraction that is still significant in its scale. -** (For doubles, the fraction would be 2^-52). +** For doubles, that would be 1/2^52. ** This method is not bulletproof: different numbers may generate the ** same key (e.g., very large numbers will overflow to 'inf') and for -** floats larger than 2^53 the result is still an integer. For those -** cases, just generate a new entry. At worst, this only wastes an entry -** with a duplicate. +** floats larger than 2^53 the result is still an integer. At worst, +** this only wastes an entry with a duplicate. */ static int luaK_numberK (FuncState *fs, lua_Number r) { TValue o, kv; @@ -627,7 +625,7 @@ static int luaK_numberK (FuncState *fs, lua_Number r) { const lua_Number k = r * (1 + q); /* key */ lua_Integer ik; setfltvalue(&kv, k); /* key as a TValue */ - if (!luaV_flttointeger(k, &ik, F2Ieq)) { /* not an integer value? */ + if (!luaV_flttointeger(k, &ik, F2Ieq)) { /* not an integral value? */ int n = k2proto(fs, &kv, &o); /* use key */ if (luaV_rawequalobj(&fs->f->k[n], &o)) /* correct value? */ return n; @@ -663,11 +661,11 @@ static int boolT (FuncState *fs) { ** Add nil to list of constants and return its index. */ static int nilK (FuncState *fs) { - lua_State *L = fs->ls->L; - TValue k; + TValue k, v; + setnilvalue(&v); /* cannot use nil as key; instead use table itself */ - sethvalue(L, &k, fs->kcache); - return k2proto(fs, &k, &G(L)->nilvalue); + sethvalue(fs->ls->L, &k, fs->kcache); + return k2proto(fs, &k, &v); } @@ -706,22 +704,6 @@ static void luaK_float (FuncState *fs, int reg, lua_Number f) { } -/* -** Get the value of 'var' in a register and generate an opcode to check -** whether that register is nil. 'k' is the index of the variable name -** in the list of constants. If its value cannot be encoded in Bx, a 0 -** will use '?' for the name. -*/ -void luaK_codecheckglobal (FuncState *fs, expdesc *var, int k, int line) { - luaK_exp2anyreg(fs, var); - luaK_fixline(fs, line); - k = (k >= MAXARG_Bx) ? 0 : k + 1; - luaK_codeABx(fs, OP_ERRNNIL, var->u.info, k); - luaK_fixline(fs, line); - freeexp(fs, var); -} - - /* ** Convert a constant in 'v' into an expression description 'e' */ @@ -802,15 +784,6 @@ void luaK_setoneret (FuncState *fs, expdesc *e) { } } -/* -** Change a vararg parameter into a regular local variable -*/ -void luaK_vapar2local (FuncState *fs, expdesc *var) { - needvatab(fs->f); /* 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 ). @@ -822,12 +795,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; /* (avoid a direct assignment; values overlap) */ + e->u.info = temp; /* (can't do a direct assignment; values overlap) */ e->k = VNONRELOC; /* becomes a non-relocatable value */ break; } @@ -859,12 +829,6 @@ void luaK_dischargevars (FuncState *fs, expdesc *e) { e->k = VRELOC; break; } - case VVARGIND: { - freeregs(fs, e->u.ind.t, e->u.ind.idx); - e->u.info = luaK_codeABC(fs, OP_GETVARG, 0, e->u.ind.t, e->u.ind.idx); - e->k = VRELOC; - break; - } case VVARARG: case VCALL: { luaK_setoneret(fs, e); break; @@ -1027,11 +991,11 @@ int luaK_exp2anyreg (FuncState *fs, expdesc *e) { /* -** Ensures final expression result is either in a register, -** in an upvalue, or it is the vararg parameter. +** Ensures final expression result is either in a register +** or in an upvalue. */ void luaK_exp2anyregup (FuncState *fs, expdesc *e) { - if ((e->k != VUPVAL && e->k != VVARGVAR) || hasjumps(e)) + if (e->k != VUPVAL || hasjumps(e)) luaK_exp2anyreg(fs, e); } @@ -1126,10 +1090,6 @@ void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) { codeABRK(fs, OP_SETFIELD, var->u.ind.t, var->u.ind.idx, ex); break; } - case VVARGIND: { - needvatab(fs->f); /* function will need a vararg table */ - /* now, assignment is to a regular table */ - } /* FALLTHROUGH */ case VINDEXED: { codeABRK(fs, OP_SETTABLE, var->u.ind.t, var->u.ind.idx, ex); break; @@ -1202,7 +1162,7 @@ void luaK_goiftrue (FuncState *fs, expdesc *e) { /* ** Emit code to go through if 'e' is false, jump otherwise. */ -static void luaK_goiffalse (FuncState *fs, expdesc *e) { +void luaK_goiffalse (FuncState *fs, expdesc *e) { int pc; /* pc of new jump */ luaK_dischargevars(fs, e); switch (e->k) { @@ -1263,7 +1223,7 @@ static void codenot (FuncState *fs, expdesc *e) { ** Check whether expression 'e' is a short literal string */ static int isKstr (FuncState *fs, expdesc *e) { - return (e->k == VK && !hasjumps(e) && e->u.info <= MAXINDEXRK && + return (e->k == VK && !hasjumps(e) && e->u.info <= MAXARG_B && ttisshrstring(&fs->f->k[e->u.info])); } @@ -1341,13 +1301,6 @@ void luaK_self (FuncState *fs, expdesc *e, expdesc *key) { } -/* auxiliary function to define indexing expressions */ -static void fillidxk (expdesc *t, int idx, expkind k) { - t->u.ind.idx = cast_byte(idx); - t->k = k; -} - - /* ** Create expression 't[k]'. 't' must have its final result already in a ** register or upvalue. Upvalues can only be indexed by literal strings. @@ -1359,33 +1312,31 @@ void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) { if (k->k == VKSTR) keystr = str2K(fs, k); lua_assert(!hasjumps(t) && - (t->k == VLOCAL || t->k == VVARGVAR || - t->k == VNONRELOC || t->k == VUPVAL)); + (t->k == VLOCAL || t->k == VNONRELOC || t->k == VUPVAL)); if (t->k == VUPVAL && !isKstr(fs, k)) /* upvalue indexed by non 'Kstr'? */ luaK_exp2anyreg(fs, t); /* put it in a register */ if (t->k == VUPVAL) { lu_byte temp = cast_byte(t->u.info); /* upvalue index */ - t->u.ind.t = temp; /* (avoid a direct assignment; values overlap) */ + t->u.ind.t = temp; /* (can't do a direct assignment; values overlap) */ lua_assert(isKstr(fs, k)); - fillidxk(t, k->u.info, VINDEXUP); /* literal short string */ - } - else if (t->k == VVARGVAR) { /* indexing the vararg parameter? */ - int kreg = luaK_exp2anyreg(fs, k); /* put key in some register */ - lu_byte vreg = cast_byte(t->u.var.ridx); /* register with vararg param. */ - lua_assert(vreg == fs->f->numparams); - t->u.ind.t = vreg; /* (avoid a direct assignment; values may overlap?) */ - fillidxk(t, kreg, VVARGIND); /* 't' represents 'vararg[k]' */ + t->u.ind.idx = cast_short(k->u.info); /* literal short string */ + t->k = VINDEXUP; } else { /* register index of the table */ - lu_byte temp = cast_byte((t->k == VLOCAL) ? t->u.var.ridx: t->u.info); - t->u.ind.t = temp; /* (avoid a direct assignment; values may overlap?) */ - if (isKstr(fs, k)) - fillidxk(t, k->u.info, VINDEXSTR); /* literal short string */ - else if (isCint(k)) /* int. constant in proper range? */ - fillidxk(t, cast_int(k->u.ival), VINDEXI); - else - fillidxk(t, luaK_exp2anyreg(fs, k), VINDEXED); /* register */ + t->u.ind.t = cast_byte((t->k == VLOCAL) ? t->u.var.ridx: t->u.info); + if (isKstr(fs, k)) { + t->u.ind.idx = cast_short(k->u.info); /* literal short string */ + t->k = VINDEXSTR; + } + else if (isCint(k)) { /* int. constant in proper range? */ + t->u.ind.idx = cast_short(k->u.ival); + t->k = VINDEXI; + } + else { + t->u.ind.idx = cast_short(luaK_exp2anyreg(fs, k)); /* register */ + t->k = VINDEXED; + } } t->u.ind.keystr = keystr; /* string index in 'k' */ t->u.ind.ro = 0; /* by default, not read-only */ @@ -1930,14 +1881,14 @@ static int finaltarget (Instruction *code, int i) { void luaK_finish (FuncState *fs) { int i; Proto *p = fs->f; - if (p->flag & PF_VATAB) /* will it use a vararg table? */ - p->flag &= cast_byte(~PF_VAHID); /* then it will not use hidden args. */ for (i = 0; i < fs->pc; i++) { Instruction *pc = &p->code[i]; + /* avoid "not used" warnings when assert is off (for 'onelua.c') */ + (void)luaP_isOT; (void)luaP_isIT; lua_assert(i == 0 || luaP_isOT(*(pc - 1)) == luaP_isIT(*pc)); switch (GET_OPCODE(*pc)) { case OP_RETURN0: case OP_RETURN1: { - if (!(fs->needclose || (p->flag & PF_VAHID))) + if (!(fs->needclose || (p->flag & PF_ISVARARG))) break; /* no extra work */ /* else use OP_RETURN to do the extra work */ SET_OPCODE(*pc, OP_RETURN); @@ -1945,23 +1896,13 @@ void luaK_finish (FuncState *fs) { case OP_RETURN: case OP_TAILCALL: { if (fs->needclose) SETARG_k(*pc, 1); /* signal that it needs to close */ - if (p->flag & PF_VAHID) /* does it use hidden arguments? */ - SETARG_C(*pc, p->numparams + 1); /* signal that */ + if (p->flag & PF_ISVARARG) + SETARG_C(*pc, p->numparams + 1); /* signal that it is vararg */ break; } - case OP_GETVARG: { - if (p->flag & PF_VATAB) /* function has a vararg table? */ - SET_OPCODE(*pc, OP_GETTABLE); /* must get vararg there */ - break; - } - case OP_VARARG: { - if (p->flag & PF_VATAB) /* function has a vararg table? */ - SETARG_k(*pc, 1); /* must get vararg there */ - break; - } - case OP_JMP: { /* to optimize jumps to jumps */ + case OP_JMP: { int target = finaltarget(p->code, i); - fixjump(fs, i, target); /* jump directly to final target */ + fixjump(fs, i, target); break; } default: break; diff --git a/lcode.h b/lcode.h index 09e5c802..94fc2417 100644 --- a/lcode.h +++ b/lcode.h @@ -68,12 +68,9 @@ LUAI_FUNC int luaK_codevABCk (FuncState *fs, OpCode o, int A, int B, int C, LUAI_FUNC int luaK_exp2const (FuncState *fs, const expdesc *e, TValue *v); LUAI_FUNC void luaK_fixline (FuncState *fs, int line); LUAI_FUNC void luaK_nil (FuncState *fs, int from, int n); -LUAI_FUNC void luaK_codecheckglobal (FuncState *fs, expdesc *var, int k, - int line); 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); @@ -82,6 +79,7 @@ LUAI_FUNC void luaK_exp2val (FuncState *fs, expdesc *e); LUAI_FUNC void luaK_self (FuncState *fs, expdesc *e, expdesc *key); LUAI_FUNC void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k); LUAI_FUNC void luaK_goiftrue (FuncState *fs, expdesc *e); +LUAI_FUNC void luaK_goiffalse (FuncState *fs, expdesc *e); LUAI_FUNC void luaK_storevar (FuncState *fs, expdesc *var, expdesc *e); LUAI_FUNC void luaK_setreturns (FuncState *fs, expdesc *e, int nresults); LUAI_FUNC void luaK_setoneret (FuncState *fs, expdesc *e); diff --git a/lcorolib.c b/lcorolib.c index eb30bf4d..23dd8441 100644 --- a/lcorolib.c +++ b/lcorolib.c @@ -189,17 +189,15 @@ static int luaB_close (lua_State *L) { return 2; } } - case COS_NORM: - return luaL_error(L, "cannot close a %s coroutine", statname[status]); - case COS_RUN: + case COS_RUN: /* running coroutine? */ lua_geti(L, LUA_REGISTRYINDEX, LUA_RIDX_MAINTHREAD); /* get main */ if (lua_tothread(L, -1) == co) return luaL_error(L, "cannot close main thread"); lua_closethread(co, L); /* close itself */ - /* previous call does not return *//* FALLTHROUGH */ - default: - lua_assert(0); + lua_assert(0); /* previous call does not return */ return 0; + default: /* normal or running coroutine */ + return luaL_error(L, "cannot close a %s coroutine", statname[status]); } } diff --git a/lctype.c b/lctype.c index b1a43e44..95422809 100644 --- a/lctype.c +++ b/lctype.c @@ -18,7 +18,7 @@ #if defined (LUA_UCID) /* accept UniCode IDentifiers? */ -/* consider all non-ASCII codepoints to be alphabetic */ +/* consider all non-ascii codepoints to be alphabetic */ #define NONA 0x01 #else #define NONA 0x00 /* default */ diff --git a/ldblib.c b/ldblib.c index 051327cc..c7b74812 100644 --- a/ldblib.c +++ b/ldblib.c @@ -427,7 +427,7 @@ static int db_debug (lua_State *L) { if (fgets(buffer, sizeof(buffer), stdin) == NULL || strcmp(buffer, "cont\n") == 0) return 0; - if (luaL_loadbufferx(L, buffer, strlen(buffer), "=(debug command)", "t") || + if (luaL_loadbuffer(L, buffer, strlen(buffer), "=(debug command)") || lua_pcall(L, 0, 0, 0)) lua_writestringerror("%s\n", luaL_tolstring(L, -1, NULL)); lua_settop(L, 0); /* remove eventual returns */ diff --git a/ldebug.c b/ldebug.c index 61c52749..9110f437 100644 --- a/ldebug.c +++ b/ldebug.c @@ -150,7 +150,7 @@ LUA_API lua_Hook lua_gethook (lua_State *L) { LUA_API int lua_gethookmask (lua_State *L) { - return cast_int(L->hookmask); + return L->hookmask; } @@ -184,7 +184,7 @@ static const char *upvalname (const Proto *p, int uv) { static const char *findvararg (CallInfo *ci, int n, StkId *pos) { - if (clLvalue(s2v(ci->func.p))->p->flag & PF_VAHID) { + if (clLvalue(s2v(ci->func.p))->p->flag & PF_ISVARARG) { int nextra = ci->u.l.nextraargs; if (n >= -nextra) { /* 'n' is negative */ *pos = ci->func.p - nextra - (n + 1); @@ -291,7 +291,7 @@ static int nextline (const Proto *p, int currentline, int pc) { static void collectvalidlines (lua_State *L, Closure *f) { if (!LuaClosure(f)) { - setnilvalue2s(L->top.p); + setnilvalue(s2v(L->top.p)); api_incr_top(L); } else { @@ -304,7 +304,7 @@ static void collectvalidlines (lua_State *L, Closure *f) { int i; TValue v; setbtvalue(&v); /* boolean 'true' to be the value of all indices */ - if (!(isvararg(p))) /* regular function? */ + if (!(p->flag & PF_ISVARARG)) /* regular function? */ i = 0; /* consider all instructions */ else { /* vararg function */ lua_assert(GET_OPCODE(p->code[0]) == OP_VARARGPREP); @@ -348,7 +348,7 @@ static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar, ar->nparams = 0; } else { - ar->isvararg = (isvararg(f->l.p)) ? 1 : 0; + ar->isvararg = (f->l.p->flag & PF_ISVARARG) ? 1 : 0; ar->nparams = f->l.p->numparams; } break; @@ -580,7 +580,7 @@ static const char *getobjname (const Proto *p, int lastpc, int reg, kname(p, k, name); return isEnv(p, lastpc, i, 1); } - case OP_GETTABLE: case OP_GETVARG: { + case OP_GETTABLE: { int k = GETARG_C(i); /* key index */ rname(p, lastpc, k, name); return isEnv(p, lastpc, i, 0); @@ -814,14 +814,6 @@ l_noret luaG_ordererror (lua_State *L, const TValue *p1, const TValue *p2) { } -l_noret luaG_errnnil (lua_State *L, LClosure *cl, int k) { - const char *globalname = "?"; /* default name if k == 0 */ - if (k > 0) - kname(cl->p, k - 1, &globalname); - luaG_runerror(L, "global '%s' already defined", globalname); -} - - /* add src:line information to 'msg' */ const char *luaG_addinfo (lua_State *L, const char *msg, TString *src, int line) { @@ -912,7 +904,7 @@ int luaG_tracecall (lua_State *L) { Proto *p = ci_func(ci)->p; ci->u.l.trap = 1; /* ensure hooks will be checked */ if (ci->u.l.savedpc == p->code) { /* first instruction (not resuming)? */ - if (isvararg(p)) + if (p->flag & PF_ISVARARG) return 0; /* hooks will start at VARARGPREP instruction */ else if (!(ci->callstatus & CIST_HOOKYIELD)) /* not yielded? */ luaD_hookcall(L, ci); /* check 'call' hook */ diff --git a/ldebug.h b/ldebug.h index 20d07818..2bfce3cb 100644 --- a/ldebug.h +++ b/ldebug.h @@ -53,7 +53,6 @@ LUAI_FUNC l_noret luaG_tointerror (lua_State *L, const TValue *p1, const TValue *p2); LUAI_FUNC l_noret luaG_ordererror (lua_State *L, const TValue *p1, const TValue *p2); -LUAI_FUNC l_noret luaG_errnnil (lua_State *L, LClosure *cl, int k); LUAI_FUNC l_noret luaG_runerror (lua_State *L, const char *fmt, ...); LUAI_FUNC const char *luaG_addinfo (lua_State *L, const char *msg, TString *src, int line); diff --git a/ldo.c b/ldo.c index fe8bf20f..776519dc 100644 --- a/ldo.c +++ b/ldo.c @@ -57,18 +57,10 @@ ** ======================================================= */ -/* chained list of long jump buffers */ -typedef struct lua_longjmp { - struct lua_longjmp *previous; - jmp_buf b; - volatile TStatus status; /* error code */ -} lua_longjmp; - - /* ** LUAI_THROW/LUAI_TRY define how Lua does exception handling. By ** default, Lua handles errors with exceptions when compiling as -** C++ code, with _longjmp/_setjmp when available (POSIX), and with +** C++ code, with _longjmp/_setjmp when asked to use them, and with ** longjmp/setjmp otherwise. */ #if !defined(LUAI_THROW) /* { */ @@ -77,38 +69,38 @@ typedef struct lua_longjmp { /* C++ exceptions */ #define LUAI_THROW(L,c) throw(c) - -static void LUAI_TRY (lua_State *L, lua_longjmp *c, Pfunc f, void *ud) { - try { - f(L, ud); /* call function protected */ - } - catch (lua_longjmp *c1) { /* Lua error */ - if (c1 != c) /* not the correct level? */ - throw; /* rethrow to upper level */ - } - catch (...) { /* non-Lua exception */ - c->status = -1; /* create some error code */ - } -} - +#define LUAI_TRY(L,c,f,ud) \ + try { (f)(L, ud); } catch(...) { if ((c)->status == 0) (c)->status = -1; } +#define luai_jmpbuf int /* dummy field */ #elif defined(LUA_USE_POSIX) /* }{ */ -/* in POSIX, use _longjmp/_setjmp (more efficient) */ +/* in POSIX, try _longjmp/_setjmp (more efficient) */ #define LUAI_THROW(L,c) _longjmp((c)->b, 1) #define LUAI_TRY(L,c,f,ud) if (_setjmp((c)->b) == 0) ((f)(L, ud)) +#define luai_jmpbuf jmp_buf #else /* }{ */ /* ISO C handling with long jumps */ #define LUAI_THROW(L,c) longjmp((c)->b, 1) #define LUAI_TRY(L,c,f,ud) if (setjmp((c)->b) == 0) ((f)(L, ud)) +#define luai_jmpbuf jmp_buf #endif /* } */ #endif /* } */ + +/* chain list of long jump buffers */ +struct lua_longjmp { + struct lua_longjmp *previous; + luai_jmpbuf b; + volatile TStatus status; /* error code */ +}; + + void luaD_seterrorobj (lua_State *L, TStatus errcode, StkId oldtop) { if (errcode == LUA_ERRMEM) { /* memory error? */ setsvalue2s(L, oldtop, G(L)->memerrmsg); /* reuse preregistered msg. */ @@ -159,7 +151,7 @@ l_noret luaD_throwbaselevel (lua_State *L, TStatus errcode) { TStatus luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) { l_uint32 oldnCcalls = L->nCcalls; - lua_longjmp lj; + struct lua_longjmp lj; lj.status = LUA_OK; lj.previous = L->errorJmp; /* chain new error handler */ L->errorJmp = &lj; @@ -182,20 +174,6 @@ TStatus luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) { #define STACKERRSPACE 200 -/* -** LUAI_MAXSTACK limits the size of the Lua stack. -** It must fit into INT_MAX/2. -*/ - -#if !defined(LUAI_MAXSTACK) -#if 1000000 < (INT_MAX / 2) -#define LUAI_MAXSTACK 1000000 -#else -#define LUAI_MAXSTACK (INT_MAX / 2u) -#endif -#endif - - /* maximum stack size that respects size_t */ #define MAXSTACK_BYSIZET ((MAX_SIZET / sizeof(StackValue)) - STACKERRSPACE) @@ -211,7 +189,7 @@ TStatus luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) { #define ERRORSTACKSIZE (MAXSTACK + STACKERRSPACE) -/* raise a stack error while running the message handler */ +/* raise an error while running the message handler */ l_noret luaD_errerr (lua_State *L) { TString *msg = luaS_newliteral(L, "error in error handling"); setsvalue2s(L, L->top.p, msg); @@ -220,25 +198,6 @@ l_noret luaD_errerr (lua_State *L) { } -/* -** Check whether stacks have enough space to run a simple function (such -** as a finalizer): At least BASIC_STACK_SIZE in the Lua stack, two -** available CallInfos, and two "slots" in the C stack. -*/ -int luaD_checkminstack (lua_State *L) { - if (getCcalls(L) >= LUAI_MAXCCALLS - 2) - return 0; /* not enough C-stack slots */ - if (L->ci->next == NULL && luaE_extendCI(L, 0) == NULL) - return 0; /* unable to allocate first ci */ - if (L->ci->next->next == NULL && luaE_extendCI(L, 0) == NULL) - return 0; /* unable to allocate second ci */ - if (L->stack_last.p - L->top.p >= BASIC_STACK_SIZE) - return 1; /* enough (BASIC_STACK_SIZE) free slots in the Lua stack */ - else /* try to grow stack to a size with enough free slots */ - return luaD_growstack(L, BASIC_STACK_SIZE, 0); -} - - /* ** In ISO C, any pointer use after the pointer has been deallocated is ** undefined behavior. So, before a stack reallocation, all pointers @@ -349,7 +308,7 @@ int luaD_reallocstack (lua_State *L, int newsize, int raiseerror) { correctstack(L, oldstack); /* change offsets back to pointers */ L->stack_last.p = L->stack.p + newsize; for (i = oldsize + EXTRA_STACK; i < newsize + EXTRA_STACK; i++) - setnilvalue2s(newstack + i); /* erase new segment */ + setnilvalue(s2v(newstack + i)); /* erase new segment */ return 1; } @@ -366,7 +325,7 @@ int luaD_growstack (lua_State *L, int n, int raiseerror) { a stack error; cannot grow further than that. */ lua_assert(stacksize(L) == ERRORSTACKSIZE); if (raiseerror) - luaD_errerr(L); /* stack error inside message handler */ + luaD_errerr(L); /* error inside message handler */ return 0; /* if not 'raiseerror', just signal it */ } else if (n < MAXSTACK) { /* avoids arithmetic overflows */ @@ -430,6 +389,12 @@ void luaD_shrinkstack (lua_State *L) { luaE_shrinkCI(L); /* shrink CI list */ } + +void luaD_inctop (lua_State *L) { + L->top.p++; + luaD_checkstack(L, 1); +} + /* }================================================================== */ @@ -500,7 +465,7 @@ static void rethook (lua_State *L, CallInfo *ci, int nres) { int ftransfer; if (isLua(ci)) { Proto *p = ci_func(ci)->p; - if (p->flag & PF_VAHID) + if (p->flag & PF_ISVARARG) delta = ci->u.l.nextraargs + p->numparams + 1; } ci->func.p += delta; /* if vararg, back to virtual 'func' */ @@ -548,7 +513,7 @@ l_sinline void genmoveresults (lua_State *L, StkId res, int nres, for (i = 0; i < nres; i++) /* move all results to correct place */ setobjs2s(L, res + i, firstresult + i); for (; i < wanted; i++) /* complete wanted number of results */ - setnilvalue2s(res + i); + setnilvalue(s2v(res + i)); L->top.p = res + wanted; /* top points after the last result */ } @@ -568,7 +533,7 @@ l_sinline void moveresults (lua_State *L, StkId res, int nres, return; case 1 + 1: /* one value needed */ if (nres == 0) /* no results? */ - setnilvalue2s(res); /* adjust with nil */ + setnilvalue(s2v(res)); /* adjust with nil */ else /* at least one result */ setobjs2s(L, res, L->top.p - nres); /* move it to proper place */ L->top.p = res + 1; @@ -618,7 +583,7 @@ void luaD_poscall (lua_State *L, CallInfo *ci, int nres) { -#define next_ci(L) (L->ci->next ? L->ci->next : luaE_extendCI(L, 1)) +#define next_ci(L) (L->ci->next ? L->ci->next : luaE_extendCI(L)) /* @@ -688,7 +653,7 @@ int luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, setobjs2s(L, ci->func.p + i, func + i); func = ci->func.p; /* moved-down function */ for (; narg1 <= nfixparams; narg1++) - setnilvalue2s(func + narg1); /* complete missing arguments */ + setnilvalue(s2v(func + narg1)); /* complete missing arguments */ ci->top.p = func + 1 + fsize; /* top for new function */ lua_assert(ci->top.p <= L->stack_last.p); ci->u.l.savedpc = p->code; /* starting point */ @@ -735,7 +700,7 @@ CallInfo *luaD_precall (lua_State *L, StkId func, int nresults) { L->ci = ci = prepCallInfo(L, func, status, func + 1 + fsize); ci->u.l.savedpc = p->code; /* starting point */ for (; narg < nfixparams; narg++) - setnilvalue2s(L->top.p++); /* complete missing arguments */ + setnilvalue(s2v(L->top.p++)); /* complete missing arguments */ lua_assert(ci->top.p <= L->stack_last.p); return ci; } @@ -1122,54 +1087,28 @@ static void checkmode (lua_State *L, const char *mode, const char *x) { } -/* -** Before the first call to the reader function, Lua reserves a slot -** with a table for anchoring stuff. -*/ static void f_parser (lua_State *L, void *ud) { LClosure *cl; struct SParser *p = cast(struct SParser *, ud); const char *mode = p->mode ? p->mode : "bt"; - int c; - Table *anchor; - ptrdiff_t otop = savestack(L, L->top.p); /* original top */ - luaD_checkstack(L, 2); - anchor = luaH_new(L); /* create the anchor table */ - sethvalue2s(L, L->top.p++, anchor); /* anchor the anchor table */ - c = zgetc(p->z); /* read first character */ + int c = zgetc(p->z); /* read first character */ if (c == LUA_SIGNATURE[0]) { int fixed = 0; if (strchr(mode, 'B') != NULL) fixed = 1; else checkmode(L, mode, "binary"); - cl = luaU_undump(L, p->z, anchor, p->name, fixed); + cl = luaU_undump(L, p->z, p->name, fixed); } else { checkmode(L, mode, "text"); - cl = luaY_parser(L, p->z, anchor, &p->buff, &p->dyd, p->name, c); + cl = luaY_parser(L, p->z, &p->buff, &p->dyd, p->name, c); } - L->top.p = restorestack(L, otop); /* restore stack */ - setclLvalue2s(L, L->top.p++, cl); /* push closure */ lua_assert(cl->nupvalues == cl->p->sizeupvalues); luaF_initupvals(L, cl); } -/* -** Anchor an object in a table in the stack. First, anchor the object -** temporarily in the stack, as luaH_set may call an emergency GC. -** Then, add it in the table with itself as its key. -*/ -void luaD_anchorobj (lua_State *L, Table *anchor, GCObject *obj) { - setgcovalue(L, s2v(L->top.p++), obj); /* temporary anchor in the stack */ - luaH_set(L, anchor, s2v(L->top.p - 1), s2v(L->top.p - 1)); - /* Because this is a new key, luaH_set will call the GC barrier, so - we don't need to call the barrier again here */ - L->top.p--; -} - - TStatus luaD_protectedparser (lua_State *L, ZIO *z, const char *name, const char *mode) { struct SParser p; diff --git a/ldo.h b/ldo.h index 85a00e38..2d4ca8be 100644 --- a/ldo.h +++ b/ldo.h @@ -88,8 +88,7 @@ LUAI_FUNC void luaD_poscall (lua_State *L, CallInfo *ci, int nres); LUAI_FUNC int luaD_reallocstack (lua_State *L, int newsize, int raiseerror); LUAI_FUNC int luaD_growstack (lua_State *L, int n, int raiseerror); LUAI_FUNC void luaD_shrinkstack (lua_State *L); -LUAI_FUNC int luaD_checkminstack (lua_State *L); -LUAI_FUNC void luaD_anchorobj (lua_State *L, Table *anchor, GCObject *obj); +LUAI_FUNC void luaD_inctop (lua_State *L); LUAI_FUNC l_noret luaD_throw (lua_State *L, TStatus errcode); LUAI_FUNC l_noret luaD_throwbaselevel (lua_State *L, TStatus errcode); diff --git a/ldump.c b/ldump.c index 57957889..a75b20d2 100644 --- a/ldump.c +++ b/ldump.c @@ -132,31 +132,27 @@ static void dumpInteger (DumpState *D, lua_Integer x) { /* -** Dump a String. First dump its "size": -** size==0 is followed by an index and means "reuse saved string with -** that index"; index==0 means NULL. -** size>=1 is followed by the string contents with real size==size-1 and -** means that string, which will be saved with the next available index. -** The real size does not include the ending '\0' (which is not dumped), -** so adding 1 to it cannot overflow a size_t. +** Dump a String. First dump its "size": size==0 means NULL; +** size==1 is followed by an index and means "reuse saved string with +** that index"; size>=2 is followed by the string contents with real +** size==size-2 and means that string, which will be saved with +** the next available index. */ static void dumpString (DumpState *D, TString *ts) { - if (ts == NULL) { - dumpVarint(D, 0); /* will "reuse" NULL */ - dumpVarint(D, 0); /* special index for NULL */ - } + if (ts == NULL) + dumpSize(D, 0); else { TValue idx; int tag = luaH_getstr(D->h, ts, &idx); if (!tagisempty(tag)) { /* string already saved? */ - dumpVarint(D, 0); /* reuse a saved string */ + dumpVarint(D, 1); /* reuse a saved string */ dumpVarint(D, l_castS2U(ivalue(&idx))); /* index of saved string */ } else { /* must write and save the string */ TValue key, value; /* to save the string in the hash */ size_t size; const char *s = getlstr(ts, size); - dumpSize(D, size + 1); + dumpSize(D, size + 2); dumpVector(D, s, size + 1); /* include ending '\0' */ D->nstr++; /* one more saved string */ setsvalue(D->L, &key, ts); /* the string is the key */ diff --git a/lfunc.c b/lfunc.c index b6fd9ceb..da7c6239 100644 --- a/lfunc.c +++ b/lfunc.c @@ -196,7 +196,8 @@ void luaF_unlinkupval (UpVal *uv) { */ void luaF_closeupval (lua_State *L, StkId level) { UpVal *uv; - while ((uv = L->openupval) != NULL && uplevel(uv) >= level) { + StkId upl; /* stack index pointed by 'uv' */ + while ((uv = L->openupval) != NULL && (upl = uplevel(uv)) >= level) { TValue *slot = &uv->u.value; /* new position for value */ lua_assert(uplevel(uv) < L->top.p); luaF_unlinkupval(uv); /* remove upvalue from 'openupval' list */ diff --git a/lgc.c b/lgc.c index cf4160c1..bbaa5ff7 100644 --- a/lgc.c +++ b/lgc.c @@ -594,10 +594,10 @@ static void traversestrongtable (global_State *g, Table *h) { */ static int getmode (global_State *g, Table *h) { const TValue *mode = gfasttm(g, h->metatable, TM_MODE); - if (mode == NULL || !ttisstring(mode)) - return 0; /* ignore non-string modes */ + if (mode == NULL || !ttisshrstring(mode)) + return 0; /* ignore non-(short)string modes */ else { - const char *smode = getstr(tsvalue(mode)); + const char *smode = getshrstr(tsvalue(mode)); const char *weakkey = strchr(smode, 'k'); const char *weakvalue = strchr(smode, 'v'); return ((weakkey != NULL) << 1) | (weakvalue != NULL); @@ -624,7 +624,7 @@ static l_mem traversetable (global_State *g, Table *h) { linkgclist(h, g->allweak); /* must clear collected entries */ break; } - return cast(l_mem, 1 + 2*sizenode(h) + h->asize); + return 1 + 2*sizenode(h) + h->asize; } @@ -709,7 +709,7 @@ static l_mem traversethread (global_State *g, lua_State *th) { if (!g->gcemergency) luaD_shrinkstack(th); /* do not change stack in emergency cycle */ for (o = th->top.p; o < th->stack_last.p + EXTRA_STACK; o++) - setnilvalue2s(o); /* clear dead stack slice */ + setnilvalue(s2v(o)); /* clear dead stack slice */ /* 'remarkupvals' may have removed thread from 'twups' list */ if (!isintwups(th) && th->openupval != NULL) { th->twups = g->twups; /* link it back to the list */ @@ -1293,7 +1293,7 @@ static void finishgencycle (lua_State *L, global_State *g) { correctgraylists(g); checkSizes(L, g); g->gcstate = GCSpropagate; /* skip restart */ - if (g->tobefnz != NULL && !g->gcemergency && luaD_checkminstack(L)) + if (!g->gcemergency) callallpendingfinalizers(L); } @@ -1472,8 +1472,7 @@ static int checkmajorminor (lua_State *L, global_State *g) { if (g->gckind == KGC_GENMAJOR) { /* generational mode? */ l_mem numbytes = gettotalbytes(g); l_mem addedbytes = numbytes - g->GCmajorminor; - l_mem limit = (addedbytes < 0) ? 0 - : applygcparam(g, MAJORMINOR, addedbytes); + l_mem limit = applygcparam(g, MAJORMINOR, addedbytes); l_mem tobecollected = numbytes - g->GCmarked; if (tobecollected > limit) { atomic2gen(L, g); /* return to generational mode */ @@ -1668,13 +1667,12 @@ static l_mem singlestep (lua_State *L, int fast) { break; } case GCScallfin: { /* call finalizers */ - if (g->tobefnz && !g->gcemergency && luaD_checkminstack(L)) { + if (g->tobefnz && !g->gcemergency) { g->gcstopem = 0; /* ok collections during finalizers */ GCTM(L); /* call one finalizer */ stepresult = CWUFIN; } - else { /* no more finalizers or emergency mode or not enough stack - to run finalizers */ + else { /* emergency mode or no more finalizers */ g->gcstate = GCSpause; /* finish collection */ stepresult = step2pause; } diff --git a/lgc.h b/lgc.h index 193ac0fc..ee054179 100644 --- a/lgc.h +++ b/lgc.h @@ -231,9 +231,8 @@ #endif #define luaC_condGC(L,pre,pos) \ - { if (G(L)->GCdebt <= 0) \ - { pre; luaC_step(L); condchangemem(L,{},{},0); pos;} \ - else condchangemem(L,pre,pos,0); } + { if (G(L)->GCdebt <= 0) { pre; luaC_step(L); pos;}; \ + condchangemem(L,pre,pos,0); } /* more often than not, 'pre'/'pos' are empty */ #define luaC_checkGC(L) luaC_condGC(L,(void)0,(void)0) diff --git a/liolib.c b/liolib.c index 57615e6f..c8f165cb 100644 --- a/liolib.c +++ b/liolib.c @@ -114,7 +114,7 @@ static int l_checkmode (const char *mode) { #if !defined(l_fseek) /* { */ -#if defined(LUA_USE_POSIX) || defined(LUA_USE_OFF_T) /* { */ +#if defined(LUA_USE_POSIX) /* { */ #include diff --git a/ljumptab.h b/ljumptab.h index 52fa6d74..8306f250 100644 --- a/ljumptab.h +++ b/ljumptab.h @@ -21,7 +21,7 @@ static const void *const disptab[NUM_OPCODES] = { #if 0 ** you can update the following list with this command: ** -** sed -n '/^OP_/!d; s/OP_/\&\&L_OP_/ ; s/,.*/,/ ; s/\/.*// ; p' lopcodes.h +** sed -n '/^OP_/\!d; s/OP_/\&\&L_OP_/ ; s/,.*/,/ ; s/\/.*// ; p' lopcodes.h ** #endif @@ -57,8 +57,8 @@ static const void *const disptab[NUM_OPCODES] = { &&L_OP_BANDK, &&L_OP_BORK, &&L_OP_BXORK, -&&L_OP_SHLI, &&L_OP_SHRI, +&&L_OP_SHLI, &&L_OP_ADD, &&L_OP_SUB, &&L_OP_MUL, @@ -106,8 +106,6 @@ static const void *const disptab[NUM_OPCODES] = { &&L_OP_SETLIST, &&L_OP_CLOSURE, &&L_OP_VARARG, -&&L_OP_GETVARG, -&&L_OP_ERRNNIL, &&L_OP_VARARGPREP, &&L_OP_EXTRAARG diff --git a/llex.c b/llex.c index 7cd9fcaf..f8bb3ea4 100644 --- a/llex.c +++ b/llex.c @@ -188,7 +188,7 @@ void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source, so they cannot be collected */ ls->envn = luaS_newliteral(L, LUA_ENV); /* get env string */ ls->brkn = luaS_newliteral(L, "break"); /* get "break" string */ -#if LUA_COMPAT_GLOBAL +#if defined(LUA_COMPAT_GLOBAL) /* compatibility mode: "global" is not a reserved word */ ls->glbn = luaS_newliteral(L, "global"); /* get "global" string */ ls->glbn->extra = 0; /* mark it as not reserved */ diff --git a/llimits.h b/llimits.h index 3f037255..223b5e6c 100644 --- a/llimits.h +++ b/llimits.h @@ -20,8 +20,8 @@ /* ** 'l_mem' is a signed integer big enough to count the total memory ** used by Lua. (It is signed due to the use of debt in several -** computations.) 'lu_mem' is a corresponding unsigned type. Usually, -** 'ptrdiff_t' should work, but we use 'long' for 16-bit machines. +** computations.) Usually, 'ptrdiff_t' should work, but we use 'long' +** for 16-bit machines. */ #if defined(LUAI_MEM) /* { external definitions? */ typedef LUAI_MEM l_mem; @@ -59,6 +59,13 @@ typedef lu_byte TStatus; #define MAX_SIZE (sizeof(size_t) < sizeof(lua_Integer) ? MAX_SIZET \ : cast_sizet(LUA_MAXINTEGER)) +/* +** floor of the log2 of the maximum signed value for integral type 't'. +** (That is, maximum 'n' such that '2^n' fits in the given signed type.) +*/ +#define log2maxs(t) (l_numbits(t) - 2) + + /* ** test whether an unsigned value is a power of 2 (or zero) */ @@ -234,12 +241,12 @@ typedef unsigned long l_uint32; /* floor division (defined as 'floor(a/b)') */ #if !defined(luai_numidiv) -#define luai_numidiv(L,a,b) l_floor(luai_numdiv(L,a,b)) +#define luai_numidiv(L,a,b) ((void)L, l_floor(luai_numdiv(L,a,b))) #endif /* float division */ #if !defined(luai_numdiv) -#define luai_numdiv(L,a,b) ((void)L, (a)/(b)) +#define luai_numdiv(L,a,b) ((a)/(b)) #endif /* @@ -267,10 +274,10 @@ typedef unsigned long l_uint32; /* the others are quite standard operations */ #if !defined(luai_numadd) -#define luai_numadd(L,a,b) ((void)L, (a)+(b)) -#define luai_numsub(L,a,b) ((void)L, (a)-(b)) -#define luai_nummul(L,a,b) ((void)L, (a)*(b)) -#define luai_numunm(L,a) ((void)L, -(a)) +#define luai_numadd(L,a,b) ((a)+(b)) +#define luai_numsub(L,a,b) ((a)-(b)) +#define luai_nummul(L,a,b) ((a)*(b)) +#define luai_numunm(L,a) (-(a)) #define luai_numeq(a,b) ((a)==(b)) #define luai_numlt(a,b) ((a)<(b)) #define luai_numle(a,b) ((a)<=(b)) @@ -280,55 +287,6 @@ typedef unsigned long l_uint32; #endif - -/* -** lua_numbertointeger converts a float number with an integral value -** to an integer, or returns 0 if the float is not within the range of -** a lua_Integer. (The range comparisons are tricky because of -** rounding. The tests here assume a two-complement representation, -** where MININTEGER always has an exact representation as a float; -** MAXINTEGER may not have one, and therefore its conversion to float -** may have an ill-defined value.) -*/ -#define lua_numbertointeger(n,p) \ - ((n) >= (LUA_NUMBER)(LUA_MININTEGER) && \ - (n) < -(LUA_NUMBER)(LUA_MININTEGER) && \ - (*(p) = (LUA_INTEGER)(n), 1)) - - - -/* -** LUAI_FUNC is a mark for all extern functions that are not to be -** exported to outside modules. -** LUAI_DDEF and LUAI_DDEC are marks for all extern (const) variables, -** none of which to be exported to outside modules (LUAI_DDEF for -** definitions and LUAI_DDEC for declarations). -** Elf and MACH/gcc (versions 3.2 and later) mark them as "hidden" to -** optimize access when Lua is compiled as a shared library. Not all elf -** targets support this attribute. Unfortunately, gcc does not offer -** a way to check whether the target offers that support, and those -** without support give a warning about it. To avoid these warnings, -** change to the default definition. -*/ -#if !defined(LUAI_FUNC) - -#if defined(__GNUC__) && ((__GNUC__*100 + __GNUC_MINOR__) >= 302) && \ - (defined(__ELF__) || defined(__MACH__)) -#define LUAI_FUNC __attribute__((visibility("internal"))) extern -#else -#define LUAI_FUNC extern -#endif - -#define LUAI_DDEC(dec) LUAI_FUNC dec -#define LUAI_DDEF /* empty */ - -#endif - - -/* Give these macros simpler names for internal use */ -#define l_likely(x) luai_likely(x) -#define l_unlikely(x) luai_unlikely(x) - /* ** {================================================================== ** "Abstraction Layer" for basic report of messages and errors diff --git a/lmathlib.c b/lmathlib.c index 87e7462a..bd34c888 100644 --- a/lmathlib.c +++ b/lmathlib.c @@ -38,37 +38,31 @@ static int math_abs (lua_State *L) { return 1; } - static int math_sin (lua_State *L) { lua_pushnumber(L, l_mathop(sin)(luaL_checknumber(L, 1))); return 1; } - static int math_cos (lua_State *L) { lua_pushnumber(L, l_mathop(cos)(luaL_checknumber(L, 1))); return 1; } - static int math_tan (lua_State *L) { lua_pushnumber(L, l_mathop(tan)(luaL_checknumber(L, 1))); return 1; } - static int math_asin (lua_State *L) { lua_pushnumber(L, l_mathop(asin)(luaL_checknumber(L, 1))); return 1; } - static int math_acos (lua_State *L) { lua_pushnumber(L, l_mathop(acos)(luaL_checknumber(L, 1))); return 1; } - static int math_atan (lua_State *L) { lua_Number y = luaL_checknumber(L, 1); lua_Number x = luaL_optnumber(L, 2, 1); @@ -173,7 +167,6 @@ static int math_ult (lua_State *L) { return 1; } - static int math_log (lua_State *L) { lua_Number x = luaL_checknumber(L, 1); lua_Number res; @@ -195,42 +188,22 @@ static int math_log (lua_State *L) { return 1; } - static int math_exp (lua_State *L) { lua_pushnumber(L, l_mathop(exp)(luaL_checknumber(L, 1))); return 1; } - static int math_deg (lua_State *L) { lua_pushnumber(L, luaL_checknumber(L, 1) * (l_mathop(180.0) / PI)); return 1; } - static int math_rad (lua_State *L) { lua_pushnumber(L, luaL_checknumber(L, 1) * (PI / l_mathop(180.0))); return 1; } -static int math_frexp (lua_State *L) { - lua_Number x = luaL_checknumber(L, 1); - int ep; - lua_pushnumber(L, l_mathop(frexp)(x, &ep)); - lua_pushinteger(L, ep); - return 2; -} - - -static int math_ldexp (lua_State *L) { - lua_Number x = luaL_checknumber(L, 1); - int ep = (int)luaL_checkinteger(L, 2); - lua_pushnumber(L, l_mathop(ldexp)(x, ep)); - return 1; -} - - static int math_min (lua_State *L) { int n = lua_gettop(L); /* number of arguments */ int imin = 1; /* index of current minimum value */ @@ -278,7 +251,7 @@ static int math_type (lua_State *L) { */ /* -** This code uses lots of shifts. ISO C does not allow shifts greater +** This code uses lots of shifts. ANSI C does not allow shifts greater ** than or equal to the width of the type being shifted, so some shifts ** are written in convoluted ways to match that restriction. For ** preprocessor tests, it assumes a width of 32 bits, so the maximum @@ -693,6 +666,20 @@ static int math_pow (lua_State *L) { return 1; } +static int math_frexp (lua_State *L) { + int e; + lua_pushnumber(L, l_mathop(frexp)(luaL_checknumber(L, 1), &e)); + lua_pushinteger(L, e); + return 2; +} + +static int math_ldexp (lua_State *L) { + lua_Number x = luaL_checknumber(L, 1); + int ep = (int)luaL_checkinteger(L, 2); + lua_pushnumber(L, l_mathop(ldexp)(x, ep)); + return 1; +} + static int math_log10 (lua_State *L) { lua_pushnumber(L, l_mathop(log10)(luaL_checknumber(L, 1))); return 1; @@ -704,35 +691,35 @@ static int math_log10 (lua_State *L) { static const luaL_Reg mathlib[] = { - {"abs", math_abs}, - {"acos", math_acos}, - {"asin", math_asin}, - {"atan", math_atan}, - {"ceil", math_ceil}, - {"cos", math_cos}, - {"deg", math_deg}, - {"exp", math_exp}, + {"abs", math_abs}, + {"acos", math_acos}, + {"asin", math_asin}, + {"atan", math_atan}, + {"ceil", math_ceil}, + {"cos", math_cos}, + {"deg", math_deg}, + {"exp", math_exp}, {"tointeger", math_toint}, {"floor", math_floor}, - {"fmod", math_fmod}, - {"frexp", math_frexp}, - {"ult", math_ult}, - {"ldexp", math_ldexp}, - {"log", math_log}, - {"max", math_max}, - {"min", math_min}, - {"modf", math_modf}, - {"rad", math_rad}, - {"sin", math_sin}, - {"sqrt", math_sqrt}, - {"tan", math_tan}, + {"fmod", math_fmod}, + {"ult", math_ult}, + {"log", math_log}, + {"max", math_max}, + {"min", math_min}, + {"modf", math_modf}, + {"rad", math_rad}, + {"sin", math_sin}, + {"sqrt", math_sqrt}, + {"tan", math_tan}, {"type", math_type}, #if defined(LUA_COMPAT_MATHLIB) {"atan2", math_atan}, - {"cosh", math_cosh}, - {"sinh", math_sinh}, - {"tanh", math_tanh}, - {"pow", math_pow}, + {"cosh", math_cosh}, + {"sinh", math_sinh}, + {"tanh", math_tanh}, + {"pow", math_pow}, + {"frexp", math_frexp}, + {"ldexp", math_ldexp}, {"log10", math_log10}, #endif /* placeholders */ diff --git a/loadlib.c b/loadlib.c index ef09c9a5..5f0c1702 100644 --- a/loadlib.c +++ b/loadlib.c @@ -306,16 +306,6 @@ static void setpath (lua_State *L, const char *fieldname, /* }================================================================== */ -/* -** External strings created by DLLs may need the DLL code to be -** deallocated. This implies that a DLL can only be unloaded after all -** its strings were deallocated. To ensure that, we create a 'library -** string' to represent each DLL, and when this string is deallocated -** it closes its corresponding DLL. -** (The string itself is irrelevant; its userdata is the DLL pointer.) -*/ - - /* ** return registry.CLIBS[path] */ @@ -330,42 +320,35 @@ static void *checkclib (lua_State *L, const char *path) { /* -** Deallocate function for library strings. -** Unload the DLL associated with the string being deallocated. -*/ -static void *freelib (void *ud, void *ptr, size_t osize, size_t nsize) { - /* string itself is irrelevant and static */ - (void)ptr; (void)osize; (void)nsize; - lsys_unloadlib(ud); /* unload library represented by the string */ - return NULL; -} - - -/* -** Create a library string that, when deallocated, will unload 'plib' -*/ -static void createlibstr (lua_State *L, void *plib) { - /* common content for all library strings */ - static const char dummy[] = "01234567890"; - lua_pushexternalstring(L, dummy, sizeof(dummy) - 1, freelib, plib); -} - - -/* -** registry.CLIBS[path] = plib -- for queries. -** Also create a reference to strlib, so that the library string will -** only be collected when registry.CLIBS is collected. +** registry.CLIBS[path] = plib -- for queries +** registry.CLIBS[#CLIBS + 1] = plib -- also keep a list of all libraries */ static void addtoclib (lua_State *L, const char *path, void *plib) { lua_getfield(L, LUA_REGISTRYINDEX, CLIBS); lua_pushlightuserdata(L, plib); - lua_setfield(L, -2, path); /* CLIBS[path] = plib */ - createlibstr(L, plib); - luaL_ref(L, -2); /* keep library string in CLIBS */ + lua_pushvalue(L, -1); + lua_setfield(L, -3, path); /* CLIBS[path] = plib */ + lua_rawseti(L, -2, luaL_len(L, -2) + 1); /* CLIBS[#CLIBS + 1] = plib */ lua_pop(L, 1); /* pop CLIBS table */ } +/* +** __gc tag method for CLIBS table: calls 'lsys_unloadlib' for all lib +** handles in list CLIBS +*/ +static int gctm (lua_State *L) { + lua_Integer n = luaL_len(L, 1); + for (; n >= 1; n--) { /* for each handle, in reverse order */ + lua_rawgeti(L, 1, n); /* get handle CLIBS[n] */ + lsys_unloadlib(lua_touserdata(L, -1)); + lua_pop(L, 1); /* pop handle */ + } + return 0; +} + + + /* error codes for 'lookforfunc' */ #define ERRLIB 1 #define ERRFUNC 2 @@ -378,8 +361,8 @@ static void addtoclib (lua_State *L, const char *path, void *plib) { ** Then, if 'sym' is '*', return true (as library has been loaded). ** Otherwise, look for symbol 'sym' in the library and push a ** C function with that symbol. -** Return 0 with 'true' or a function in the stack; in case of -** errors, return an error code with an error message in the stack. +** Return 0 and 'true' or a function in the stack; in case of +** errors, return an error code and an error message in the stack. */ static int lookforfunc (lua_State *L, const char *path, const char *sym) { void *reg = checkclib(L, path); /* check loaded C libraries */ @@ -541,7 +524,7 @@ static int searcher_Lua (lua_State *L) { const char *name = luaL_checkstring(L, 1); filename = findfile(L, name, "path", LUA_LSUBSEP); if (filename == NULL) return 1; /* module not found in this path */ - return checkload(L, (luaL_loadfilex(L, filename, "bt") == LUA_OK), filename); + return checkload(L, (luaL_loadfile(L, filename) == LUA_OK), filename); } @@ -721,9 +704,21 @@ static void createsearcherstable (lua_State *L) { } -LUAMOD_API int luaopen_package (lua_State *L) { +/* +** create table CLIBS to keep track of loaded C libraries, +** setting a finalizer to close all libraries when closing state. +*/ +static void createclibstable (lua_State *L) { luaL_getsubtable(L, LUA_REGISTRYINDEX, CLIBS); /* create CLIBS table */ - lua_pop(L, 1); /* will not use it now */ + lua_createtable(L, 0, 1); /* create metatable for CLIBS */ + lua_pushcfunction(L, gctm); + lua_setfield(L, -2, "__gc"); /* set finalizer for CLIBS table */ + lua_setmetatable(L, -2); +} + + +LUAMOD_API int luaopen_package (lua_State *L) { + createclibstable(L); luaL_newlib(L, pk_funcs); /* create 'package' table */ createsearcherstable(L); /* set paths */ diff --git a/lobject.c b/lobject.c index 6997cfd0..1c32ecf7 100644 --- a/lobject.c +++ b/lobject.c @@ -31,8 +31,7 @@ /* -** Computes ceil(log2(x)), which is the smallest integer n such that -** x <= (1 << n). +** Computes ceil(log2(x)) */ lu_byte luaO_ceillog2 (unsigned int x) { static const lu_byte log_2[256] = { /* log_2[i - 1] = ceil(log2(i)) */ @@ -87,9 +86,8 @@ lu_byte luaO_codeparam (unsigned int p) { ** overflow, so we check which order is best. */ l_mem luaO_applyparam (lu_byte p, l_mem x) { - int m = p & 0xF; /* mantissa */ + unsigned int m = p & 0xF; /* mantissa */ int e = (p >> 4); /* exponent */ - lua_assert(x >= 0); if (e > 0) { /* normalized? */ e--; /* correct exponent */ m += 0x10; /* correct mantissa; maximum value is 0x1F */ @@ -387,7 +385,7 @@ size_t luaO_str2num (const char *s, TValue *o) { int luaO_utf8esc (char *buff, l_uint32 x) { int n = 1; /* number of bytes put in buffer (backwards) */ lua_assert(x <= 0x7FFFFFFFu); - if (x < 0x80) /* ASCII? */ + if (x < 0x80) /* ascii? */ buff[UTF8BUFFSZ - 1] = cast_char(x); else { /* need continuation bytes */ unsigned int mfb = 0x3f; /* maximum that fits in first byte */ diff --git a/lobject.h b/lobject.h index 82bd9703..bc2f69ab 100644 --- a/lobject.h +++ b/lobject.h @@ -208,8 +208,7 @@ typedef union { #define ttisstrictnil(o) checktag((o), LUA_VNIL) -#define setnilvalue(obj) settt_(obj, LUA_VNIL) -#define setnilvalue2s(stk) setnilvalue(s2v(stk)) +#define setnilvalue(obj) settt_(obj, LUA_VNIL) #define isabstkey(v) checktag((v), LUA_VABSTKEY) @@ -419,7 +418,6 @@ typedef struct TString { #define strisshr(ts) ((ts)->shrlen >= 0) -#define isextstr(ts) (ttislngstring(ts) && tsvalue(ts)->shrlen != LSTRREG) /* @@ -584,18 +582,9 @@ typedef struct AbsLineInfo { /* ** Flags in Prototypes */ -#define PF_VAHID 1 /* function has hidden vararg arguments */ -#define PF_VATAB 2 /* function has vararg table */ -#define PF_FIXED 4 /* prototype has parts in fixed memory */ +#define PF_ISVARARG 1 +#define PF_FIXED 2 /* prototype has parts in fixed memory */ -/* a vararg function either has hidden args. or a vararg table */ -#define isvararg(p) ((p)->flag & (PF_VAHID | PF_VATAB)) - -/* -** mark that a function needs a vararg table. (The flag PF_VAHID will -** be cleared later.) -*/ -#define needvatab(p) ((p)->flag |= PF_VATAB) /* ** Function Prototypes @@ -827,7 +816,7 @@ typedef struct Table { #define twoto(x) (1u<<(x)) -#define sizenode(t) cast_uint(twoto((t)->lsizenode)) +#define sizenode(t) (twoto((t)->lsizenode)) /* size of buffer for 'luaO_utf8esc' function */ diff --git a/lopcodes.c b/lopcodes.c index bb1a4162..092c3902 100644 --- a/lopcodes.c +++ b/lopcodes.c @@ -53,8 +53,8 @@ LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = { ,opmode(0, 0, 0, 0, 1, iABC) /* OP_BANDK */ ,opmode(0, 0, 0, 0, 1, iABC) /* OP_BORK */ ,opmode(0, 0, 0, 0, 1, iABC) /* OP_BXORK */ - ,opmode(0, 0, 0, 0, 1, iABC) /* OP_SHLI */ ,opmode(0, 0, 0, 0, 1, iABC) /* OP_SHRI */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_SHLI */ ,opmode(0, 0, 0, 0, 1, iABC) /* OP_ADD */ ,opmode(0, 0, 0, 0, 1, iABC) /* OP_SUB */ ,opmode(0, 0, 0, 0, 1, iABC) /* OP_MUL */ @@ -102,28 +102,35 @@ LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = { ,opmode(0, 0, 1, 0, 0, ivABC) /* OP_SETLIST */ ,opmode(0, 0, 0, 0, 1, iABx) /* OP_CLOSURE */ ,opmode(0, 1, 0, 0, 1, iABC) /* OP_VARARG */ - ,opmode(0, 0, 0, 0, 1, iABC) /* OP_GETVARG */ - ,opmode(0, 0, 0, 0, 0, iABx) /* OP_ERRNNIL */ - ,opmode(0, 0, 0, 0, 0, iABC) /* OP_VARARGPREP */ + ,opmode(0, 0, 1, 0, 1, iABC) /* OP_VARARGPREP */ ,opmode(0, 0, 0, 0, 0, iAx) /* OP_EXTRAARG */ }; -#define testITMode(m) (luaP_opmodes[m] & (1 << 5)) + +/* +** Check whether instruction sets top for next instruction, that is, +** it results in multiple values. +*/ +int luaP_isOT (Instruction i) { + OpCode op = GET_OPCODE(i); + switch (op) { + case OP_TAILCALL: return 1; + default: + return testOTMode(op) && GETARG_C(i) == 0; + } +} /* -** Check whether instruction uses top. That happens for OP_VARARGPREP -** and for instructions that use multiple values set by the previous -** instruction. +** Check whether instruction uses top from previous instruction, that is, +** it accepts multiple results. */ int luaP_isIT (Instruction i) { OpCode op = GET_OPCODE(i); switch (op) { case OP_SETLIST: - return GETARG_vB(i) == 0; - case OP_VARARGPREP: - return 1; + return testITMode(GET_OPCODE(i)) && GETARG_vB(i) == 0; default: return testITMode(GET_OPCODE(i)) && GETARG_B(i) == 0; } diff --git a/lopcodes.h b/lopcodes.h index 86cff065..97870038 100644 --- a/lopcodes.h +++ b/lopcodes.h @@ -224,8 +224,8 @@ enum OpMode {iABC, ivABC, iABx, iAsBx, iAx, isJ}; /* -** Grep "ORDER OP" if you change this enum. -** See "Notes" below for more information about some instructions. +** Grep "ORDER OP" if you change these enums. Opcodes marked with a (*) +** has extra descriptions in the notes after the enumeration. */ typedef enum { @@ -238,7 +238,7 @@ OP_LOADF,/* A sBx R[A] := (lua_Number)sBx */ OP_LOADK,/* A Bx R[A] := K[Bx] */ OP_LOADKX,/* A R[A] := K[extra arg] */ OP_LOADFALSE,/* A R[A] := false */ -OP_LFALSESKIP,/*A R[A] := false; pc++ */ +OP_LFALSESKIP,/*A R[A] := false; pc++ (*) */ OP_LOADTRUE,/* A R[A] := true */ OP_LOADNIL,/* A B R[A], R[A+1], ..., R[A+B] := nil */ OP_GETUPVAL,/* A B R[A] := UpValue[B] */ @@ -272,8 +272,8 @@ OP_BANDK,/* A B C R[A] := R[B] & K[C]:integer */ OP_BORK,/* A B C R[A] := R[B] | K[C]:integer */ OP_BXORK,/* A B C R[A] := R[B] ~ K[C]:integer */ -OP_SHLI,/* A B sC R[A] := sC << R[B] */ OP_SHRI,/* A B sC R[A] := R[B] >> sC */ +OP_SHLI,/* A B sC R[A] := sC << R[B] */ OP_ADD,/* A B C R[A] := R[B] + R[C] */ OP_SUB,/* A B C R[A] := R[B] - R[C] */ @@ -289,7 +289,7 @@ OP_BXOR,/* A B C R[A] := R[B] ~ R[C] */ OP_SHL,/* A B C R[A] := R[B] << R[C] */ OP_SHR,/* A B C R[A] := R[B] >> R[C] */ -OP_MMBIN,/* A B C call C metamethod over R[A] and R[B] */ +OP_MMBIN,/* A B C call C metamethod over R[A] and R[B] (*) */ OP_MMBINI,/* A sB C k call C metamethod over R[A] and sB */ OP_MMBINK,/* A B C k call C metamethod over R[A] and K[B] */ @@ -315,12 +315,12 @@ OP_GTI,/* A sB k if ((R[A] > sB) ~= k) then pc++ */ OP_GEI,/* A sB k if ((R[A] >= sB) ~= k) then pc++ */ OP_TEST,/* A k if (not R[A] == k) then pc++ */ -OP_TESTSET,/* A B k if (not R[B] == k) then pc++ else R[A] := R[B] */ +OP_TESTSET,/* A B k if (not R[B] == k) then pc++ else R[A] := R[B] (*) */ OP_CALL,/* A B C R[A], ... ,R[A+C-2] := R[A](R[A+1], ... ,R[A+B-1]) */ OP_TAILCALL,/* A B C k return R[A](R[A+1], ... ,R[A+B-1]) */ -OP_RETURN,/* A B C k return R[A], ... ,R[A+B-2] */ +OP_RETURN,/* A B C k return R[A], ... ,R[A+B-2] (see note) */ OP_RETURN0,/* return */ OP_RETURN1,/* A return R[A] */ @@ -336,13 +336,9 @@ OP_SETLIST,/* A vB vC k R[A][vC+i] := R[A+i], 1 <= i <= vB */ OP_CLOSURE,/* A Bx R[A] := closure(KPROTO[Bx]) */ -OP_VARARG,/* A B C k R[A], ..., R[A+C-2] = varargs */ +OP_VARARG,/* A C R[A], R[A+1], ..., R[A+C-2] = vararg */ -OP_GETVARG, /* A B C R[A] := R[B][R[C]], R[B] is vararg parameter */ - -OP_ERRNNIL,/* A Bx raise error if R[A] ~= nil (K[Bx - 1] is global name)*/ - -OP_VARARGPREP,/* (adjust varargs) */ +OP_VARARGPREP,/*A (adjust vararg parameters) */ OP_EXTRAARG/* Ax extra (larger) argument for previous opcode */ } OpCode; @@ -371,8 +367,7 @@ OP_EXTRAARG/* Ax extra (larger) argument for previous opcode */ OP_RETURN*, OP_SETLIST) may use 'top'. (*) In OP_VARARG, if (C == 0) then use actual number of varargs and - set top (like in OP_CALL with C == 0). 'k' means function has a - vararg table, which is in R[B]. + set top (like in OP_CALL with C == 0). (*) In OP_RETURN, if (B == 0) then return up to 'top'. @@ -387,23 +382,18 @@ OP_EXTRAARG/* Ax extra (larger) argument for previous opcode */ power of 2) plus 1, or zero for size zero. If not k, the array size is vC. Otherwise, the array size is EXTRAARG _ vC. - (*) In OP_ERRNNIL, (Bx == 0) means index of global name doesn't - fit in Bx. (So, that name is not available for the error message.) - (*) For comparisons, k specifies what condition the test should accept (true or false). (*) In OP_MMBINI/OP_MMBINK, k means the arguments were flipped - (the constant is the first operand). + (the constant is the first operand). - (*) All comparison and test instructions assume that the instruction - being skipped (pc++) is a jump. + (*) All 'skips' (pc++) assume that next instruction is a jump. (*) In instructions OP_RETURN/OP_TAILCALL, 'k' specifies that the function builds upvalues, which may need to be closed. C > 0 means - the function has hidden vararg arguments, so that its 'func' must be - corrected before returning; in this case, (C - 1) is its number of - fixed parameters. + the function is vararg, so that its 'func' must be corrected before + returning; in this case, (C - 1) is its number of fixed parameters. (*) In comparisons with an immediate operand, C signals whether the original operand was a float. (It must be corrected in case of @@ -417,8 +407,8 @@ OP_EXTRAARG/* Ax extra (larger) argument for previous opcode */ ** bits 0-2: op mode ** bit 3: instruction set register A ** bit 4: operator is a test (next instruction must be a jump) -** bit 5: used by 'luaP_isIT' -** bit 6: used by 'luaP_isOT' +** bit 5: instruction uses 'L->top' set by previous instruction (when B == 0) +** bit 6: instruction sets 'L->top' for next instruction (when C == 0) ** bit 7: instruction is an MM instruction (call a metamethod) */ @@ -427,17 +417,12 @@ LUAI_DDEC(const lu_byte luaP_opmodes[NUM_OPCODES];) #define getOpMode(m) (cast(enum OpMode, luaP_opmodes[m] & 7)) #define testAMode(m) (luaP_opmodes[m] & (1 << 3)) #define testTMode(m) (luaP_opmodes[m] & (1 << 4)) +#define testITMode(m) (luaP_opmodes[m] & (1 << 5)) +#define testOTMode(m) (luaP_opmodes[m] & (1 << 6)) #define testMMMode(m) (luaP_opmodes[m] & (1 << 7)) -/* Check whether instruction sets top for next instruction, that is, -** it results in multiple values. Used only for tests. -*/ -#define luaP_isOT(i) \ - (GET_OPCODE(i) == OP_TAILCALL || \ - ((luaP_opmodes[GET_OPCODE(i)] & (1 << 6)) && GETARG_C(i) == 0)) - - +LUAI_FUNC int luaP_isOT (Instruction i); LUAI_FUNC int luaP_isIT (Instruction i); diff --git a/lopnames.h b/lopnames.h index 0554a2e9..965cec9b 100644 --- a/lopnames.h +++ b/lopnames.h @@ -45,8 +45,8 @@ static const char *const opnames[] = { "BANDK", "BORK", "BXORK", - "SHLI", "SHRI", + "SHLI", "ADD", "SUB", "MUL", @@ -94,8 +94,6 @@ static const char *const opnames[] = { "SETLIST", "CLOSURE", "VARARG", - "GETVARG", - "ERRNNIL", "VARARGPREP", "EXTRAARG", NULL diff --git a/loslib.c b/loslib.c index 111ac2f8..4623ad5e 100644 --- a/loslib.c +++ b/loslib.c @@ -34,7 +34,7 @@ #if defined(LUA_USE_WINDOWS) #define LUA_STRFTIMEOPTIONS "aAbBcdHIjmMpSUwWxXyYzZ%" \ "||" "#c#x#d#H#I#j#m#M#S#U#w#W#y#Y" /* two-char options */ -#elif defined(LUA_USE_C89) /* C89 (only 1-char options) */ +#elif defined(LUA_USE_C89) /* ANSI C 89 (only 1-char options) */ #define LUA_STRFTIMEOPTIONS "aAbBcdHIjmMpSUwWxXyYZ%" #else /* C99 specification */ #define LUA_STRFTIMEOPTIONS "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%" \ @@ -273,7 +273,7 @@ static int getfield (lua_State *L, const char *key, int d, int delta) { static const char *checkoption (lua_State *L, const char *conv, - size_t convlen, char *buff) { + ptrdiff_t convlen, char *buff) { const char *option = LUA_STRFTIMEOPTIONS; unsigned oplen = 1; /* length of options being checked */ for (; *option != '\0' && oplen <= convlen; option += oplen) { @@ -333,8 +333,7 @@ static int os_date (lua_State *L) { size_t reslen; char *buff = luaL_prepbuffsize(&b, SIZETIMEFMT); s++; /* skip '%' */ - /* copy specifier to 'cc' */ - s = checkoption(L, s, ct_diff2sz(se - s), cc + 1); + s = checkoption(L, s, se - s, cc + 1); /* copy specifier to 'cc' */ reslen = strftime(buff, SIZETIMEFMT, cc, stm); luaL_addsize(&b, reslen); } @@ -345,22 +344,11 @@ static int os_date (lua_State *L) { } -static int os_time_aux (lua_State *L, time_t t, int err) { - if (err || t != (time_t)(l_timet)t) - return luaL_error(L, - "time result cannot be represented in this installation"); - l_pushtime(L, t); - return 1; -} - - static int os_time (lua_State *L) { - if (lua_isnoneornil(L, 1)) { /* called without args? */ - time_t t = time(NULL); /* get current time; error if it is -1 */ - return os_time_aux(L, t, (t == (time_t)(-1))); - } + time_t t; + if (lua_isnoneornil(L, 1)) /* called without args? */ + t = time(NULL); /* get current time */ else { - time_t t; struct tm ts; luaL_checktype(L, 1, LUA_TTABLE); lua_settop(L, 1); /* make sure table is at the top */ @@ -371,12 +359,14 @@ static int os_time (lua_State *L) { ts.tm_min = getfield(L, "min", 0, 0); ts.tm_sec = getfield(L, "sec", 0, 0); ts.tm_isdst = getboolfield(L, "isdst"); - ts.tm_wday = -1; /* if call succeeds, it will set this value */ t = mktime(&ts); setallfields(L, &ts); /* update fields with normalized values */ - /* error if tm_wday was not set */ - return os_time_aux(L, t, ts.tm_wday == -1); } + if (t != (time_t)(l_timet)t || t == (time_t)(-1)) + return luaL_error(L, + "time result cannot be represented in this installation"); + l_pushtime(L, t); + return 1; } @@ -416,17 +406,17 @@ static int os_exit (lua_State *L) { static const luaL_Reg syslib[] = { - {"clock", os_clock}, - {"date", os_date}, - {"difftime", os_difftime}, - {"execute", os_execute}, - {"exit", os_exit}, - {"getenv", os_getenv}, - {"remove", os_remove}, - {"rename", os_rename}, + {"clock", os_clock}, + {"date", os_date}, + {"difftime", os_difftime}, + {"execute", os_execute}, + {"exit", os_exit}, + {"getenv", os_getenv}, + {"remove", os_remove}, + {"rename", os_rename}, {"setlocale", os_setlocale}, - {"time", os_time}, - {"tmpname", os_tmpname}, + {"time", os_time}, + {"tmpname", os_tmpname}, {NULL, NULL} }; diff --git a/lparser.c b/lparser.c index 3c26a4fd..201dbe8b 100644 --- a/lparser.c +++ b/lparser.c @@ -30,7 +30,7 @@ -/* maximum number of variable declarations per function (must be +/* maximum number of variable declarationss per function (must be smaller than 250, due to the bytecode format) */ #define MAXVARS 200 @@ -197,7 +197,7 @@ static int new_varkind (LexState *ls, TString *name, lu_byte kind) { Dyndata *dyd = ls->dyd; Vardesc *var; luaM_growvector(L, dyd->actvar.arr, dyd->actvar.n + 1, - dyd->actvar.size, Vardesc, SHRT_MAX, "variable declarations"); + dyd->actvar.size, Vardesc, SHRT_MAX, "variable declarationss"); var = &dyd->actvar.arr[dyd->actvar.n++]; var->vd.kind = kind; /* default */ var->vd.name = name; @@ -279,9 +279,7 @@ static void init_var (FuncState *fs, expdesc *e, int vidx) { /* -** Raises an error if variable described by 'e' is read only; moreover, -** if 'e' is t[exp] where t is the vararg parameter, change it to index -** a real table. (Virtual vararg tables cannot be changed.) +** Raises an error if variable described by 'e' is read only */ static void check_readonly (LexState *ls, expdesc *e) { FuncState *fs = ls->fs; @@ -291,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 VVARGVAR: { + case VLOCAL: { Vardesc *vardesc = getlocalvardesc(fs, e->u.var.vidx); if (vardesc->vd.kind != VDKREG) /* not a regular variable? */ varname = vardesc->vd.name; @@ -303,10 +301,6 @@ static void check_readonly (LexState *ls, expdesc *e) { varname = up->name; break; } - case VVARGIND: { - needvatab(fs->f); /* function will need a vararg table */ - e->k = VINDEXED; - } /* FALLTHROUGH */ case VINDEXUP: case VINDEXSTR: case VINDEXED: { /* global variable */ if (e->u.ind.ro) /* read-only? */ varname = tsvalue(&fs->f->k[e->u.ind.keystr]); @@ -432,11 +426,8 @@ 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); } } @@ -476,13 +467,8 @@ 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 (!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 */ + if (v == VLOCAL && !base) + markupval(fs, var->u.var.vidx); /* local will be used as an upval */ } else { /* not found at current level; try upvalues */ int idx = searchupvalue(fs, n); /* try existing upvalues */ @@ -499,20 +485,6 @@ static void singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) { } -static void buildglobal (LexState *ls, TString *varname, expdesc *var) { - FuncState *fs = ls->fs; - expdesc key; - init_exp(var, VGLOBAL, -1); /* global by default */ - singlevaraux(fs, ls->envn, var, 1); /* get environment variable */ - if (var->k == VGLOBAL) - luaK_semerror(ls, "%s is global when accessing variable '%s'", - LUA_ENV, getstr(varname)); - luaK_exp2anyregup(fs, var); /* _ENV could be a constant */ - codestring(&key, varname); /* key is variable name */ - luaK_indexed(fs, var, &key); /* 'var' represents _ENV[varname] */ -} - - /* ** Find a variable with the given name 'n', handling global variables ** too. @@ -522,11 +494,18 @@ static void buildvar (LexState *ls, TString *varname, expdesc *var) { init_exp(var, VGLOBAL, -1); /* global by default */ singlevaraux(fs, varname, var, 1); if (var->k == VGLOBAL) { /* global name? */ + expdesc key; int info = var->u.info; /* global by default in the scope of a global declaration? */ if (info == -2) luaK_semerror(ls, "variable '%s' not declared", getstr(varname)); - buildglobal(ls, varname, var); + singlevaraux(fs, ls->envn, var, 1); /* get environment variable */ + if (var->k == VGLOBAL) + luaK_semerror(ls, "_ENV is global when accessing variable '%s'", + getstr(varname)); + luaK_exp2anyregup(fs, var); /* but could be a constant */ + codestring(&key, varname); /* key is variable name */ + luaK_indexed(fs, var, &key); /* env[varname] */ if (info != -1 && ls->dyd->actvar.arr[info].vd.kind == GDKCONST) var->u.ind.ro = 1; /* mark variable as read-only */ else /* anyway must be a global */ @@ -547,7 +526,6 @@ static void singlevar (LexState *ls, expdesc *var) { static void adjust_assign (LexState *ls, int nvars, int nexps, expdesc *e) { FuncState *fs = ls->fs; int needed = nvars - nexps; /* extra values needed */ - luaK_checkstack(fs, needed); if (hasmultret(e->k)) { /* last expression has multiple returns? */ int extra = needed + 1; /* discount last expression itself */ if (extra < 0) @@ -687,7 +665,7 @@ static void createlabel (LexState *ls, TString *name, int line, int last) { /* -** Traverse the pending gotos of the finishing block checking whether +** Traverse the pending goto's of the finishing block checking whether ** each match some label of that block. Those that do not match are ** "exported" to the outer block, to be solved there. In particular, ** its 'nactvar' is updated with the level of the inner block, @@ -821,7 +799,8 @@ static void open_func (LexState *ls, FuncState *fs, BlockCnt *bl) { luaC_objbarrier(L, f, f->source); f->maxstacksize = 2; /* registers 0/1 are always valid */ fs->kcache = luaH_new(L); /* create table for function */ - luaD_anchorobj(L, ls->h, obj2gco(fs->kcache)); /* anchor it */ + sethvalue2s(L, L->top.p, fs->kcache); /* anchor it */ + luaD_inctop(L); enterblock(fs, bl, 0); } @@ -830,7 +809,6 @@ static void close_func (LexState *ls) { lua_State *L = ls->L; FuncState *fs = ls->fs; Proto *f = fs->f; - TValue temp; luaK_ret(fs, luaY_nvarstack(fs), 0); /* final return */ leaveblock(fs); lua_assert(fs->bl == NULL); @@ -843,10 +821,8 @@ static void close_func (LexState *ls) { luaM_shrinkvector(L, f->p, f->sizep, fs->np, Proto *); luaM_shrinkvector(L, f->locvars, f->sizelocvars, fs->ndebugvars, LocVar); luaM_shrinkvector(L, f->upvalues, f->sizeupvalues, fs->nups, Upvaldesc); - /* remove kcache table from scanner table ("weigh" its anchor) */ - sethvalue(L, &temp, fs->kcache); /* key to be set to nil */ - luaH_set(L, ls->h, &temp, &G(L)->nilvalue); ls->fs = fs->prev; + L->top.p--; /* pop kcache table */ luaC_checkGC(L); } @@ -922,19 +898,6 @@ typedef struct ConsControl { } ConsControl; -/* -** Maximum number of elements in a constructor, to control the following: -** * counter overflows; -** * overflows in 'extra' for OP_NEWTABLE and OP_SETLIST; -** * overflows when adding multiple returns in OP_SETLIST. -*/ -#define MAX_CNST (INT_MAX/2) -#if MAX_CNST/(MAXARG_vC + 1) > MAXARG_Ax -#undef MAX_CNST -#define MAX_CNST (MAXARG_Ax * (MAXARG_vC + 1)) -#endif - - static void recfield (LexState *ls, ConsControl *cc) { /* recfield -> (NAME | '['exp']') = exp */ FuncState *fs = ls->fs; @@ -955,7 +918,7 @@ static void recfield (LexState *ls, ConsControl *cc) { static void closelistfield (FuncState *fs, ConsControl *cc) { - lua_assert(cc->tostore > 0); + if (cc->v.k == VVOID) return; /* there is no list item */ luaK_exp2nextreg(fs, &cc->v); cc->v.k = VVOID; if (cc->tostore >= cc->maxtostore) { @@ -1043,12 +1006,10 @@ static void constructor (LexState *ls, expdesc *t) { checknext(ls, '{' /*}*/); cc.maxtostore = maxtostore(fs); do { + lua_assert(cc.v.k == VVOID || cc.tostore > 0); if (ls->t.token == /*{*/ '}') break; - if (cc.v.k != VVOID) /* is there a previous list item? */ - closelistfield(fs, &cc); /* close it */ + closelistfield(fs, &cc); field(ls, &cc); - luaY_checklimit(fs, cc.tostore + cc.na + cc.nh, MAX_CNST, - "items in a constructor"); } while (testnext(ls, ',') || testnext(ls, ';')); check_match(ls, /*{*/ '}', '{' /*}*/, line); lastlistfield(fs, &cc); @@ -1058,9 +1019,9 @@ static void constructor (LexState *ls, expdesc *t) { /* }====================================================================== */ -static void setvararg (FuncState *fs) { - fs->f->flag |= PF_VAHID; /* by default, use hidden vararg arguments */ - luaK_codeABC(fs, OP_VARARGPREP, 0, 0, 0); +static void setvararg (FuncState *fs, int nparams) { + fs->f->flag |= PF_ISVARARG; + luaK_codeABC(fs, OP_VARARGPREP, nparams, 0, 0); } @@ -1069,7 +1030,7 @@ static void parlist (LexState *ls) { FuncState *fs = ls->fs; Proto *f = fs->f; int nparams = 0; - int varargk = 0; + int isvararg = 0; if (ls->t.token != ')') { /* is 'parlist' not empty? */ do { switch (ls->t.token) { @@ -1079,26 +1040,19 @@ static void parlist (LexState *ls) { break; } case TK_DOTS: { - varargk = 1; - luaX_next(ls); /* skip '...' */ - if (ls->t.token == TK_NAME) - new_varkind(ls, str_checkname(ls), RDKVAVAR); - else - new_localvarliteral(ls, "(vararg table)"); + luaX_next(ls); + isvararg = 1; break; } default: luaX_syntaxerror(ls, " or '...' expected"); } - } while (!varargk && testnext(ls, ',')); + } while (!isvararg && testnext(ls, ',')); } adjustlocalvars(ls, nparams); f->numparams = cast_byte(fs->nactvar); - if (varargk) { - setvararg(fs); /* declared vararg */ - adjustlocalvars(ls, 1); /* vararg parameter */ - } - /* reserve registers for parameters (plus vararg parameter, if present) */ - luaK_reserveregs(fs, fs->nactvar); + if (isvararg) + setvararg(fs, f->numparams); /* declared vararg */ + luaK_reserveregs(fs, fs->nactvar); /* reserve registers for parameters */ } @@ -1166,7 +1120,6 @@ static void funcargs (LexState *ls, expdesc *f) { } default: { luaX_syntaxerror(ls, "function arguments expected"); - return; /* to avoid warnings */ } } lua_assert(f->k == VNONRELOC); @@ -1286,9 +1239,9 @@ static void simpleexp (LexState *ls, expdesc *v) { } case TK_DOTS: { /* vararg */ FuncState *fs = ls->fs; - check_condition(ls, isvararg(fs->f), + check_condition(ls, fs->f->flag & PF_ISVARARG, "cannot use '...' outside a vararg function"); - init_exp(v, VVARARG, luaK_codeABC(fs, OP_VARARG, 0, fs->f->numparams, 1)); + init_exp(v, VVARARG, luaK_codeABC(fs, OP_VARARG, 0, 0, 1)); break; } case '{' /*}*/: { /* constructor */ @@ -1482,15 +1435,6 @@ static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v) { } } - -/* Create code to store the "top" register in 'var' */ -static void storevartop (FuncState *fs, expdesc *var) { - expdesc e; - init_exp(&e, VNONRELOC, fs->freereg - 1); - luaK_storevar(fs, var, &e); /* will also free the top register */ -} - - /* ** Parse and compile a multiple assignment. The first "variable" ** (a 'suffixedexp') was already read by the caller. @@ -1524,7 +1468,8 @@ static void restassign (LexState *ls, struct LHS_assign *lh, int nvars) { return; /* avoid default */ } } - storevartop(ls->fs, &lh->v); /* default assignment */ + init_exp(&e, VNONRELOC, ls->fs->freereg-1); /* default assignment */ + luaK_storevar(ls->fs, &lh->v, &e); } @@ -1614,6 +1559,7 @@ static void repeatstat (LexState *ls, int line) { statlist(ls); check_match(ls, TK_UNTIL, TK_REPEAT, line); condexit = cond(ls); /* read condition (inside scope block) */ + leaveblock(fs); /* finish scope */ if (bl2.upval) { /* upvalues? */ int exit = luaK_jump(fs); /* normal exit must jump over fix */ luaK_patchtohere(fs, condexit); /* repetition must close upvalues */ @@ -1622,7 +1568,6 @@ static void repeatstat (LexState *ls, int line) { luaK_patchtohere(fs, exit); /* normal exit comes to here */ } luaK_patchlist(fs, condexit, repeat_init); /* close the loop */ - leaveblock(fs); /* finish scope */ leaveblock(fs); /* finish loop */ } @@ -1867,7 +1812,7 @@ static lu_byte getglobalattribute (LexState *ls, lu_byte df) { switch (kind) { case RDKTOCLOSE: luaK_semerror(ls, "global variables cannot be to-be-closed"); - return kind; /* to avoid warnings */ + break; /* to avoid warnings */ case RDKCONST: return GDKCONST; /* adjust kind for global variable */ default: @@ -1876,74 +1821,25 @@ static lu_byte getglobalattribute (LexState *ls, lu_byte df) { } -static void checkglobal (LexState *ls, TString *varname, int line) { - FuncState *fs = ls->fs; - expdesc var; - int k; - buildglobal(ls, varname, &var); /* create global variable in 'var' */ - k = var.u.ind.keystr; /* index of global name in 'k' */ - luaK_codecheckglobal(fs, &var, k, line); -} - - -/* -** Recursively traverse list of globals to be initalized. When -** going, generate table description for the global. In the end, -** after all indices have been generated, read list of initializing -** expressions. When returning, generate the assignment of the value on -** the stack to the corresponding table description. 'n' is the variable -** being handled, range [0, nvars - 1]. -*/ -static void initglobal (LexState *ls, int nvars, int firstidx, int n, - int line) { - if (n == nvars) { /* traversed all variables? */ - expdesc e; - int nexps = explist(ls, &e); /* read list of expressions */ - adjust_assign(ls, nvars, nexps, &e); - } - else { /* handle variable 'n' */ - FuncState *fs = ls->fs; - expdesc var; - TString *varname = getlocalvardesc(fs, firstidx + n)->vd.name; - buildglobal(ls, varname, &var); /* create global variable in 'var' */ - enterlevel(ls); /* control recursion depth */ - initglobal(ls, nvars, firstidx, n + 1, line); - leavelevel(ls); - checkglobal(ls, varname, line); - storevartop(fs, &var); - } -} - - -static void globalnames (LexState *ls, lu_byte defkind) { - FuncState *fs = ls->fs; - int nvars = 0; - int lastidx; /* index of last registered variable */ - do { /* for each name */ - TString *vname = str_checkname(ls); - lu_byte kind = getglobalattribute(ls, defkind); - lastidx = new_varkind(ls, vname, kind); - nvars++; - } while (testnext(ls, ',')); - if (testnext(ls, '=')) /* initialization? */ - initglobal(ls, nvars, lastidx - nvars + 1, 0, ls->linenumber); - fs->nactvar = cast_short(fs->nactvar + nvars); /* activate declaration */ -} - - static void globalstat (LexState *ls) { /* globalstat -> (GLOBAL) attrib '*' globalstat -> (GLOBAL) attrib NAME attrib {',' NAME attrib} */ FuncState *fs = ls->fs; /* get prefixed attribute (if any); default is regular global variable */ lu_byte defkind = getglobalattribute(ls, GDKREG); - if (!testnext(ls, '*')) - globalnames(ls, defkind); - else { + if (testnext(ls, '*')) { /* use NULL as name to represent '*' entries */ new_varkind(ls, NULL, defkind); fs->nactvar++; /* activate declaration */ } + else { + do { /* list of names */ + TString *vname = str_checkname(ls); + lu_byte kind = getglobalattribute(ls, defkind); + new_varkind(ls, vname, kind); + fs->nactvar++; /* activate declaration */ + } while (testnext(ls, ',')); + } } @@ -1954,9 +1850,8 @@ static void globalfunc (LexState *ls, int line) { TString *fname = str_checkname(ls); new_varkind(ls, fname, GDKREG); /* declare global variable */ fs->nactvar++; /* enter its scope */ - buildglobal(ls, fname, &var); + buildvar(ls, fname, &var); body(ls, &b, 0, ls->linenumber); /* compile and return closure in 'b' */ - checkglobal(ls, fname, line); luaK_storevar(fs, &var, &b); luaK_fixline(fs, line); /* definition "happens" in the first line */ } @@ -2114,7 +2009,7 @@ static void statement (LexState *ls) { gotostat(ls, line); break; } -#if LUA_COMPAT_GLOBAL +#if defined(LUA_COMPAT_GLOBAL) case TK_NAME: { /* compatibility code to parse global keyword when "global" is not reserved */ @@ -2154,7 +2049,7 @@ static void mainfunc (LexState *ls, FuncState *fs) { BlockCnt bl; Upvaldesc *env; open_func(ls, fs, &bl); - setvararg(fs); /* main function is always vararg */ + setvararg(fs, 0); /* main function is always declared vararg */ env = allocupvalue(fs); /* ...set environment upvalue */ env->instack = 1; env->idx = 0; @@ -2168,14 +2063,16 @@ static void mainfunc (LexState *ls, FuncState *fs) { } -LClosure *luaY_parser (lua_State *L, ZIO *z, Table *anchor, Mbuffer *buff, +LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, Dyndata *dyd, const char *name, int firstchar) { LexState lexstate; FuncState funcstate; - LClosure *cl; - lexstate.h = anchor; /* table for scanner */ - cl = luaF_newLclosure(L, 1); /* create main closure */ - luaD_anchorobj(L, anchor, obj2gco(cl)); /* anchor it in scanner table */ + LClosure *cl = luaF_newLclosure(L, 1); /* create main closure */ + setclLvalue2s(L, L->top.p, cl); /* anchor it (to avoid being collected) */ + luaD_inctop(L); + lexstate.h = luaH_new(L); /* create table for scanner */ + sethvalue2s(L, L->top.p, lexstate.h); /* anchor it */ + luaD_inctop(L); funcstate.f = cl->p = luaF_newproto(L); luaC_objbarrier(L, cl, cl->p); funcstate.f->source = luaS_new(L, name); /* create and anchor TString */ @@ -2188,6 +2085,7 @@ LClosure *luaY_parser (lua_State *L, ZIO *z, Table *anchor, Mbuffer *buff, lua_assert(!funcstate.prev && funcstate.nups == 1 && !lexstate.fs); /* all scopes should be correctly finished */ lua_assert(dyd->actvar.n == 0 && dyd->gt.n == 0 && dyd->label.n == 0); - return cl; + L->top.p--; /* remove scanner's table */ + return cl; /* closure is on the stack, too */ } diff --git a/lparser.h b/lparser.h index 4fad6bdc..fdbb9b8a 100644 --- a/lparser.h +++ b/lparser.h @@ -37,8 +37,6 @@ 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) */ @@ -51,8 +49,6 @@ typedef enum { ind.ro = true if it represents a read-only global; ind.keystr = if key is a string, index in 'k' of that string; -1 if key is not a string */ - VVARGIND, /* indexed vararg parameter; - ind.* as in VINDEXED */ VINDEXUP, /* indexed upvalue; ind.idx = key's K index; ind.* as in VINDEXED */ @@ -101,11 +97,10 @@ typedef struct expdesc { /* kinds of variables */ #define VDKREG 0 /* regular local */ #define RDKCONST 1 /* local constant */ -#define RDKVAVAR 2 /* vararg parameter */ -#define RDKTOCLOSE 3 /* to-be-closed */ -#define RDKCTC 4 /* local compile-time constant */ -#define GDKREG 5 /* regular global */ -#define GDKCONST 6 /* global constant */ +#define RDKTOCLOSE 2 /* to-be-closed */ +#define RDKCTC 3 /* local compile-time constant */ +#define GDKREG 4 /* regular global */ +#define GDKCONST 5 /* global constant */ /* variables that live in registers */ #define varinreg(v) ((v)->vd.kind <= RDKTOCLOSE) @@ -189,9 +184,8 @@ typedef struct FuncState { LUAI_FUNC lu_byte luaY_nvarstack (FuncState *fs); LUAI_FUNC void luaY_checklimit (FuncState *fs, int v, int l, const char *what); -LUAI_FUNC LClosure *luaY_parser (lua_State *L, ZIO *z, Table *anchor, - Mbuffer *buff, Dyndata *dyd, - const char *name, int firstchar); +LUAI_FUNC LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, + Dyndata *dyd, const char *name, int firstchar); #endif diff --git a/lstate.c b/lstate.c index ada0b856..70a11aae 100644 --- a/lstate.c +++ b/lstate.c @@ -68,19 +68,14 @@ void luaE_setdebt (global_State *g, l_mem debt) { } -CallInfo *luaE_extendCI (lua_State *L, int err) { +CallInfo *luaE_extendCI (lua_State *L) { CallInfo *ci; - ci = luaM_reallocvector(L, NULL, 0, 1, CallInfo); - if (l_unlikely(ci == NULL)) { /* allocation failed? */ - if (err) - luaM_error(L); /* raise the error */ - return NULL; /* else only report it */ - } - ci->next = L->ci->next; - ci->previous = L->ci; + lua_assert(L->ci->next == NULL); + ci = luaM_new(L, CallInfo); + lua_assert(L->ci->next == NULL); L->ci->next = ci; - if (ci->next) - ci->next->previous = ci; + ci->previous = L->ci; + ci->next = NULL; ci->u.l.trap = 0; L->nci++; return ci; @@ -151,7 +146,7 @@ LUAI_FUNC void luaE_incCstack (lua_State *L) { static void resetCI (lua_State *L) { CallInfo *ci = L->ci = &L->base_ci; ci->func.p = L->stack.p; - setnilvalue2s(ci->func.p); /* 'function' entry for basic 'ci' */ + setnilvalue(s2v(ci->func.p)); /* 'function' entry for basic 'ci' */ ci->top.p = ci->func.p + 1 + LUA_MINSTACK; /* +1 for 'function' entry */ ci->u.c.k = NULL; ci->callstatus = CIST_C; @@ -166,7 +161,7 @@ static void stack_init (lua_State *L1, lua_State *L) { L1->stack.p = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK, StackValue); L1->tbclist.p = L1->stack.p; for (i = 0; i < BASIC_STACK_SIZE + EXTRA_STACK; i++) - setnilvalue2s(L1->stack.p + i); /* erase new stack */ + setnilvalue(s2v(L1->stack.p + i)); /* erase new stack */ L1->stack_last.p = L1->stack.p + BASIC_STACK_SIZE; /* initialize first ci */ resetCI(L1); diff --git a/lstate.h b/lstate.h index 30a560a7..f841c232 100644 --- a/lstate.h +++ b/lstate.h @@ -85,7 +85,7 @@ typedef struct CallInfo CallInfo; ** they must be visited again at the end of the cycle), but they are ** marked black because assignments to them must activate barriers (to ** move them back to TOUCHED1). -** - Open upvalues are kept gray to avoid barriers, but they stay out +** - Open upvales are kept gray to avoid barriers, but they stay out ** of gray lists. (They don't even have a 'gclist' field.) */ @@ -232,7 +232,7 @@ struct CallInfo { /* call is running a C function (still in first 16 bits) */ #define CIST_C (1u << (CIST_RECST + 3)) /* call is on a fresh "luaV_execute" frame */ -#define CIST_FRESH (cast(l_uint32, CIST_C) << 1) +#define CIST_FRESH cast(l_uint32, CIST_C << 1) /* function is closing tbc variables */ #define CIST_CLSRET (CIST_FRESH << 1) /* function has tbc variables to close */ @@ -249,6 +249,10 @@ struct CallInfo { #define CIST_HOOKYIELD (CIST_TAIL << 1) /* function "called" a finalizer */ #define CIST_FIN (CIST_HOOKYIELD << 1) +#if defined(LUA_COMPAT_LT_LE) +/* using __lt for __le */ +#define CIST_LEQ (CIST_FIN << 1) +#endif #define get_nresults(cs) (cast_int((cs) & CIST_NRESULTS) - 1) @@ -383,7 +387,7 @@ typedef struct global_State { /* -** Union of all collectable objects +** Union of all collectable objects (only for conversions) ** ISO C99, 6.5.2.3 p.5: ** "if a union contains several structures that share a common initial ** sequence [...], and if the union object currently contains one @@ -403,32 +407,32 @@ union GCUnion { }; -/* macros to convert a GCObject into a specific value -** ISO C99, 6.3.2.2 p.7: -** "A pointer to an object or incomplete type may be converted to a -** pointer to a different object or incomplete type. If the resulting -** pointer is not correctly aligned for the pointed-to type, the -** behavior is undefined. Otherwise, when converted back again, the -** result shall compare equal to the original pointer." +/* +** ISO C99, 6.7.2.1 p.14: +** "A pointer to a union object, suitably converted, points to each of +** its members [...], and vice versa." */ -#define gco2(v,T,o) check_exp((o)->tt == v, cast(T*, o)) -#define gco2nv(t,T,o) check_exp(novariant((o)->tt) == t, cast(T*, o)) -#define gco2ts(o) gco2nv(LUA_TSTRING, TString, o) -#define gco2u(o) gco2(LUA_VUSERDATA, Udata, o) -#define gco2lcl(o) (&gco2(LUA_VLCL, Closure, o)->l) -#define gco2ccl(o) (&gco2(LUA_VCCL, Closure, o)->c) -#define gco2cl(o) gco2nv(LUA_TFUNCTION, Closure, o) -#define gco2t(o) gco2(LUA_VTABLE, Table, o) -#define gco2p(o) gco2(LUA_VPROTO, Proto, o) -#define gco2th(o) gco2(LUA_VTHREAD, lua_State, o) -#define gco2upv(o) gco2(LUA_VUPVAL, UpVal, o) +#define cast_u(o) cast(union GCUnion *, (o)) + +/* macros to convert a GCObject into a specific value */ +#define gco2ts(o) \ + check_exp(novariant((o)->tt) == LUA_TSTRING, &((cast_u(o))->ts)) +#define gco2u(o) check_exp((o)->tt == LUA_VUSERDATA, &((cast_u(o))->u)) +#define gco2lcl(o) check_exp((o)->tt == LUA_VLCL, &((cast_u(o))->cl.l)) +#define gco2ccl(o) check_exp((o)->tt == LUA_VCCL, &((cast_u(o))->cl.c)) +#define gco2cl(o) \ + check_exp(novariant((o)->tt) == LUA_TFUNCTION, &((cast_u(o))->cl)) +#define gco2t(o) check_exp((o)->tt == LUA_VTABLE, &((cast_u(o))->h)) +#define gco2p(o) check_exp((o)->tt == LUA_VPROTO, &((cast_u(o))->p)) +#define gco2th(o) check_exp((o)->tt == LUA_VTHREAD, &((cast_u(o))->th)) +#define gco2upv(o) check_exp((o)->tt == LUA_VUPVAL, &((cast_u(o))->upv)) /* ** macro to convert a Lua object into a GCObject +** (The access to 'tt' tries to ensure that 'v' is actually a Lua object.) */ -#define obj2gco(v) \ - check_exp(novariant((v)->tt) >= LUA_TSTRING, cast(GCObject*, v)) +#define obj2gco(v) check_exp((v)->tt >= LUA_TSTRING, &(cast_u(v)->gc)) /* actual number of total memory allocated */ @@ -438,7 +442,7 @@ union GCUnion { LUAI_FUNC void luaE_setdebt (global_State *g, l_mem debt); LUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1); LUAI_FUNC lu_mem luaE_threadsize (lua_State *L); -LUAI_FUNC CallInfo *luaE_extendCI (lua_State *L, int err); +LUAI_FUNC CallInfo *luaE_extendCI (lua_State *L); LUAI_FUNC void luaE_shrinkCI (lua_State *L); LUAI_FUNC void luaE_checkcstack (lua_State *L); LUAI_FUNC void luaE_incCstack (lua_State *L); diff --git a/lstring.c b/lstring.c index 75635142..b5c8f89f 100644 --- a/lstring.c +++ b/lstring.c @@ -39,18 +39,18 @@ /* -** generic equality for strings +** equality for long strings */ -int luaS_eqstr (TString *a, TString *b) { - size_t len1, len2; - const char *s1 = getlstr(a, len1); - const char *s2 = getlstr(b, len2); - return ((len1 == len2) && /* equal length and ... */ - (memcmp(s1, s2, len1) == 0)); /* equal contents */ +int luaS_eqlngstr (TString *a, TString *b) { + size_t len = a->u.lnglen; + lua_assert(a->tt == LUA_VLNGSTR && b->tt == LUA_VLNGSTR); + return (a == b) || /* same instance or... */ + ((len == b->u.lnglen) && /* equal length and ... */ + (memcmp(getlngstr(a), getlngstr(b), len) == 0)); /* equal contents */ } -static unsigned luaS_hash (const char *str, size_t l, unsigned seed) { +unsigned luaS_hash (const char *str, size_t l, unsigned seed) { unsigned int h = seed ^ cast_uint(l); for (; l > 0; l--) h ^= ((h<<5) + (h>>2) + cast_byte(str[l - 1])); @@ -315,9 +315,28 @@ static void f_newext (lua_State *L, void *ud) { } +static void f_pintern (lua_State *L, void *ud) { + struct NewExt *ne = cast(struct NewExt *, ud); + ne->ts = internshrstr(L, ne->s, ne->len); +} + + TString *luaS_newextlstr (lua_State *L, const char *s, size_t len, lua_Alloc falloc, void *ud) { struct NewExt ne; + if (len <= LUAI_MAXSHORTLEN) { /* short string? */ + ne.s = s; ne.len = len; + if (!falloc) + f_pintern(L, &ne); /* just internalize string */ + else { + TStatus status = luaD_rawrunprotected(L, f_pintern, &ne); + (*falloc)(ud, cast_voidp(s), len + 1, 0); /* free external string */ + if (status != LUA_OK) /* memory error? */ + luaM_error(L); /* re-raise memory error */ + } + return ne.ts; + } + /* "normal" case: long strings */ if (!falloc) { ne.kind = LSTRFIX; f_newext(L, &ne); /* just create header */ @@ -338,16 +357,3 @@ TString *luaS_newextlstr (lua_State *L, } -/* -** Normalize an external string: If it is short, internalize it. -*/ -TString *luaS_normstr (lua_State *L, TString *ts) { - size_t len = ts->u.lnglen; - if (len > LUAI_MAXSHORTLEN) - return ts; /* long string; keep the original */ - else { - const char *str = getlngstr(ts); - return internshrstr(L, str, len); - } -} - diff --git a/lstring.h b/lstring.h index 1643c3d8..1751e043 100644 --- a/lstring.h +++ b/lstring.h @@ -54,8 +54,9 @@ #define eqshrstr(a,b) check_exp((a)->tt == LUA_VSHRSTR, (a) == (b)) +LUAI_FUNC unsigned luaS_hash (const char *str, size_t l, unsigned seed); LUAI_FUNC unsigned luaS_hashlongstr (TString *ts); -LUAI_FUNC int luaS_eqstr (TString *a, TString *b); +LUAI_FUNC int luaS_eqlngstr (TString *a, TString *b); LUAI_FUNC void luaS_resize (lua_State *L, int newsize); LUAI_FUNC void luaS_clearcache (global_State *g); LUAI_FUNC void luaS_init (lua_State *L); @@ -68,6 +69,5 @@ LUAI_FUNC TString *luaS_createlngstrobj (lua_State *L, size_t l); LUAI_FUNC TString *luaS_newextlstr (lua_State *L, const char *s, size_t len, lua_Alloc falloc, void *ud); LUAI_FUNC size_t luaS_sizelngstr (size_t len, int kind); -LUAI_FUNC TString *luaS_normstr (lua_State *L, TString *ts); #endif diff --git a/lstrlib.c b/lstrlib.c index dd3c0fd0..306cd0bf 100644 --- a/lstrlib.c +++ b/lstrlib.c @@ -132,31 +132,27 @@ static int str_upper (lua_State *L) { } -/* -** MAX_SIZE is limited both by size_t and lua_Integer. -** When x <= MAX_SIZE, x can be safely cast to size_t or lua_Integer. -*/ static int str_rep (lua_State *L) { - size_t len, lsep; - const char *s = luaL_checklstring(L, 1, &len); + size_t l, lsep; + const char *s = luaL_checklstring(L, 1, &l); lua_Integer n = luaL_checkinteger(L, 2); const char *sep = luaL_optlstring(L, 3, "", &lsep); - if (n <= 0 || (len | lsep) == 0) - lua_pushliteral(L, ""); /* no repetitions or both strings empty */ - else if (l_unlikely(len > MAX_SIZE - lsep || - cast_st2S(len + lsep) > cast_st2S(MAX_SIZE) / n)) + if (n <= 0) + lua_pushliteral(L, ""); + else if (l_unlikely(l + lsep < l || l + lsep > MAX_SIZE / cast_sizet(n))) return luaL_error(L, "resulting string too large"); else { - size_t totallen = (cast_sizet(n) * (len + lsep)) - lsep; + size_t totallen = ((size_t)n * (l + lsep)) - lsep; luaL_Buffer b; char *p = luaL_buffinitsize(L, &b, totallen); while (n-- > 1) { /* first n-1 copies (followed by separator) */ - memcpy(p, s, len * sizeof(char)); p += len; + memcpy(p, s, l * sizeof(char)); p += l; if (lsep > 0) { /* empty 'memcpy' is not that cheap */ - memcpy(p, sep, lsep * sizeof(char)); p += lsep; + memcpy(p, sep, lsep * sizeof(char)); + p += lsep; } } - memcpy(p, s, len * sizeof(char)); /* last copy without separator */ + memcpy(p, s, l * sizeof(char)); /* last copy (not followed by separator) */ luaL_pushresultsize(&b, totallen); } return 1; @@ -269,18 +265,11 @@ static int tonum (lua_State *L, int arg) { } -/* -** To be here, either the first operand was a string or the first -** operand didn't have a corresponding metamethod. (Otherwise, that -** other metamethod would have been called.) So, if this metamethod -** doesn't work, the only other option would be for the second -** operand to have a different metamethod. -*/ -static void trymt (lua_State *L, const char *mtkey, const char *opname) { +static void trymt (lua_State *L, const char *mtname) { lua_settop(L, 2); /* back to the original arguments */ if (l_unlikely(lua_type(L, 2) == LUA_TSTRING || - !luaL_getmetafield(L, 2, mtkey))) - luaL_error(L, "attempt to %s a '%s' with a '%s'", opname, + !luaL_getmetafield(L, 2, mtname))) + luaL_error(L, "attempt to %s a '%s' with a '%s'", mtname + 2, luaL_typename(L, -2), luaL_typename(L, -1)); lua_insert(L, -3); /* put metamethod before arguments */ lua_call(L, 2, 1); /* call metamethod */ @@ -291,7 +280,7 @@ static int arith (lua_State *L, int op, const char *mtname) { if (tonum(L, 1) && tonum(L, 2)) lua_arith(L, op); /* result will be on the top */ else - trymt(L, mtname, mtname + 2); + trymt(L, mtname); return 1; } @@ -757,25 +746,19 @@ static int nospecials (const char *p, size_t l) { } -/* -** Prepare state for matches. These fields are not affected by each match. -*/ static void prepstate (MatchState *ms, lua_State *L, const char *s, size_t ls, const char *p, size_t lp) { ms->L = L; + ms->matchdepth = MAXCCALLS; ms->src_init = s; ms->src_end = s + ls; ms->p_end = p + lp; } -/* -** (Re)prepare state for a match, setting fields that change during -** each match. -*/ static void reprepstate (MatchState *ms) { - ms->matchdepth = MAXCCALLS; ms->level = 0; + lua_assert(ms->matchdepth == MAXCCALLS); } @@ -974,7 +957,7 @@ static int str_gsub (lua_State *L) { reprepstate(&ms); /* (re)prepare state for new match */ if ((e = match(&ms, src, p)) != NULL && e != lastmatch) { /* match? */ n++; - changed = add_value(&ms, &b, src, e, tr) || changed; + changed = add_value(&ms, &b, src, e, tr) | changed; src = lastmatch = e; } else if (src < ms.src_end) /* otherwise, skip one character */ @@ -1732,7 +1715,7 @@ static int str_packsize (lua_State *L) { luaL_argcheck(L, opt != Kstring && opt != Kzstr, 1, "variable-length format"); size += ntoalign; /* total space used by option */ - luaL_argcheck(L, totalsize <= MAX_SIZE - size, + luaL_argcheck(L, totalsize <= LUA_MAXINTEGER - size, 1, "format result too large"); totalsize += size; } @@ -1828,8 +1811,8 @@ static int str_unpack (lua_State *L) { lua_Unsigned len = (lua_Unsigned)unpackint(L, data + pos, h.islittle, cast_int(size), 0); luaL_argcheck(L, len <= ld - pos - size, 2, "data string too short"); - lua_pushlstring(L, data + pos + size, cast_sizet(len)); - pos += cast_sizet(len); /* skip string */ + lua_pushlstring(L, data + pos + size, len); + pos += len; /* skip string */ break; } case Kzstr: { diff --git a/ltable.c b/ltable.c index 2f2b5c1f..0b3ec176 100644 --- a/ltable.c +++ b/ltable.c @@ -156,7 +156,7 @@ static Node *hashint (const Table *t, lua_Integer i) { ** The main computation should be just ** n = frexp(n, &i); return (n * INT_MAX) + i ** but there are some numerical subtleties. -** In a two-complement representation, INT_MAX may not have an exact +** In a two-complement representation, INT_MAX does not has an exact ** representation as a float, but INT_MIN does; because the absolute ** value of 'frexp' is smaller than 1 (unless 'n' is inf/NaN), the ** absolute value of the product 'frexp * -INT_MIN' is smaller or equal @@ -234,51 +234,41 @@ l_sinline Node *mainpositionfromnode (const Table *t, Node *nd) { ** Check whether key 'k1' is equal to the key in node 'n2'. This ** equality is raw, so there are no metamethods. Floats with integer ** values have been normalized, so integers cannot be equal to -** floats. It is assumed that 'eqshrstr' is simply pointer equality, -** so that short strings are handled in the default case. The flag -** 'deadok' means to accept dead keys as equal to their original values. -** (Only collectable objects can produce dead keys.) Note that dead -** long strings are also compared by identity. Once a key is dead, -** its corresponding value may be collected, and then another value -** can be created with the same address. If this other value is given -** to 'next', 'equalkey' will signal a false positive. In a regular -** traversal, this situation should never happen, as all keys given to -** 'next' came from the table itself, and therefore could not have been -** collected. Outside a regular traversal, we have garbage in, garbage -** out. What is relevant is that this false positive does not break -** anything. (In particular, 'next' will return some other valid item -** on the table or nil.) +** floats. It is assumed that 'eqshrstr' is simply pointer equality, so +** that short strings are handled in the default case. +** A true 'deadok' means to accept dead keys as equal to their original +** values. All dead keys are compared in the default case, by pointer +** identity. (Only collectable objects can produce dead keys.) Note that +** dead long strings are also compared by identity. +** Once a key is dead, its corresponding value may be collected, and +** then another value can be created with the same address. If this +** other value is given to 'next', 'equalkey' will signal a false +** positive. In a regular traversal, this situation should never happen, +** as all keys given to 'next' came from the table itself, and therefore +** could not have been collected. Outside a regular traversal, we +** have garbage in, garbage out. What is relevant is that this false +** positive does not break anything. (In particular, 'next' will return +** some other valid item on the table or nil.) */ static int equalkey (const TValue *k1, const Node *n2, int deadok) { - if (rawtt(k1) != keytt(n2)) { /* not the same variants? */ - if (keyisshrstr(n2) && ttislngstring(k1)) { - /* an external string can be equal to a short-string key */ - return luaS_eqstr(tsvalue(k1), keystrval(n2)); - } - else if (deadok && keyisdead(n2) && iscollectable(k1)) { - /* a collectable value can be equal to a dead key */ + if ((rawtt(k1) != keytt(n2)) && /* not the same variants? */ + !(deadok && keyisdead(n2) && iscollectable(k1))) + return 0; /* cannot be same key */ + switch (keytt(n2)) { + case LUA_VNIL: case LUA_VFALSE: case LUA_VTRUE: + return 1; + case LUA_VNUMINT: + return (ivalue(k1) == keyival(n2)); + case LUA_VNUMFLT: + return luai_numeq(fltvalue(k1), fltvalueraw(keyval(n2))); + case LUA_VLIGHTUSERDATA: + return pvalue(k1) == pvalueraw(keyval(n2)); + case LUA_VLCF: + return fvalue(k1) == fvalueraw(keyval(n2)); + case ctb(LUA_VLNGSTR): + return luaS_eqlngstr(tsvalue(k1), keystrval(n2)); + default: return gcvalue(k1) == gcvalueraw(keyval(n2)); - } - else - return 0; /* otherwise, different variants cannot be equal */ - } - else { /* equal variants */ - switch (keytt(n2)) { - case LUA_VNIL: case LUA_VFALSE: case LUA_VTRUE: - return 1; - case LUA_VNUMINT: - return (ivalue(k1) == keyival(n2)); - case LUA_VNUMFLT: - return luai_numeq(fltvalue(k1), fltvalueraw(keyval(n2))); - case LUA_VLIGHTUSERDATA: - return pvalue(k1) == pvalueraw(keyval(n2)); - case LUA_VLCF: - return fvalue(k1) == fvalueraw(keyval(n2)); - case ctb(LUA_VLNGSTR): - return luaS_eqstr(tsvalue(k1), keystrval(n2)); - default: - return gcvalue(k1) == gcvalueraw(keyval(n2)); - } } } @@ -651,9 +641,10 @@ static void reinserthash (lua_State *L, Table *ot, Table *t) { /* -** Exchange the hash part of 't1' and 't2'. (In 'flags', only the dummy -** bit must be exchanged: The metamethod bits do not change during a -** resize, so the "real" table can keep their values.) +** Exchange the hash part of 't1' and 't2'. (In 'flags', only the +** dummy bit must be exchanged: The 'isrealasize' is not related +** to the hash part, and the metamethod bits do not change during +** a resize, so the "real" table can keep their values.) */ static void exchangehashpart (Table *t1, Table *t2) { lu_byte lsizenode = t1->lsizenode; @@ -1155,28 +1146,19 @@ void luaH_finishset (lua_State *L, Table *t, const TValue *key, lua_assert(hres != HOK); if (hres == HNOTFOUND) { TValue aux; - const TValue *actk = key; /* actual key to insert */ if (l_unlikely(ttisnil(key))) luaG_runerror(L, "table index is nil"); else if (ttisfloat(key)) { lua_Number f = fltvalue(key); lua_Integer k; - if (luaV_flttointeger(f, &k, F2Ieq)) { /* is key equal to an integer? */ - setivalue(&aux, k); - actk = &aux; /* use the integer as the key */ + if (luaV_flttointeger(f, &k, F2Ieq)) { + setivalue(&aux, k); /* key is equal to an integer */ + key = &aux; /* insert it as an integer */ } else if (l_unlikely(luai_numisnan(f))) luaG_runerror(L, "table index is NaN"); } - else if (isextstr(key)) { /* external string? */ - /* If string is short, must internalize it to be used as table key */ - TString *ts = luaS_normstr(L, tsvalue(key)); - setsvalue2s(L, L->top.p++, ts); /* anchor 'ts' (EXTRA_STACK) */ - luaH_newkey(L, t, s2v(L->top.p - 1), value); - L->top.p--; - return; - } - luaH_newkey(L, t, actk, value); + luaH_newkey(L, t, key, value); } else if (hres > 0) { /* regular Node? */ setobj2t(L, gval(gnode(t, hres - HFIRSTNODE)), value); @@ -1220,36 +1202,24 @@ void luaH_setint (lua_State *L, Table *t, lua_Integer key, TValue *value) { /* ** Try to find a boundary in the hash part of table 't'. From the -** caller, we know that 'asize + 1' is present. We want to find a larger -** key that is absent from the table, so that we can do a binary search -** between the two keys to find a boundary. We keep doubling 'j' until -** we get an absent index. If the doubling would overflow, we try -** LUA_MAXINTEGER. If it is absent, we are ready for the binary search. -** ('j', being max integer, is larger or equal to 'i', but it cannot be -** equal because it is absent while 'i' is present.) Otherwise, 'j' is a -** boundary. ('j + 1' cannot be a present integer key because it is not -** a valid integer in Lua.) -** About 'rnd': If we used a fixed algorithm, a bad actor could fill -** a table with only the keys that would be probed, in such a way that -** a small table could result in a huge length. To avoid that, we use -** the state's seed as a source of randomness. For the first probe, -** we "randomly double" 'i' by adding to it a random number roughly its -** width. +** caller, we know that 'j' is zero or present and that 'j + 1' is +** present. We want to find a larger key that is absent from the +** table, so that we can do a binary search between the two keys to +** find a boundary. We keep doubling 'j' until we get an absent index. +** If the doubling would overflow, we try LUA_MAXINTEGER. If it is +** absent, we are ready for the binary search. ('j', being max integer, +** is larger or equal to 'i', but it cannot be equal because it is +** absent while 'i' is present; so 'j > i'.) Otherwise, 'j' is a +** boundary. ('j + 1' cannot be a present integer key because it is +** not a valid integer in Lua.) */ -static lua_Unsigned hash_search (lua_State *L, Table *t, unsigned asize) { - lua_Unsigned i = asize + 1; /* caller ensures t[i] is present */ - unsigned rnd = G(L)->seed; - int n = (asize > 0) ? luaO_ceillog2(asize) : 0; /* width of 'asize' */ - unsigned mask = (1u << n) - 1; /* 11...111 with the width of 'asize' */ - unsigned incr = (rnd & mask) + 1; /* first increment (at least 1) */ - lua_Unsigned j = (incr <= l_castS2U(LUA_MAXINTEGER) - i) ? i + incr : i + 1; - rnd >>= n; /* used 'n' bits from 'rnd' */ - while (!hashkeyisempty(t, j)) { /* repeat until an absent t[j] */ +static lua_Unsigned hash_search (Table *t, lua_Unsigned j) { + lua_Unsigned i; + if (j == 0) j++; /* the caller ensures 'j + 1' is present */ + do { i = j; /* 'i' is a present index */ - if (j <= l_castS2U(LUA_MAXINTEGER)/2 - 1) { - j = j*2 + (rnd & 1); /* try again with 2j or 2j+1 */ - rnd >>= 1; - } + if (j <= l_castS2U(LUA_MAXINTEGER) / 2) + j *= 2; else { j = LUA_MAXINTEGER; if (hashkeyisempty(t, j)) /* t[j] not present? */ @@ -1257,7 +1227,7 @@ static lua_Unsigned hash_search (lua_State *L, Table *t, unsigned asize) { else /* weird case */ return j; /* well, max integer is a boundary... */ } - } + } while (!hashkeyisempty(t, j)); /* repeat until an absent t[j] */ /* i < j && t[i] present && t[j] absent */ while (j - i > 1u) { /* do a binary search between them */ lua_Unsigned m = (i + j) / 2; @@ -1298,7 +1268,7 @@ static lua_Unsigned newhint (Table *t, unsigned hint) { ** If there is no array part, or its last element is non empty, the ** border may be in the hash part. */ -lua_Unsigned luaH_getn (lua_State *L, Table *t) { +lua_Unsigned luaH_getn (Table *t) { unsigned asize = t->asize; if (asize > 0) { /* is there an array part? */ const unsigned maxvicinity = 4; @@ -1339,7 +1309,7 @@ lua_Unsigned luaH_getn (lua_State *L, Table *t) { if (isdummy(t) || hashkeyisempty(t, asize + 1)) return asize; /* 'asize + 1' is empty */ else /* 'asize + 1' is also non empty */ - return hash_search(L, t, asize); + return hash_search(t, asize); } diff --git a/ltable.h b/ltable.h index f3b7bc7e..ca21e692 100644 --- a/ltable.h +++ b/ltable.h @@ -173,7 +173,7 @@ LUAI_FUNC void luaH_resizearray (lua_State *L, Table *t, unsigned nasize); LUAI_FUNC lu_mem luaH_size (Table *t); LUAI_FUNC void luaH_free (lua_State *L, Table *t); LUAI_FUNC int luaH_next (lua_State *L, Table *t, StkId key); -LUAI_FUNC lua_Unsigned luaH_getn (lua_State *L, Table *t); +LUAI_FUNC lua_Unsigned luaH_getn (Table *t); #if defined(LUA_DEBUG) diff --git a/ltablib.c b/ltablib.c index 15c3c09f..46ecb5e0 100644 --- a/ltablib.c +++ b/ltablib.c @@ -42,17 +42,15 @@ static int checkfield (lua_State *L, const char *key, int n) { /* ** Check that 'arg' either is a table or can behave like one (that is, -** has a metatable with the required metamethods). +** has a metatable with the required metamethods) */ static void checktab (lua_State *L, int arg, int what) { - int tp = lua_type(L, arg); - if (tp != LUA_TTABLE) { /* is it not a table? */ + if (lua_type(L, arg) != LUA_TTABLE) { /* is it not a table? */ int n = 1; /* number of elements to pop */ if (lua_getmetatable(L, arg) && /* must have metatable */ (!(what & TAB_R) || checkfield(L, "__index", ++n)) && (!(what & TAB_W) || checkfield(L, "__newindex", ++n)) && - (!(what & TAB_L) || /* strings don't need '__len' to have a length */ - tp == LUA_TSTRING || checkfield(L, "__len", ++n))) { + (!(what & TAB_L) || checkfield(L, "__len", ++n))) { lua_pop(L, n); /* pop metatable and tested metamethods */ } else @@ -206,9 +204,8 @@ static int tpack (lua_State *L) { static int tunpack (lua_State *L) { lua_Unsigned n; - lua_Integer len = aux_getn(L, 1, TAB_R); lua_Integer i = luaL_optinteger(L, 2, 1); - lua_Integer e = luaL_opt(L, luaL_checkinteger, 3, len); + lua_Integer e = luaL_opt(L, luaL_checkinteger, 3, luaL_len(L, 1)); if (i > e) return 0; /* empty range */ n = l_castS2U(e) - l_castS2U(i); /* number of elements minus 1 */ if (l_unlikely(n >= (unsigned int)INT_MAX || diff --git a/ltests.c b/ltests.c index 2bf5545a..e7bc66dd 100644 --- a/ltests.c +++ b/ltests.c @@ -164,13 +164,13 @@ static void warnf (void *ud, const char *msg, int tocont) { #define MARK 0x55 /* 01010101 (a nice pattern) */ -typedef union memHeader { +typedef union Header { LUAI_MAXALIGN; struct { size_t size; int type; } d; -} memHeader; +} Header; #if !defined(EXTERNMEMCHECK) @@ -193,14 +193,14 @@ Memcontrol l_memcontrol = {0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL}}; -static void freeblock (Memcontrol *mc, memHeader *block) { +static void freeblock (Memcontrol *mc, Header *block) { if (block) { size_t size = block->d.size; int i; for (i = 0; i < MARKSIZE; i++) /* check marks after block */ lua_assert(*(cast_charp(block + 1) + size + i) == MARK); mc->objcount[block->d.type]--; - fillmem(block, sizeof(memHeader) + size + MARKSIZE); /* erase block */ + fillmem(block, sizeof(Header) + size + MARKSIZE); /* erase block */ free(block); /* actually free block */ mc->numblocks--; /* update counts */ mc->total -= size; @@ -210,7 +210,7 @@ static void freeblock (Memcontrol *mc, memHeader *block) { void *debug_realloc (void *ud, void *b, size_t oldsize, size_t size) { Memcontrol *mc = cast(Memcontrol *, ud); - memHeader *block = cast(memHeader *, b); + Header *block = cast(Header *, b); int type; if (mc->memlimit == 0) { /* first time? */ char *limit = getenv("MEMLIMIT"); /* initialize memory limit */ @@ -241,12 +241,12 @@ void *debug_realloc (void *ud, void *b, size_t oldsize, size_t size) { if (size > oldsize && mc->total+size-oldsize > mc->memlimit) return NULL; /* fake a memory allocation error */ else { - memHeader *newblock; + Header *newblock; int i; size_t commonsize = (oldsize < size) ? oldsize : size; - size_t realsize = sizeof(memHeader) + size + MARKSIZE; + size_t realsize = sizeof(Header) + size + MARKSIZE; if (realsize < size) return NULL; /* arithmetic overflow! */ - newblock = cast(memHeader *, malloc(realsize)); /* alloc a new block */ + newblock = cast(Header *, malloc(realsize)); /* alloc a new block */ if (newblock == NULL) return NULL; /* really out of memory? */ if (block) { @@ -480,7 +480,7 @@ static int lua_checkpc (CallInfo *ci) { } -static void check_stack (global_State *g, lua_State *L1) { +static void checkstack (global_State *g, lua_State *L1) { StkId o; CallInfo *ci; UpVal *uv; @@ -517,7 +517,7 @@ static void checkrefs (global_State *g, GCObject *o) { break; } case LUA_VTHREAD: { - check_stack(g, gco2th(o)); + checkstack(g, gco2th(o)); break; } case LUA_VLCL: { @@ -908,17 +908,6 @@ static int get_limits (lua_State *L) { } -static int get_sizes (lua_State *L) { - lua_newtable(L); - setnameval(L, "Lua state", sizeof(lua_State)); - setnameval(L, "global state", sizeof(global_State)); - setnameval(L, "TValue", sizeof(TValue)); - setnameval(L, "Node", sizeof(Node)); - setnameval(L, "stack Value", sizeof(StackValue)); - return 1; -} - - static int mem_query (lua_State *L) { if (lua_isnone(L, 1)) { lua_pushinteger(L, cast_Integer(l_memcontrol.total)); @@ -1077,12 +1066,8 @@ static int tracegc (lua_State *L) { static int hash_query (lua_State *L) { if (lua_isnone(L, 2)) { - TString *ts; luaL_argcheck(L, lua_type(L, 1) == LUA_TSTRING, 1, "string expected"); - ts = tsvalue(obj_at(L, 1)); - if (ts->tt == LUA_VLNGSTR) - luaS_hashlongstr(ts); /* make sure long string has a hash */ - lua_pushinteger(L, cast_int(ts->hash)); + lua_pushinteger(L, cast_int(tsvalue(obj_at(L, 1))->hash)); } else { TValue *o = obj_at(L, 1); @@ -1106,27 +1091,6 @@ static int stacklevel (lua_State *L) { } -static int resetCI (lua_State *L) { - CallInfo *ci = L->ci; - while (ci->next != NULL) { - CallInfo *tofree = ci->next; - ci->next = ci->next->next; - luaM_free(L, tofree); - L->nci--; - } - return 0; -} - - -static int reallocstack (lua_State *L) { - int n = cast_int(luaL_checkinteger(L, 1)); - lua_lock(L); - luaD_reallocstack(L, cast_int(L->top.p - L->stack.p) + n, 1); - lua_unlock(L); - return 0; -} - - static int table_query (lua_State *L) { const Table *t; int i = cast_int(luaL_optinteger(L, 2, -1)); @@ -1145,7 +1109,7 @@ static int table_query (lua_State *L) { if (!tagisempty(*getArrTag(t, i))) arr2obj(t, cast_uint(i), s2v(L->top.p)); else - setnilvalue2s(L->top.p); + setnilvalue(s2v(L->top.p)); api_incr_top(L); lua_pushnil(L); } @@ -1302,7 +1266,7 @@ static int doonnewstack (lua_State *L) { lua_State *L1 = lua_newthread(L); size_t l; const char *s = luaL_checklstring(L, 1, &l); - int status = luaL_loadbufferx(L1, s, l, s, "t"); + int status = luaL_loadbuffer(L1, s, l, s); if (status == LUA_OK) status = lua_pcall(L1, 0, 0, 0); lua_pushinteger(L, status); @@ -1382,7 +1346,7 @@ static int doremote (lua_State *L) { const char *code = luaL_checklstring(L, 2, &lcode); int status; lua_settop(L1, 0); - status = luaL_loadbufferx(L1, code, lcode, code, "t"); + status = luaL_loadbuffer(L1, code, lcode, code); if (status == LUA_OK) status = lua_pcall(L1, 0, LUA_MULTRET, 0); if (status != LUA_OK) { @@ -1738,7 +1702,7 @@ static int runC (lua_State *L, lua_State *L1, const char *pc) { lua_pushinteger(L1, luaL_len(L1, getindex)); } else if EQ("loadfile") { - luaL_loadfilex(L1, luaL_checkstring(L1, getnum), "t"); + luaL_loadfile(L1, luaL_checkstring(L1, getnum)); } else if EQ("loadstring") { size_t slen; @@ -2203,9 +2167,6 @@ static const struct luaL_Reg tests_funcs[] = { {"s2d", s2d}, {"sethook", sethook}, {"stacklevel", stacklevel}, - {"resetCI", resetCI}, - {"reallocstack", reallocstack}, - {"sizes", get_sizes}, {"testC", testC}, {"makeCfunc", makeCfunc}, {"totalmem", mem_query}, diff --git a/ltests.h b/ltests.h index f5f14cd6..43f08162 100644 --- a/ltests.h +++ b/ltests.h @@ -13,8 +13,8 @@ /* test Lua with compatibility code */ #define LUA_COMPAT_MATHLIB +#define LUA_COMPAT_LT_LE #undef LUA_COMPAT_GLOBAL -#define LUA_COMPAT_GLOBAL 0 #define LUA_DEBUG @@ -64,7 +64,7 @@ LUA_API Memcontrol l_memcontrol; #define luai_tracegc(L,f) luai_tracegctest(L, f) -extern void luai_tracegctest (lua_State *L, int first); +LUAI_FUNC void luai_tracegctest (lua_State *L, int first); /* @@ -76,26 +76,26 @@ extern void *l_Trick; /* ** Function to traverse and check all memory used by Lua */ -extern int lua_checkmemory (lua_State *L); +LUAI_FUNC int lua_checkmemory (lua_State *L); /* ** Function to print an object GC-friendly */ struct GCObject; -extern void lua_printobj (lua_State *L, struct GCObject *o); +LUAI_FUNC void lua_printobj (lua_State *L, struct GCObject *o); /* ** Function to print a value */ struct TValue; -extern void lua_printvalue (struct TValue *v); +LUAI_FUNC void lua_printvalue (struct TValue *v); /* ** Function to print the stack */ -extern void lua_printstack (lua_State *L); -extern int lua_printallstack (lua_State *L); +LUAI_FUNC void lua_printstack (lua_State *L); +LUAI_FUNC int lua_printallstack (lua_State *L); /* test for lock/unlock */ @@ -122,14 +122,14 @@ LUA_API int luaB_opentests (lua_State *L); LUA_API void *debug_realloc (void *ud, void *block, size_t osize, size_t nsize); - +#if defined(lua_c) #define luaL_newstate() \ lua_newstate(debug_realloc, &l_memcontrol, luaL_makeseed(NULL)) #define luai_openlibs(L) \ { luaL_openlibs(L); \ luaL_requiref(L, "T", luaB_opentests, 1); \ lua_pop(L, 1); } - +#endif @@ -143,13 +143,19 @@ LUA_API void *debug_realloc (void *ud, void *block, #define STRCACHE_N 23 #define STRCACHE_M 5 -#define MAXINDEXRK 1 + +/* +** This one is not compatible with tests for opcode optimizations, +** as it blocks some optimizations +#define MAXINDEXRK 0 +*/ /* ** Reduce maximum stack size to make stack-overflow tests run faster. ** (But value is still large enough to overflow smaller integers.) */ +#undef LUAI_MAXSTACK #define LUAI_MAXSTACK 68000 diff --git a/ltm.c b/ltm.c index cfe90e30..8eca2d6e 100644 --- a/ltm.c +++ b/ltm.c @@ -196,12 +196,28 @@ void luaT_trybiniTM (lua_State *L, const TValue *p1, lua_Integer i2, /* ** Calls an order tag method. +** For lessequal, LUA_COMPAT_LT_LE keeps compatibility with old +** behavior: if there is no '__le', try '__lt', based on l <= r iff +** !(r < l) (assuming a total order). If the metamethod yields during +** this substitution, the continuation has to know about it (to negate +** the result of rtop.p, event); /* try original event */ if (tag >= 0) /* found tag method? */ return !tagisfalse(tag); +#if defined(LUA_COMPAT_LT_LE) + else if (event == TM_LE) { + /* try '!(p2 < p1)' for '(p1 <= p2)' */ + L->ci->callstatus |= CIST_LEQ; /* mark it is doing 'lt' for 'le' */ + tag = callbinTM(L, p2, p1, L->top.p, TM_LT); + L->ci->callstatus ^= CIST_LEQ; /* clear mark */ + if (tag >= 0) /* found tag method? */ + return tagisfalse(tag); + } +#endif luaG_ordererror(L, p1, p2); /* no metamethod found */ return 0; /* to avoid warnings */ } @@ -224,141 +240,37 @@ int luaT_callorderiTM (lua_State *L, const TValue *p1, int v2, } -/* -** 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; - TValue key, value; - 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)); - luaC_checkGC(L); -} - - -/* -** initial stack: func arg1 ... argn extra1 ... -** ^ ci->func ^ L->top -** final stack: func nil ... nil extra1 ... func arg1 ... argn -** ^ ci->func -*/ -static void buildhiddenargs (lua_State *L, CallInfo *ci, const Proto *p, - int totalargs, int nfixparams, int nextra) { +void luaT_adjustvarargs (lua_State *L, int nfixparams, CallInfo *ci, + const Proto *p) { int i; + int actual = cast_int(L->top.p - ci->func.p) - 1; /* number of arguments */ + int nextra = actual - nfixparams; /* number of extra arguments */ ci->u.l.nextraargs = nextra; luaD_checkstack(L, p->maxstacksize + 1); - /* copy function to the top of the stack, after extra arguments */ + /* copy function to the top of the stack */ setobjs2s(L, L->top.p++, ci->func.p); - /* move fixed parameters to after the copied function */ + /* move fixed parameters to the top of the stack */ for (i = 1; i <= nfixparams; i++) { setobjs2s(L, L->top.p++, ci->func.p + i); - setnilvalue2s(ci->func.p + i); /* erase original parameter (for GC) */ + setnilvalue(s2v(ci->func.p + i)); /* erase original parameter (for GC) */ } - ci->func.p += totalargs + 1; /* 'func' now lives after hidden arguments */ - ci->top.p += totalargs + 1; + ci->func.p += actual + 1; + ci->top.p += actual + 1; + lua_assert(L->top.p <= ci->top.p && ci->top.p <= L->stack_last.p); } -void luaT_adjustvarargs (lua_State *L, CallInfo *ci, const Proto *p) { - int totalargs = cast_int(L->top.p - ci->func.p) - 1; - int nfixparams = p->numparams; - int nextra = totalargs - nfixparams; /* number of extra arguments */ - if (p->flag & PF_VATAB) { /* does it need a vararg table? */ - lua_assert(!(p->flag & PF_VAHID)); - createvarargtab(L, ci->func.p + nfixparams + 1, nextra); - /* move table to proper place (last parameter) */ - setobjs2s(L, ci->func.p + nfixparams + 1, L->top.p - 1); - } - else { /* no table */ - lua_assert(p->flag & PF_VAHID); - buildhiddenargs(L, ci, p, totalargs, nfixparams, nextra); - /* set vararg parameter to nil */ - setnilvalue2s(ci->func.p + nfixparams + 1); - lua_assert(L->top.p <= ci->top.p && ci->top.p <= L->stack_last.p); - } -} - - -void luaT_getvararg (CallInfo *ci, StkId ra, TValue *rc) { +void luaT_getvarargs (lua_State *L, CallInfo *ci, StkId where, int wanted) { + int i; int nextra = ci->u.l.nextraargs; - lua_Integer n; - if (tointegerns(rc, &n)) { /* integral value? */ - if (l_castS2U(n) - 1 < cast_uint(nextra)) { - StkId slot = ci->func.p - nextra + cast_int(n) - 1; - setobjs2s(((lua_State*)NULL), ra, slot); - return; - } - } - else if (ttisstring(rc)) { /* string value? */ - size_t len; - const char *s = getlstr(tsvalue(rc), len); - if (len == 1 && s[0] == 'n') { /* key is "n"? */ - setivalue(s2v(ra), nextra); - return; - } - } - setnilvalue2s(ra); /* else produce nil */ -} - - -/* -** Get the number of extra arguments in a vararg function. If vararg -** table has been optimized away, that number is in the call info. -** Otherwise, get the field 'n' from the vararg table and check that it -** has a proper value (non-negative integer not larger than the stack -** limit). -*/ -static int getnumargs (lua_State *L, CallInfo *ci, Table *h) { - if (h == NULL) /* no vararg table? */ - return ci->u.l.nextraargs; - else { - TValue res; - if (luaH_getshortstr(h, luaS_new(L, "n"), &res) != LUA_VNUMINT || - l_castS2U(ivalue(&res)) > cast_uint(INT_MAX/2)) - luaG_runerror(L, "vararg table has no proper 'n'"); - return cast_int(ivalue(&res)); - } -} - - -/* -** Get 'wanted' vararg arguments and put them in 'where'. 'vatab' is -** the register of the vararg table or -1 if there is no vararg table. -*/ -void luaT_getvarargs (lua_State *L, CallInfo *ci, StkId where, int wanted, - int vatab) { - Table *h = (vatab < 0) ? NULL : hvalue(s2v(ci->func.p + vatab + 1)); - int nargs = getnumargs(L, ci, h); /* number of available vararg args. */ - int i, touse; /* 'touse' is minimum between 'wanted' and 'nargs' */ if (wanted < 0) { - touse = wanted = nargs; /* get all extra arguments available */ - checkstackp(L, nargs, where); /* ensure stack space */ - L->top.p = where + nargs; /* next instruction will need top */ - } - else - touse = (nargs > wanted) ? wanted : nargs; - if (h == NULL) { /* no vararg table? */ - for (i = 0; i < touse; i++) /* get vararg values from the stack */ - setobjs2s(L, where + i, ci->func.p - nargs + i); - } - else { /* get vararg values from vararg table */ - for (i = 0; i < touse; i++) { - lu_byte tag = luaH_getint(h, i + 1, s2v(where + i)); - if (tagisempty(tag)) - setnilvalue2s(where + i); - } + wanted = nextra; /* get all extra arguments available */ + checkstackp(L, nextra, where); /* ensure stack space */ + L->top.p = where + nextra; /* next instruction will need top */ } + for (i = 0; i < wanted && i < nextra; i++) + setobjs2s(L, where + i, ci->func.p - nextra + i); for (; i < wanted; i++) /* complete required results with nil */ - setnilvalue2s(where + i); + setnilvalue(s2v(where + i)); } diff --git a/ltm.h b/ltm.h index afc7ad00..ba2e4760 100644 --- a/ltm.h +++ b/ltm.h @@ -49,7 +49,7 @@ typedef enum { ** Mask with 1 in all fast-access methods. A 1 in any of these bits ** in the flag of a (meta)table means the metatable does not have the ** corresponding metamethod field. (Bit 6 of the flag indicates that -** the table is using the dummy node.) +** the table is using the dummy node; bit 7 is used for 'isrealasize'.) */ #define maskflags cast_byte(~(~0u << (TM_EQ + 1))) @@ -95,11 +95,10 @@ LUAI_FUNC int luaT_callorderTM (lua_State *L, const TValue *p1, LUAI_FUNC int luaT_callorderiTM (lua_State *L, const TValue *p1, int v2, int inv, int isfloat, TMS event); -LUAI_FUNC void luaT_adjustvarargs (lua_State *L, struct CallInfo *ci, - const Proto *p); -LUAI_FUNC void luaT_getvararg (CallInfo *ci, StkId ra, TValue *rc); -LUAI_FUNC void luaT_getvarargs (lua_State *L, struct CallInfo *ci, StkId where, - int wanted, int vatab); +LUAI_FUNC void luaT_adjustvarargs (lua_State *L, int nfixparams, + struct CallInfo *ci, const Proto *p); +LUAI_FUNC void luaT_getvarargs (lua_State *L, struct CallInfo *ci, + StkId where, int wanted); #endif diff --git a/lua.c b/lua.c index 858a04c0..3fe9b7da 100644 --- a/lua.c +++ b/lua.c @@ -30,12 +30,6 @@ #define LUA_INIT_VAR "LUA_INIT" #endif -/* Name of the environment variable with the name of the readline library */ -#if !defined(LUA_RLLIB_VAR) -#define LUA_RLLIB_VAR "LUA_READLINELIB" -#endif - - #define LUA_INITVARVERSION LUA_INIT_VAR LUA_VERSUFFIX @@ -207,12 +201,12 @@ static int dochunk (lua_State *L, int status) { static int dofile (lua_State *L, const char *name) { - return dochunk(L, luaL_loadfilex(L, name, "bt")); + return dochunk(L, luaL_loadfile(L, name)); } static int dostring (lua_State *L, const char *s, const char *name) { - return dochunk(L, luaL_loadbufferx(L, s, strlen(s), name, "t")); + return dochunk(L, luaL_loadbuffer(L, s, strlen(s), name)); } @@ -266,7 +260,7 @@ static int handle_script (lua_State *L, char **argv) { const char *fname = argv[0]; if (strcmp(fname, "-") == 0 && strcmp(argv[-1], "--") != 0) fname = NULL; /* stdin */ - status = luaL_loadfilex(L, fname, "bt"); + status = luaL_loadfile(L, fname); if (status == LUA_OK) { int n = pushargs(L); /* push arguments to script */ status = docall(L, n, LUA_MULTRET); @@ -309,8 +303,7 @@ static int collectargs (char **argv, int *first) { case '-': /* '--' */ if (argv[i][2] != '\0') /* extra characters after '--'? */ return has_error; /* invalid option */ - /* if there is a script name, it comes after '--' */ - *first = (argv[i + 1] != NULL) ? i + 1 : 0; + *first = i + 1; return args; case '\0': /* '-' */ return args; /* script "name" is '-' */ @@ -355,7 +348,6 @@ static int collectargs (char **argv, int *first) { */ static int runargs (lua_State *L, char **argv, int n) { int i; - lua_warning(L, "@off", 0); /* by default, Lua stand-alone has warnings off */ for (i = 1; i < n; i++) { int option = argv[i][1]; lua_assert(argv[i][0] == '-'); /* already checked */ @@ -380,21 +372,12 @@ static int runargs (lua_State *L, char **argv, int n) { } -static char *(*l_getenv)(const char *name); - -/* Function to ignore environment variables, used by option -E */ -static char *no_getenv (const char *name) { - UNUSED(name); - return NULL; -} - - static int handle_luainit (lua_State *L) { const char *name = "=" LUA_INITVARVERSION; - const char *init = l_getenv(name + 1); + const char *init = getenv(name + 1); if (init == NULL) { name = "=" LUA_INIT_VAR; - init = l_getenv(name + 1); /* try alternative name */ + init = getenv(name + 1); /* try alternative name */ } if (init == NULL) return LUA_OK; else if (init[0] == '@') @@ -454,24 +437,13 @@ static int handle_luainit (lua_State *L) { ** the standard input. ** * lua_saveline defines how to "save" a read line in a "history". ** * lua_freeline defines how to free a line read by lua_readline. +** +** If lua_readline is defined, all of them should be defined. */ #if !defined(lua_readline) /* { */ -/* Otherwise, all previously listed functions should be defined. */ -#if defined(LUA_USE_READLINE) /* { */ -/* Lua will be linked with '-lreadline' */ - -#include -#include - -#define lua_initreadline(L) ((void)L, rl_readline_name="lua") -#define lua_readline(buff,prompt) ((void)buff, readline(prompt)) -#define lua_saveline(line) add_history(line) -#define lua_freeline(line) free(line) - -#else /* }{ */ -/* use dynamically loaded readline (or nothing) */ +/* Code to use the readline library, either statically or dynamically linked */ /* pointer to 'readline' function (if any) */ typedef char *(*l_readlineT) (const char *prompt); @@ -507,41 +479,43 @@ static void lua_freeline (char *line) { } -#if defined(LUA_USE_DLOPEN) && defined(LUA_READLINELIB) /* { */ -/* try to load 'readline' dynamically */ +#if defined(LUA_USE_READLINE) /* { */ +/* assume Lua will be linked with '-lreadline' */ +#include +#include + +static void lua_initreadline(lua_State *L) { + UNUSED(L); + rl_readline_name = "lua"; + l_readline = readline; + l_addhist = add_history; +} + +#elif defined(LUA_USE_DLOPEN) && defined(LUA_READLINELIB) /* }{ */ + +/* try to load 'readline' dynamically */ #include static void lua_initreadline (lua_State *L) { - const char *rllib = l_getenv(LUA_RLLIB_VAR); /* name of readline library */ - void *lib; /* library handle */ - if (rllib == NULL) /* no environment variable? */ - rllib = LUA_READLINELIB; /* use default name */ - lib = dlopen(rllib, RTLD_NOW | RTLD_LOCAL); - if (lib != NULL) { + void *lib = dlopen(LUA_READLINELIB, RTLD_NOW | RTLD_LOCAL); + if (lib == NULL) + lua_warning(L, "library '" LUA_READLINELIB "' not found", 0); + else { const char **name = cast(const char**, dlsym(lib, "rl_readline_name")); if (name != NULL) *name = "lua"; l_readline = cast(l_readlineT, cast_func(dlsym(lib, "readline"))); l_addhist = cast(l_addhistT, cast_func(dlsym(lib, "add_history"))); - if (l_readline != NULL) /* could load readline function? */ - return; /* everything ok */ - /* else emit a warning */ } - lua_warning(L, "unable to load readline library '", 1); - lua_warning(L, rllib, 1); - lua_warning(L, "'", 0); } -#else /* }{ */ -/* no dlopen or LUA_READLINELIB undefined */ +#else /* }{ */ -/* Leave pointers with NULL */ -#define lua_initreadline(L) ((void)L) +/* no readline; leave function pointers as NULL */ +#define lua_initreadline(L) cast(void, L) -#endif /* } */ - -#endif /* } */ +#endif /* } */ #endif /* } */ @@ -609,11 +583,11 @@ static int pushline (lua_State *L, int firstline) { static int addreturn (lua_State *L) { const char *line = lua_tostring(L, -1); /* original line */ const char *retline = lua_pushfstring(L, "return %s;", line); - int status = luaL_loadbufferx(L, retline, strlen(retline), "=stdin", "t"); + int status = luaL_loadbuffer(L, retline, strlen(retline), "=stdin"); if (status == LUA_OK) lua_remove(L, -2); /* remove modified line */ else - lua_pop(L, 2); /* pop result from 'luaL_loadbufferx' and modified line */ + lua_pop(L, 2); /* pop result from 'luaL_loadbuffer' and modified line */ return status; } @@ -640,7 +614,7 @@ static int multiline (lua_State *L) { const char *line = lua_tolstring(L, 1, &len); /* get first line */ checklocal(line); for (;;) { /* repeat until gets a complete statement */ - int status = luaL_loadbufferx(L, line, len, "=stdin", "t"); /* try it */ + int status = luaL_loadbuffer(L, line, len, "=stdin"); /* try it */ if (!incomplete(L, status) || !pushline(L, 0)) return status; /* should not or cannot try to add continuation line */ lua_remove(L, -2); /* remove error message (from incomplete line) */ @@ -714,13 +688,7 @@ static void doREPL (lua_State *L) { /* }================================================================== */ #if !defined(luai_openlibs) -#if defined(LUA_NODEBUGLIB) -/* With this option, code must require the debug library before using it */ -#define luai_openlibs(L) luaL_openselectedlibs(L, ~LUA_DBLIBK, LUA_DBLIBK) -#else -/* The default is to open all standard libraries */ -#define luai_openlibs(L) luaL_openselectedlibs(L, ~0, 0) -#endif +#define luai_openlibs(L) luaL_openselectedlibs(L, ~0, 0) #endif @@ -742,19 +710,18 @@ static int pmain (lua_State *L) { if (args & has_v) /* option '-v'? */ print_version(); if (args & has_E) { /* option '-E'? */ - l_getenv = &no_getenv; /* program will ignore environment variables */ lua_pushboolean(L, 1); /* signal for libraries to ignore env. vars. */ lua_setfield(L, LUA_REGISTRYINDEX, "LUA_NOENV"); } - else - l_getenv = &getenv; luai_openlibs(L); /* open standard libraries */ createargtable(L, argv, argc, script); /* create table 'arg' */ lua_gc(L, LUA_GCRESTART); /* start GC... */ lua_gc(L, LUA_GCGEN); /* ...in generational mode */ - if (handle_luainit(L) != LUA_OK) /* run LUA_INIT */ - return 0; /* error running LUA_INIT */ - if (!runargs(L, argv, optlim)) /* execute arguments -e, -l, and -W */ + if (!(args & has_E)) { /* no option '-E'? */ + if (handle_luainit(L) != LUA_OK) /* run LUA_INIT */ + return 0; /* error running LUA_INIT */ + } + if (!runargs(L, argv, optlim)) /* execute arguments -e and -l */ return 0; /* something failed */ if (script > 0) { /* execute main script (if there is one) */ if (handle_script(L, argv + script) != LUA_OK) diff --git a/lua.h b/lua.h index 6deaed49..95e0db32 100644 --- a/lua.h +++ b/lua.h @@ -13,13 +13,13 @@ #include -#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2026 Lua.org, PUC-Rio" +#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2025 Lua.org, PUC-Rio" #define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes" #define LUA_VERSION_MAJOR_N 5 #define LUA_VERSION_MINOR_N 5 -#define LUA_VERSION_RELEASE_N 1 +#define LUA_VERSION_RELEASE_N 0 #define LUA_VERSION_NUM (LUA_VERSION_MAJOR_N * 100 + LUA_VERSION_MINOR_N) #define LUA_VERSION_RELEASE_NUM (LUA_VERSION_NUM * 100 + LUA_VERSION_RELEASE_N) @@ -37,10 +37,10 @@ /* ** Pseudo-indices -** (The stack size is limited to INT_MAX/2; we keep some free empty -** space after that to help overflow detection.) +** (-LUAI_MAXSTACK is the minimum valid index; we keep some free empty +** space after that to help overflow detection) */ -#define LUA_REGISTRYINDEX (-(INT_MAX/2 + 1000)) +#define LUA_REGISTRYINDEX (-LUAI_MAXSTACK - 1000) #define lua_upvalueindex(i) (LUA_REGISTRYINDEX - (i)) @@ -432,6 +432,13 @@ LUA_API void (lua_closeslot) (lua_State *L, int idx); ** compatibility macros ** =============================================================== */ +#if defined(LUA_COMPAT_APIINTCASTS) + +#define lua_pushunsigned(L,n) lua_pushinteger(L, (lua_Integer)(n)) +#define lua_tounsignedx(L,i,is) ((lua_Unsigned)lua_tointegerx(L,i,is)) +#define lua_tounsigned(L,i) lua_tounsignedx(L,(i),NULL) + +#endif #define lua_newuserdata(L,s) lua_newuserdatauv(L,s,1) #define lua_getuservalue(L,idx) lua_getiuservalue(L,idx,1) @@ -521,7 +528,7 @@ struct lua_Debug { /****************************************************************************** -* Copyright (C) 1994-2026 Lua.org, PUC-Rio. +* Copyright (C) 1994-2025 Lua.org, PUC-Rio. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the diff --git a/luaconf.h b/luaconf.h index bdac085c..51e77547 100644 --- a/luaconf.h +++ b/luaconf.h @@ -59,7 +59,7 @@ /* -** When POSIX DLL ('LUA_USE_DLOPEN') is enabled, the Lua stand-alone +** When Posix DLL ('LUA_USE_DLOPEN') is enabled, the Lua stand-alone ** application will try to dynamically link a 'readline' facility ** for its REPL. In that case, LUA_READLINELIB is the name of the ** library it will look for those facilities. If lua.c cannot open @@ -70,16 +70,14 @@ #if defined(LUA_USE_LINUX) #define LUA_USE_POSIX #define LUA_USE_DLOPEN /* needs an extra library: -ldl */ -#if !defined(LUA_READLINELIB) #define LUA_READLINELIB "libreadline.so" #endif -#endif #if defined(LUA_USE_MACOSX) #define LUA_USE_POSIX -#define LUA_USE_DLOPEN /* macOS does not need -ldl */ -#define LUA_USE_READLINE /* needs an extra library: -lreadline */ +#define LUA_USE_DLOPEN /* MacOS does not need -ldl */ +#define LUA_READLINELIB "libedit.dylib" #endif @@ -90,7 +88,7 @@ #if defined(LUA_USE_C89) && defined(LUA_USE_POSIX) -#error "POSIX is not compatible with C89" +#error "Posix is not compatible with C89" #endif @@ -140,7 +138,7 @@ /* @@ LUA_32BITS enables Lua with 32-bit integers and 32-bit floats. */ -/* #define LUA_32BITS */ +#define LUA_32BITS 0 /* @@ -155,7 +153,7 @@ #endif -#if defined(LUA_32BITS) /* { */ +#if LUA_32BITS /* { */ /* ** 32-bit integers and 'float' */ @@ -226,17 +224,17 @@ #if !defined(LUA_PATH_DEFAULT) #define LUA_PATH_DEFAULT \ - LUA_LDIR "?.lua;" LUA_LDIR "?\\init.lua;" \ - LUA_CDIR "?.lua;" LUA_CDIR "?\\init.lua;" \ - LUA_SHRDIR "?.lua;" LUA_SHRDIR "?\\init.lua;" \ + LUA_LDIR"?.lua;" LUA_LDIR"?\\init.lua;" \ + LUA_CDIR"?.lua;" LUA_CDIR"?\\init.lua;" \ + LUA_SHRDIR"?.lua;" LUA_SHRDIR"?\\init.lua;" \ ".\\?.lua;" ".\\?\\init.lua" #endif #if !defined(LUA_CPATH_DEFAULT) #define LUA_CPATH_DEFAULT \ - LUA_CDIR "?.dll;" \ - LUA_CDIR "..\\lib\\lua\\" LUA_VDIR "\\?.dll;" \ - LUA_CDIR "loadall.dll;" ".\\?.dll" + LUA_CDIR"?.dll;" \ + LUA_CDIR"..\\lib\\lua\\" LUA_VDIR "\\?.dll;" \ + LUA_CDIR"loadall.dll;" ".\\?.dll" #endif #else /* }{ */ @@ -247,14 +245,14 @@ #if !defined(LUA_PATH_DEFAULT) #define LUA_PATH_DEFAULT \ - LUA_LDIR "?.lua;" LUA_LDIR "?/init.lua;" \ - LUA_CDIR "?.lua;" LUA_CDIR "?/init.lua;" \ + LUA_LDIR"?.lua;" LUA_LDIR"?/init.lua;" \ + LUA_CDIR"?.lua;" LUA_CDIR"?/init.lua;" \ "./?.lua;" "./?/init.lua" #endif #if !defined(LUA_CPATH_DEFAULT) #define LUA_CPATH_DEFAULT \ - LUA_CDIR "?.so;" LUA_CDIR "loadall.so;" "./?.so" + LUA_CDIR"?.so;" LUA_CDIR"loadall.so;" "./?.so" #endif #endif /* } */ @@ -321,13 +319,32 @@ ** More often than not the libs go together with the core. */ #define LUALIB_API LUA_API - -#if defined(__cplusplus) -/* Lua uses the "C name" when calling open functions */ -#define LUAMOD_API extern "C" -#else #define LUAMOD_API LUA_API -#endif + + +/* +@@ LUAI_FUNC is a mark for all extern functions that are not to be +** exported to outside modules. +@@ LUAI_DDEF and LUAI_DDEC are marks for all extern (const) variables, +** none of which to be exported to outside modules (LUAI_DDEF for +** definitions and LUAI_DDEC for declarations). +** CHANGE them if you need to mark them in some special way. Elf/gcc +** (versions 3.2 and later) mark them as "hidden" to optimize access +** when Lua is compiled as a shared library. Not all elf targets support +** this attribute. Unfortunately, gcc does not offer a way to check +** whether the target offers that support, and those without support +** give a warning about it. To avoid these warnings, change to the +** default definition. +*/ +#if defined(__GNUC__) && ((__GNUC__*100 + __GNUC_MINOR__) >= 302) && \ + defined(__ELF__) /* { */ +#define LUAI_FUNC __attribute__((visibility("internal"))) extern +#else /* }{ */ +#define LUAI_FUNC extern +#endif /* } */ + +#define LUAI_DDEC(dec) LUAI_FUNC dec +#define LUAI_DDEF /* empty */ /* }================================================================== */ @@ -341,18 +358,39 @@ /* @@ LUA_COMPAT_GLOBAL avoids 'global' being a reserved word */ -#if !defined(LUA_COMPAT_GLOBAL) -#define LUA_COMPAT_GLOBAL 1 -#endif +#define LUA_COMPAT_GLOBAL +/* +@@ LUA_COMPAT_5_3 controls other macros for compatibility with Lua 5.3. +** You can define it to get all options, or change specific options +** to fit your specific needs. +*/ +#if defined(LUA_COMPAT_5_3) /* { */ + /* @@ LUA_COMPAT_MATHLIB controls the presence of several deprecated ** functions in the mathematical library. ** (These functions were already officially removed in 5.3; ** nevertheless they are still available here.) */ -/* #define LUA_COMPAT_MATHLIB */ +#define LUA_COMPAT_MATHLIB + +/* +@@ LUA_COMPAT_APIINTCASTS controls the presence of macros for +** manipulating other integer types (lua_pushunsigned, lua_tounsigned, +** luaL_checkint, luaL_checklong, etc.) +** (These macros were also officially removed in 5.3, but they are still +** available here.) +*/ +#define LUA_COMPAT_APIINTCASTS + + +/* +@@ LUA_COMPAT_LT_LE controls the emulation of the '__le' metamethod +** using '__lt'. +*/ +#define LUA_COMPAT_LT_LE /* @@ -369,6 +407,8 @@ #define lua_equal(L,idx1,idx2) lua_compare(L,(idx1),(idx2),LUA_OPEQ) #define lua_lessthan(L,idx1,idx2) lua_compare(L,(idx1),(idx2),LUA_OPLT) +#endif /* } */ + /* }================================================================== */ @@ -400,11 +440,26 @@ */ -/* The following definition is good for most cases here */ +/* The following definitions are good for most cases here */ #define l_floor(x) (l_mathop(floor)(x)) +/* +@@ lua_numbertointeger converts a float number with an integral value +** to an integer, or returns 0 if float is not within the range of +** a lua_Integer. (The range comparisons are tricky because of +** rounding. The tests here assume a two-complement representation, +** where MININTEGER always has an exact representation as a float; +** MAXINTEGER may not have one, and therefore its conversion to float +** may have an ill-defined value.) +*/ +#define lua_numbertointeger(n,p) \ + ((n) >= (LUA_NUMBER)(LUA_MININTEGER) && \ + (n) < -(LUA_NUMBER)(LUA_MININTEGER) && \ + (*(p) = (LUA_INTEGER)(n), 1)) + + /* now the variable definitions */ #if LUA_FLOAT_TYPE == LUA_FLOAT_FLOAT /* { single float */ @@ -653,7 +708,7 @@ */ #if !defined(luai_likely) -#if !defined(LUA_NOBUILTIN) && defined(__GNUC__) && (__GNUC__ >= 3) +#if defined(__GNUC__) && !defined(LUA_NOBUILTIN) #define luai_likely(x) (__builtin_expect(((x) != 0), 1)) #define luai_unlikely(x) (__builtin_expect(((x) != 0), 0)) #else @@ -664,6 +719,13 @@ #endif +#if defined(LUA_CORE) || defined(LUA_LIB) +/* shorter names for Lua's own use */ +#define l_likely(x) luai_likely(x) +#define l_unlikely(x) luai_unlikely(x) +#endif + + /* }================================================================== */ @@ -701,6 +763,20 @@ ** ===================================================================== */ +/* +@@ LUAI_MAXSTACK limits the size of the Lua stack. +** CHANGE it if you need a different limit. This limit is arbitrary; +** its only purpose is to stop Lua from consuming unlimited stack +** space and to reserve some numbers for pseudo-indices. +** (It must fit into max(int)/2.) +*/ +#if 1000000 < (INT_MAX / 2) +#define LUAI_MAXSTACK 1000000 +#else +#define LUAI_MAXSTACK (INT_MAX / 2u) +#endif + + /* @@ LUA_EXTRASPACE defines the size of a raw memory area associated with ** a Lua state with very fast access. @@ -725,17 +801,10 @@ /* -@@ LUAI_MAXALIGN defines fields that ensure proper alignment for -** memory areas offered by Lua (e.g., userdata memory). -** Add fields to it if you need alignment for non-ISO objects. +@@ LUAI_MAXALIGN defines fields that, when used in a union, ensure +** maximum alignment for the other items in that union. */ -#if defined(LLONG_MAX) -/* use ISO C99 stuff */ -#define LUAI_MAXALIGN long double u; void *s; long long l -#else -/* use only C89 stuff */ #define LUAI_MAXALIGN lua_Number n; double u; void *s; lua_Integer i; long l -#endif /* }================================================================== */ @@ -752,5 +821,7 @@ + + #endif diff --git a/lundump.c b/lundump.c index d5fdc64b..ade40384 100644 --- a/lundump.c +++ b/lundump.c @@ -109,7 +109,7 @@ static lua_Unsigned loadVarint (LoadState *S, lua_Unsigned limit) { static size_t loadSize (LoadState *S) { - return cast_sizet(loadVarint(S, MAX_SIZE)); + return loadVarint(S, MAX_SIZE); } @@ -147,20 +147,20 @@ static void loadString (LoadState *S, Proto *p, TString **sl) { TString *ts; TValue sv; size_t size = loadSize(S); - if (size == 0) { /* previously saved string? */ + if (size == 0) { /* no string? */ + lua_assert(*sl == NULL); /* must be prefilled */ + return; + } + else if (size == 1) { /* previously saved string? */ lua_Unsigned idx = loadVarint(S, LUA_MAXUNSIGNED); /* get its index */ TValue stv; - if (idx == 0) { /* no string? */ - lua_assert(*sl == NULL); /* must be prefilled */ - return; - } if (novariant(luaH_getint(S->h, l_castU2S(idx), &stv)) != LUA_TSTRING) error(S, "invalid string index"); *sl = ts = tsvalue(&stv); /* get its value */ luaC_objbarrier(L, p, ts); return; /* do not save it again */ } - else if ((size -= 1) <= LUAI_MAXSHORTLEN) { /* short string? */ + else if ((size -= 2) <= LUAI_MAXSHORTLEN) { /* short string? */ char buff[LUAI_MAXSHORTLEN + 1]; /* extra space for '\0' */ loadVector(S, buff, size + 1); /* load string into buffer */ *sl = ts = luaS_newlstr(L, buff, size); /* create string */ @@ -327,8 +327,7 @@ static void loadFunction (LoadState *S, Proto *f) { f->linedefined = loadInt(S); f->lastlinedefined = loadInt(S); f->numparams = loadByte(S); - /* get only the meaningful flags */ - f->flag = cast_byte(loadByte(S) & ~PF_FIXED); + f->flag = loadByte(S) & PF_ISVARARG; /* get only the meaningful flags */ if (S->fixed) f->flag |= PF_FIXED; /* signal that code is fixed */ f->maxstacksize = loadByte(S); @@ -392,8 +391,7 @@ static void checkHeader (LoadState *S) { /* ** Load precompiled chunk. */ -LClosure *luaU_undump (lua_State *L, ZIO *Z, Table *anchor, const char *name, - int fixed) { +LClosure *luaU_undump (lua_State *L, ZIO *Z, const char *name, int fixed) { LoadState S; LClosure *cl; if (*name == '@' || *name == '=') @@ -406,16 +404,20 @@ LClosure *luaU_undump (lua_State *L, ZIO *Z, Table *anchor, const char *name, S.fixed = cast_byte(fixed); S.offset = 1; /* fist byte was already read */ checkHeader(&S); - S.h = anchor; - S.nstr = 0; cl = luaF_newLclosure(L, loadByte(&S)); - luaD_anchorobj(L, anchor, obj2gco(cl)); + setclLvalue2s(L, L->top.p, cl); + luaD_inctop(L); + S.h = luaH_new(L); /* create list of saved strings */ + S.nstr = 0; + sethvalue2s(L, L->top.p, S.h); /* anchor it */ + luaD_inctop(L); cl->p = luaF_newproto(L); luaC_objbarrier(L, cl, cl->p); loadFunction(&S, cl->p); if (cl->nupvalues != cl->p->sizeupvalues) error(&S, "corrupted chunk"); luai_verifycode(L, cl->p); + L->top.p--; /* pop table */ return cl; } diff --git a/lundump.h b/lundump.h index 186e25f8..c4e06f9e 100644 --- a/lundump.h +++ b/lundump.h @@ -30,8 +30,8 @@ /* load one chunk; from lundump.c */ -LUAI_FUNC LClosure* luaU_undump (lua_State* L, ZIO* Z, Table *anchor, - const char* name, int fixed); +LUAI_FUNC LClosure* luaU_undump (lua_State* L, ZIO* Z, const char* name, + int fixed); /* dump one chunk; from ldump.c */ LUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, diff --git a/lutf8lib.c b/lutf8lib.c index 0cd7f9c3..4c9784e0 100644 --- a/lutf8lib.c +++ b/lutf8lib.c @@ -10,6 +10,7 @@ #include "lprefix.h" +#include #include #include #include @@ -46,7 +47,7 @@ static lua_Integer u_posrelat (lua_Integer pos, size_t len) { ** Decode one UTF-8 sequence, returning NULL if byte sequence is ** invalid. The array 'limits' stores the minimum value for each ** sequence length, to check for overlong representations. Its first -** entry forces an error for non-ASCII bytes with no continuation +** entry forces an error for non-ascii bytes with no continuation ** bytes (count == 0). */ static const char *utf8_decode (const char *s, l_uint32 *val, int strict) { @@ -54,10 +55,8 @@ static const char *utf8_decode (const char *s, l_uint32 *val, int strict) { {~(l_uint32)0, 0x80, 0x800, 0x10000u, 0x200000u, 0x4000000u}; unsigned int c = (unsigned char)s[0]; l_uint32 res = 0; /* final result */ - if (c < 0x80) /* ASCII? */ + if (c < 0x80) /* ascii? */ res = c; - else if (c >= 0xfe) /* c >= 1111 1110b ? */ - return NULL; /* would need six or more continuation bytes */ else { int count = 0; /* to count number of continuation bytes */ for (; c & 0x40; c <<= 1) { /* while it needs continuation bytes... */ @@ -66,9 +65,8 @@ static const char *utf8_decode (const char *s, l_uint32 *val, int strict) { return NULL; /* invalid byte sequence */ res = (res << 6) | (cc & 0x3F); /* add lower 6 bits from cont. byte */ } - lua_assert(count <= 5); res |= ((l_uint32)(c & 0x7F) << (count * 5)); /* add first byte */ - if (res > MAXUTF || res < limits[count]) + if (count > 5 || res > MAXUTF || res < limits[count]) return NULL; /* invalid byte sequence */ s += count; /* skip continuation bytes read */ } @@ -149,7 +147,7 @@ static int codepoint (lua_State *L) { static void pushutfchar (lua_State *L, int arg) { lua_Unsigned code = (lua_Unsigned)luaL_checkinteger(L, arg); luaL_argcheck(L, code <= MAXUTF, arg, "value out of range"); - lua_pushfstring(L, "%U", cast(unsigned long, code)); + lua_pushfstring(L, "%U", (long)code); } @@ -217,10 +215,9 @@ static int byteoffset (lua_State *L) { } lua_pushinteger(L, posi + 1); /* initial position */ if ((s[posi] & 0x80) != 0) { /* multi-byte character? */ - if (iscont(s[posi])) - return luaL_error(L, "initial position is a continuation byte"); - while (iscontp(s + posi + 1)) - posi++; /* skip to last continuation byte */ + do { + posi++; + } while (iscontp(s + posi + 1)); /* skip to final byte */ } /* else one-byte character: final position is the initial one */ lua_pushinteger(L, posi + 1); /* 'posi' now is the final position */ diff --git a/lvm.c b/lvm.c index 46170534..97dfe5ee 100644 --- a/lvm.c +++ b/lvm.c @@ -268,9 +268,9 @@ static int forprep (lua_State *L, StkId ra) { /* ** Execute a step of a float numerical for loop, returning ** true iff the loop must continue. (The integer case is -** written inline with opcode OP_FORLOOP, for performance.) +** written online with opcode OP_FORLOOP, for performance.) */ -static int floatforloop (lua_State *L, StkId ra) { +static int floatforloop (StkId ra) { lua_Number step = fltvalue(s2v(ra + 1)); lua_Number limit = fltvalue(s2v(ra)); lua_Number idx = fltvalue(s2v(ra + 2)); /* control variable */ @@ -303,7 +303,7 @@ lu_byte luaV_finishget (lua_State *L, const TValue *t, TValue *key, else { /* 't' is a table */ tm = fasttm(L, hvalue(t)->metatable, TM_INDEX); /* table's metamethod */ if (tm == NULL) { /* no metamethod? */ - setnilvalue2s(val); /* result is nil */ + setnilvalue(s2v(val)); /* result is nil */ return LUA_VNIL; } /* else will try the metamethod */ @@ -360,32 +360,18 @@ void luaV_finishset (lua_State *L, const TValue *t, TValue *key, luaT_callTM(L, tm, t, key, val); return; } - t = tm; /* else must repeat assignment over 'tm' */ - /* do the equivalent to 'luaV_fastset', but saving 'h' */ - if (!ttistable(t)) - hres = HNOTATABLE; - else { - Table *h = hvalue(t); /* next call can change the value at 't' */ - hres = luaH_pset(h, key, val); - if (hres == HOK) { - luaC_barrierback(L, obj2gco(h), val); /* luaV_finishfastset */ - return; /* done */ - } + t = tm; /* else repeat assignment over 'tm' */ + luaV_fastset(t, key, val, hres, luaH_pset); + if (hres == HOK) { + luaV_finishfastset(L, t, val); + return; /* done */ } - /* else 'return luaV_finishset(L, t, key, val, hres)' (loop) */ + /* else 'return luaV_finishset(L, t, key, val, slot)' (loop) */ } luaG_runerror(L, "'__newindex' chain too long; possible loop"); } -/* -** Function to be used for 0-terminated string order comparison -*/ -#if !defined(l_strcoll) -#define l_strcoll strcoll -#endif - - /* ** Compare two strings 'ts1' x 'ts2', returning an integer less-equal- ** -greater than zero if 'ts1' is less-equal-greater than 'ts2'. @@ -400,7 +386,7 @@ static int l_strcmp (const TString *ts1, const TString *ts2) { size_t rl2; const char *s2 = getlstr(ts2, rl2); for (;;) { /* for each segment */ - int temp = l_strcoll(s1, s2); + int temp = strcoll(s1, s2); if (temp != 0) /* not equal? */ return temp; /* done */ else { /* strings are equal up to a '\0' */ @@ -587,74 +573,52 @@ int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r) { */ int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2) { const TValue *tm; - if (ttype(t1) != ttype(t2)) /* not the same type? */ - return 0; - else if (ttypetag(t1) != ttypetag(t2)) { - switch (ttypetag(t1)) { - case LUA_VNUMINT: { /* integer == float? */ - /* integer and float can only be equal if float has an integer - value equal to the integer */ - lua_Integer i2; - return (luaV_flttointeger(fltvalue(t2), &i2, F2Ieq) && - ivalue(t1) == i2); - } - case LUA_VNUMFLT: { /* float == integer? */ - lua_Integer i1; /* see comment in previous case */ - return (luaV_flttointeger(fltvalue(t1), &i1, F2Ieq) && - i1 == ivalue(t2)); - } - case LUA_VSHRSTR: case LUA_VLNGSTR: { - /* compare two strings with different variants: they can be - equal when one string is a short string and the other is - an external string */ - return luaS_eqstr(tsvalue(t1), tsvalue(t2)); - } - default: - /* only numbers (integer/float) and strings (long/short) can have - equal values with different variants */ - return 0; + if (ttypetag(t1) != ttypetag(t2)) { /* not the same variant? */ + if (ttype(t1) != ttype(t2) || ttype(t1) != LUA_TNUMBER) + return 0; /* only numbers can be equal with different variants */ + else { /* two numbers with different variants */ + /* One of them is an integer. If the other does not have an + integer value, they cannot be equal; otherwise, compare their + integer values. */ + lua_Integer i1, i2; + return (luaV_tointegerns(t1, &i1, F2Ieq) && + luaV_tointegerns(t2, &i2, F2Ieq) && + i1 == i2); } } - else { /* equal variants */ - switch (ttypetag(t1)) { - case LUA_VNIL: case LUA_VFALSE: case LUA_VTRUE: - return 1; - case LUA_VNUMINT: - return (ivalue(t1) == ivalue(t2)); - case LUA_VNUMFLT: - return (fltvalue(t1) == fltvalue(t2)); - case LUA_VLIGHTUSERDATA: return pvalue(t1) == pvalue(t2); - case LUA_VSHRSTR: - return eqshrstr(tsvalue(t1), tsvalue(t2)); - case LUA_VLNGSTR: - return luaS_eqstr(tsvalue(t1), tsvalue(t2)); - case LUA_VUSERDATA: { - if (uvalue(t1) == uvalue(t2)) return 1; - else if (L == NULL) return 0; - tm = fasttm(L, uvalue(t1)->metatable, TM_EQ); - if (tm == NULL) - tm = fasttm(L, uvalue(t2)->metatable, TM_EQ); - break; /* will try TM */ - } - case LUA_VTABLE: { - if (hvalue(t1) == hvalue(t2)) return 1; - else if (L == NULL) return 0; - tm = fasttm(L, hvalue(t1)->metatable, TM_EQ); - if (tm == NULL) - tm = fasttm(L, hvalue(t2)->metatable, TM_EQ); - break; /* will try TM */ - } - case LUA_VLCF: - return (fvalue(t1) == fvalue(t2)); - default: /* functions and threads */ - return (gcvalue(t1) == gcvalue(t2)); + /* values have same type and same variant */ + switch (ttypetag(t1)) { + case LUA_VNIL: case LUA_VFALSE: case LUA_VTRUE: return 1; + case LUA_VNUMINT: return (ivalue(t1) == ivalue(t2)); + case LUA_VNUMFLT: return luai_numeq(fltvalue(t1), fltvalue(t2)); + case LUA_VLIGHTUSERDATA: return pvalue(t1) == pvalue(t2); + case LUA_VLCF: return fvalue(t1) == fvalue(t2); + case LUA_VSHRSTR: return eqshrstr(tsvalue(t1), tsvalue(t2)); + case LUA_VLNGSTR: return luaS_eqlngstr(tsvalue(t1), tsvalue(t2)); + case LUA_VUSERDATA: { + if (uvalue(t1) == uvalue(t2)) return 1; + else if (L == NULL) return 0; + tm = fasttm(L, uvalue(t1)->metatable, TM_EQ); + if (tm == NULL) + tm = fasttm(L, uvalue(t2)->metatable, TM_EQ); + break; /* will try TM */ } - if (tm == NULL) /* no TM? */ - return 0; /* objects are different */ - else { - int tag = luaT_callTMres(L, tm, t1, t2, L->top.p); /* call TM */ - return !tagisfalse(tag); + case LUA_VTABLE: { + if (hvalue(t1) == hvalue(t2)) return 1; + else if (L == NULL) return 0; + tm = fasttm(L, hvalue(t1)->metatable, TM_EQ); + if (tm == NULL) + tm = fasttm(L, hvalue(t2)->metatable, TM_EQ); + break; /* will try TM */ } + default: + return gcvalue(t1) == gcvalue(t2); + } + if (tm == NULL) /* no TM? */ + return 0; /* objects are different */ + else { + int tag = luaT_callTMres(L, tm, t1, t2, L->top.p); /* call TM */ + return !tagisfalse(tag); } } @@ -663,11 +627,6 @@ int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2) { #define tostring(L,o) \ (ttisstring(o) || (cvt2str(o) && (luaO_tostring(L, o), 1))) -/* -** Check whether object is a short empty string to optimize concatenation. -** (External strings can be empty too; they will be concatenated like -** non-empty ones.) -*/ #define isemptystr(o) (ttisshrstring(o) && tsvalue(o)->shrlen == 0) /* copy strings in stack from top - n up to top - 1 to buffer */ @@ -702,8 +661,8 @@ void luaV_concat (lua_State *L, int total) { setobjs2s(L, top - 2, top - 1); /* result is second op. */ } else { - /* at least two string values; get as many as possible */ - size_t tl = tsslen(tsvalue(s2v(top - 1))); /* total length */ + /* at least two non-empty string values; get as many as possible */ + size_t tl = tsslen(tsvalue(s2v(top - 1))); TString *ts; /* collect total length and number of strings */ for (n = 1; n < total && tostring(L, s2v(top - n - 1)); n++) { @@ -741,7 +700,7 @@ void luaV_objlen (lua_State *L, StkId ra, const TValue *rb) { Table *h = hvalue(rb); tm = fasttm(L, h->metatable, TM_LEN); if (tm) break; /* metamethod? break switch to call it */ - setivalue(s2v(ra), l_castU2S(luaH_getn(L, h))); /* else primitive len */ + setivalue(s2v(ra), l_castU2S(luaH_getn(h))); /* else primitive len */ return; } case LUA_VSHRSTR: { @@ -880,6 +839,12 @@ void luaV_finishOp (lua_State *L) { case OP_EQ: { /* note that 'OP_EQI'/'OP_EQK' cannot yield */ int res = !l_isfalse(s2v(L->top.p - 1)); L->top.p--; +#if defined(LUA_COMPAT_LT_LE) + if (ci->callstatus & CIST_LEQ) { /* "<=" using "<" instead? */ + ci->callstatus ^= CIST_LEQ; /* clear mark */ + res = !res; /* negate result */ + } +#endif lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_JMP); if (res != GETARG_k(inst)) /* condition failed? */ ci->u.l.savedpc++; /* skip jump instruction */ @@ -923,10 +888,6 @@ void luaV_finishOp (lua_State *L) { /* ** {================================================================== ** Macros for arithmetic/bitwise/comparison opcodes in 'luaV_execute' -** -** All these macros are to be used exclusively inside the main -** interpreter loop (function luaV_execute) and may access directly -** the local variables of that function (L, i, pc, ci, etc.). ** =================================================================== */ @@ -948,17 +909,17 @@ void luaV_finishOp (lua_State *L) { ** operation, 'fop' is the float operation. */ #define op_arithI(L,iop,fop) { \ - TValue *ra = vRA(i); \ + StkId ra = RA(i); \ TValue *v1 = vRB(i); \ int imm = GETARG_sC(i); \ if (ttisinteger(v1)) { \ lua_Integer iv1 = ivalue(v1); \ - pc++; setivalue(ra, iop(L, iv1, imm)); \ + pc++; setivalue(s2v(ra), iop(L, iv1, imm)); \ } \ else if (ttisfloat(v1)) { \ lua_Number nb = fltvalue(v1); \ lua_Number fimm = cast_num(imm); \ - pc++; setfltvalue(ra, fop(L, nb, fimm)); \ + pc++; setfltvalue(s2v(ra), fop(L, nb, fimm)); \ }} @@ -969,7 +930,6 @@ void luaV_finishOp (lua_State *L) { #define op_arithf_aux(L,v1,v2,fop) { \ lua_Number n1; lua_Number n2; \ if (tonumberns(v1, n1) && tonumberns(v2, n2)) { \ - StkId ra = RA(i); \ pc++; setfltvalue(s2v(ra), fop(L, n1, n2)); \ }} @@ -978,6 +938,7 @@ void luaV_finishOp (lua_State *L) { ** Arithmetic operations over floats and others with register operands. */ #define op_arithf(L,fop) { \ + StkId ra = RA(i); \ TValue *v1 = vRB(i); \ TValue *v2 = vRC(i); \ op_arithf_aux(L, v1, v2, fop); } @@ -987,6 +948,7 @@ void luaV_finishOp (lua_State *L) { ** Arithmetic operations with K operands for floats. */ #define op_arithfK(L,fop) { \ + StkId ra = RA(i); \ TValue *v1 = vRB(i); \ TValue *v2 = KC(i); lua_assert(ttisnumber(v2)); \ op_arithf_aux(L, v1, v2, fop); } @@ -996,8 +958,8 @@ void luaV_finishOp (lua_State *L) { ** Arithmetic operations over integers and floats. */ #define op_arith_aux(L,v1,v2,iop,fop) { \ + StkId ra = RA(i); \ if (ttisinteger(v1) && ttisinteger(v2)) { \ - StkId ra = RA(i); \ lua_Integer i1 = ivalue(v1); lua_Integer i2 = ivalue(v2); \ pc++; setivalue(s2v(ra), iop(L, i1, i2)); \ } \ @@ -1026,12 +988,12 @@ void luaV_finishOp (lua_State *L) { ** Bitwise operations with constant operand. */ #define op_bitwiseK(L,op) { \ + StkId ra = RA(i); \ TValue *v1 = vRB(i); \ TValue *v2 = KC(i); \ lua_Integer i1; \ lua_Integer i2 = ivalue(v2); \ if (tointegerns(v1, &i1)) { \ - StkId ra = RA(i); \ pc++; setivalue(s2v(ra), op(i1, i2)); \ }} @@ -1040,11 +1002,11 @@ void luaV_finishOp (lua_State *L) { ** Bitwise operations with register operands. */ #define op_bitwise(L,op) { \ + StkId ra = RA(i); \ TValue *v1 = vRB(i); \ TValue *v2 = vRC(i); \ lua_Integer i1; lua_Integer i2; \ if (tointegerns(v1, &i1) && tointegerns(v2, &i2)) { \ - StkId ra = RA(i); \ pc++; setivalue(s2v(ra), op(i1, i2)); \ }} @@ -1055,18 +1017,18 @@ void luaV_finishOp (lua_State *L) { ** integers. */ #define op_order(L,opi,opn,other) { \ - TValue *ra = vRA(i); \ + StkId ra = RA(i); \ int cond; \ TValue *rb = vRB(i); \ - if (ttisinteger(ra) && ttisinteger(rb)) { \ - lua_Integer ia = ivalue(ra); \ + if (ttisinteger(s2v(ra)) && ttisinteger(rb)) { \ + lua_Integer ia = ivalue(s2v(ra)); \ lua_Integer ib = ivalue(rb); \ cond = opi(ia, ib); \ } \ - else if (ttisnumber(ra) && ttisnumber(rb)) \ - cond = opn(ra, rb); \ + else if (ttisnumber(s2v(ra)) && ttisnumber(rb)) \ + cond = opn(s2v(ra), rb); \ else \ - Protect(cond = other(L, ra, rb)); \ + Protect(cond = other(L, s2v(ra), rb)); \ docondjump(); } @@ -1075,19 +1037,19 @@ void luaV_finishOp (lua_State *L) { ** always small enough to have an exact representation as a float.) */ #define op_orderI(L,opi,opf,inv,tm) { \ - TValue *ra = vRA(i); \ + StkId ra = RA(i); \ int cond; \ int im = GETARG_sB(i); \ - if (ttisinteger(ra)) \ - cond = opi(ivalue(ra), im); \ - else if (ttisfloat(ra)) { \ - lua_Number fa = fltvalue(ra); \ + if (ttisinteger(s2v(ra))) \ + cond = opi(ivalue(s2v(ra)), im); \ + else if (ttisfloat(s2v(ra))) { \ + lua_Number fa = fltvalue(s2v(ra)); \ lua_Number fim = cast_num(im); \ cond = opf(fa, fim); \ } \ else { \ int isf = GETARG_C(i); \ - Protect(cond = luaT_callorderiTM(L, ra, im, inv, isf, tm)); \ + Protect(cond = luaT_callorderiTM(L, s2v(ra), im, inv, isf, tm)); \ } \ docondjump(); } @@ -1106,7 +1068,6 @@ void luaV_finishOp (lua_State *L) { #define RA(i) (base+GETARG_A(i)) -#define vRA(i) s2v(RA(i)) #define RB(i) (base+GETARG_B(i)) #define vRB(i) s2v(RB(i)) #define KB(i) (k+GETARG_B(i)) @@ -1117,7 +1078,7 @@ void luaV_finishOp (lua_State *L) { -#define updatetrap(ci) (trap = cast_int(ci->u.l.trap)) +#define updatetrap(ci) (trap = ci->u.l.trap) #define updatebase(ci) (base = ci->func.p + 1) @@ -1147,14 +1108,14 @@ void luaV_finishOp (lua_State *L) { /* ** Correct global 'pc'. */ -#define savepc(ci) (ci->u.l.savedpc = pc) +#define savepc(L) (ci->u.l.savedpc = pc) /* ** Whenever code can raise errors, the global 'pc' and the global ** 'top' must be correct to report occasional errors. */ -#define savestate(L,ci) (savepc(ci), L->top.p = ci->top.p) +#define savestate(L,ci) (savepc(L), L->top.p = ci->top.p) /* @@ -1164,7 +1125,7 @@ void luaV_finishOp (lua_State *L) { #define Protect(exp) (savestate(L,ci), (exp), updatetrap(ci)) /* special version that does not change the top */ -#define ProtectNT(exp) (savepc(ci), (exp), updatetrap(ci)) +#define ProtectNT(exp) (savepc(L), (exp), updatetrap(ci)) /* ** Protect code that can only raise errors. (That is, it cannot change @@ -1182,7 +1143,7 @@ void luaV_finishOp (lua_State *L) { /* 'c' is the limit of live values in the stack */ #define checkGC(L,c) \ - { luaC_condGC(L, (savepc(ci), L->top.p = (c)), \ + { luaC_condGC(L, (savepc(L), L->top.p = (c)), \ updatetrap(ci)); \ luai_threadyield(L); } @@ -1211,7 +1172,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) { #include "ljumptab.h" #endif startfunc: - trap = cast_int(L->hookmask); + trap = L->hookmask; returning: /* trap already set */ cl = ci_func(ci); k = cl->p->k; @@ -1489,16 +1450,6 @@ void luaV_execute (lua_State *L, CallInfo *ci) { op_bitwiseK(L, l_bxor); vmbreak; } - vmcase(OP_SHLI) { - StkId ra = RA(i); - TValue *rb = vRB(i); - int ic = GETARG_sC(i); - lua_Integer ib; - if (tointegerns(rb, &ib)) { - pc++; setivalue(s2v(ra), luaV_shiftl(ic, ib)); - } - vmbreak; - } vmcase(OP_SHRI) { StkId ra = RA(i); TValue *rb = vRB(i); @@ -1509,6 +1460,16 @@ void luaV_execute (lua_State *L, CallInfo *ci) { } vmbreak; } + vmcase(OP_SHLI) { + StkId ra = RA(i); + TValue *rb = vRB(i); + int ic = GETARG_sC(i); + lua_Integer ib; + if (tointegerns(rb, &ib)) { + pc++; setivalue(s2v(ra), luaV_shiftl(ic, ib)); + } + vmbreak; + } vmcase(OP_ADD) { op_arith(L, l_addi, luai_numadd); vmbreak; @@ -1551,14 +1512,14 @@ void luaV_execute (lua_State *L, CallInfo *ci) { op_bitwise(L, l_bxor); vmbreak; } - vmcase(OP_SHL) { - op_bitwise(L, luaV_shiftl); - vmbreak; - } vmcase(OP_SHR) { op_bitwise(L, luaV_shiftr); vmbreak; } + vmcase(OP_SHL) { + op_bitwise(L, luaV_shiftl); + vmbreak; + } vmcase(OP_MMBIN) { StkId ra = RA(i); Instruction pi = *(pc - 2); /* original arith. expression */ @@ -1731,7 +1692,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) { if (b != 0) /* fixed number of arguments? */ L->top.p = ra + b; /* top signals number of arguments */ /* else previous instruction set top */ - savepc(ci); /* in case of errors */ + savepc(L); /* in case of errors */ if ((newci = luaD_precall(L, ra, nresults)) == NULL) updatetrap(ci); /* C call; nothing else to be done */ else { /* Lua call: run function in this same C frame */ @@ -1847,7 +1808,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) { pc -= GETARG_Bx(i); /* jump back */ } } - else if (floatforloop(L, ra)) /* float loop */ + else if (floatforloop(ra)) /* float loop */ pc -= GETARG_Bx(i); /* jump back */ updatetrap(ci); /* allows a signal to break the loop */ vmbreak; @@ -1907,7 +1868,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) { vmcase(OP_SETLIST) { StkId ra = RA(i); unsigned n = cast_uint(GETARG_vB(i)); - unsigned last = cast_uint(GETARG_vC(i)); + unsigned int last = cast_uint(GETARG_vC(i)); Table *h = hvalue(s2v(ra)); if (n == 0) n = cast_uint(L->top.p - ra) - 1; /* get up to the top */ @@ -1941,25 +1902,12 @@ void luaV_execute (lua_State *L, CallInfo *ci) { } vmcase(OP_VARARG) { StkId ra = RA(i); - int n = GETARG_C(i) - 1; /* required results (-1 means all) */ - int vatab = GETARG_k(i) ? GETARG_B(i) : -1; - Protect(luaT_getvarargs(L, ci, ra, n, vatab)); - vmbreak; - } - vmcase(OP_GETVARG) { - StkId ra = RA(i); - TValue *rc = vRC(i); - luaT_getvararg(ci, ra, rc); - vmbreak; - } - vmcase(OP_ERRNNIL) { - TValue *ra = vRA(i); - if (!ttisnil(ra)) - halfProtect(luaG_errnnil(L, cl, GETARG_Bx(i))); + int n = GETARG_C(i) - 1; /* required results */ + Protect(luaT_getvarargs(L, ci, ra, n)); vmbreak; } vmcase(OP_VARARGPREP) { - ProtectNT(luaT_adjustvarargs(L, ci, cl->p)); + ProtectNT(luaT_adjustvarargs(L, GETARG_A(i), ci, cl->p)); if (l_unlikely(trap)) { /* previous "Protect" updated trap */ luaD_hookcall(L, ci); L->oldpc = 1; /* next opcode will be seen as a "new" line */ diff --git a/makefile b/makefile index 8144dcb6..8506e93c 100644 --- a/makefile +++ b/makefile @@ -15,9 +15,9 @@ CWARNSCPP= \ -Wdouble-promotion \ -Wmissing-declarations \ -Wconversion \ + -Wstrict-overflow=2 \ # the next warnings might be useful sometimes, # but usually they generate too much noise - # -Wstrict-overflow=2 \ # -Werror \ # -pedantic # warns if we use jump tables \ # -Wformat=2 \ @@ -60,29 +60,24 @@ CWARNS= $(CWARNSCPP) $(CWARNSC) $(CWARNGCC) # create problems; some are only available in newer gcc versions. To # use some of them, we also have to define an environment variable # ASAN_OPTIONS="detect_invalid_pointer_pairs=2". -# -fsanitize=undefined (you may need to add "-lubsan" to libs) +# -fsanitize=undefined # -fsanitize=pointer-subtract -fsanitize=address -fsanitize=pointer-compare - -# Test mode: Add test library, turn on asserts, redefine several -# constants ("to give some bugs a chance"), track memory use, and add -# debug information. # TESTS= -DLUA_USER_H='"ltests.h"' -Og -g + LOCAL = $(TESTS) $(CWARNS) # To enable Linux goodies, -DLUA_USE_LINUX # For C89, "-std=c89 -DLUA_USE_C89" # Note that Linux/Posix options are not compatible with C89 -# (For 32-bit, add option "-m32" to MYCFLAGS and MYLDFLAGS.) MYCFLAGS= $(LOCAL) -std=c99 -DLUA_USE_LINUX -MYLDFLAGS= -Wl,-E +MYLDFLAGS= $(LOCAL) -Wl,-E MYLIBS= -ldl CC= gcc -# (Optionally we can use -march=native -mno-avx512f.) -CFLAGS= -Wall -O2 $(MYCFLAGS) -fno-stack-protector -fno-common +CFLAGS= -Wall -O2 $(MYCFLAGS) -fno-stack-protector -fno-common -march=native AR= ar rc RANLIB= ranlib RM= rm -f @@ -171,7 +166,8 @@ ldump.o: ldump.c lprefix.h lua.h luaconf.h lapi.h llimits.h lstate.h \ lfunc.o: lfunc.c lprefix.h lua.h luaconf.h ldebug.h lstate.h lobject.h \ llimits.h ltm.h lzio.h lmem.h ldo.h lfunc.h lgc.h lgc.o: lgc.c lprefix.h lua.h luaconf.h ldebug.h lstate.h lobject.h \ - llimits.h ltm.h lzio.h lmem.h ldo.h lfunc.h lgc.h lstring.h ltable.h + llimits.h ltm.h lzio.h lmem.h ldo.h lfunc.h lgc.h llex.h lstring.h \ + ltable.h linit.o: linit.c lprefix.h lua.h luaconf.h lualib.h lauxlib.h llimits.h liolib.o: liolib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h llimits.h llex.o: llex.c lprefix.h lua.h luaconf.h lctype.h llimits.h ldebug.h \ diff --git a/manual/2html b/manual/2html index 23f37ac6..ac5ea043 100755 --- a/manual/2html +++ b/manual/2html @@ -1,4 +1,4 @@ -#!/usr/bin/env lua +#!/usr/bin/env lua5.3 -- special marks: @@ -8,11 +8,11 @@ --------------------------------------------------------------- header = [[ - + -Lua 5.5 Reference Manual +Lua 5.4 Reference Manual @@ -23,14 +23,14 @@ header = [[

[Lua logo] -Lua 5.5 Reference Manual +Lua 5.4 Reference Manual

by Roberto Ierusalimschy, Luiz Henrique de Figueiredo, Waldemar Celes

Copyright -© 2026 Lua.org, PUC-Rio. All rights reserved. +© 2025 Lua.org, PUC-Rio. All rights reserved.


@@ -58,7 +58,7 @@ end local function compose (f,g) assert(f and g) - return function (...) return g(f(...)) end + return function (s) return g(f(s)) end end local function concat (f, g) @@ -395,10 +395,9 @@ APIEntry = function (e) local apiicmd, ne = string.match(e, "^(.-)(.*)") --io.stderr:write(e) if not apiicmd then - return antipara(Tag.hr() .. Tag.h3(a)) .. Tag.pre(h, {class="api"}) .. e + return antipara(Tag.hr() .. Tag.h3(a)) .. Tag.pre(h) .. e else - return antipara(Tag.hr() .. Tag.h3(a)) .. apiicmd .. - Tag.pre(h, {class="api"}) .. ne + return antipara(Tag.hr() .. Tag.h3(a)) .. apiicmd .. Tag.pre(h) .. ne end end, diff --git a/manual/manual.of b/manual/manual.of index e3c7cd25..5bab781b 100644 --- a/manual/manual.of +++ b/manual/manual.of @@ -107,7 +107,7 @@ for small machines and embedded systems. Unless stated otherwise, any overflow when manipulating integer values @def{wrap around}, -according to the usual rules of two's complement arithmetic. +according to the usual rules of two-complement arithmetic. (In other words, the actual result is the unique representable integer that is equal modulo @M{2@sp{n}} to the mathematical result, @@ -127,8 +127,7 @@ strings can contain any 8-bit value, including @x{embedded zeros} (@Char{\0}). Lua is also encoding-agnostic; it makes no assumptions about the contents of a string. -The length of any string in Lua must fit in a Lua integer, -and the string plus a small header must fit in @id{size_t}. +The length of any string in Lua must fit in a Lua integer. Lua can call (and manipulate) functions written in Lua and functions written in C @see{functioncall}. @@ -230,7 +229,7 @@ as the following example illustrates: @verbatim{ X = 1 -- Ok, global by default do - global Y -- voids the implicit initial declaration + global Y -- voids implicit initial declaration Y = 1 -- Ok, Y declared as global X = 1 -- ERROR, X not declared end @@ -270,7 +269,7 @@ print(x) --> 10 (the global one) Notice that, in a declaration like @T{local x = x}, the new @id{x} being declared is not in scope yet, -and so the @id{x} on the right-hand side refers to the outside variable. +and so the @id{x} in the left-hand side refers to the outside variable. Because of the @x{lexical scoping} rules, local variables can be freely accessed by functions @@ -1556,8 +1555,7 @@ It has the following syntax: exp @bnfter{,} exp @bnfopt{@bnfter{,} exp} @Rw{do} block @Rw{end}} } The given identifier (@bnfNter{Name}) defines the control variable, -which is a new read-only (@id{const}) variable local to the loop body -(@emph{block}). +which is a new read-only variable local to the loop body (@emph{block}). The loop starts by evaluating once the three control expressions. Their values are called respectively @@ -1612,7 +1610,7 @@ works as follows. The names @rep{var_i} declare loop variables local to the loop body. The first of these variables is the @emph{control variable}, -which is a read-only (@id{const}) variable. +which is a read-only variable. The loop starts by evaluating @rep{explist} to produce four values: @@ -1653,22 +1651,15 @@ Function calls are explained in @See{functioncall}. @sect3{localvar| @title{Variable Declarations} Local and global variables can be declared anywhere inside a block. -The declaration can include an initialization: +The declaration for locals can include an initialization: @Produc{ @producname{stat}@producbody{@Rw{local} attnamelist @bnfopt{@bnfter{=} explist}} -@producname{stat}@producbody{@Rw{global} - attnamelist @bnfopt{@bnfter{=} explist}} +@producname{stat}@producbody{@Rw{global} attnamelist} } -If there is no initialization, -local variables are initialized with @nil; -global variables are left unchanged. -Otherwise, the initialization gets the same adjustment +If present, an initial assignment has the same semantics of a multiple assignment @see{assignment}. -Moreover, for global variables, -the initialization will raise a runtime error -if the variable is already defined, -that is, it has a non-nil value. +Otherwise, all local variables are initialized with @nil. The list of names may be prefixed by an attribute (a name between angle brackets) @@ -1721,14 +1712,13 @@ and a program that starts with any other global declaration (e.g., @T{global none}) can only refer to declared variables. Note that, for global variables, -the effect of any declaration is only syntactical -(except for the optional assignment): +the effect of any declaration is only syntactical: @verbatim{ global X , _G X = 1 -- ERROR _ENV.X = 1 -- Ok _G.print(X) -- Ok -foo() -- 'foo' can freely change any global +foo() -- 'foo' can freely change any global } A chunk is also a block @see{chunks}, @@ -2091,12 +2081,12 @@ Note that keys that are not positive integers do not interfere with borders. A table with exactly one border is called a @def{sequence}. -For instance, the table @T{{10,20,30,40,50}} is a sequence, +For instance, the table @T{{10, 20, 30, 40, 50}} is a sequence, as it has only one border (5). -The table @T{{10,20,30,nil,50}} has two borders (3 and 5), +The table @T{{10, 20, 30, nil, 50}} has two borders (3 and 5), and therefore it is not a sequence. (The @nil at index 4 is called a @emphx{hole}.) -The table @T{{nil,20,30,nil,nil,60,nil}} +The table @T{{nil, 20, 30, nil, nil, 60, nil}} has three borders (0, 3, and 6), so it is not a sequence, too. The table @T{{}} is a sequence with border 0. @@ -2221,7 +2211,7 @@ The form } can be used to emulate methods. A call @T{v:name(@rep{args})} -is syntactic sugar for @T{v.name(v, @rep{args})}, +is syntactic sugar for @T{v.name(v,@rep{args})}, except that @id{v} is evaluated only once. Arguments have the following syntax: @@ -2268,7 +2258,7 @@ return x or f(x) -- results adjusted to 1 @sect3{func-def| @title{Function Definitions} -The syntax for a function definition is +The syntax for function definition is @Produc{ @producname{functiondef}@producbody{@Rw{function} funcbody} @producname{funcbody}@producbody{@bnfter{(} @bnfopt{parlist} @bnfter{)} block @Rw{end}} @@ -2318,10 +2308,71 @@ global function f () @rep{body} end } translates to @verbatim{ -global f; global f = function () @rep{body} end +global f; f = function () @rep{body} end } -The second @Rw{global} makes the assignment an initialization, -which will raise an error if that global is already defined. + +A function definition is an executable expression, +whose value has type @emph{function}. +When Lua precompiles a chunk, +all its function bodies are precompiled too, +but they are not created yet. +Then, whenever Lua executes the function definition, +the function is @emph{instantiated} (or @emph{closed}). +This function instance, or @emphx{closure}, +is the final value of the expression. + +Parameters act as local variables that are +initialized with the argument values: +@Produc{ +@producname{parlist}@producbody{namelist @bnfopt{@bnfter{,} @bnfter{...}} @Or + @bnfter{...}} +} +When a Lua function is called, +it adjusts its list of @x{arguments} to +the length of its list of parameters @see{multires}, +unless the function is a @def{variadic function}, +which is indicated by three dots (@Char{...}) +at the end of its parameter list. +A variadic function does not adjust its argument list; +instead, it collects all extra arguments and supplies them +to the function through a @def{vararg expression}, +which is also written as three dots. +The value of this expression is a list of all actual extra arguments, +similar to a function with multiple results @see{multires}. + + +As an example, consider the following definitions: +@verbatim{ +function f(a, b) end +function g(a, b, ...) end +function r() return 1,2,3 end +} +Then, we have the following mapping from arguments to parameters and +to the vararg expression: +@verbatim{ +CALL PARAMETERS + +f(3) a=3, b=nil +f(3, 4) a=3, b=4 +f(3, 4, 5) a=3, b=4 +f(r(), 10) a=1, b=10 +f(r()) a=1, b=2 + +g(3) a=3, b=nil, ... -> (nothing) +g(3, 4) a=3, b=4, ... -> (nothing) +g(3, 4, 5, 8) a=3, b=4, ... -> 5 8 +g(5, r()) a=5, b=1, ... -> 2 3 +} + +Results are returned using the @Rw{return} statement @see{control}. +If control reaches the end of a function +without encountering a @Rw{return} statement, +then the function returns with no results. + +@index{multiple return} +There is a system-dependent limit on the number of values +that a function may return. +This limit is guaranteed to be at least 1000. The @emphx{colon} syntax is used to emulate @def{methods}, @@ -2335,104 +2386,10 @@ is syntactic sugar for t.a.b.c.f = function (self, @rep{params}) @rep{body} end } -A function definition is an executable expression, -whose value has type @emph{function}. -When Lua precompiles a chunk, -all its function bodies are precompiled too, -but they are not created yet. -Then, whenever Lua executes the function definition, -the function is @emph{instantiated} (or @emph{closed}). -This function instance, or @emphx{closure}, -is the final value of the expression. - -Results are returned using the @Rw{return} statement @see{control}. -If control reaches the end of a function -without encountering a @Rw{return} statement, -then the function returns with no results. - -@index{multiple return} -There is a system-dependent limit on the number of values -that a function may return. -This limit is guaranteed to be at least 1000. - -@sect4{@title{Parameters} - -Parameters act as local variables that are -initialized with the argument values: -@Produc{ -@producname{parlist}@producbody{namelist @bnfopt{@bnfter{,} varargparam} @Or - varargparam} -@producname{varargparam}@producbody{@bnfter{...} @bnfopt{@bnfNter{Name}}} -} -When a Lua function is called, -it adjusts its list of @x{arguments} to -the length of its list of parameters @see{multires}, -unless the function is a @def{variadic function}, -which is indicated by three dots (@Char{...}) -at the end of its parameter list. -A variadic function does not adjust its argument list; -instead, it collects all extra arguments and supplies them -to the function through a @def{vararg table}. -In that table, -the values at indices 1, 2, etc. are the extra arguments, -and the value at index @St{n} is the number of extra arguments. - -As an example, consider the following definitions: -@verbatim{ -function f(a, b) end -function g(a, b, ...) end -function r() return 1,2,3 end -} -Then, we have the following mapping from arguments to parameters and -to the vararg table: -@verbatim{ -CALL PARAMETERS - -f(3) a=3, b=nil -f(3, 4) a=3, b=4 -f(3, 4, 5) a=3, b=4 -f(r(), 10) a=1, b=10 -f(r()) a=1, b=2 - -g(3) a=3, b=nil, va. table -> {n = 0} -g(3, 4) a=3, b=4, va. table -> {n = 0} -g(3, 4, 5, 8) a=3, b=4, va. table -> {5, 8, n = 2} -g(5, r()) a=5, b=1, va. table -> {2, 3, n = 2} } -A vararg table in a variadic function can have an optional name, -given after the three dots. -When present, -that name denotes a read-only local variable that -refers to the vararg table. -If the vararg table does not have a name, -it can only be accessed through a vararg expression. - -A vararg expression is also written as three dots, -and its value is a list of the values in the vararg table, -from 1 to the integer value at index @St{n}. -(Therefore, if the code does not modify the vararg table, -this list corresponds to the extra arguments in the function call.) -This list behaves like the results from a -function with multiple results @see{multires}. - -As an optimization, -if the vararg table satisfies some conditions, -the code does not create an actual table and instead translates -the indexing expressions and the vararg expressions -into accesses to the internal vararg data. -The conditions are as follows: -If the vararg table has a name, -that name is not an upvalue in a nested function -and it is used only as the base table -in the syntactic constructions @T{t[exp]} or @T{t.id}. -Note that an anonymous vararg table always satisfy these conditions. - -} - -} - -@sect3{multires| @title{Lists of Expressions, Multiple Results, and Adjustment} +@sect3{multires| @title{Lists of expressions, multiple results, +and adjustment} Both function calls and vararg expressions can result in multiple values. These expressions are called @def{multires expressions}. @@ -2449,22 +2406,22 @@ These are the places where Lua expects a list of expressions: @description{ @item{A @rw{return} statement, -for instance @T{return e1,e2,e3} @see{control}.} +for instance @T{return e1, e2, e3} @see{control}.} @item{A table constructor, -for instance @T{{e1,e2,e3}} @see{tableconstructor}.} +for instance @T{{e1, e2, e3}} @see{tableconstructor}.} @item{The arguments of a function call, -for instance @T{foo(e1,e2,e3)} @see{functioncall}.} +for instance @T{foo(e1, e2, e3)} @see{functioncall}.} @item{A multiple assignment, -for instance @T{a,b,c = e1,e2,e3} @see{assignment}.} +for instance @T{a , b, c = e1, e2, e3} @see{assignment}.} -@item{A local or global declaration, -which is similar to a multiple assignment.} +@item{A local declaration, +for instance @T{local a , b, c = e1, e2, e3} @see{localvar}.} @item{The initial values in a generic @rw{for} loop, -for instance @T{for k in e1,e2,e3 do ... end} @see{for}.} +for instance @T{for k in e1, e2, e3 do ... end} @see{for}.} } In the last four cases, @@ -2472,7 +2429,8 @@ the list of values from the list of expressions must be @emph{adjusted} to a specific length: the number of parameters in a call to a non-variadic function @see{func-def}, -the number of variables in a multiple assignment or a declaration, +the number of variables in a multiple assignment or +a local declaration, and exactly four values for a generic @rw{for} loop. The @def{adjustment} follows these rules: If there are more values than needed, @@ -2501,7 +2459,7 @@ we recommend assigning the vararg expression to a single variable and using that variable in its place. -Here are some examples of uses of multires expressions. +Here are some examples of uses of mutlres expressions. In all cases, when the construction needs @Q{the n-th result} and there is no such result, it uses a @nil. @@ -2690,21 +2648,9 @@ which behaves like a nil value. } -@sect3{constchar|@title{Pointers to Strings} +@sect3{constchar|@title{Pointers to strings} -Several functions in the API have parameters -that are pointers to C strings (@T{const char*}). -Some of these parameters have an associated length (@T{size_t}). -Unless stated otherwise, -when there is an associated length, -the string can contain embedded zeros; -moreover, the pointer can be @id{NULL} if the length is zero. -When there is no associated length, -the pointer must point to a zero-terminated string. -In any case, the string contents should remain unchanged -until the function returns. - -Several functions in the API also return pointers (@T{const char*}) +Several functions in the API return pointers (@T{const char*}) to Lua strings in the stack. (See @Lid{lua_pushfstring}, @Lid{lua_pushlstring}, @Lid{lua_pushstring}, and @Lid{lua_tolstring}. @@ -2877,16 +2823,7 @@ status codes to indicate different kinds of errors or other conditions: For such errors, Lua does not call the @x{message handler}. } -@item{@defid{LUA_ERRERR}| -stack overflow while running the @x{message handler} -due to another stack overflow. -More often than not, -this error is the result of some other error while running -a message handler. -An error in a message handler will call the handler again, -which will generate the error again, and so on, -until this loop exhausts the stack and cause this error. -} +@item{@defid{LUA_ERRERR}| error while running the @x{message handler}.} @item{@defid{LUA_ERRSYNTAX}| syntax error during precompilation or format error in a binary chunk.} @@ -3067,7 +3004,7 @@ typedef void * (*lua_Alloc) (void *ud, size_t osize, size_t nsize);| -The type of the @x{memory-allocator function} used by Lua states. +The type of the @x{memory-allocation function} used by Lua states. The allocator function must provide a functionality similar to @id{realloc}, but not exactly the same. @@ -3102,12 +3039,11 @@ the allocator must behave like @id{realloc}. In particular, the allocator returns @id{NULL} if and only if it cannot fulfill the request. -Here is a simple implementation for the @x{allocator function}, -corresponding to the function @Lid{luaL_alloc} from the -auxiliary library. +Here is a simple implementation for the @x{allocator function}. +It is used in the auxiliary library by @Lid{luaL_newstate}. @verbatim{ -void *luaL_alloc (void *ud, void *ptr, size_t osize, - size_t nsize) { +static void *l_alloc (void *ud, void *ptr, size_t osize, + size_t nsize) { (void)ud; (void)osize; /* not used */ if (nsize == 0) { free(ptr); @@ -3534,7 +3470,7 @@ This function should not be called by a finalizer. @APIEntry{lua_Alloc lua_getallocf (lua_State *L, void **ud);| @apii{0,0,-} -Returns the @x{memory-allocator function} of a given state. +Returns the @x{memory-allocation function} of a given state. If @id{ud} is not @id{NULL}, Lua stores in @T{*ud} the opaque pointer given when the memory-allocator function was set. @@ -3652,9 +3588,9 @@ because a pseudo-index is not an actual stack position. The type of integers in Lua. By default this type is @id{long long}, -(usually a 64-bit two's complement integer), +(usually a 64-bit two-complement integer), but that can be changed to @id{long} or @id{int} -(usually a 32-bit two's complement integer). +(usually a 32-bit two-complement integer). (See @id{LUA_INT_TYPE} in @id{luaconf.h}.) Lua also defines the constants @@ -3891,7 +3827,7 @@ is a seed for the hashing of strings. @apii{0,1,m} Creates a new empty table and pushes it onto the stack. -It is equivalent to @T{lua_createtable(L,0,0)}. +It is equivalent to @T{lua_createtable(L, 0, 0)}. } @@ -3915,12 +3851,8 @@ like any Lua object. This function creates and pushes on the stack a new full userdata, with @id{nuvalue} associated Lua values, called @id{user values}, plus an associated block of raw memory with @id{size} bytes. - -The user values can be set and read with the functions -@Lid{lua_setiuservalue} and @Lid{lua_getiuservalue}. -The block of memory is suitably aligned for any @N{ISO C} object. -(See macro @id{LUAI_MAXALIGN} in file @id{luaconf.h} for other -alignment requirements.) +(The user values can be set and read with the functions +@Lid{lua_setiuservalue} and @Lid{lua_getiuservalue}.) The function returns the address of the block of memory. Lua ensures that this address is valid as long as @@ -3962,8 +3894,8 @@ this confuses the next call to @Lid{lua_next}. This function may raise an error if the given key is neither @nil nor present in the table. - -See function @Lid{next} for more details about the traversal. +See function @Lid{next} for the caveats of modifying +the table during its traversal. } @@ -3992,8 +3924,8 @@ This macro may evaluate its arguments more than once. } -@APIEntry{unsigned lua_numbertocstring (lua_State *L, int idx, - char *buff);| +@APIEntry{unsigned (lua_numbertocstring) (lua_State *L, int idx, + char *buff);| @apii{0,0,-} Converts the number at acceptable index @id{idx} to a string @@ -4118,7 +4050,7 @@ This function is equivalent to @Lid{lua_pushcclosure} with no upvalues. } -@APIEntry{const char *lua_pushexternalstring (lua_State *L, +@APIEntry{const char *(lua_pushexternalstring) (lua_State *L, const char *s, size_t len, lua_Alloc falloc, void *ud);| @apii{0,1,m} @@ -4141,18 +4073,21 @@ the string @id{s} as the block, the length plus one (to account for the ending zero) as the old size, and 0 as the new size. +Lua always @x{internalizes} strings with lengths up to 40 characters. +So, for strings in that range, +this function will immediately internalize the string +and call @id{falloc} to free the buffer. + Even when using an external buffer, Lua still has to allocate a header for the string. In case of a memory-allocation error, Lua will call @id{falloc} before raising the error. -The function returns a pointer to the string (that is, @id{s}). - } @APIEntry{const char *lua_pushfstring (lua_State *L, const char *fmt, ...);| -@apii{0,1,v} +@apii{0,1,m} Pushes onto the stack a formatted string and returns a pointer to this string @see{constchar}. @@ -4172,9 +4107,6 @@ A conversion specifier (and its corresponding extra argument) can be Every occurrence of @Char{%} in the string @id{fmt} must form a valid conversion specifier. -Besides memory allocation errors, -this function may raise an error if the resulting string is too large. - } @APIEntry{void lua_pushglobaltable (lua_State *L);| @@ -4207,7 +4139,7 @@ light userdata with the same @N{C address}. } @APIEntry{const char *lua_pushliteral (lua_State *L, const char *s);| -@apii{0,1,v} +@apii{0,1,m} This macro is equivalent to @Lid{lua_pushstring}, but should be used only when @id{s} is a literal string. @@ -4216,7 +4148,7 @@ but should be used only when @id{s} is a literal string. } @APIEntry{const char *lua_pushlstring (lua_State *L, const char *s, size_t len);| -@apii{0,1,v} +@apii{0,1,m} Pushes the string pointed to by @id{s} with size @id{len} onto the stack. @@ -4228,9 +4160,6 @@ including @x{embedded zeros}. Returns a pointer to the internal copy of the string @see{constchar}. -Besides memory allocation errors, -this function may raise an error if the string is too large. - } @APIEntry{void lua_pushnil (lua_State *L);| @@ -4448,7 +4377,7 @@ Starts and resumes a coroutine in the given thread @id{L}. To start a coroutine, you push the main function plus any arguments onto the empty stack of the thread. -Then you call @Lid{lua_resume}, +then you call @Lid{lua_resume}, with @id{nargs} being the number of arguments. The function returns when the coroutine suspends, finishes its execution, or raises an unprotected error. @@ -4628,7 +4557,7 @@ You can resume threads with status @Lid{LUA_OK} } @APIEntry{size_t lua_stringtonumber (lua_State *L, const char *s);| -@apii{0,0|1,-} +@apii{0,1,-} Converts the zero-terminated string @id{s} to a number, pushes that number into the stack, @@ -4958,7 +4887,7 @@ Lua calls the given @x{continuation function} @id{k} to continue the execution of the @N{C function} that yielded @see{continuations}. This continuation function receives the same stack from the previous function, -with all the results (@id{nresults}) removed and +with the @id{n} results removed and replaced by the arguments passed to @Lid{lua_resume}. Moreover, the continuation function receives the value @id{ctx} @@ -5048,7 +4977,7 @@ the function was defined in a string where } @item{@id{srclen}| -the length of the string @id{source}. +The length of the string @id{source}. } @item{@id{short_src}| @@ -5090,8 +5019,8 @@ then @id{name} is set to @id{NULL}. @item{@id{namewhat}| explains the @T{name} field. The value of @T{namewhat} can be -@T{"global"}, @T{"local"}, @T{"upvalue"}, -@T{"field"}, @T{""} (the empty string), plus some other options, +@T{"global"}, @T{"local"}, @T{"method"}, +@T{"field"}, @T{"upvalue"}, or @T{""} (the empty string), according to how the function was called. (Lua uses the empty string when no other option seems to apply.) } @@ -5212,7 +5141,7 @@ running at the given level; } @item{@Char{S}| -fills in the fields @id{source}, @id{srclen}, @id{short_src}, +fills in the fields @id{source}, @id{short_src}, @id{linedefined}, @id{lastlinedefined}, and @id{what}; } @@ -5388,9 +5317,7 @@ Returns @id{NULL} (and pops nothing) when the index is greater than the number of active local variables. -Parameters @id{ar} and @id{n} are as in the function @Lid{lua_getlocal}, -except that @id{ar} cannot be @id{NULL}, -as @id{lua_setlocal} only operates on activation records. +Parameters @id{ar} and @id{n} are as in the function @Lid{lua_getlocal}. } @@ -5457,7 +5384,7 @@ the auxiliary library provides higher-level functions for some common tasks. All functions and types from the auxiliary library -are defined in the header file @id{lauxlib.h} and +are defined in header file @id{lauxlib.h} and have a prefix @id{luaL_}. All functions in the auxiliary library are built on @@ -5601,7 +5528,7 @@ Its pattern of use is as follows: @item{First declare a variable @id{b} of type @Lid{luaL_Buffer}.} -@item{Then initialize it with a call @T{luaL_buffinit(L,&b)}.} +@item{Then initialize it with a call @T{luaL_buffinit(L, &b)}.} @item{ Then add string pieces to the buffer calling any of @@ -5622,12 +5549,12 @@ you can use the buffer like this: @item{First declare a variable @id{b} of type @Lid{luaL_Buffer}.} @item{Then initialize it and preallocate a space of -size @id{sz} with a call @T{luaL_buffinitsize(L,&b,sz)}.} +size @id{sz} with a call @T{luaL_buffinitsize(L, &b, sz)}.} @item{Then produce the string into that space.} @item{ -Finish by calling @T{luaL_pushresultsize(&b,sz)}, +Finish by calling @T{luaL_pushresultsize(&b, sz)}, where @id{sz} is the total size of the resulting string copied into that space (which may be less than or equal to the preallocated size). @@ -6020,8 +5947,9 @@ it does not run it. @apii{0,0,-} Returns a value with a weak attempt for randomness. -The parameter @id{L} can be @id{NULL} -if there is no Lua state available. +(It produces that value based on the current date and time +and the address of an internal variable, +in case the machine has Address Space Layout Randomization.) } @@ -6071,23 +5999,14 @@ In both cases, the function pushes onto the stack the final value associated with @id{tname} in the registry. -Usage note: Beware the use of the return value of this function -to conditionally initialize the new metatable -(e.g., by adding metamethods to it). -If the initialization raises an error, -the metatable will not be properly initialized, -but a subsequent execution of that code will detect that the -metatable already exists and then skip the initialization. - } @APIEntry{lua_State *luaL_newstate (void);| @apii{0,0,-} Creates a new Lua state. -It calls @Lid{lua_newstate} with @Lid{luaL_alloc} as -the allocator function and the result of @T{luaL_makeseed(NULL)} -as the seed, +It calls @Lid{lua_newstate} with an +allocator based on the @N{ISO C} allocation functions and then sets a warning function and a panic function @see{C-error} that print messages to the standard error output. @@ -6240,7 +6159,7 @@ You should not manually set integer keys in the table after the first use of @Lid{luaL_ref}. You can retrieve an object referred by the reference @id{r} -by calling @T{lua_rawgeti(L,t,r)} or @T{lua_geti(L,t,r)}. +by calling @T{lua_rawgeti(L, t, r)} or @T{lua_geti(L, t, r)}. The function @Lid{luaL_unref} frees a reference. If the object on the top of the stack is @nil, @@ -6311,15 +6230,6 @@ in the registry @seeC{luaL_newmetatable}. } -@APIEntry{ -void *luaL_alloc (void *ud, void *ptr, size_t osize, size_t nsize);| - -A standard allocator function for Lua @seeF{lua_Alloc}, -built on top of the C functions @id{realloc} and @id{free}. - -} - - @APIEntry{ typedef struct luaL_Stream { FILE *f; @@ -6518,7 +6428,7 @@ the host program can call the function @Lid{luaL_openlibs}. Alternatively, the host can select which libraries to open, by using @Lid{luaL_openselectedlibs}. -Both functions are declared in the header file @id{lualib.h}. +Both functions are defined in the header file @id{lualib.h}. @index{lualib.h} The stand-alone interpreter @id{lua} @see{lua-sa} @@ -6665,7 +6575,7 @@ The call always returns the previous value of the parameter. If the call does not give a new value, the value is left unchanged. -Lua stores these values in a compressed format, +Lua rounds these values before storing them; so, the value returned as the previous value may not be exactly the last value set. } @@ -6679,10 +6589,10 @@ This function should not be called by a finalizer. } @LibEntry{dofile ([filename])| -Opens the named file and executes its content as a Lua chunk, -returning all values returned by the chunk. +Opens the named file and executes its content as a Lua chunk. When called without arguments, @id{dofile} executes the content of the standard input (@id{stdin}). +Returns all values returned by the chunk. In case of errors, @id{dofile} propagates the error to its caller. (That is, @id{dofile} does not run in protected mode.) @@ -6831,18 +6741,19 @@ In particular, you may set existing fields to nil. @LibEntry{pairs (t)| If @id{t} has a metamethod @idx{__pairs}, -calls it with @id{t} as argument and returns the first four +calls it with @id{t} as argument and returns the first three results from the call. Otherwise, -returns the @Lid{next} function, the table @id{t}, plus two @nil values, +returns three values: the @Lid{next} function, the table @id{t}, and @nil, so that the construction @verbatim{ for k,v in pairs(t) do @rep{body} end } will iterate over all key@En{}value pairs of table @id{t}. -See function @Lid{next} for more details about the traversal. +See function @Lid{next} for the caveats of modifying +the table during its traversal. } @@ -6997,7 +6908,7 @@ and @St{userdata}. A global variable (not a function) that holds a string containing the running Lua version. -The current value of this variable is @St{Lua 5.5}. +The current value of this variable is @St{Lua 5.4}. } @@ -7053,7 +6964,7 @@ in case of error (either the original error that stopped the coroutine or errors in closing methods), this function returns @false plus the error object; -otherwise it returns @true. +otherwise ir returns @true. } @@ -7243,7 +7154,7 @@ to search for a @N{C loader}. Lua initializes the @N{C path} @Lid{package.cpath} in the same way it initializes the Lua path @Lid{package.path}, -using the environment variable @defid{LUA_CPATH_5_5}, +using the environment variable @defid{LUA_CPATH_5_4}, or the environment variable @defid{LUA_CPATH}, or a default path defined in @id{luaconf.h}. @@ -7312,7 +7223,7 @@ A string with the path used by @Lid{require} to search for a Lua loader. At start-up, Lua initializes this variable with -the value of the environment variable @defid{LUA_PATH_5_5} or +the value of the environment variable @defid{LUA_PATH_5_4} or the environment variable @defid{LUA_PATH} or with a default path defined in @id{luaconf.h}, if those environment variables are not defined. @@ -7683,9 +7594,9 @@ x = string.gsub("4+5 = $return 4+5$", "%$(.-)%$", function (s) end) -- x="4+5 = 9" -local t = {name="lua", version="5.5"} +local t = {name="lua", version="5.4"} x = string.gsub("$name-$version.tar.gz", "%$(%w+)", t) --- x="lua-5.5.tar.gz" +-- x="lua-5.4.tar.gz" } } @@ -7769,7 +7680,7 @@ If @id{j} is absent, then it is assumed to be equal to @num{-1} In particular, the call @T{string.sub(s,1,j)} returns a prefix of @id{s} with length @id{j}, -and @T{string.sub(s,-i)} (for a positive @id{i}) +and @T{string.sub(s, -i)} (for a positive @id{i}) returns a suffix of @id{s} with length @id{i}. @@ -8205,7 +8116,7 @@ the function returns @fail. A negative @id{n} gets characters before position @id{i}. The default for @id{i} is 1 when @id{n} is non-negative and @T{#s + 1} otherwise, -so that @T{utf8.offset(s,-n)} gets the offset of the +so that @T{utf8.offset(s, -n)} gets the offset of the @id{n}-th character from the end of the string. As a special case, @@ -8258,7 +8169,7 @@ the table will have; its default is zero. Inserts element @id{value} at position @id{pos} in @id{list}, shifting up the elements -@T{list[pos],list[pos+1],@Cdots,list[#list]}. +@T{list[pos], list[pos+1], @Cdots, list[#list]}. The default value for @id{pos} is @T{#list+1}, so that a call @T{table.insert(t,x)} inserts @id{x} at the end of the list @id{t}. @@ -8296,7 +8207,7 @@ Removes from @id{list} the element at position @id{pos}, returning the value of the removed element. When @id{pos} is an integer between 1 and @T{#list}, it shifts down the elements -@T{list[pos+1],list[pos+2],@Cdots,list[#list]} +@T{list[pos+1], list[pos+2], @Cdots, list[#list]} and erases element @T{list[#list]}; The index @id{pos} can also be 0 when @T{#list} is 0, or @T{#list + 1}. @@ -8426,17 +8337,6 @@ that rounds the quotient towards zero. (integer/float) } -@LibEntry{math.frexp (x)| - -Returns two numbers @id{m} and @id{e} such that @M{x = m2@sp{e}}, -where @id{e} is an integer. -When @id{x} is zero, NaN, +inf, or -inf, -@id{m} is equal to @id{x}; -otherwise, the absolute value of @id{m} -is in the range @C{(} @M{[0.5, 1)} @C{]}. - -} - @LibEntry{math.huge| The float value @idx{HUGE_VAL}, @@ -8444,12 +8344,6 @@ a value greater than any other numeric value. } -@LibEntry{math.ldexp (m, e)| - -Returns @M{m2@sp{e}}, where @id{e} is an integer. - -} - @LibEntry{math.log (x [, base])| Returns the logarithm of @id{x} in the given base. @@ -8505,7 +8399,7 @@ Converts the angle @id{x} from degrees to radians. When called without arguments, returns a pseudo-random float with uniform distribution -in the range @C{(} @M{[0, 1)}. @C{]} +in the range @C{(} @M{[0,1)}. @C{]} When called with two integers @id{m} and @id{n}, @id{math.random} returns a pseudo-random integer with uniform distribution in the range @M{[m, n]}. @@ -9132,7 +9026,6 @@ which automatically removes the file when the program ends. This library provides the functionality of the @link{debugI|debug interface} to Lua programs. - You should exert care when using this library. Several of its functions violate basic assumptions about Lua code @@ -9142,8 +9035,6 @@ that userdata metatables cannot be changed by Lua code; that Lua programs do not crash) and therefore can compromise otherwise secure code. Moreover, some functions in this library may be slow. -It is good practice to always require this library explicitly -before using it. All functions in this library are provided inside the @defid{debug} table. @@ -9229,10 +9120,6 @@ Compile-time constants may not appear in this listing, if they were optimized away by the compiler. Negative indices refer to vararg arguments; @num{-1} is the first vararg argument. -These negative indices are only available when the vararg table -has been optimized away; -otherwise, the vararg arguments are available in the vararg table. - The function returns @fail if there is no variable with the given index, and raises an error when called with a level out of range. @@ -9445,7 +9332,7 @@ when the standard input (@id{stdin}) is a terminal, and as @T{lua -} otherwise. When called without the option @T{-E}, -the interpreter checks for an environment variable @defid{LUA_INIT_5_5} +the interpreter checks for an environment variable @defid{LUA_INIT_5_4} (or @defid{LUA_INIT} if the versioned name is not defined) before running any argument. If the variable content has the format @T{@At@rep{filename}}, @@ -9622,9 +9509,6 @@ change between versions. @item{ The word @Rw{global} is a reserved word. Do not use it as a regular name. - -The compilation option @id{LUA_COMPAT_GLOBAL} (see @id{luaconf.h}) -makes @id{global} a regular word. } @item{ @@ -9756,7 +9640,7 @@ and @bnfNter{LiteralString}, see @See{lexical}.) @OrNL @Rw{local} @Rw{function} @bnfNter{Name} funcbody @OrNL @Rw{global} @Rw{function} @bnfNter{Name} funcbody @OrNL @Rw{local} attnamelist @bnfopt{@bnfter{=} explist} -@OrNL @Rw{global} attnamelist @bnfopt{@bnfter{=} explist} +@OrNL @Rw{global} attnamelist @OrNL @Rw{global} @bnfopt{attrib} @bnfter{*} } @@ -9818,10 +9702,8 @@ and @bnfNter{LiteralString}, see @See{lexical}.) @producname{funcbody}@producbody{@bnfter{(} @bnfopt{parlist} @bnfter{)} block @Rw{end}} -@producname{parlist}@producbody{namelist @bnfopt{@bnfter{,} varargparam} @Or - varargparam} - -@producname{varargparam}@producbody{@bnfter{...} @bnfopt{@bnfNter{Name}}} +@producname{parlist}@producbody{namelist @bnfopt{@bnfter{,} @bnfter{...}} + @Or @bnfter{...}} @producname{tableconstructor}@producbody{@bnfter{@Open} @bnfopt{fieldlist} @bnfter{@Close}} diff --git a/onelua.c b/onelua.c index e7171213..2a434961 100644 --- a/onelua.c +++ b/onelua.c @@ -5,14 +5,10 @@ ** ** $ gcc -O2 -std=c99 -o lua onelua.c -lm ** -** or (for C89) +** or ** ** $ gcc -O2 -std=c89 -DLUA_USE_C89 -o lua onelua.c -lm ** -** or (for Linux) -** -** gcc -O2 -o lua -DLUA_USE_LINUX -Wl,-E onelua.c -lm -ldl -** */ /* default is to build the full interpreter */ @@ -34,15 +30,7 @@ #define LUA_USE_LINUX #define LUA_USE_MACOSX #define LUA_USE_POSIX -#endif - - -/* -** Other specific features -*/ -#if 0 -#define LUA_32BITS -#define LUA_USE_C89 +#define LUA_ANSI #endif @@ -66,10 +54,12 @@ #include #include + /* setup for luaconf.h */ #define LUA_CORE #define LUA_LIB - +#define ltable_c +#define lvm_c #include "luaconf.h" /* do not export internal symbols */ @@ -120,11 +110,6 @@ #include "linit.c" #endif -/* test library -- used only for internal development */ -#if defined(LUA_DEBUG) -#include "ltests.c" -#endif - /* lua */ #ifdef MAKE_LUA #include "lua.c" diff --git a/testes/api.lua b/testes/api.lua index 9855f541..b3791654 100644 --- a/testes/api.lua +++ b/testes/api.lua @@ -246,8 +246,7 @@ assert(not T.testC("compare LT 1 4, return 1")) assert(not T.testC("compare LE 9 1, return 1")) assert(not T.testC("compare EQ 9 9, return 1")) -local b = {__lt = function (a,b) return a[1] < b[1] end, - __le = function (a,b) return a[1] <= b[1] end} +local b = {__lt = function (a,b) return a[1] < b[1] end} local a1,a3,a4 = setmetatable({1}, b), setmetatable({3}, b), setmetatable({4}, b) diff --git a/testes/attrib.lua b/testes/attrib.lua index f4156086..d8b6e0f3 100644 --- a/testes/attrib.lua +++ b/testes/attrib.lua @@ -308,11 +308,11 @@ else _ENV.x, _ENV.y = nil end - _ENV = _G -- testing preload + do local p = package package = {} @@ -331,26 +331,6 @@ do assert(type(package.path) == "string") end - -do print("testing external strings") - package.cpath = DC"?" - local lib2 = require"lib2-v2" - local t = {} - for _, len in ipairs{0, 10, 39, 40, 41, 1000} do - local str = string.rep("a", len) - local str1 = lib2.newstr(str) - assert(str == str1) - assert(not T or T.hash(str) == T.hash(str1)) - t[str1] = 20; assert(t[str] == 20 and t[str1] == 20) - t[str] = 10; assert(t[str1] == 10) - local tt = {[str1] = str1} - assert(next(tt) == str1 and next(tt, str1) == nil) - assert(tt[str] == str) - local str2 = lib2.newstr(str1) - assert(str == str2 and t[str2] == 10 and tt[str2] == str) - end -end - print('+') end --] @@ -467,7 +447,7 @@ do end --- test of large float/integer indices +-- test of large float/integer indices -- compute maximum integer where all bits fit in a float local maxint = math.maxinteger diff --git a/testes/bwcoercion.lua b/testes/bwcoercion.lua index 0544944d..cd735ab0 100644 --- a/testes/bwcoercion.lua +++ b/testes/bwcoercion.lua @@ -4,7 +4,7 @@ local strsub = string.sub local print = print -global none +_ENV = nil -- Try to convert a value to an integer, without assuming any coercion. local function toint (x) diff --git a/testes/calls.lua b/testes/calls.lua index cd4510a2..21441701 100644 --- a/testes/calls.lua +++ b/testes/calls.lua @@ -24,7 +24,7 @@ assert(not pcall(type)) -- testing local-function recursion -global fact = false +global fact; fact = false do local res = 1 local function fact (n) @@ -65,7 +65,7 @@ a.b.c:f2('k', 12); assert(a.b.c.k == 12) print('+') -global t = nil -- 'declare' t +global t; t = nil -- 'declare' t function f(a,b,c) local d = 'a'; t={a,b,c,d} end f( -- this line change must be valid @@ -372,32 +372,6 @@ do -- another bug (in 5.4.0) end -if T then - -- check stack level when calling reader function - local function get (str) - local pos = 0 - local level = nil - return function () - pos = pos + 1 - local c = string.sub(str, pos, pos) - local newlevel = T.stacklevel() - if not level then - level = newlevel - else - assert(level == newlevel) - end - return #c > 0 and c or nil - end - end - - local str = "local function foo () end; return 121" - assert(assert(load(get(str)))() == 121) - - str = string.dump(load(str)) - assert(assert(load(get(str)))() == 121) -end - - x = string.dump(load("x = 1; return x")) a = assert(load(read1(x), nil, "b")) assert(a() == 1 and _G.x == 1) diff --git a/testes/coroutine.lua b/testes/coroutine.lua index ba394e0c..4881d964 100644 --- a/testes/coroutine.lua +++ b/testes/coroutine.lua @@ -702,9 +702,7 @@ else assert(t.currentline == t.linedefined + 2) assert(not debug.getinfo(c, 1)) -- no other level assert(coroutine.resume(c)) -- run next line - local n,v = debug.getlocal(c, 0, 2) -- check vararg table - assert(n == "(vararg table)" and v == nil) - local n,v = debug.getlocal(c, 0, 3) -- check next local + local n,v = debug.getlocal(c, 0, 2) -- check next local assert(n == "b" and v == 10) v = {coroutine.resume(c)} -- finish coroutine assert(v[1] == true and v[2] == 2 and v[3] == 3 and v[4] == undef) diff --git a/testes/db.lua b/testes/db.lua index e15a5be6..0f174f17 100644 --- a/testes/db.lua +++ b/testes/db.lua @@ -356,8 +356,8 @@ function f(a,b) global assert, g, string local _, y = debug.getlocal(1, 2) assert(x == a and y == b) - assert(debug.setlocal(2, 4, "pera") == "AA".."AA") - assert(debug.setlocal(2, 5, "manga") == "B") + assert(debug.setlocal(2, 3, "pera") == "AA".."AA") + assert(debug.setlocal(2, 4, "manga") == "B") x = debug.getinfo(2) assert(x.func == g and x.what == "Lua" and x.name == 'g' and x.nups == 2 and string.find(x.source, "^@.*db%.lua$")) @@ -392,7 +392,7 @@ function g (...) global * local B = 13 global assert - local x,y = debug.getlocal(1,6) + local x,y = debug.getlocal(1,5) assert(x == 'B' and y == 13) end end @@ -458,8 +458,7 @@ local function collectlocals (level) local tab = {} for i = 1, math.huge do local n, v = debug.getlocal(level + 1, i) - if not (n and string.find(n, "^[a-zA-Z0-9_]+$") or - n == "(vararg table)") then + if not (n and string.find(n, "^[a-zA-Z0-9_]+$")) then break -- consider only real variables end tab[n] = v @@ -726,9 +725,6 @@ assert(t.isvararg == false and t.nparams == 3 and t.nups == 0) t = debug.getinfo(function (a,b,...) return t[a] end, "u") assert(t.isvararg == true and t.nparams == 2 and t.nups == 1) -t = debug.getinfo(function (a,b,...t) t.n = 2; return t[a] end, "u") -assert(t.isvararg == true and t.nparams == 2 and t.nups == 0) - t = debug.getinfo(1) -- main assert(t.isvararg == true and t.nparams == 0 and t.nups == 1 and debug.getupvalue(t.func, 1) == "_ENV") diff --git a/testes/errors.lua b/testes/errors.lua index c82d5b3b..4230a352 100644 --- a/testes/errors.lua +++ b/testes/errors.lua @@ -159,9 +159,6 @@ assert(not string.find(doit"aaa={13}; local bbbb=1; aaa[bbbb](3)", "'bbbb'")) checkmessage("aaa={13}; local bbbb=1; aaa[bbbb](3)", "number") checkmessage("aaa=(1)..{}", "a table value") -checkmessage("local function foo (...t) return t.xx + 1 end; foo()", - "field 'xx'") - -- bug in 5.4.6 checkmessage("a = {_ENV = {}}; print(a._ENV.x + 1)", "field 'x'") @@ -421,28 +418,28 @@ end -- testing line error -local function lineerror (s, l, w) +local function lineerror (s, l) local err,msg = pcall(load(s)) local line = tonumber(string.match(msg, ":(%d+):")) - assert((line == l or (not line and not l)) and string.find(msg, w)) + assert(line == l or (not line and not l)) end -lineerror("local a\n for i=1,'a' do \n print(i) \n end", 2, "limit") -lineerror("\n local a \n for k,v in 3 \n do \n print(k) \n end", 3, "to call") -lineerror("\n\n for k,v in \n 3 \n do \n print(k) \n end", 4, "to call") -lineerror("function a.x.y ()\na=a+1\nend", 1, "index") +lineerror("local a\n for i=1,'a' do \n print(i) \n end", 2) +lineerror("\n local a \n for k,v in 3 \n do \n print(k) \n end", 3) +lineerror("\n\n for k,v in \n 3 \n do \n print(k) \n end", 4) +lineerror("function a.x.y ()\na=a+1\nend", 1) -lineerror("a = \na\n+\n{}", 3, "arithmetic") -lineerror("a = \n3\n+\n(\n4\n/\nprint)", 6, "arithmetic") -lineerror("a = \nprint\n+\n(\n4\n/\n7)", 3, "arithmetic") +lineerror("a = \na\n+\n{}", 3) +lineerror("a = \n3\n+\n(\n4\n/\nprint)", 6) +lineerror("a = \nprint\n+\n(\n4\n/\n7)", 3) -lineerror("a\n=\n-\n\nprint\n;", 3, "arithmetic") +lineerror("a\n=\n-\n\nprint\n;", 3) lineerror([[ a ( -- << 23) -]], 2, "call") +]], 2) lineerror([[ local a = {x = 13} @@ -452,7 +449,7 @@ x ( -- << 23 ) -]], 5, "call") +]], 5) lineerror([[ local a = {x = 13} @@ -462,17 +459,17 @@ x ( 23 + a ) -]], 6, "arithmetic") +]], 6) local p = [[ function g() f() end function f(x) error('a', XX) end g() ]] -XX=3;lineerror((p), 3, "a") -XX=0;lineerror((p), false, "a") -XX=1;lineerror((p), 2, "a") -XX=2;lineerror((p), 1, "a") +XX=3;lineerror((p), 3) +XX=0;lineerror((p), false) +XX=1;lineerror((p), 2) +XX=2;lineerror((p), 1) _G.XX, _G.g, _G.f = nil @@ -480,7 +477,7 @@ lineerror([[ local b = false if not b then error 'test' -end]], 3, "test") +end]], 3) lineerror([[ local b = false @@ -490,7 +487,7 @@ if not b then error 'test' end end -end]], 5, "test") +end]], 5) lineerror([[ _ENV = 1 @@ -498,7 +495,7 @@ global function foo () local a = 10 return a end -]], 2, "index") +]], 2) -- bug in 5.4.0 @@ -506,37 +503,17 @@ lineerror([[ local a = 0 local b = 1 local c = b % a -]], 3, "perform") +]], 3) do -- Force a negative estimate for base line. Error in instruction 2 -- (after VARARGPREP, GETGLOBAL), with first absolute line information -- (forced by too many lines) in instruction 0. local s = string.format("%s return __A.x", string.rep("\n", 300)) - lineerror(s, 301, "index") + lineerror(s, 301) end -local function stxlineerror (s, l, w) - local err,msg = load(s) - local line = tonumber(string.match(msg, ":(%d+):")) - assert((line == l or (not line and not l)) and string.find(msg, w, 1, true)) -end - -stxlineerror([[ -::L1:: -::L1:: -]], 2, "already defined") - -stxlineerror([[ -global none -local x = b -]], 2, "not declared") - -stxlineerror([[ -local a, b -]], 1, "multiple") - if not _soft then -- several tests that exhaust the Lua stack collectgarbage() @@ -712,26 +689,21 @@ end -- testing syntax limits local function testrep (init, rep, close, repc, finalresult) - local function gencode (n) - return init .. string.rep(rep, n) .. close .. string.rep(repc, n) - end - local res, msg = load(gencode(100)) -- 100 levels is OK - assert(res) + local s = init .. string.rep(rep, 100) .. close .. string.rep(repc, 100) + local res, msg = load(s) + assert(res) -- 100 levels is OK if (finalresult) then assert(res() == finalresult) end - local res, msg = load(gencode(500)) -- 500 levels not ok + s = init .. string.rep(rep, 500) + local res, msg = load(s) -- 500 levels not ok assert(not res and (string.find(msg, "too many") or string.find(msg, "overflow"))) end -testrep("local a", ",a", ";", "") -- local variables -testrep("local a", ",a", "= 1", ",1") -- local variables initialized -testrep("local a", ",a", "= f()", "") -- local variables initialized testrep("local a; a", ",a", "= 1", ",1") -- multiple assignment -testrep("local a; a=", "{", "0", "}") -- constructors -testrep("return ", "(", "2", ")", 2) -- parentheses --- nested calls (a(a(a(a(...))))) +testrep("local a; a=", "{", "0", "}") +testrep("return ", "(", "2", ")", 2) testrep("local function a (x) return x end; return ", "a(", "2.2", ")", 2.2) testrep("", "do ", "", " end") testrep("", "while a do ", "", " end") diff --git a/testes/events.lua b/testes/events.lua index fa9966ab..7e434b1f 100644 --- a/testes/events.lua +++ b/testes/events.lua @@ -390,18 +390,6 @@ do for i=1, 10 do t[i] = 1 end end - -do -- bug since 5.4 - local parent = {} - parent.__newindex = parent - collectgarbage() - local child = setmetatable({}, parent) - child.__newindex = {x = "hello"} - collectgarbage("step") - assert(parent.__newindex.x == "hello") -end - - -- concat metamethod x numbers (bug in 5.1.1) c = {} local x diff --git a/testes/files.lua b/testes/files.lua index 04936565..d4e327b7 100644 --- a/testes/files.lua +++ b/testes/files.lua @@ -715,7 +715,7 @@ do end -if T and T.nonblock and not _port then +if T and T.nonblock then print("testing failed write") -- unable to write anything to /dev/full @@ -840,7 +840,7 @@ assert(os.date("!\0\0") == "\0\0") local x = string.rep("a", 10000) assert(os.date(x) == x) local t = os.time() -global D = os.date("*t", t) +global D; D = os.date("*t", t) assert(os.date(string.rep("%d", 1000), t) == string.rep(os.date("%d", t), 1000)) assert(os.date(string.rep("%", 200)) == string.rep("%", 100)) @@ -854,13 +854,6 @@ local function checkDateTable (t) _G.D = nil end - -do -- testing mktime returning -1 - local t = os.date("*t", -1) - assert(os.time(t) == -1) -end - - checkDateTable(os.time()) if not _port then -- assume that time_t can represent these values diff --git a/testes/gc.lua b/testes/gc.lua index e50d9029..62713dac 100644 --- a/testes/gc.lua +++ b/testes/gc.lua @@ -707,46 +707,4 @@ end collectgarbage(oldmode) - -if T then - print("testing stack issues when calling finalizers") - - local X - local obj - - local function initobj () - X = false - obj = setmetatable({}, {__gc = function () X = true end}) - end - - local function loop (n) - if n > 0 then loop(n - 1) end - end - - -- should not try to call finalizer without a CallInfo available - initobj() - loop(20) -- ensure stack space - T.resetCI() -- remove extra CallInfos - T.alloccount(0) -- cannot allocate more CallInfos - obj = nil - collectgarbage() -- will not call finalizer - T.alloccount() - assert(X == false) - collectgarbage() -- now will call finalizer (it was still pending) - assert(X == true) - - -- should not try to call finalizer without stack space available - initobj() - loop(5) -- ensure enough CallInfos - T.reallocstack(0) -- remove extra stack slots - T.alloccount(0) -- cannot reallocate stack - obj = nil - collectgarbage() -- will not call finalizer - T.alloccount() - assert(X == false) - collectgarbage() -- now will call finalizer (it was still pending) - assert(X == true) -end - - print('OK') diff --git a/testes/gengc.lua b/testes/gengc.lua index 84c1a8ee..ea99bdc4 100644 --- a/testes/gengc.lua +++ b/testes/gengc.lua @@ -162,51 +162,6 @@ end assert(collectgarbage'isrunning') -do - -- bug in 5.0: when computing whether it should return from gen-major - -- to gen-minor, the difference between the total memory and the - -- previous total memory can be negative, which results in that - -- negative value being left-shifted (UB) - - local lim = 1e6 - - -- make major collections non-incremental - local oldsm = collectgarbage("param", "stepmul", 0) - - -- make "majorminor" large enough to force a left-shift - -- when applying the parameter (internal details) - local oldmm = collectgarbage("param", "majorminor", 2000) - - collectgarbage(); collectgarbage() - assert(not T or T.gcquery() == "genminor") - - local M = collectgarbage"count" * 1024 - - -- create a large table - local t = {} - for i = 1, lim do t[i] = true end - assert(collectgarbage"count" * 1024 > M + lim * string.packsize"j") - - -- force collector to "generational major" mode, doing several - -- minor collections that recover no memory - collectgarbage"step"; collectgarbage"step"; collectgarbage"step" - assert(not T or T.gcquery() == "genmajor") - - -- shrink the table - for i = 1, lim do t[i] = nil end - t[2 * lim] = true - assert(collectgarbage"count" < M * 5/4) - - -- bug was here, an assert violation when checking whether to - -- return to 'genminor' - collectgarbage"step" - - -- restore previous parameters - collectgarbage("param", "stepmul", oldsm) - collectgarbage("param", "majorminor", oldmm) -end - - do print"testing stop-the-world collection" local step = collectgarbage("param", "stepsize", 0); collectgarbage("incremental") @@ -221,20 +176,6 @@ do print"testing stop-the-world collection" assert(collectgarbage("param", "stepsize") == step) end - -if T then -- test GC parameter codification - for _, percentage in ipairs{5, 10, 12, 20, 50, 100, 200, 500} do - local param = T.codeparam(percentage) -- codify percentage - for _, value in ipairs{1, 2, 10, 100, 257, 1023, 6500, 100000} do - local exact = value*percentage // 100 - local aprox = T.applyparam(param, value) -- apply percentage - -- difference is at most 10% (+1 compensates difference due to - -- rounding to integers) - assert(math.abs(aprox - exact) <= exact/10 + 1) - end - end -end - collectgarbage(oldmode) print('OK') diff --git a/testes/goto.lua b/testes/goto.lua index 906208b5..3519e75d 100644 --- a/testes/goto.lua +++ b/testes/goto.lua @@ -293,7 +293,6 @@ end foo() -------------------------------------------------------------------------- --- check for compilation errors local function checkerr (code, err) local st, msg = load(code) assert(not st and string.find(msg, err)) @@ -381,7 +380,7 @@ do global * Y = x + Y assert(_ENV.Y == 20) - Y = nil + end @@ -412,66 +411,5 @@ do -- mixing lots of global/local declarations _ENV.x200 = nil end -do print "testing initialization in global declarations" - global a, b, c = 10, 20, 30 - assert(_ENV.a == 10 and b == 20 and c == 30) - _ENV.a = nil; _ENV.b = nil; _ENV.c = nil; - - global a, b, c = 10 - assert(_ENV.a == 10 and b == nil and c == nil) - _ENV.a = nil; _ENV.b = nil; _ENV.c = nil; - - global table - global a, b, c, d = table.unpack{1, 2, 3, 6, 5} - assert(_ENV.a == 1 and b == 2 and c == 3 and d == 6) - a = nil; b = nil; c = nil; d = nil - - local a, b = 100, 200 - do - global a, b = a, b - end - assert(_ENV.a == 100 and _ENV.b == 200) - _ENV.a = nil; _ENV.b = nil - - - assert(_ENV.a == nil and _ENV.b == nil and _ENV.c == nil and _ENV.d == nil) -end - -do - global table, string - -- global initialization when names don't fit in K - - -- to fill constant table - local code = {} - for i = 1, 300 do code[i] = "'" .. i .. "'" end - code = table.concat(code, ",") - code = string.format([[ - return function (_ENV) - local dummy = {%s} -- fill initial positions in constant table, - -- so that initialization must use registers for global names - global a, b, c = 10, 20, 30 - end]], code) - - local fun = assert(load(code))() - - local env = {} - fun(env) - assert(env.a == 10 and env.b == 20 and env.c == 30) -end - - -do -- testing global redefinitions - -- cannot use 'checkerr' as errors are not compile time - global pcall - local f = assert(load("global print = 10")) - local st, msg = pcall(f) - assert(string.find(msg, "global 'print' already defined")) - - local f = assert(load("local _ENV = {AA = false}; global AA = 10")) - local st, msg = pcall(f) - assert(string.find(msg, "global 'AA' already defined")) - -end - print'OK' diff --git a/testes/heavy.lua b/testes/heavy.lua index e7219a91..3b4e4ce3 100644 --- a/testes/heavy.lua +++ b/testes/heavy.lua @@ -1,8 +1,6 @@ -- $Id: testes/heavy.lua,v $ -- See Copyright Notice in file lua.h -global * - local function teststring () print("creating a string too long") do @@ -49,9 +47,9 @@ local function loadrep (x, what) end -local function controlstruct () +function controlstruct () print("control structure too long") - local lim = ((1 << 24) - 2) // 4 + local lim = ((1 << 24) - 2) // 3 local s = string.rep("a = a + 1\n", lim) s = "while true do " .. s .. "end" assert(load(s)) @@ -65,7 +63,7 @@ local function controlstruct () end -local function manylines () +function manylines () print("loading chunk with too many lines") local st, msg = loadrep("\n", "lines") assert(not st and string.find(msg, "too many lines")) @@ -73,7 +71,7 @@ local function manylines () end -local function hugeid () +function hugeid () print("loading chunk with huge identifier") local st, msg = loadrep("a", "chars") assert(not st and @@ -82,7 +80,7 @@ local function hugeid () print('+') end -local function toomanyinst () +function toomanyinst () print("loading chunk with too many instructions") local st, msg = loadrep("a = 10; ", "instructions") print('+') @@ -109,7 +107,7 @@ local function loadrepfunc (prefix, f) end -local function toomanyconst () +function toomanyconst () print("loading function with too many constants") loadrepfunc("function foo () return {0,", function (n) @@ -128,7 +126,7 @@ local function toomanyconst () end -local function toomanystr () +function toomanystr () local a = {} local st, msg = pcall(function () for i = 1, math.huge do @@ -146,7 +144,7 @@ local function toomanystr () end -local function toomanyidx () +function toomanyidx () local a = {} local st, msg = pcall(function () for i = 1, math.huge do diff --git a/testes/libs/lib11.c b/testes/libs/lib11.c index 6a85f4d6..377d0c48 100644 --- a/testes/libs/lib11.c +++ b/testes/libs/lib11.c @@ -1,7 +1,7 @@ #include "lua.h" /* function from lib1.c */ -LUAMOD_API int lib1_export (lua_State *L); +int lib1_export (lua_State *L); LUAMOD_API int luaopen_lib11 (lua_State *L) { return lib1_export(L); diff --git a/testes/libs/lib22.c b/testes/libs/lib22.c index b377cce5..8e656502 100644 --- a/testes/libs/lib22.c +++ b/testes/libs/lib22.c @@ -1,7 +1,3 @@ -/* implementation for lib2-v2 */ - -#include - #include "lua.h" #include "lauxlib.h" @@ -12,54 +8,8 @@ static int id (lua_State *L) { } -struct STR { - void *ud; - lua_Alloc allocf; -}; - - -static void *t_freestr (void *ud, void *ptr, size_t osize, size_t nsize) { - struct STR *blk = (struct STR*)ptr - 1; - blk->allocf(blk->ud, blk, sizeof(struct STR) + osize, 0); - return NULL; -} - - -static int newstr (lua_State *L) { - size_t len; - const char *str = luaL_checklstring(L, 1, &len); - void *ud; - lua_Alloc allocf = lua_getallocf(L, &ud); - struct STR *blk = (struct STR*)allocf(ud, NULL, 0, - len + 1 + sizeof(struct STR)); - if (blk == NULL) { /* allocation error? */ - lua_pushliteral(L, "not enough memory"); - lua_error(L); /* raise a memory error */ - } - blk->ud = ud; blk->allocf = allocf; - memcpy(blk + 1, str, len + 1); - lua_pushexternalstring(L, (char *)(blk + 1), len, t_freestr, L); - return 1; -} - - -/* -** Create an external string and keep it in the registry, so that it -** will test that the library code is still available (to deallocate -** this string) when closing the state. -*/ -static void initstr (lua_State *L) { - lua_pushcfunction(L, newstr); - lua_pushstring(L, - "012345678901234567890123456789012345678901234567890123456789"); - lua_call(L, 1, 1); /* call newstr("0123...") */ - luaL_ref(L, LUA_REGISTRYINDEX); /* keep string in the registry */ -} - - static const struct luaL_Reg funcs[] = { {"id", id}, - {"newstr", newstr}, {NULL, NULL} }; @@ -68,7 +18,6 @@ LUAMOD_API int luaopen_lib2 (lua_State *L) { lua_settop(L, 2); lua_setglobal(L, "y"); /* y gets 2nd parameter */ lua_setglobal(L, "x"); /* x gets 1st parameter */ - initstr(L); luaL_newlib(L, funcs); return 1; } diff --git a/testes/libs/makefile b/testes/libs/makefile index cf4c6881..4e7f965e 100644 --- a/testes/libs/makefile +++ b/testes/libs/makefile @@ -5,7 +5,7 @@ LUA_DIR = ../../ CC = gcc # compilation should generate Dynamic-Link Libraries -CFLAGS = -Wall -O2 -I$(LUA_DIR) -fPIC -shared +CFLAGS = -Wall -std=c99 -O2 -I$(LUA_DIR) -fPIC -shared # libraries used by the tests all: lib1.so lib11.so lib2.so lib21.so lib2-v2.so diff --git a/testes/locals.lua b/testes/locals.lua index e9718341..02f41980 100644 --- a/testes/locals.lua +++ b/testes/locals.lua @@ -310,7 +310,8 @@ do -- testing presence of second argument local function foo (howtoclose, obj, n) local ca -- copy of 'a' visible inside its close metamethod do - local a = func2close(function (...t) + local a = func2close(function (...) + local t = table.pack(...) assert(select("#", ...) == n) assert(t.n == n and t[1] == ca and (t.n < 2 or t[2] == obj)) ca = 15 -- final value to be returned if howtoclose=="scope" @@ -910,7 +911,8 @@ do local extrares -- result from extra yield (if any) - local function check (body, extra, ...t) + local function check (body, extra, ...) + local t = table.pack(...) -- expected returns local co = coroutine.wrap(body) if extra then extrares = co() -- runs until first (extra) yield @@ -1179,25 +1181,6 @@ if rawget(_G, "T") then end -do - -- detail in scopes of variables in the loop of 'repeat-until' - local res = {} - local function foo (a) - repeat - local x - local i = setmetatable({}, {__close = function () - res[#res + 1] = debug.getlocal(2, 2) -- get 'x' - res[#res + 1] = debug.getlocal(2, 3) -- get 'i' - a = true - end}) - until a - end - foo(false) - -- loop variables still in scope when closing 'i', both when 'repeat' - -- repeats and when 'repeat' stops. - assert(res[1] == "x" and res[2] == "i" and res[3] == "x" and res[4] == "i") -end - -- to-be-closed variables in generic for loops do diff --git a/testes/main.lua b/testes/main.lua index 98d36951..eb63d588 100644 --- a/testes/main.lua +++ b/testes/main.lua @@ -78,9 +78,6 @@ end RUN('lua -v') -RUN('lua -v > %s', out) -local release = string.match(getoutput(), "Lua (%d+%.%d+%.%d+)") - print(string.format("(temporary program file used in these tests: %s)", prog)) -- running stdin as a file @@ -93,7 +90,7 @@ prepfile[[ 1, a ) ]] -RUN('lua - -- < %s > %s', prog, out) +RUN('lua - < %s > %s', prog, out) checkout("1\tnil\n") RUN('echo "print(10)\nprint(2)\n" | lua > %s', out) @@ -136,7 +133,7 @@ checkout("-h\n") prepfile("print(package.path)") -- test LUA_PATH -RUN('env LUA_INIT= LUA_PATH=x lua -- %s > %s', prog, out) +RUN('env LUA_INIT= LUA_PATH=x lua %s > %s', prog, out) checkout("x\n") -- test LUA_PATH_version @@ -170,9 +167,7 @@ checkout("10\n11\n") -- test errors in LUA_INIT NoRun('LUA_INIT:1: msg', 'env LUA_INIT="error(\'msg\')" lua') - -print("testing option '-E'") - +-- test option '-E' local defaultpath, defaultCpath do @@ -197,22 +192,6 @@ assert(not string.find(defaultpath, "xxx") and string.find(defaultCpath, "lua")) --- (LUA_READLINELIB was introduced in 5.5.1) -if release >= "5.5.1" then - print"testing readline library name" - -- should generate a warning when trying to load inexistent library "xuxu" - local env = [[LUA_READLINELIB=xuxu LUA_INIT="warn('@allow')"]] - local code = 'echo " " | env %s lua %s -W -i >%s 2>&1' - RUN(code, env, "", out) -- run code with no extra options - assert(string.find(getoutput(), - "warning: unable to load readline library 'xuxu'")) - - RUN(code, env, "-E", out) -- run again with option -E - -- no warning when LUA_READLINELIB is to be ignored - assert(not string.find(getoutput(), "warning")) -end - - -- test replacement of ';;' to default path local function convert (p) prepfile("print(package.path)") @@ -379,7 +358,7 @@ RUN([[lua -e"_PROMPT='' _PROMPT2=''" -i < %s > %s]], prog, out) checkprogout("6\n10\n10\n\n") prepfile("a = [[b\nc\nd\ne]]\na") -RUN([[lua -e"_PROMPT='' _PROMPT2=''" -i -- < %s > %s]], prog, out) +RUN([[lua -e"_PROMPT='' _PROMPT2=''" -i < %s > %s]], prog, out) checkprogout("b\nc\nd\ne\n\n") -- input interrupted in continuation line @@ -509,13 +488,12 @@ assert(not os.remove(out)) -- invalid options NoRun("unrecognized option '-h'", "lua -h") NoRun("unrecognized option '---'", "lua ---") -NoRun("unrecognized option '-Ex'", "lua -Ex --") +NoRun("unrecognized option '-Ex'", "lua -Ex") NoRun("unrecognized option '-vv'", "lua -vv") NoRun("unrecognized option '-iv'", "lua -iv") NoRun("'-e' needs argument", "lua -e") NoRun("syntax error", "lua -e a") NoRun("'-l' needs argument", "lua -l") -NoRun("-i", "lua -- -i") -- handles -i as a script name if T then -- test library? diff --git a/testes/math.lua b/testes/math.lua index 54d19c40..0d228d09 100644 --- a/testes/math.lua +++ b/testes/math.lua @@ -685,18 +685,6 @@ assert(eq(math.exp(0), 1)) assert(eq(math.sin(10), math.sin(10%(2*math.pi)))) -do print("testing ldexp/frexp") - global ipairs - for _, x in ipairs{0, 10, 32, -math.pi, 1e10, 1e-10, math.huge, -math.huge} do - local m, p = math.frexp(x) - assert(math.ldexp(m, p) == x) - local am = math.abs(m) - assert(m == x or (0.5 <= am and am < 1)) - end - -end - - assert(tonumber(' 1.3e-2 ') == 1.3e-2) assert(tonumber(' -1.00000000000001 ') == -1.00000000000001) diff --git a/testes/memerr.lua b/testes/memerr.lua index a55514a9..77cb47cb 100644 --- a/testes/memerr.lua +++ b/testes/memerr.lua @@ -42,12 +42,8 @@ checkerr(MEMERRMSG, f) T.alloccount() -- remove limit --- preallocate stack space -local function deep (n) if n > 0 then deep(n - 1) end end - - -- test memory errors; increase limit for maximum memory by steps, --- so that we get memory errors in all allocations of a given +-- o that we get memory errors in all allocations of a given -- task, until there is enough memory to complete the task without -- errors. local function testbytes (s, f) @@ -57,7 +53,6 @@ local function testbytes (s, f) local a,b = nil while true do collectgarbage(); collectgarbage() - deep(4) T.totalmem(M) a, b = T.testC("pcall 0 1 0; pushstatus; return 2", f) T.totalmem(0) -- remove limit @@ -82,7 +77,6 @@ local function testalloc (s, f) local a,b = nil while true do collectgarbage(); collectgarbage() - deep(4) T.alloccount(M) a, b = T.testC("pcall 0 1 0; pushstatus; return 2", f) T.alloccount() -- remove limit @@ -93,19 +87,21 @@ local function testalloc (s, f) M = M + 1 -- increase allocation limit end print(string.format("minimum allocations for %s: %d allocations", s, M)) - return M + return a end local function testamem (s, f) - local aloc = testalloc(s, f) - local res = testbytes(s, f) - return {aloc = aloc, res = res} + testalloc(s, f) + return testbytes(s, f) end -local b = testamem("function call", function () return 10 end) -assert(b.res == 10 and b.aloc == 0) +-- doing nothing +b = testamem("doing nothing", function () return 10 end) +assert(b == 10) + +-- testing memory errors when creating a new state testamem("state creation", function () local st = T.newstate() @@ -125,18 +121,6 @@ testamem("coroutine creation", function() return coroutine.create(print) end) -do -- vararg tables - local function pack (...t) return t end - local b = testamem("vararg table", function () - return pack(10, 20, 30, 40, "hello") - end) - assert(b.aloc == 3) -- new table uses three memory blocks - -- table optimized away - local function sel (n, ...arg) return arg[n] + arg.n end - local b = testamem("optimized vararg table", - function () return sel(2.0, 20, 30) end) - assert(b.res == 32 and b.aloc == 0) -- no memory needed for this case -end -- testing to-be-closed variables testamem("to-be-closed variables", function() @@ -166,9 +150,9 @@ local function expand (n,s) e, s, expand(n-1,s), e) end -G=0; collectgarbage() +G=0; collectgarbage(); a =collectgarbage("count") load(expand(20,"G=G+1"))() -assert(G==20); collectgarbage() +assert(G==20); collectgarbage(); -- assert(gcinfo() <= a+1) G = nil testamem("running code on new thread", function () @@ -176,14 +160,6 @@ testamem("running code on new thread", function () end) -do -- external strings - local str = string.rep("a", 100) - testamem("creating external strings", function () - return T.externstr(str) - end) -end - - -- testing memory x compiler testamem("loadstring", function () @@ -282,25 +258,6 @@ testamem("growing stack", function () return foo(100) end) - -collectgarbage() -collectgarbage() -global io, T, setmetatable, collectgarbage, print - -local Count = 0 -testamem("finalizers", function () - local X = false - local obj = setmetatable({}, {__gc = function () X = true end}) - obj = nil - T.resetCI() -- remove extra CallInfos - T.reallocstack(18) -- remove extra stack slots - Count = Count + 1 - io.stderr:write(Count, "\n") - T.trick(io) - collectgarbage() - return X -end) - -- }================================================================== diff --git a/testes/nextvar.lua b/testes/nextvar.lua index 098e7891..03810a8e 100644 --- a/testes/nextvar.lua +++ b/testes/nextvar.lua @@ -345,18 +345,6 @@ do end end - -do print("testing attack on table length") - local t = {} - local lim = math.floor(math.log(math.maxinteger, 2)) - 1 - for i = lim, 0, -1 do - t[2^i] = true - end - assert(t[1 << lim]) - -- next loop should not take forever - for i = 1, #t do end -end - local nofind = {} @@ -905,18 +893,13 @@ local function foo1 (e,i) if i <= e.n then return i,a[i] end end -local closed = false -setmetatable(a, {__pairs = function (x) - local tbc = setmetatable({}, {__close = function () closed = true end}) - return foo, x, 0, tbc - end}) +setmetatable(a, {__pairs = function (x) return foo, x, 0 end}) local i = 0 for k,v in pairs(a) do i = i + 1 assert(k == i and v == k+1) end -assert(closed) -- 'tbc' has been closed a.n = 5 a[3] = 30 diff --git a/testes/pm.lua b/testes/pm.lua index feab33db..720d2a35 100644 --- a/testes/pm.lua +++ b/testes/pm.lua @@ -347,16 +347,6 @@ do -- init parameter in gmatch end -do -- bug since 5.3 - local N = 20000 - local iter = string.gmatch(string.rep("a", N), string.rep("a?", N)) - pcall(iter) -- error for pattern too complex - -- calling function again found recursion count ('matchdepth') equal - -- to -1, so it did not detect next C-stack overflow - pcall(iter) -end - - -- tests for `%f' (`frontiers') assert(string.gsub("aaa aa a aaa a", "%f[%w]a", "x") == "xaa xa x xaa x") diff --git a/testes/sort.lua b/testes/sort.lua index 92aaca3c..b0127660 100644 --- a/testes/sort.lua +++ b/testes/sort.lua @@ -72,19 +72,6 @@ assert(a==1 and x==nil) a,x = unpack({1,2}, 1, 1) assert(a==1 and x==nil) - -do -- unpack with non-tables - local debug = require"debug" - local oldmt = debug.getmetatable(0) - local str = "hello" - debug.setmetatable(0, - { __len = function () return #str end, - __index = function (_, i) return string.sub(str, i, i) end}) - assert(table.concat({table.unpack(0)}) == str) - debug.setmetatable(0, oldmt) -- restore original metatable for numbers -end - - do local maxi = (1 << 31) - 1 -- maximum value for an int (usually) local mini = -(1 << 31) -- minimum value for an int (usually) diff --git a/testes/strings.lua b/testes/strings.lua index 84ff1154..46912d43 100644 --- a/testes/strings.lua +++ b/testes/strings.lua @@ -540,23 +540,6 @@ else assert(y == x) local z = T.externstr(x) -- external allocated long string assert(z == y) - - local e = T.externstr("") -- empty external string - assert(e .. "x" == "x" and "x" .. e == "x") - assert(e .. e == "" and #e == 0) - - -- external string as the "n" key in vararg table - local n = T.externstr("n") - local n0 = T.externstr("n\0") - local function aux (...t) assert(t[n0] == nil); return t[n] end - assert(aux(10, 20, 30) == 3) - - -- external string as mode in weak table - local t = setmetatable({}, {__mode = T.externstr("kv")}) - t[{}] = {} - assert(next(t)) - collectgarbage() - assert(next(t) == nil) end print('OK') diff --git a/testes/tracegc.lua b/testes/tracegc.lua index c1154f90..9c5c1b3f 100644 --- a/testes/tracegc.lua +++ b/testes/tracegc.lua @@ -1,17 +1,12 @@ -- track collections - local M = {} -- import list -local stderr, collectgarbage = io.stderr, collectgarbage +local setmetatable, stderr, collectgarbage = + setmetatable, io.stderr, collectgarbage --- the debug version of setmetatable does not create any object (such as --- a '__metatable' string), and so it is more appropriate to be used in --- a finalizer -local setmetatable = require"debug".setmetatable - -global none +_ENV = nil local active = false diff --git a/testes/utf8.lua b/testes/utf8.lua index 8a0213d6..143c6d34 100644 --- a/testes/utf8.lua +++ b/testes/utf8.lua @@ -152,20 +152,11 @@ checkerror("position out of bounds", utf8.offset, "", 1, -1) checkerror("continuation byte", utf8.offset, "𦧺", 1, 2) checkerror("continuation byte", utf8.offset, "𦧺", 1, 2) checkerror("continuation byte", utf8.offset, "\x80", 1) -checkerror("continuation byte", utf8.offset, "\x9c", -1) -- error in indices for len checkerror("out of bounds", utf8.len, "abc", 0, 2) checkerror("out of bounds", utf8.len, "abc", 1, 4) -do -- missing continuation bytes - -- get what is available - local p, e = utf8.offset("\xE0", 1) - assert(p == 1 and e == 1) - local p, e = utf8.offset("\xE0\x9e", -1) - assert(p == 1 and e == 2) -end - local s = "hello World" local t = {string.byte(s, 1, -1)} @@ -238,18 +229,10 @@ s = "\0 \x7F\z s = string.gsub(s, " ", "") check(s, {0,0x7F, 0x80,0x7FF, 0x800,0xFFFF, 0x10000,0x10FFFF}) - --- again, without strictness -s = "\xF0\x90\x80\x80 \xF7\xBF\xBF\xBF\z - \xF8\x88\x80\x80\x80 \xFB\xBF\xBF\xBF\xBF\z - \xFC\x84\x80\x80\x80\x80 \xFD\xBF\xBF\xBF\xBF\xBF" -s = string.gsub(s, " ", "") -check(s, {0x10000,0x1FFFFF, 0x200000,0x3FFFFFF, 0x4000000,0x7FFFFFFF}, true) - do -- original UTF-8 values local s = "\u{4000000}\u{7FFFFFFF}" - assert(s == "\xFC\x84\x80\x80\x80\x80\xFD\xBF\xBF\xBF\xBF\xBF") + assert(#s == 12) check(s, {0x4000000, 0x7FFFFFFF}, true) s = "\u{200000}\u{3FFFFFF}" @@ -265,10 +248,6 @@ local x = "日本語a-4\0éó" check(x, {26085, 26412, 35486, 97, 45, 52, 0, 233, 243}) --- more than 5 continuation bytes -assert(not utf8.len("\xff\x8f\x8f\x8f\x8f\x8f\x8f\x8f")) - - -- Supplementary Characters check("𣲷𠜎𠱓𡁻𠵼ab𠺢", {0x23CB7, 0x2070E, 0x20C53, 0x2107B, 0x20D7C, 0x61, 0x62, 0x20EA2,}) diff --git a/testes/vararg.lua b/testes/vararg.lua index 043fa7d4..10553de2 100644 --- a/testes/vararg.lua +++ b/testes/vararg.lua @@ -3,12 +3,9 @@ print('testing vararg') -local function f (a, ...t) +local function f (a, ...) local x = {n = select('#', ...), ...} - assert(x.n == t.n) - for i = 1, x.n do - assert(a[i] == x[i] and x[i] == t[i]) - end + for i = 1, x.n do assert(a[i] == x[i]) end return x.n end @@ -20,7 +17,7 @@ local function c12 (...) return res, 2 end -local function vararg (... t) return t end +local function vararg (...) return {n = select('#', ...), ...} end local call = function (f, args) return f(table.unpack(args, 1, args.n)) end @@ -101,40 +98,8 @@ a,b,c,d,e = f(4) assert(a==nil and b==nil and c==nil and d==nil and e==nil) -do -- vararg expressions using unpack - local function aux (a, v, ...t) - for k, val in pairs(v) do t[k] = val end - return ... - end - - local t = table.pack(aux(10, {11, [5] = 24}, 1, 2, 3, nil, 4)) - assert(t.n == 5 and t[1] == 11 and t[2] == 2 and t[3] == 3 - and t[4] == nil and t[5] == 24) - - local t = table.pack(aux(nil, {1, [20] = "a", [30] = "b", n = 30})) - assert(t.n == 30 and t[1] == 1 and t[20] == "a" and t[30] == "b") - -- table has only those four elements - assert(next(t, next(t, next(t, next(t, next(t, nil))))) == nil) - - local a, b, c, d = aux(nil, {}, 10, 20, 30) - assert(a == 10 and b == 20 and c == 30 and d == nil) - - local function aux (a, b, n, ...t) t.n = n; return b, ... end - local t = table.pack(aux(10, 1, 10000)) - assert(t.n == 10001 and t[1] == 1 and #t == 1) - - local function checkerr (emsg, f, ...) - local st, msg = pcall(f, ...) - assert(not st and string.find(msg, emsg)) - end - checkerr("no proper 'n'", aux, 1, 1, -1) - checkerr("no proper 'n'", aux, 1, 1, math.maxinteger) - checkerr("no proper 'n'", aux, 1, 1, math.mininteger) - checkerr("no proper 'n'", aux, 1, 1, 1.0) -end - -- varargs for main chunks -local f = assert(load[[ return {...} ]]) +local f = load[[ return {...} ]] local x = f(2,3) assert(x[1] == 2 and x[2] == 3 and x[3] == undef) @@ -182,79 +147,5 @@ 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 - - -do -- _ENV as vararg parameter - local st, msg = load[[ - local function aux (... _ENV) - global a - a = 10 - end ]] - assert(string.find(msg, "const variable 'a'")) - - local function aux (..._ENV) - global a; a = 10 - return a - end - assert(aux() == 10) - - local function aux (... _ENV) - global a = 10 - return a - end - assert(aux() == 10) -end - - -do -- access to vararg parameter - local function notab (keys, t, ...v) - for _, k in pairs(keys) do - assert(t[k] == v[k]) - end - assert(t.n == v.n) - return ... - end - - local t = table.pack(10, 20, 30) - local keys = {-1, 0, 1, t.n, t.n + 1, 1.0, 1.1, "n", print, "k", "1"} - notab(keys, t, 10, 20, 30) -- ensure stack space - local m = collectgarbage"count" - notab(keys, t, 10, 20, 30) - -- 'notab' does not create any table/object - assert(m == collectgarbage"count") - - -- writing to the vararg table - local function foo (...t) - t[1] = t[1] + 10 - return t[1] - end - assert(foo(10, 30) == 20) -end - print('OK')