Compare commits

..

No commits in common. "master" and "=list" have entirely different histories.

81 changed files with 1179 additions and 2463 deletions

40
lapi.c
View file

@ -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--;

View file

@ -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;
}

View file

@ -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);

View file

@ -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);

155
lcode.c
View file

@ -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 <token>" 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 <const>).
@ -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;

View file

@ -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);

View file

@ -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]);
}
}

View file

@ -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 */

View file

@ -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 */

View file

@ -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 */

View file

@ -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);

131
ldo.c
View file

@ -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;

3
ldo.h
View file

@ -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);

22
ldump.c
View file

@ -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 */

View file

@ -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 */

20
lgc.c
View file

@ -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;
}

5
lgc.h
View file

@ -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)

View file

@ -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 <sys/types.h>

View file

@ -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

2
llex.c
View file

@ -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 */

View file

@ -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

View file

@ -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 */

View file

@ -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 */

View file

@ -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 */

View file

@ -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 */

View file

@ -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;
}

View file

@ -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);

View file

@ -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

View file

@ -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}
};

220
lparser.c
View file

@ -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, "<name> 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 */
}

View file

@ -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

View file

@ -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);

View file

@ -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);

View file

@ -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);
}
}

View file

@ -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

View file

@ -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: {

150
ltable.c
View file

@ -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);
}

View file

@ -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)

View file

@ -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 ||

View file

@ -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},

View file

@ -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

156
ltm.c
View file

@ -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 r<l); bit CIST_LEQ in the call status keeps that
** information.
*/
int luaT_callorderTM (lua_State *L, const TValue *p1, const TValue *p2,
TMS event) {
int tag = callbinTM(L, p1, p2, L->top.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));
}

11
ltm.h
View file

@ -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

115
lua.c
View file

@ -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 <readline/readline.h>
#include <readline/history.h>
#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 <readline/readline.h>
#include <readline/history.h>
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 <dlfcn.h>
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)

19
lua.h
View file

@ -13,13 +13,13 @@
#include <stddef.h>
#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

147
luaconf.h
View file

@ -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

View file

@ -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;
}

View file

@ -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,

View file

@ -10,6 +10,7 @@
#include "lprefix.h"
#include <assert.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
@ -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 */

266
lvm.c
View file

@ -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 */

View file

@ -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 \

View file

@ -1,4 +1,4 @@
#!/usr/bin/env lua
#!/usr/bin/env lua5.3
-- special marks:
@ -8,11 +8,11 @@
---------------------------------------------------------------
header = [[
<!DOCTYPE html>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<html>
<head>
<title>Lua 5.5 Reference Manual</title>
<title>Lua 5.4 Reference Manual</title>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
<link rel="stylesheet" href="lua.css">
<link rel="stylesheet" href="manual.css">
@ -23,14 +23,14 @@ header = [[
<hr>
<h1>
<a href="http://www.lua.org/home.html"><img src="logo.gif" alt="[Lua logo]" border="0"></a>
Lua 5.5 Reference Manual
Lua 5.4 Reference Manual
</h1>
by Roberto Ierusalimschy, Luiz Henrique de Figueiredo, Waldemar Celes
<p>
<small>
<a href="http://www.lua.org/copyright.html">Copyright</a>
&copy; 2026 Lua.org, PUC-Rio. All rights reserved.
&copy; 2025 Lua.org, PUC-Rio. All rights reserved.
</small>
<hr>
@ -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, "^(.-</span>)(.*)")
--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,

View file

@ -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 <const>, _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}}

View file

@ -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 <string.h>
#include <time.h>
/* 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"

View file

@ -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)

View file

@ -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

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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<const> 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")

View file

@ -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 <close> 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")

View file

@ -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

View file

@ -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

View file

@ -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')

View file

@ -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')

View file

@ -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<const> 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<const> 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'

View file

@ -1,8 +1,6 @@
-- $Id: testes/heavy.lua,v $
-- See Copyright Notice in file lua.h
global <const> *
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

View file

@ -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);

View file

@ -1,7 +1,3 @@
/* implementation for lib2-v2 */
#include <string.h>
#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;
}

View file

@ -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

View file

@ -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 <close> = func2close(function (...t)
local a <close> = 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 <close> = 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

View file

@ -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?

View file

@ -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)

View file

@ -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)
-- }==================================================================

View file

@ -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

View file

@ -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")

View file

@ -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)

View file

@ -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')

View file

@ -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

View file

@ -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,})

View file

@ -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 <const> 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')