mirror of
https://github.com/lua/lua
synced 2026-06-08 15:34:49 +00:00
Compare commits
92 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 40b76de2d7 | |||
| 0465c23b3e | |||
| 53b41d0cdd | |||
| 36c1f6d949 | |||
| 0da6d320f7 | |||
| ae23e72601 | |||
| 4c5d5063a5 | |||
| 3228a97c6a | |||
| 0c16a42d61 | |||
| d0bd25d2e7 | |||
| 29cf284089 | |||
| c037162a1a | |||
| efddc2309c | |||
| f1bb2773bb | |||
| 51269bd783 | |||
| 377cbea61b | |||
| 36d5d2b284 | |||
| 9e501d9855 | |||
| 10eb89d114 | |||
| 7c40c5edb2 | |||
| b60e2bcd7c | |||
| c6b4848238 | |||
| efbc297545 | |||
| cfcaa9493b | |||
| 3360710bd3 | |||
| e992c6a959 | |||
| f5d1e8639b | |||
| 2a7cf4f319 | |||
| 5cfc725a8b | |||
| 45c7ae5b1b | |||
| 962f444a75 | |||
| c4e2c91973 | |||
| 632a71b24d | |||
| 578ae5745c | |||
| a5522f06d2 | |||
| 3d03ae5bd6 | |||
| 82d721a855 | |||
| 104b0fc700 | |||
| 8164d09338 | |||
| 985ef32248 | |||
| a07f6a8241 | |||
| f33cc4ddec | |||
| d94f7ba304 | |||
| 4cf498210e | |||
| 5b7d998764 | |||
| 81f4def54f | |||
| e44f3a2ffc | |||
| f791bb6906 | |||
| d342328e5b | |||
| 0149b781d4 | |||
| d4eff00234 | |||
| fca974486d | |||
| 26755cad99 | |||
| b352217b84 | |||
| 9c66903cc5 | |||
| 30a7b93439 | |||
| 7a92f3f99a | |||
| 3347c9d32d | |||
| 25c54fe60e | |||
| 0cc3c9447c | |||
| 8fb1af0e33 | |||
| 140b672e2e | |||
| 9ea06e61f2 | |||
| ffbcadfb41 | |||
| 0b73ed8f08 | |||
| f87416f1a3 | |||
| 03a3473687 | |||
| 9a3940380a | |||
| 711890624f | |||
| 13d2326a23 | |||
| 06c5d3825f | |||
| c345877e4c | |||
| 907d172c11 | |||
| 88aa4049ad | |||
| c688b00f73 | |||
| dd095677e3 | |||
| 53dc5a3bba | |||
| 5b179eaf6a | |||
| 8fddca81e7 | |||
| c33bb08ffe | |||
| e3716ee161 | |||
| 303f415559 | |||
| ccb8b307f1 | |||
| 60b6599e83 | |||
| c612685d4b | |||
| 85a3c1699c | |||
| f65d1f9e02 | |||
| 942c10a5e3 | |||
| 8485687908 | |||
| 03d672a95c | |||
| 03bf7fdd4f | |||
| 59a1adf194 |
@@ -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");
|
api_check(L, idx <= ci->top.p - (func + 1), "new top too large");
|
||||||
diff = ((func + 1) + idx) - L->top.p;
|
diff = ((func + 1) + idx) - L->top.p;
|
||||||
for (; diff > 0; diff--)
|
for (; diff > 0; diff--)
|
||||||
setnilvalue(s2v(L->top.p++)); /* clear new slots */
|
setnilvalue2s(L->top.p++); /* clear new slots */
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
api_check(L, -(idx+1) <= (L->top.p - (func + 1)), "invalid new top");
|
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),
|
api_check(L, (L->ci->callstatus & CIST_TBC) && (L->tbclist.p == level),
|
||||||
"no variable to close at given level");
|
"no variable to close at given level");
|
||||||
level = luaF_close(L, level, CLOSEKTOP, 0);
|
level = luaF_close(L, level, CLOSEKTOP, 0);
|
||||||
setnilvalue(s2v(level));
|
setnilvalue2s(level);
|
||||||
lua_unlock(L);
|
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);
|
const TValue *o = index2value(L, idx);
|
||||||
if (ttisnumber(o)) {
|
if (ttisnumber(o)) {
|
||||||
unsigned len = luaO_tostringbuff(o, buff);
|
unsigned len = luaO_tostringbuff(o, buff);
|
||||||
@@ -440,7 +440,13 @@ LUA_API lua_Unsigned lua_rawlen (lua_State *L, int idx) {
|
|||||||
case LUA_VSHRSTR: return cast(lua_Unsigned, tsvalue(o)->shrlen);
|
case LUA_VSHRSTR: return cast(lua_Unsigned, tsvalue(o)->shrlen);
|
||||||
case LUA_VLNGSTR: return cast(lua_Unsigned, tsvalue(o)->u.lnglen);
|
case LUA_VLNGSTR: return cast(lua_Unsigned, tsvalue(o)->u.lnglen);
|
||||||
case LUA_VUSERDATA: return cast(lua_Unsigned, uvalue(o)->len);
|
case LUA_VUSERDATA: return cast(lua_Unsigned, uvalue(o)->len);
|
||||||
case LUA_VTABLE: return luaH_getn(hvalue(o));
|
case LUA_VTABLE: {
|
||||||
|
lua_Unsigned res;
|
||||||
|
lua_lock(L);
|
||||||
|
res = luaH_getn(L, hvalue(o));
|
||||||
|
lua_unlock(L);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
default: return 0;
|
default: return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -478,7 +484,7 @@ LUA_API lua_State *lua_tothread (lua_State *L, int idx) {
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
** Returns a pointer to the internal representation of an object.
|
** Returns a pointer to the internal representation of an object.
|
||||||
** Note that ANSI C does not allow the conversion of a pointer to
|
** Note that ISO C does not allow the conversion of a pointer to
|
||||||
** function to a 'void*', so the conversion here goes through
|
** function to a 'void*', so the conversion here goes through
|
||||||
** a 'size_t'. (As the returned pointer is only informative, this
|
** a 'size_t'. (As the returned pointer is only informative, this
|
||||||
** conversion should not be a problem.)
|
** conversion should not be a problem.)
|
||||||
@@ -507,7 +513,7 @@ LUA_API const void *lua_topointer (lua_State *L, int idx) {
|
|||||||
|
|
||||||
LUA_API void lua_pushnil (lua_State *L) {
|
LUA_API void lua_pushnil (lua_State *L) {
|
||||||
lua_lock(L);
|
lua_lock(L);
|
||||||
setnilvalue(s2v(L->top.p));
|
setnilvalue2s(L->top.p);
|
||||||
api_incr_top(L);
|
api_incr_top(L);
|
||||||
lua_unlock(L);
|
lua_unlock(L);
|
||||||
}
|
}
|
||||||
@@ -564,7 +570,7 @@ LUA_API const char *lua_pushexternalstring (lua_State *L,
|
|||||||
LUA_API const char *lua_pushstring (lua_State *L, const char *s) {
|
LUA_API const char *lua_pushstring (lua_State *L, const char *s) {
|
||||||
lua_lock(L);
|
lua_lock(L);
|
||||||
if (s == NULL)
|
if (s == NULL)
|
||||||
setnilvalue(s2v(L->top.p));
|
setnilvalue2s(L->top.p);
|
||||||
else {
|
else {
|
||||||
TString *ts;
|
TString *ts;
|
||||||
ts = luaS_new(L, s);
|
ts = luaS_new(L, s);
|
||||||
@@ -679,7 +685,7 @@ static int auxgetstr (lua_State *L, const TValue *t, const char *k) {
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
** The following function assumes that the registry cannot be a weak
|
** The following function assumes that the registry cannot be a weak
|
||||||
** table, so that en mergency collection while using the global table
|
** table; so, an emergency collection while using the global table
|
||||||
** cannot collect it.
|
** cannot collect it.
|
||||||
*/
|
*/
|
||||||
static void getGlobalTable (lua_State *L, TValue *gt) {
|
static void getGlobalTable (lua_State *L, TValue *gt) {
|
||||||
@@ -737,7 +743,7 @@ LUA_API int lua_geti (lua_State *L, int idx, lua_Integer n) {
|
|||||||
|
|
||||||
static int finishrawget (lua_State *L, lu_byte tag) {
|
static int finishrawget (lua_State *L, lu_byte tag) {
|
||||||
if (tagisempty(tag)) /* avoid copying empty items to the stack */
|
if (tagisempty(tag)) /* avoid copying empty items to the stack */
|
||||||
setnilvalue(s2v(L->top.p));
|
setnilvalue2s(L->top.p);
|
||||||
api_incr_top(L);
|
api_incr_top(L);
|
||||||
lua_unlock(L);
|
lua_unlock(L);
|
||||||
return novariant(tag);
|
return novariant(tag);
|
||||||
@@ -830,7 +836,7 @@ LUA_API int lua_getiuservalue (lua_State *L, int idx, int n) {
|
|||||||
o = index2value(L, idx);
|
o = index2value(L, idx);
|
||||||
api_check(L, ttisfulluserdata(o), "full userdata expected");
|
api_check(L, ttisfulluserdata(o), "full userdata expected");
|
||||||
if (n <= 0 || n > uvalue(o)->nuvalue) {
|
if (n <= 0 || n > uvalue(o)->nuvalue) {
|
||||||
setnilvalue(s2v(L->top.p));
|
setnilvalue2s(L->top.p);
|
||||||
t = LUA_TNONE;
|
t = LUA_TNONE;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -1116,6 +1122,7 @@ LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data,
|
|||||||
ZIO z;
|
ZIO z;
|
||||||
TStatus status;
|
TStatus status;
|
||||||
lua_lock(L);
|
lua_lock(L);
|
||||||
|
luaC_checkGC(L);
|
||||||
if (!chunkname) chunkname = "?";
|
if (!chunkname) chunkname = "?";
|
||||||
luaZ_init(L, &z, reader, data);
|
luaZ_init(L, &z, reader, data);
|
||||||
status = luaD_protectedparser(L, &z, chunkname, mode);
|
status = luaD_protectedparser(L, &z, chunkname, mode);
|
||||||
@@ -1195,11 +1202,16 @@ LUA_API int lua_gc (lua_State *L, int what, ...) {
|
|||||||
case LUA_GCSTEP: {
|
case LUA_GCSTEP: {
|
||||||
lu_byte oldstp = g->gcstp;
|
lu_byte oldstp = g->gcstp;
|
||||||
l_mem n = cast(l_mem, va_arg(argp, size_t));
|
l_mem n = cast(l_mem, va_arg(argp, size_t));
|
||||||
|
l_mem newdebt;
|
||||||
int work = 0; /* true if GC did some work */
|
int work = 0; /* true if GC did some work */
|
||||||
g->gcstp = 0; /* allow GC to run (other bits must be zero here) */
|
g->gcstp = 0; /* allow GC to run (other bits must be zero here) */
|
||||||
if (n <= 0)
|
if (n <= 0)
|
||||||
n = g->GCdebt; /* force to run one basic step */
|
newdebt = 0; /* force to run one basic step */
|
||||||
luaE_setdebt(g, g->GCdebt - n);
|
else if (g->GCdebt >= n - MAX_LMEM) /* no overflow? */
|
||||||
|
newdebt = g->GCdebt - n;
|
||||||
|
else /* overflow */
|
||||||
|
newdebt = -MAX_LMEM; /* set debt to miminum value */
|
||||||
|
luaE_setdebt(g, newdebt);
|
||||||
luaC_condGC(L, (void)0, work = 1);
|
luaC_condGC(L, (void)0, work = 1);
|
||||||
if (work && g->gcstate == GCSpause) /* end of cycle? */
|
if (work && g->gcstate == GCSpause) /* end of cycle? */
|
||||||
res = 1; /* signal it */
|
res = 1; /* signal it */
|
||||||
|
|||||||
@@ -742,7 +742,7 @@ typedef struct LoadF {
|
|||||||
|
|
||||||
static const char *getF (lua_State *L, void *ud, size_t *size) {
|
static const char *getF (lua_State *L, void *ud, size_t *size) {
|
||||||
LoadF *lf = (LoadF *)ud;
|
LoadF *lf = (LoadF *)ud;
|
||||||
(void)L; /* not used */
|
UNUSED(L);
|
||||||
if (lf->n > 0) { /* are there pre-read characters to be read? */
|
if (lf->n > 0) { /* are there pre-read characters to be read? */
|
||||||
*size = lf->n; /* return them (chars already in buffer) */
|
*size = lf->n; /* return them (chars already in buffer) */
|
||||||
lf->n = 0; /* no more pre-read characters */
|
lf->n = 0; /* no more pre-read characters */
|
||||||
@@ -856,7 +856,7 @@ typedef struct LoadS {
|
|||||||
|
|
||||||
static const char *getS (lua_State *L, void *ud, size_t *size) {
|
static const char *getS (lua_State *L, void *ud, size_t *size) {
|
||||||
LoadS *ls = (LoadS *)ud;
|
LoadS *ls = (LoadS *)ud;
|
||||||
(void)L; /* not used */
|
UNUSED(L);
|
||||||
if (ls->size == 0) return NULL;
|
if (ls->size == 0) return NULL;
|
||||||
*size = ls->size;
|
*size = ls->size;
|
||||||
ls->size = 0;
|
ls->size = 0;
|
||||||
@@ -874,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) {
|
LUALIB_API int luaL_loadstring (lua_State *L, const char *s) {
|
||||||
return luaL_loadbuffer(L, s, strlen(s), s);
|
return luaL_loadbufferx(L, s, strlen(s), s, "t");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* }====================================================== */
|
/* }====================================================== */
|
||||||
@@ -1046,8 +1046,8 @@ LUALIB_API const char *luaL_gsub (lua_State *L, const char *s,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) {
|
void *luaL_alloc (void *ud, void *ptr, size_t osize, size_t nsize) {
|
||||||
(void)ud; (void)osize; /* not used */
|
UNUSED(ud); UNUSED(osize);
|
||||||
if (nsize == 0) {
|
if (nsize == 0) {
|
||||||
free(ptr);
|
free(ptr);
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -1172,16 +1172,20 @@ static unsigned int luai_makeseed (void) {
|
|||||||
|
|
||||||
|
|
||||||
LUALIB_API unsigned int luaL_makeseed (lua_State *L) {
|
LUALIB_API unsigned int luaL_makeseed (lua_State *L) {
|
||||||
(void)L; /* unused */
|
UNUSED(L);
|
||||||
return luai_makeseed();
|
return luai_makeseed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
LUALIB_API lua_State *luaL_newstate (void) {
|
/*
|
||||||
lua_State *L = lua_newstate(l_alloc, NULL, 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));
|
||||||
if (l_likely(L)) {
|
if (l_likely(L)) {
|
||||||
lua_atpanic(L, &panic);
|
lua_atpanic(L, &panic);
|
||||||
lua_setwarnf(L, warnfoff, L); /* default is warnings off */
|
lua_setwarnf(L, warnfon, L);
|
||||||
}
|
}
|
||||||
return L;
|
return L;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -81,6 +81,9 @@ 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_fileresult) (lua_State *L, int stat, const char *fname);
|
||||||
LUALIB_API int (luaL_execresult) (lua_State *L, int stat);
|
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 */
|
/* predefined references */
|
||||||
#define LUA_NOREF (-2)
|
#define LUA_NOREF (-2)
|
||||||
@@ -100,7 +103,7 @@ LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s);
|
|||||||
|
|
||||||
LUALIB_API lua_State *(luaL_newstate) (void);
|
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);
|
LUALIB_API lua_Integer (luaL_len) (lua_State *L, int idx);
|
||||||
|
|
||||||
|
|||||||
+21
-27
@@ -279,21 +279,22 @@ static int luaB_next (lua_State *L) {
|
|||||||
|
|
||||||
static int pairscont (lua_State *L, int status, lua_KContext k) {
|
static int pairscont (lua_State *L, int status, lua_KContext k) {
|
||||||
(void)L; (void)status; (void)k; /* unused */
|
(void)L; (void)status; (void)k; /* unused */
|
||||||
return 3;
|
return 4; /* __pairs did all the work, just return its results */
|
||||||
}
|
}
|
||||||
|
|
||||||
static int luaB_pairs (lua_State *L) {
|
static int luaB_pairs (lua_State *L) {
|
||||||
luaL_checkany(L, 1);
|
luaL_checkany(L, 1);
|
||||||
if (luaL_getmetafield(L, 1, "__pairs") == LUA_TNIL) { /* no metamethod? */
|
if (luaL_getmetafield(L, 1, "__pairs") == LUA_TNIL) { /* no metamethod? */
|
||||||
lua_pushcfunction(L, luaB_next); /* will return generator, */
|
lua_pushcfunction(L, luaB_next); /* will return generator and */
|
||||||
lua_pushvalue(L, 1); /* state, */
|
lua_pushvalue(L, 1); /* state */
|
||||||
lua_pushnil(L); /* and initial value */
|
lua_pushnil(L); /* initial value */
|
||||||
|
lua_pushnil(L); /* to-be-closed object */
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
lua_pushvalue(L, 1); /* argument 'self' to metamethod */
|
lua_pushvalue(L, 1); /* argument 'self' to metamethod */
|
||||||
lua_callk(L, 1, 3, 0, pairscont); /* get 3 values from metamethod */
|
lua_callk(L, 1, 4, 0, pairscont); /* get 4 values from metamethod */
|
||||||
}
|
}
|
||||||
return 3;
|
return 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -339,9 +340,11 @@ static int load_aux (lua_State *L, int status, int envidx) {
|
|||||||
|
|
||||||
|
|
||||||
static const char *getMode (lua_State *L, int idx) {
|
static const char *getMode (lua_State *L, int idx) {
|
||||||
const char *mode = luaL_optstring(L, idx, "bt");
|
const char *mode = luaL_optstring(L, idx, NULL);
|
||||||
if (strchr(mode, 'B') != NULL) /* Lua code cannot use fixed buffers */
|
if (mode != NULL && strchr(mode, 'B') != NULL) {
|
||||||
|
/* Lua code cannot use fixed buffers */
|
||||||
luaL_argerror(L, idx, "invalid mode");
|
luaL_argerror(L, idx, "invalid mode");
|
||||||
|
}
|
||||||
return mode;
|
return mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -363,33 +366,24 @@ static int luaB_loadfile (lua_State *L) {
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** reserved slot, above all arguments, to hold a copy of the returned
|
** Reader for generic 'load' function.
|
||||||
** 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) {
|
static const char *generic_reader (lua_State *L, void *ud, size_t *size) {
|
||||||
(void)(ud); /* not used */
|
int *firstcall = cast(int *, ud);
|
||||||
luaL_checkstack(L, 2, "too many nested functions");
|
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_pushvalue(L, 1); /* get function */
|
||||||
lua_call(L, 0, 1); /* call it */
|
lua_call(L, 0, 1); /* call it */
|
||||||
if (lua_isnil(L, -1)) {
|
if (lua_isnil(L, -1)) {
|
||||||
lua_pop(L, 1); /* pop result */
|
|
||||||
*size = 0;
|
*size = 0;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
else if (l_unlikely(!lua_isstring(L, -1)))
|
else if (l_unlikely(!lua_isstring(L, -1)))
|
||||||
luaL_error(L, "reader function must return a string");
|
luaL_error(L, "reader function must return a string");
|
||||||
lua_replace(L, RESERVEDSLOT); /* save string in reserved slot */
|
return lua_tolstring(L, -1, size);
|
||||||
return lua_tolstring(L, RESERVEDSLOT, size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -404,10 +398,10 @@ static int luaB_load (lua_State *L) {
|
|||||||
status = luaL_loadbufferx(L, s, l, chunkname, mode);
|
status = luaL_loadbufferx(L, s, l, chunkname, mode);
|
||||||
}
|
}
|
||||||
else { /* loading from a reader function */
|
else { /* loading from a reader function */
|
||||||
|
int firstcall = 1; /* userdata for generic_reader */
|
||||||
const char *chunkname = luaL_optstring(L, 2, "=(load)");
|
const char *chunkname = luaL_optstring(L, 2, "=(load)");
|
||||||
luaL_checktype(L, 1, LUA_TFUNCTION);
|
luaL_checktype(L, 1, LUA_TFUNCTION);
|
||||||
lua_settop(L, RESERVEDSLOT); /* create reserved slot */
|
status = lua_load(L, generic_reader, &firstcall, chunkname, mode);
|
||||||
status = lua_load(L, generic_reader, NULL, chunkname, mode);
|
|
||||||
}
|
}
|
||||||
return load_aux(L, status, env);
|
return load_aux(L, status, env);
|
||||||
}
|
}
|
||||||
@@ -424,7 +418,7 @@ static int dofilecont (lua_State *L, int d1, lua_KContext d2) {
|
|||||||
static int luaB_dofile (lua_State *L) {
|
static int luaB_dofile (lua_State *L) {
|
||||||
const char *fname = luaL_optstring(L, 1, NULL);
|
const char *fname = luaL_optstring(L, 1, NULL);
|
||||||
lua_settop(L, 1);
|
lua_settop(L, 1);
|
||||||
if (l_unlikely(luaL_loadfile(L, fname) != LUA_OK))
|
if (l_unlikely(luaL_loadfilex(L, fname, "bt") != LUA_OK))
|
||||||
return lua_error(L);
|
return lua_error(L);
|
||||||
lua_callk(L, 0, LUA_MULTRET, 0, dofilecont);
|
lua_callk(L, 0, LUA_MULTRET, 0, dofilecont);
|
||||||
return dofilecont(L, 0, 0);
|
return dofilecont(L, 0, 0);
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ l_noret luaK_semerror (LexState *ls, const char *fmt, ...) {
|
|||||||
va_list argp;
|
va_list argp;
|
||||||
pushvfstring(ls->L, argp, fmt, msg);
|
pushvfstring(ls->L, argp, fmt, msg);
|
||||||
ls->t.token = 0; /* remove "near <token>" from final message */
|
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);
|
luaX_syntaxerror(ls, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -565,20 +566,20 @@ static int k2proto (FuncState *fs, TValue *key, TValue *v) {
|
|||||||
TValue val;
|
TValue val;
|
||||||
Proto *f = fs->f;
|
Proto *f = fs->f;
|
||||||
int tag = luaH_get(fs->kcache, key, &val); /* query scanner table */
|
int tag = luaH_get(fs->kcache, key, &val); /* query scanner table */
|
||||||
int k;
|
|
||||||
if (!tagisempty(tag)) { /* is there an index there? */
|
if (!tagisempty(tag)) { /* is there an index there? */
|
||||||
k = cast_int(ivalue(&val));
|
int k = cast_int(ivalue(&val));
|
||||||
/* collisions can happen only for float keys */
|
/* collisions can happen only for float keys */
|
||||||
lua_assert(ttisfloat(key) || luaV_rawequalobj(&f->k[k], v));
|
lua_assert(ttisfloat(key) || luaV_rawequalobj(&f->k[k], v));
|
||||||
return k; /* reuse index */
|
return k; /* reuse index */
|
||||||
}
|
}
|
||||||
/* constant not found; create a new entry */
|
else { /* constant not found; create a new entry */
|
||||||
k = addk(fs, f, v);
|
int k = addk(fs, f, v);
|
||||||
/* cache it for reuse; numerical value does not need GC barrier;
|
/* cache it for reuse; numerical value does not need GC barrier;
|
||||||
table is not a metatable, so it does not need to invalidate cache */
|
table is not a metatable, so it does not need to invalidate cache */
|
||||||
setivalue(&val, k);
|
setivalue(&val, k);
|
||||||
luaH_set(fs->ls->L, fs->kcache, key, &val);
|
luaH_set(fs->ls->L, fs->kcache, key, &val);
|
||||||
return k;
|
return k;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -604,13 +605,14 @@ static int luaK_intK (FuncState *fs, lua_Integer n) {
|
|||||||
/*
|
/*
|
||||||
** Add a float to list of constants and return its index. Floats
|
** Add a float to list of constants and return its index. Floats
|
||||||
** with integral values need a different key, to avoid collision
|
** with integral values need a different key, to avoid collision
|
||||||
** with actual integers. To that, we add to the number its smaller
|
** with actual integers. To that end, we add to the number its smaller
|
||||||
** power-of-two fraction that is still significant in its scale.
|
** power-of-two fraction that is still significant in its scale.
|
||||||
** For doubles, that would be 1/2^52.
|
** (For doubles, the fraction would be 2^-52).
|
||||||
** This method is not bulletproof: different numbers may generate the
|
** This method is not bulletproof: different numbers may generate the
|
||||||
** same key (e.g., very large numbers will overflow to 'inf') and for
|
** same key (e.g., very large numbers will overflow to 'inf') and for
|
||||||
** floats larger than 2^53 the result is still an integer. At worst,
|
** floats larger than 2^53 the result is still an integer. For those
|
||||||
** this only wastes an entry with a duplicate.
|
** cases, just generate a new entry. At worst, this only wastes an entry
|
||||||
|
** with a duplicate.
|
||||||
*/
|
*/
|
||||||
static int luaK_numberK (FuncState *fs, lua_Number r) {
|
static int luaK_numberK (FuncState *fs, lua_Number r) {
|
||||||
TValue o, kv;
|
TValue o, kv;
|
||||||
@@ -625,7 +627,7 @@ static int luaK_numberK (FuncState *fs, lua_Number r) {
|
|||||||
const lua_Number k = r * (1 + q); /* key */
|
const lua_Number k = r * (1 + q); /* key */
|
||||||
lua_Integer ik;
|
lua_Integer ik;
|
||||||
setfltvalue(&kv, k); /* key as a TValue */
|
setfltvalue(&kv, k); /* key as a TValue */
|
||||||
if (!luaV_flttointeger(k, &ik, F2Ieq)) { /* not an integral value? */
|
if (!luaV_flttointeger(k, &ik, F2Ieq)) { /* not an integer value? */
|
||||||
int n = k2proto(fs, &kv, &o); /* use key */
|
int n = k2proto(fs, &kv, &o); /* use key */
|
||||||
if (luaV_rawequalobj(&fs->f->k[n], &o)) /* correct value? */
|
if (luaV_rawequalobj(&fs->f->k[n], &o)) /* correct value? */
|
||||||
return n;
|
return n;
|
||||||
@@ -661,11 +663,11 @@ static int boolT (FuncState *fs) {
|
|||||||
** Add nil to list of constants and return its index.
|
** Add nil to list of constants and return its index.
|
||||||
*/
|
*/
|
||||||
static int nilK (FuncState *fs) {
|
static int nilK (FuncState *fs) {
|
||||||
TValue k, v;
|
lua_State *L = fs->ls->L;
|
||||||
setnilvalue(&v);
|
TValue k;
|
||||||
/* cannot use nil as key; instead use table itself */
|
/* cannot use nil as key; instead use table itself */
|
||||||
sethvalue(fs->ls->L, &k, fs->kcache);
|
sethvalue(L, &k, fs->kcache);
|
||||||
return k2proto(fs, &k, &v);
|
return k2proto(fs, &k, &G(L)->nilvalue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -704,6 +706,22 @@ 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'
|
** Convert a constant in 'v' into an expression description 'e'
|
||||||
*/
|
*/
|
||||||
@@ -784,6 +802,15 @@ 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>).
|
** Ensure that expression 'e' is not a variable (nor a <const>).
|
||||||
@@ -795,9 +822,12 @@ void luaK_dischargevars (FuncState *fs, expdesc *e) {
|
|||||||
const2exp(const2val(fs, e), e);
|
const2exp(const2val(fs, e), e);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case VVARGVAR: {
|
||||||
|
luaK_vapar2local(fs, e); /* turn it into a local variable */
|
||||||
|
} /* FALLTHROUGH */
|
||||||
case VLOCAL: { /* already in a register */
|
case VLOCAL: { /* already in a register */
|
||||||
int temp = e->u.var.ridx;
|
int temp = e->u.var.ridx;
|
||||||
e->u.info = temp; /* (can't do a direct assignment; values overlap) */
|
e->u.info = temp; /* (avoid a direct assignment; values overlap) */
|
||||||
e->k = VNONRELOC; /* becomes a non-relocatable value */
|
e->k = VNONRELOC; /* becomes a non-relocatable value */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -829,6 +859,12 @@ void luaK_dischargevars (FuncState *fs, expdesc *e) {
|
|||||||
e->k = VRELOC;
|
e->k = VRELOC;
|
||||||
break;
|
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: {
|
case VVARARG: case VCALL: {
|
||||||
luaK_setoneret(fs, e);
|
luaK_setoneret(fs, e);
|
||||||
break;
|
break;
|
||||||
@@ -991,11 +1027,11 @@ int luaK_exp2anyreg (FuncState *fs, expdesc *e) {
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Ensures final expression result is either in a register
|
** Ensures final expression result is either in a register,
|
||||||
** or in an upvalue.
|
** in an upvalue, or it is the vararg parameter.
|
||||||
*/
|
*/
|
||||||
void luaK_exp2anyregup (FuncState *fs, expdesc *e) {
|
void luaK_exp2anyregup (FuncState *fs, expdesc *e) {
|
||||||
if (e->k != VUPVAL || hasjumps(e))
|
if ((e->k != VUPVAL && e->k != VVARGVAR) || hasjumps(e))
|
||||||
luaK_exp2anyreg(fs, e);
|
luaK_exp2anyreg(fs, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1090,6 +1126,10 @@ void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) {
|
|||||||
codeABRK(fs, OP_SETFIELD, var->u.ind.t, var->u.ind.idx, ex);
|
codeABRK(fs, OP_SETFIELD, var->u.ind.t, var->u.ind.idx, ex);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case VVARGIND: {
|
||||||
|
needvatab(fs->f); /* function will need a vararg table */
|
||||||
|
/* now, assignment is to a regular table */
|
||||||
|
} /* FALLTHROUGH */
|
||||||
case VINDEXED: {
|
case VINDEXED: {
|
||||||
codeABRK(fs, OP_SETTABLE, var->u.ind.t, var->u.ind.idx, ex);
|
codeABRK(fs, OP_SETTABLE, var->u.ind.t, var->u.ind.idx, ex);
|
||||||
break;
|
break;
|
||||||
@@ -1162,7 +1202,7 @@ void luaK_goiftrue (FuncState *fs, expdesc *e) {
|
|||||||
/*
|
/*
|
||||||
** Emit code to go through if 'e' is false, jump otherwise.
|
** Emit code to go through if 'e' is false, jump otherwise.
|
||||||
*/
|
*/
|
||||||
void luaK_goiffalse (FuncState *fs, expdesc *e) {
|
static void luaK_goiffalse (FuncState *fs, expdesc *e) {
|
||||||
int pc; /* pc of new jump */
|
int pc; /* pc of new jump */
|
||||||
luaK_dischargevars(fs, e);
|
luaK_dischargevars(fs, e);
|
||||||
switch (e->k) {
|
switch (e->k) {
|
||||||
@@ -1223,7 +1263,7 @@ static void codenot (FuncState *fs, expdesc *e) {
|
|||||||
** Check whether expression 'e' is a short literal string
|
** Check whether expression 'e' is a short literal string
|
||||||
*/
|
*/
|
||||||
static int isKstr (FuncState *fs, expdesc *e) {
|
static int isKstr (FuncState *fs, expdesc *e) {
|
||||||
return (e->k == VK && !hasjumps(e) && e->u.info <= MAXARG_B &&
|
return (e->k == VK && !hasjumps(e) && e->u.info <= MAXINDEXRK &&
|
||||||
ttisshrstring(&fs->f->k[e->u.info]));
|
ttisshrstring(&fs->f->k[e->u.info]));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1301,6 +1341,13 @@ 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
|
** Create expression 't[k]'. 't' must have its final result already in a
|
||||||
** register or upvalue. Upvalues can only be indexed by literal strings.
|
** register or upvalue. Upvalues can only be indexed by literal strings.
|
||||||
@@ -1312,31 +1359,33 @@ void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) {
|
|||||||
if (k->k == VKSTR)
|
if (k->k == VKSTR)
|
||||||
keystr = str2K(fs, k);
|
keystr = str2K(fs, k);
|
||||||
lua_assert(!hasjumps(t) &&
|
lua_assert(!hasjumps(t) &&
|
||||||
(t->k == VLOCAL || t->k == VNONRELOC || t->k == VUPVAL));
|
(t->k == VLOCAL || t->k == VVARGVAR ||
|
||||||
|
t->k == VNONRELOC || t->k == VUPVAL));
|
||||||
if (t->k == VUPVAL && !isKstr(fs, k)) /* upvalue indexed by non 'Kstr'? */
|
if (t->k == VUPVAL && !isKstr(fs, k)) /* upvalue indexed by non 'Kstr'? */
|
||||||
luaK_exp2anyreg(fs, t); /* put it in a register */
|
luaK_exp2anyreg(fs, t); /* put it in a register */
|
||||||
if (t->k == VUPVAL) {
|
if (t->k == VUPVAL) {
|
||||||
lu_byte temp = cast_byte(t->u.info); /* upvalue index */
|
lu_byte temp = cast_byte(t->u.info); /* upvalue index */
|
||||||
t->u.ind.t = temp; /* (can't do a direct assignment; values overlap) */
|
t->u.ind.t = temp; /* (avoid a direct assignment; values overlap) */
|
||||||
lua_assert(isKstr(fs, k));
|
lua_assert(isKstr(fs, k));
|
||||||
t->u.ind.idx = cast_short(k->u.info); /* literal short string */
|
fillidxk(t, k->u.info, VINDEXUP); /* literal short string */
|
||||||
t->k = VINDEXUP;
|
}
|
||||||
|
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]' */
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* register index of the table */
|
/* register index of the table */
|
||||||
t->u.ind.t = cast_byte((t->k == VLOCAL) ? t->u.var.ridx: t->u.info);
|
lu_byte temp = cast_byte((t->k == VLOCAL) ? t->u.var.ridx: t->u.info);
|
||||||
if (isKstr(fs, k)) {
|
t->u.ind.t = temp; /* (avoid a direct assignment; values may overlap?) */
|
||||||
t->u.ind.idx = cast_short(k->u.info); /* literal short string */
|
if (isKstr(fs, k))
|
||||||
t->k = VINDEXSTR;
|
fillidxk(t, k->u.info, VINDEXSTR); /* literal short string */
|
||||||
}
|
else if (isCint(k)) /* int. constant in proper range? */
|
||||||
else if (isCint(k)) { /* int. constant in proper range? */
|
fillidxk(t, cast_int(k->u.ival), VINDEXI);
|
||||||
t->u.ind.idx = cast_short(k->u.ival);
|
else
|
||||||
t->k = VINDEXI;
|
fillidxk(t, luaK_exp2anyreg(fs, k), VINDEXED); /* register */
|
||||||
}
|
|
||||||
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.keystr = keystr; /* string index in 'k' */
|
||||||
t->u.ind.ro = 0; /* by default, not read-only */
|
t->u.ind.ro = 0; /* by default, not read-only */
|
||||||
@@ -1881,14 +1930,14 @@ static int finaltarget (Instruction *code, int i) {
|
|||||||
void luaK_finish (FuncState *fs) {
|
void luaK_finish (FuncState *fs) {
|
||||||
int i;
|
int i;
|
||||||
Proto *p = fs->f;
|
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++) {
|
for (i = 0; i < fs->pc; i++) {
|
||||||
Instruction *pc = &p->code[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));
|
lua_assert(i == 0 || luaP_isOT(*(pc - 1)) == luaP_isIT(*pc));
|
||||||
switch (GET_OPCODE(*pc)) {
|
switch (GET_OPCODE(*pc)) {
|
||||||
case OP_RETURN0: case OP_RETURN1: {
|
case OP_RETURN0: case OP_RETURN1: {
|
||||||
if (!(fs->needclose || (p->flag & PF_ISVARARG)))
|
if (!(fs->needclose || (p->flag & PF_VAHID)))
|
||||||
break; /* no extra work */
|
break; /* no extra work */
|
||||||
/* else use OP_RETURN to do the extra work */
|
/* else use OP_RETURN to do the extra work */
|
||||||
SET_OPCODE(*pc, OP_RETURN);
|
SET_OPCODE(*pc, OP_RETURN);
|
||||||
@@ -1896,13 +1945,23 @@ void luaK_finish (FuncState *fs) {
|
|||||||
case OP_RETURN: case OP_TAILCALL: {
|
case OP_RETURN: case OP_TAILCALL: {
|
||||||
if (fs->needclose)
|
if (fs->needclose)
|
||||||
SETARG_k(*pc, 1); /* signal that it needs to close */
|
SETARG_k(*pc, 1); /* signal that it needs to close */
|
||||||
if (p->flag & PF_ISVARARG)
|
if (p->flag & PF_VAHID) /* does it use hidden arguments? */
|
||||||
SETARG_C(*pc, p->numparams + 1); /* signal that it is vararg */
|
SETARG_C(*pc, p->numparams + 1); /* signal that */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OP_JMP: {
|
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 */
|
||||||
int target = finaltarget(p->code, i);
|
int target = finaltarget(p->code, i);
|
||||||
fixjump(fs, i, target);
|
fixjump(fs, i, target); /* jump directly to final target */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: break;
|
default: break;
|
||||||
|
|||||||
@@ -68,9 +68,12 @@ 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 int luaK_exp2const (FuncState *fs, const expdesc *e, TValue *v);
|
||||||
LUAI_FUNC void luaK_fixline (FuncState *fs, int line);
|
LUAI_FUNC void luaK_fixline (FuncState *fs, int line);
|
||||||
LUAI_FUNC void luaK_nil (FuncState *fs, int from, int n);
|
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_reserveregs (FuncState *fs, int n);
|
||||||
LUAI_FUNC void luaK_checkstack (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_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 void luaK_dischargevars (FuncState *fs, expdesc *e);
|
||||||
LUAI_FUNC int luaK_exp2anyreg (FuncState *fs, expdesc *e);
|
LUAI_FUNC int luaK_exp2anyreg (FuncState *fs, expdesc *e);
|
||||||
LUAI_FUNC void luaK_exp2anyregup (FuncState *fs, expdesc *e);
|
LUAI_FUNC void luaK_exp2anyregup (FuncState *fs, expdesc *e);
|
||||||
@@ -79,7 +82,6 @@ LUAI_FUNC void luaK_exp2val (FuncState *fs, expdesc *e);
|
|||||||
LUAI_FUNC void luaK_self (FuncState *fs, expdesc *e, expdesc *key);
|
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_indexed (FuncState *fs, expdesc *t, expdesc *k);
|
||||||
LUAI_FUNC void luaK_goiftrue (FuncState *fs, expdesc *e);
|
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_storevar (FuncState *fs, expdesc *var, expdesc *e);
|
||||||
LUAI_FUNC void luaK_setreturns (FuncState *fs, expdesc *e, int nresults);
|
LUAI_FUNC void luaK_setreturns (FuncState *fs, expdesc *e, int nresults);
|
||||||
LUAI_FUNC void luaK_setoneret (FuncState *fs, expdesc *e);
|
LUAI_FUNC void luaK_setoneret (FuncState *fs, expdesc *e);
|
||||||
|
|||||||
+6
-4
@@ -189,15 +189,17 @@ static int luaB_close (lua_State *L) {
|
|||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case COS_RUN: /* running coroutine? */
|
case COS_NORM:
|
||||||
|
return luaL_error(L, "cannot close a %s coroutine", statname[status]);
|
||||||
|
case COS_RUN:
|
||||||
lua_geti(L, LUA_REGISTRYINDEX, LUA_RIDX_MAINTHREAD); /* get main */
|
lua_geti(L, LUA_REGISTRYINDEX, LUA_RIDX_MAINTHREAD); /* get main */
|
||||||
if (lua_tothread(L, -1) == co)
|
if (lua_tothread(L, -1) == co)
|
||||||
return luaL_error(L, "cannot close main thread");
|
return luaL_error(L, "cannot close main thread");
|
||||||
lua_closethread(co, L); /* close itself */
|
lua_closethread(co, L); /* close itself */
|
||||||
lua_assert(0); /* previous call does not return */
|
/* previous call does not return *//* FALLTHROUGH */
|
||||||
|
default:
|
||||||
|
lua_assert(0);
|
||||||
return 0;
|
return 0;
|
||||||
default: /* normal or running coroutine */
|
|
||||||
return luaL_error(L, "cannot close a %s coroutine", statname[status]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
|
|
||||||
#if defined (LUA_UCID) /* accept UniCode IDentifiers? */
|
#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
|
#define NONA 0x01
|
||||||
#else
|
#else
|
||||||
#define NONA 0x00 /* default */
|
#define NONA 0x00 /* default */
|
||||||
|
|||||||
@@ -427,7 +427,7 @@ static int db_debug (lua_State *L) {
|
|||||||
if (fgets(buffer, sizeof(buffer), stdin) == NULL ||
|
if (fgets(buffer, sizeof(buffer), stdin) == NULL ||
|
||||||
strcmp(buffer, "cont\n") == 0)
|
strcmp(buffer, "cont\n") == 0)
|
||||||
return 0;
|
return 0;
|
||||||
if (luaL_loadbuffer(L, buffer, strlen(buffer), "=(debug command)") ||
|
if (luaL_loadbufferx(L, buffer, strlen(buffer), "=(debug command)", "t") ||
|
||||||
lua_pcall(L, 0, 0, 0))
|
lua_pcall(L, 0, 0, 0))
|
||||||
lua_writestringerror("%s\n", luaL_tolstring(L, -1, NULL));
|
lua_writestringerror("%s\n", luaL_tolstring(L, -1, NULL));
|
||||||
lua_settop(L, 0); /* remove eventual returns */
|
lua_settop(L, 0); /* remove eventual returns */
|
||||||
|
|||||||
@@ -184,7 +184,7 @@ static const char *upvalname (const Proto *p, int uv) {
|
|||||||
|
|
||||||
|
|
||||||
static const char *findvararg (CallInfo *ci, int n, StkId *pos) {
|
static const char *findvararg (CallInfo *ci, int n, StkId *pos) {
|
||||||
if (clLvalue(s2v(ci->func.p))->p->flag & PF_ISVARARG) {
|
if (clLvalue(s2v(ci->func.p))->p->flag & PF_VAHID) {
|
||||||
int nextra = ci->u.l.nextraargs;
|
int nextra = ci->u.l.nextraargs;
|
||||||
if (n >= -nextra) { /* 'n' is negative */
|
if (n >= -nextra) { /* 'n' is negative */
|
||||||
*pos = ci->func.p - nextra - (n + 1);
|
*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) {
|
static void collectvalidlines (lua_State *L, Closure *f) {
|
||||||
if (!LuaClosure(f)) {
|
if (!LuaClosure(f)) {
|
||||||
setnilvalue(s2v(L->top.p));
|
setnilvalue2s(L->top.p);
|
||||||
api_incr_top(L);
|
api_incr_top(L);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -304,7 +304,7 @@ static void collectvalidlines (lua_State *L, Closure *f) {
|
|||||||
int i;
|
int i;
|
||||||
TValue v;
|
TValue v;
|
||||||
setbtvalue(&v); /* boolean 'true' to be the value of all indices */
|
setbtvalue(&v); /* boolean 'true' to be the value of all indices */
|
||||||
if (!(p->flag & PF_ISVARARG)) /* regular function? */
|
if (!(isvararg(p))) /* regular function? */
|
||||||
i = 0; /* consider all instructions */
|
i = 0; /* consider all instructions */
|
||||||
else { /* vararg function */
|
else { /* vararg function */
|
||||||
lua_assert(GET_OPCODE(p->code[0]) == OP_VARARGPREP);
|
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;
|
ar->nparams = 0;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ar->isvararg = (f->l.p->flag & PF_ISVARARG) ? 1 : 0;
|
ar->isvararg = (isvararg(f->l.p)) ? 1 : 0;
|
||||||
ar->nparams = f->l.p->numparams;
|
ar->nparams = f->l.p->numparams;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -580,7 +580,7 @@ static const char *getobjname (const Proto *p, int lastpc, int reg,
|
|||||||
kname(p, k, name);
|
kname(p, k, name);
|
||||||
return isEnv(p, lastpc, i, 1);
|
return isEnv(p, lastpc, i, 1);
|
||||||
}
|
}
|
||||||
case OP_GETTABLE: {
|
case OP_GETTABLE: case OP_GETVARG: {
|
||||||
int k = GETARG_C(i); /* key index */
|
int k = GETARG_C(i); /* key index */
|
||||||
rname(p, lastpc, k, name);
|
rname(p, lastpc, k, name);
|
||||||
return isEnv(p, lastpc, i, 0);
|
return isEnv(p, lastpc, i, 0);
|
||||||
@@ -814,6 +814,14 @@ 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' */
|
/* add src:line information to 'msg' */
|
||||||
const char *luaG_addinfo (lua_State *L, const char *msg, TString *src,
|
const char *luaG_addinfo (lua_State *L, const char *msg, TString *src,
|
||||||
int line) {
|
int line) {
|
||||||
@@ -904,7 +912,7 @@ int luaG_tracecall (lua_State *L) {
|
|||||||
Proto *p = ci_func(ci)->p;
|
Proto *p = ci_func(ci)->p;
|
||||||
ci->u.l.trap = 1; /* ensure hooks will be checked */
|
ci->u.l.trap = 1; /* ensure hooks will be checked */
|
||||||
if (ci->u.l.savedpc == p->code) { /* first instruction (not resuming)? */
|
if (ci->u.l.savedpc == p->code) { /* first instruction (not resuming)? */
|
||||||
if (p->flag & PF_ISVARARG)
|
if (isvararg(p))
|
||||||
return 0; /* hooks will start at VARARGPREP instruction */
|
return 0; /* hooks will start at VARARGPREP instruction */
|
||||||
else if (!(ci->callstatus & CIST_HOOKYIELD)) /* not yielded? */
|
else if (!(ci->callstatus & CIST_HOOKYIELD)) /* not yielded? */
|
||||||
luaD_hookcall(L, ci); /* check 'call' hook */
|
luaD_hookcall(L, ci); /* check 'call' hook */
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ LUAI_FUNC l_noret luaG_tointerror (lua_State *L, const TValue *p1,
|
|||||||
const TValue *p2);
|
const TValue *p2);
|
||||||
LUAI_FUNC l_noret luaG_ordererror (lua_State *L, const TValue *p1,
|
LUAI_FUNC l_noret luaG_ordererror (lua_State *L, const TValue *p1,
|
||||||
const TValue *p2);
|
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 l_noret luaG_runerror (lua_State *L, const char *fmt, ...);
|
||||||
LUAI_FUNC const char *luaG_addinfo (lua_State *L, const char *msg,
|
LUAI_FUNC const char *luaG_addinfo (lua_State *L, const char *msg,
|
||||||
TString *src, int line);
|
TString *src, int line);
|
||||||
|
|||||||
@@ -57,10 +57,18 @@
|
|||||||
** =======================================================
|
** =======================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* 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
|
** LUAI_THROW/LUAI_TRY define how Lua does exception handling. By
|
||||||
** default, Lua handles errors with exceptions when compiling as
|
** default, Lua handles errors with exceptions when compiling as
|
||||||
** C++ code, with _longjmp/_setjmp when asked to use them, and with
|
** C++ code, with _longjmp/_setjmp when available (POSIX), and with
|
||||||
** longjmp/setjmp otherwise.
|
** longjmp/setjmp otherwise.
|
||||||
*/
|
*/
|
||||||
#if !defined(LUAI_THROW) /* { */
|
#if !defined(LUAI_THROW) /* { */
|
||||||
@@ -69,38 +77,38 @@
|
|||||||
|
|
||||||
/* C++ exceptions */
|
/* C++ exceptions */
|
||||||
#define LUAI_THROW(L,c) throw(c)
|
#define LUAI_THROW(L,c) throw(c)
|
||||||
#define LUAI_TRY(L,c,f,ud) \
|
|
||||||
try { (f)(L, ud); } catch(...) { if ((c)->status == 0) (c)->status = -1; }
|
static void LUAI_TRY (lua_State *L, lua_longjmp *c, Pfunc f, void *ud) {
|
||||||
#define luai_jmpbuf int /* dummy field */
|
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 */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#elif defined(LUA_USE_POSIX) /* }{ */
|
#elif defined(LUA_USE_POSIX) /* }{ */
|
||||||
|
|
||||||
/* in POSIX, try _longjmp/_setjmp (more efficient) */
|
/* in POSIX, use _longjmp/_setjmp (more efficient) */
|
||||||
#define LUAI_THROW(L,c) _longjmp((c)->b, 1)
|
#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_TRY(L,c,f,ud) if (_setjmp((c)->b) == 0) ((f)(L, ud))
|
||||||
#define luai_jmpbuf jmp_buf
|
|
||||||
|
|
||||||
#else /* }{ */
|
#else /* }{ */
|
||||||
|
|
||||||
/* ISO C handling with long jumps */
|
/* ISO C handling with long jumps */
|
||||||
#define LUAI_THROW(L,c) longjmp((c)->b, 1)
|
#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_TRY(L,c,f,ud) if (setjmp((c)->b) == 0) ((f)(L, ud))
|
||||||
#define luai_jmpbuf jmp_buf
|
|
||||||
|
|
||||||
#endif /* } */
|
#endif /* } */
|
||||||
|
|
||||||
#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) {
|
void luaD_seterrorobj (lua_State *L, TStatus errcode, StkId oldtop) {
|
||||||
if (errcode == LUA_ERRMEM) { /* memory error? */
|
if (errcode == LUA_ERRMEM) { /* memory error? */
|
||||||
setsvalue2s(L, oldtop, G(L)->memerrmsg); /* reuse preregistered msg. */
|
setsvalue2s(L, oldtop, G(L)->memerrmsg); /* reuse preregistered msg. */
|
||||||
@@ -151,7 +159,7 @@ l_noret luaD_throwbaselevel (lua_State *L, TStatus errcode) {
|
|||||||
|
|
||||||
TStatus luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) {
|
TStatus luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) {
|
||||||
l_uint32 oldnCcalls = L->nCcalls;
|
l_uint32 oldnCcalls = L->nCcalls;
|
||||||
struct lua_longjmp lj;
|
lua_longjmp lj;
|
||||||
lj.status = LUA_OK;
|
lj.status = LUA_OK;
|
||||||
lj.previous = L->errorJmp; /* chain new error handler */
|
lj.previous = L->errorJmp; /* chain new error handler */
|
||||||
L->errorJmp = &lj;
|
L->errorJmp = &lj;
|
||||||
@@ -174,6 +182,20 @@ TStatus luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) {
|
|||||||
#define STACKERRSPACE 200
|
#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 */
|
/* maximum stack size that respects size_t */
|
||||||
#define MAXSTACK_BYSIZET ((MAX_SIZET / sizeof(StackValue)) - STACKERRSPACE)
|
#define MAXSTACK_BYSIZET ((MAX_SIZET / sizeof(StackValue)) - STACKERRSPACE)
|
||||||
|
|
||||||
@@ -189,7 +211,7 @@ TStatus luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) {
|
|||||||
#define ERRORSTACKSIZE (MAXSTACK + STACKERRSPACE)
|
#define ERRORSTACKSIZE (MAXSTACK + STACKERRSPACE)
|
||||||
|
|
||||||
|
|
||||||
/* raise an error while running the message handler */
|
/* raise a stack error while running the message handler */
|
||||||
l_noret luaD_errerr (lua_State *L) {
|
l_noret luaD_errerr (lua_State *L) {
|
||||||
TString *msg = luaS_newliteral(L, "error in error handling");
|
TString *msg = luaS_newliteral(L, "error in error handling");
|
||||||
setsvalue2s(L, L->top.p, msg);
|
setsvalue2s(L, L->top.p, msg);
|
||||||
@@ -198,6 +220,25 @@ 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
|
** In ISO C, any pointer use after the pointer has been deallocated is
|
||||||
** undefined behavior. So, before a stack reallocation, all pointers
|
** undefined behavior. So, before a stack reallocation, all pointers
|
||||||
@@ -308,7 +349,7 @@ int luaD_reallocstack (lua_State *L, int newsize, int raiseerror) {
|
|||||||
correctstack(L, oldstack); /* change offsets back to pointers */
|
correctstack(L, oldstack); /* change offsets back to pointers */
|
||||||
L->stack_last.p = L->stack.p + newsize;
|
L->stack_last.p = L->stack.p + newsize;
|
||||||
for (i = oldsize + EXTRA_STACK; i < newsize + EXTRA_STACK; i++)
|
for (i = oldsize + EXTRA_STACK; i < newsize + EXTRA_STACK; i++)
|
||||||
setnilvalue(s2v(newstack + i)); /* erase new segment */
|
setnilvalue2s(newstack + i); /* erase new segment */
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -325,7 +366,7 @@ int luaD_growstack (lua_State *L, int n, int raiseerror) {
|
|||||||
a stack error; cannot grow further than that. */
|
a stack error; cannot grow further than that. */
|
||||||
lua_assert(stacksize(L) == ERRORSTACKSIZE);
|
lua_assert(stacksize(L) == ERRORSTACKSIZE);
|
||||||
if (raiseerror)
|
if (raiseerror)
|
||||||
luaD_errerr(L); /* error inside message handler */
|
luaD_errerr(L); /* stack error inside message handler */
|
||||||
return 0; /* if not 'raiseerror', just signal it */
|
return 0; /* if not 'raiseerror', just signal it */
|
||||||
}
|
}
|
||||||
else if (n < MAXSTACK) { /* avoids arithmetic overflows */
|
else if (n < MAXSTACK) { /* avoids arithmetic overflows */
|
||||||
@@ -389,12 +430,6 @@ void luaD_shrinkstack (lua_State *L) {
|
|||||||
luaE_shrinkCI(L); /* shrink CI list */
|
luaE_shrinkCI(L); /* shrink CI list */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void luaD_inctop (lua_State *L) {
|
|
||||||
L->top.p++;
|
|
||||||
luaD_checkstack(L, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* }================================================================== */
|
/* }================================================================== */
|
||||||
|
|
||||||
|
|
||||||
@@ -465,7 +500,7 @@ static void rethook (lua_State *L, CallInfo *ci, int nres) {
|
|||||||
int ftransfer;
|
int ftransfer;
|
||||||
if (isLua(ci)) {
|
if (isLua(ci)) {
|
||||||
Proto *p = ci_func(ci)->p;
|
Proto *p = ci_func(ci)->p;
|
||||||
if (p->flag & PF_ISVARARG)
|
if (p->flag & PF_VAHID)
|
||||||
delta = ci->u.l.nextraargs + p->numparams + 1;
|
delta = ci->u.l.nextraargs + p->numparams + 1;
|
||||||
}
|
}
|
||||||
ci->func.p += delta; /* if vararg, back to virtual 'func' */
|
ci->func.p += delta; /* if vararg, back to virtual 'func' */
|
||||||
@@ -513,7 +548,7 @@ l_sinline void genmoveresults (lua_State *L, StkId res, int nres,
|
|||||||
for (i = 0; i < nres; i++) /* move all results to correct place */
|
for (i = 0; i < nres; i++) /* move all results to correct place */
|
||||||
setobjs2s(L, res + i, firstresult + i);
|
setobjs2s(L, res + i, firstresult + i);
|
||||||
for (; i < wanted; i++) /* complete wanted number of results */
|
for (; i < wanted; i++) /* complete wanted number of results */
|
||||||
setnilvalue(s2v(res + i));
|
setnilvalue2s(res + i);
|
||||||
L->top.p = res + wanted; /* top points after the last result */
|
L->top.p = res + wanted; /* top points after the last result */
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -533,7 +568,7 @@ l_sinline void moveresults (lua_State *L, StkId res, int nres,
|
|||||||
return;
|
return;
|
||||||
case 1 + 1: /* one value needed */
|
case 1 + 1: /* one value needed */
|
||||||
if (nres == 0) /* no results? */
|
if (nres == 0) /* no results? */
|
||||||
setnilvalue(s2v(res)); /* adjust with nil */
|
setnilvalue2s(res); /* adjust with nil */
|
||||||
else /* at least one result */
|
else /* at least one result */
|
||||||
setobjs2s(L, res, L->top.p - nres); /* move it to proper place */
|
setobjs2s(L, res, L->top.p - nres); /* move it to proper place */
|
||||||
L->top.p = res + 1;
|
L->top.p = res + 1;
|
||||||
@@ -583,7 +618,7 @@ void luaD_poscall (lua_State *L, CallInfo *ci, int nres) {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
#define next_ci(L) (L->ci->next ? L->ci->next : luaE_extendCI(L))
|
#define next_ci(L) (L->ci->next ? L->ci->next : luaE_extendCI(L, 1))
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -653,7 +688,7 @@ int luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func,
|
|||||||
setobjs2s(L, ci->func.p + i, func + i);
|
setobjs2s(L, ci->func.p + i, func + i);
|
||||||
func = ci->func.p; /* moved-down function */
|
func = ci->func.p; /* moved-down function */
|
||||||
for (; narg1 <= nfixparams; narg1++)
|
for (; narg1 <= nfixparams; narg1++)
|
||||||
setnilvalue(s2v(func + narg1)); /* complete missing arguments */
|
setnilvalue2s(func + narg1); /* complete missing arguments */
|
||||||
ci->top.p = func + 1 + fsize; /* top for new function */
|
ci->top.p = func + 1 + fsize; /* top for new function */
|
||||||
lua_assert(ci->top.p <= L->stack_last.p);
|
lua_assert(ci->top.p <= L->stack_last.p);
|
||||||
ci->u.l.savedpc = p->code; /* starting point */
|
ci->u.l.savedpc = p->code; /* starting point */
|
||||||
@@ -700,7 +735,7 @@ CallInfo *luaD_precall (lua_State *L, StkId func, int nresults) {
|
|||||||
L->ci = ci = prepCallInfo(L, func, status, func + 1 + fsize);
|
L->ci = ci = prepCallInfo(L, func, status, func + 1 + fsize);
|
||||||
ci->u.l.savedpc = p->code; /* starting point */
|
ci->u.l.savedpc = p->code; /* starting point */
|
||||||
for (; narg < nfixparams; narg++)
|
for (; narg < nfixparams; narg++)
|
||||||
setnilvalue(s2v(L->top.p++)); /* complete missing arguments */
|
setnilvalue2s(L->top.p++); /* complete missing arguments */
|
||||||
lua_assert(ci->top.p <= L->stack_last.p);
|
lua_assert(ci->top.p <= L->stack_last.p);
|
||||||
return ci;
|
return ci;
|
||||||
}
|
}
|
||||||
@@ -1087,28 +1122,54 @@ 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) {
|
static void f_parser (lua_State *L, void *ud) {
|
||||||
LClosure *cl;
|
LClosure *cl;
|
||||||
struct SParser *p = cast(struct SParser *, ud);
|
struct SParser *p = cast(struct SParser *, ud);
|
||||||
const char *mode = p->mode ? p->mode : "bt";
|
const char *mode = p->mode ? p->mode : "bt";
|
||||||
int c = zgetc(p->z); /* read first character */
|
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 */
|
||||||
if (c == LUA_SIGNATURE[0]) {
|
if (c == LUA_SIGNATURE[0]) {
|
||||||
int fixed = 0;
|
int fixed = 0;
|
||||||
if (strchr(mode, 'B') != NULL)
|
if (strchr(mode, 'B') != NULL)
|
||||||
fixed = 1;
|
fixed = 1;
|
||||||
else
|
else
|
||||||
checkmode(L, mode, "binary");
|
checkmode(L, mode, "binary");
|
||||||
cl = luaU_undump(L, p->z, p->name, fixed);
|
cl = luaU_undump(L, p->z, anchor, p->name, fixed);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
checkmode(L, mode, "text");
|
checkmode(L, mode, "text");
|
||||||
cl = luaY_parser(L, p->z, &p->buff, &p->dyd, p->name, c);
|
cl = luaY_parser(L, p->z, anchor, &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);
|
lua_assert(cl->nupvalues == cl->p->sizeupvalues);
|
||||||
luaF_initupvals(L, cl);
|
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,
|
TStatus luaD_protectedparser (lua_State *L, ZIO *z, const char *name,
|
||||||
const char *mode) {
|
const char *mode) {
|
||||||
struct SParser p;
|
struct SParser p;
|
||||||
|
|||||||
@@ -88,7 +88,8 @@ 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_reallocstack (lua_State *L, int newsize, int raiseerror);
|
||||||
LUAI_FUNC int luaD_growstack (lua_State *L, int n, int raiseerror);
|
LUAI_FUNC int luaD_growstack (lua_State *L, int n, int raiseerror);
|
||||||
LUAI_FUNC void luaD_shrinkstack (lua_State *L);
|
LUAI_FUNC void luaD_shrinkstack (lua_State *L);
|
||||||
LUAI_FUNC void luaD_inctop (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 l_noret luaD_throw (lua_State *L, TStatus errcode);
|
LUAI_FUNC l_noret luaD_throw (lua_State *L, TStatus errcode);
|
||||||
LUAI_FUNC l_noret luaD_throwbaselevel (lua_State *L, TStatus errcode);
|
LUAI_FUNC l_noret luaD_throwbaselevel (lua_State *L, TStatus errcode);
|
||||||
|
|||||||
@@ -132,27 +132,31 @@ static void dumpInteger (DumpState *D, lua_Integer x) {
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Dump a String. First dump its "size": size==0 means NULL;
|
** Dump a String. First dump its "size":
|
||||||
** size==1 is followed by an index and means "reuse saved string with
|
** size==0 is followed by an index and means "reuse saved string with
|
||||||
** that index"; size>=2 is followed by the string contents with real
|
** that index"; index==0 means NULL.
|
||||||
** size==size-2 and means that string, which will be saved with
|
** size>=1 is followed by the string contents with real size==size-1 and
|
||||||
** the next available index.
|
** 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.
|
||||||
*/
|
*/
|
||||||
static void dumpString (DumpState *D, TString *ts) {
|
static void dumpString (DumpState *D, TString *ts) {
|
||||||
if (ts == NULL)
|
if (ts == NULL) {
|
||||||
dumpSize(D, 0);
|
dumpVarint(D, 0); /* will "reuse" NULL */
|
||||||
|
dumpVarint(D, 0); /* special index for NULL */
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
TValue idx;
|
TValue idx;
|
||||||
int tag = luaH_getstr(D->h, ts, &idx);
|
int tag = luaH_getstr(D->h, ts, &idx);
|
||||||
if (!tagisempty(tag)) { /* string already saved? */
|
if (!tagisempty(tag)) { /* string already saved? */
|
||||||
dumpVarint(D, 1); /* reuse a saved string */
|
dumpVarint(D, 0); /* reuse a saved string */
|
||||||
dumpVarint(D, l_castS2U(ivalue(&idx))); /* index of saved string */
|
dumpVarint(D, l_castS2U(ivalue(&idx))); /* index of saved string */
|
||||||
}
|
}
|
||||||
else { /* must write and save the string */
|
else { /* must write and save the string */
|
||||||
TValue key, value; /* to save the string in the hash */
|
TValue key, value; /* to save the string in the hash */
|
||||||
size_t size;
|
size_t size;
|
||||||
const char *s = getlstr(ts, size);
|
const char *s = getlstr(ts, size);
|
||||||
dumpSize(D, size + 2);
|
dumpSize(D, size + 1);
|
||||||
dumpVector(D, s, size + 1); /* include ending '\0' */
|
dumpVector(D, s, size + 1); /* include ending '\0' */
|
||||||
D->nstr++; /* one more saved string */
|
D->nstr++; /* one more saved string */
|
||||||
setsvalue(D->L, &key, ts); /* the string is the key */
|
setsvalue(D->L, &key, ts); /* the string is the key */
|
||||||
|
|||||||
@@ -196,8 +196,7 @@ void luaF_unlinkupval (UpVal *uv) {
|
|||||||
*/
|
*/
|
||||||
void luaF_closeupval (lua_State *L, StkId level) {
|
void luaF_closeupval (lua_State *L, StkId level) {
|
||||||
UpVal *uv;
|
UpVal *uv;
|
||||||
StkId upl; /* stack index pointed by 'uv' */
|
while ((uv = L->openupval) != NULL && uplevel(uv) >= level) {
|
||||||
while ((uv = L->openupval) != NULL && (upl = uplevel(uv)) >= level) {
|
|
||||||
TValue *slot = &uv->u.value; /* new position for value */
|
TValue *slot = &uv->u.value; /* new position for value */
|
||||||
lua_assert(uplevel(uv) < L->top.p);
|
lua_assert(uplevel(uv) < L->top.p);
|
||||||
luaF_unlinkupval(uv); /* remove upvalue from 'openupval' list */
|
luaF_unlinkupval(uv); /* remove upvalue from 'openupval' list */
|
||||||
|
|||||||
@@ -594,10 +594,10 @@ static void traversestrongtable (global_State *g, Table *h) {
|
|||||||
*/
|
*/
|
||||||
static int getmode (global_State *g, Table *h) {
|
static int getmode (global_State *g, Table *h) {
|
||||||
const TValue *mode = gfasttm(g, h->metatable, TM_MODE);
|
const TValue *mode = gfasttm(g, h->metatable, TM_MODE);
|
||||||
if (mode == NULL || !ttisshrstring(mode))
|
if (mode == NULL || !ttisstring(mode))
|
||||||
return 0; /* ignore non-(short)string modes */
|
return 0; /* ignore non-string modes */
|
||||||
else {
|
else {
|
||||||
const char *smode = getshrstr(tsvalue(mode));
|
const char *smode = getstr(tsvalue(mode));
|
||||||
const char *weakkey = strchr(smode, 'k');
|
const char *weakkey = strchr(smode, 'k');
|
||||||
const char *weakvalue = strchr(smode, 'v');
|
const char *weakvalue = strchr(smode, 'v');
|
||||||
return ((weakkey != NULL) << 1) | (weakvalue != NULL);
|
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 */
|
linkgclist(h, g->allweak); /* must clear collected entries */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return 1 + 2*sizenode(h) + h->asize;
|
return cast(l_mem, 1 + 2*sizenode(h) + h->asize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -709,7 +709,7 @@ static l_mem traversethread (global_State *g, lua_State *th) {
|
|||||||
if (!g->gcemergency)
|
if (!g->gcemergency)
|
||||||
luaD_shrinkstack(th); /* do not change stack in emergency cycle */
|
luaD_shrinkstack(th); /* do not change stack in emergency cycle */
|
||||||
for (o = th->top.p; o < th->stack_last.p + EXTRA_STACK; o++)
|
for (o = th->top.p; o < th->stack_last.p + EXTRA_STACK; o++)
|
||||||
setnilvalue(s2v(o)); /* clear dead stack slice */
|
setnilvalue2s(o); /* clear dead stack slice */
|
||||||
/* 'remarkupvals' may have removed thread from 'twups' list */
|
/* 'remarkupvals' may have removed thread from 'twups' list */
|
||||||
if (!isintwups(th) && th->openupval != NULL) {
|
if (!isintwups(th) && th->openupval != NULL) {
|
||||||
th->twups = g->twups; /* link it back to the list */
|
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);
|
correctgraylists(g);
|
||||||
checkSizes(L, g);
|
checkSizes(L, g);
|
||||||
g->gcstate = GCSpropagate; /* skip restart */
|
g->gcstate = GCSpropagate; /* skip restart */
|
||||||
if (!g->gcemergency)
|
if (g->tobefnz != NULL && !g->gcemergency && luaD_checkminstack(L))
|
||||||
callallpendingfinalizers(L);
|
callallpendingfinalizers(L);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1667,12 +1667,13 @@ static l_mem singlestep (lua_State *L, int fast) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case GCScallfin: { /* call finalizers */
|
case GCScallfin: { /* call finalizers */
|
||||||
if (g->tobefnz && !g->gcemergency) {
|
if (g->tobefnz && !g->gcemergency && luaD_checkminstack(L)) {
|
||||||
g->gcstopem = 0; /* ok collections during finalizers */
|
g->gcstopem = 0; /* ok collections during finalizers */
|
||||||
GCTM(L); /* call one finalizer */
|
GCTM(L); /* call one finalizer */
|
||||||
stepresult = CWUFIN;
|
stepresult = CWUFIN;
|
||||||
}
|
}
|
||||||
else { /* emergency mode or no more finalizers */
|
else { /* no more finalizers or emergency mode or not enough stack
|
||||||
|
to run finalizers */
|
||||||
g->gcstate = GCSpause; /* finish collection */
|
g->gcstate = GCSpause; /* finish collection */
|
||||||
stepresult = step2pause;
|
stepresult = step2pause;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ static int l_checkmode (const char *mode) {
|
|||||||
|
|
||||||
#if !defined(l_fseek) /* { */
|
#if !defined(l_fseek) /* { */
|
||||||
|
|
||||||
#if defined(LUA_USE_POSIX) /* { */
|
#if defined(LUA_USE_POSIX) || defined(LUA_USE_OFF_T) /* { */
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
|||||||
+4
-2
@@ -21,7 +21,7 @@ static const void *const disptab[NUM_OPCODES] = {
|
|||||||
#if 0
|
#if 0
|
||||||
** you can update the following list with this command:
|
** 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
|
#endif
|
||||||
|
|
||||||
@@ -57,8 +57,8 @@ static const void *const disptab[NUM_OPCODES] = {
|
|||||||
&&L_OP_BANDK,
|
&&L_OP_BANDK,
|
||||||
&&L_OP_BORK,
|
&&L_OP_BORK,
|
||||||
&&L_OP_BXORK,
|
&&L_OP_BXORK,
|
||||||
&&L_OP_SHRI,
|
|
||||||
&&L_OP_SHLI,
|
&&L_OP_SHLI,
|
||||||
|
&&L_OP_SHRI,
|
||||||
&&L_OP_ADD,
|
&&L_OP_ADD,
|
||||||
&&L_OP_SUB,
|
&&L_OP_SUB,
|
||||||
&&L_OP_MUL,
|
&&L_OP_MUL,
|
||||||
@@ -106,6 +106,8 @@ static const void *const disptab[NUM_OPCODES] = {
|
|||||||
&&L_OP_SETLIST,
|
&&L_OP_SETLIST,
|
||||||
&&L_OP_CLOSURE,
|
&&L_OP_CLOSURE,
|
||||||
&&L_OP_VARARG,
|
&&L_OP_VARARG,
|
||||||
|
&&L_OP_GETVARG,
|
||||||
|
&&L_OP_ERRNNIL,
|
||||||
&&L_OP_VARARGPREP,
|
&&L_OP_VARARGPREP,
|
||||||
&&L_OP_EXTRAARG
|
&&L_OP_EXTRAARG
|
||||||
|
|
||||||
|
|||||||
@@ -188,7 +188,7 @@ void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source,
|
|||||||
so they cannot be collected */
|
so they cannot be collected */
|
||||||
ls->envn = luaS_newliteral(L, LUA_ENV); /* get env string */
|
ls->envn = luaS_newliteral(L, LUA_ENV); /* get env string */
|
||||||
ls->brkn = luaS_newliteral(L, "break"); /* get "break" string */
|
ls->brkn = luaS_newliteral(L, "break"); /* get "break" string */
|
||||||
#if defined(LUA_COMPAT_GLOBAL)
|
#if LUA_COMPAT_GLOBAL
|
||||||
/* compatibility mode: "global" is not a reserved word */
|
/* compatibility mode: "global" is not a reserved word */
|
||||||
ls->glbn = luaS_newliteral(L, "global"); /* get "global" string */
|
ls->glbn = luaS_newliteral(L, "global"); /* get "global" string */
|
||||||
ls->glbn->extra = 0; /* mark it as not reserved */
|
ls->glbn->extra = 0; /* mark it as not reserved */
|
||||||
|
|||||||
@@ -20,8 +20,8 @@
|
|||||||
/*
|
/*
|
||||||
** 'l_mem' is a signed integer big enough to count the total memory
|
** '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
|
** used by Lua. (It is signed due to the use of debt in several
|
||||||
** computations.) Usually, 'ptrdiff_t' should work, but we use 'long'
|
** computations.) 'lu_mem' is a corresponding unsigned type. Usually,
|
||||||
** for 16-bit machines.
|
** 'ptrdiff_t' should work, but we use 'long' for 16-bit machines.
|
||||||
*/
|
*/
|
||||||
#if defined(LUAI_MEM) /* { external definitions? */
|
#if defined(LUAI_MEM) /* { external definitions? */
|
||||||
typedef LUAI_MEM l_mem;
|
typedef LUAI_MEM l_mem;
|
||||||
@@ -59,13 +59,6 @@ typedef lu_byte TStatus;
|
|||||||
#define MAX_SIZE (sizeof(size_t) < sizeof(lua_Integer) ? MAX_SIZET \
|
#define MAX_SIZE (sizeof(size_t) < sizeof(lua_Integer) ? MAX_SIZET \
|
||||||
: cast_sizet(LUA_MAXINTEGER))
|
: 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)
|
** test whether an unsigned value is a power of 2 (or zero)
|
||||||
*/
|
*/
|
||||||
@@ -241,12 +234,12 @@ typedef unsigned long l_uint32;
|
|||||||
|
|
||||||
/* floor division (defined as 'floor(a/b)') */
|
/* floor division (defined as 'floor(a/b)') */
|
||||||
#if !defined(luai_numidiv)
|
#if !defined(luai_numidiv)
|
||||||
#define luai_numidiv(L,a,b) ((void)L, l_floor(luai_numdiv(L,a,b)))
|
#define luai_numidiv(L,a,b) l_floor(luai_numdiv(L,a,b))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* float division */
|
/* float division */
|
||||||
#if !defined(luai_numdiv)
|
#if !defined(luai_numdiv)
|
||||||
#define luai_numdiv(L,a,b) ((a)/(b))
|
#define luai_numdiv(L,a,b) ((void)L, (a)/(b))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -274,10 +267,10 @@ typedef unsigned long l_uint32;
|
|||||||
|
|
||||||
/* the others are quite standard operations */
|
/* the others are quite standard operations */
|
||||||
#if !defined(luai_numadd)
|
#if !defined(luai_numadd)
|
||||||
#define luai_numadd(L,a,b) ((a)+(b))
|
#define luai_numadd(L,a,b) ((void)L, (a)+(b))
|
||||||
#define luai_numsub(L,a,b) ((a)-(b))
|
#define luai_numsub(L,a,b) ((void)L, (a)-(b))
|
||||||
#define luai_nummul(L,a,b) ((a)*(b))
|
#define luai_nummul(L,a,b) ((void)L, (a)*(b))
|
||||||
#define luai_numunm(L,a) (-(a))
|
#define luai_numunm(L,a) ((void)L, -(a))
|
||||||
#define luai_numeq(a,b) ((a)==(b))
|
#define luai_numeq(a,b) ((a)==(b))
|
||||||
#define luai_numlt(a,b) ((a)<(b))
|
#define luai_numlt(a,b) ((a)<(b))
|
||||||
#define luai_numle(a,b) ((a)<=(b))
|
#define luai_numle(a,b) ((a)<=(b))
|
||||||
@@ -287,6 +280,55 @@ typedef unsigned long l_uint32;
|
|||||||
#endif
|
#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
|
** "Abstraction Layer" for basic report of messages and errors
|
||||||
|
|||||||
+30
-17
@@ -38,31 +38,37 @@ static int math_abs (lua_State *L) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int math_sin (lua_State *L) {
|
static int math_sin (lua_State *L) {
|
||||||
lua_pushnumber(L, l_mathop(sin)(luaL_checknumber(L, 1)));
|
lua_pushnumber(L, l_mathop(sin)(luaL_checknumber(L, 1)));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int math_cos (lua_State *L) {
|
static int math_cos (lua_State *L) {
|
||||||
lua_pushnumber(L, l_mathop(cos)(luaL_checknumber(L, 1)));
|
lua_pushnumber(L, l_mathop(cos)(luaL_checknumber(L, 1)));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int math_tan (lua_State *L) {
|
static int math_tan (lua_State *L) {
|
||||||
lua_pushnumber(L, l_mathop(tan)(luaL_checknumber(L, 1)));
|
lua_pushnumber(L, l_mathop(tan)(luaL_checknumber(L, 1)));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int math_asin (lua_State *L) {
|
static int math_asin (lua_State *L) {
|
||||||
lua_pushnumber(L, l_mathop(asin)(luaL_checknumber(L, 1)));
|
lua_pushnumber(L, l_mathop(asin)(luaL_checknumber(L, 1)));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int math_acos (lua_State *L) {
|
static int math_acos (lua_State *L) {
|
||||||
lua_pushnumber(L, l_mathop(acos)(luaL_checknumber(L, 1)));
|
lua_pushnumber(L, l_mathop(acos)(luaL_checknumber(L, 1)));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int math_atan (lua_State *L) {
|
static int math_atan (lua_State *L) {
|
||||||
lua_Number y = luaL_checknumber(L, 1);
|
lua_Number y = luaL_checknumber(L, 1);
|
||||||
lua_Number x = luaL_optnumber(L, 2, 1);
|
lua_Number x = luaL_optnumber(L, 2, 1);
|
||||||
@@ -167,6 +173,7 @@ static int math_ult (lua_State *L) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int math_log (lua_State *L) {
|
static int math_log (lua_State *L) {
|
||||||
lua_Number x = luaL_checknumber(L, 1);
|
lua_Number x = luaL_checknumber(L, 1);
|
||||||
lua_Number res;
|
lua_Number res;
|
||||||
@@ -188,22 +195,42 @@ static int math_log (lua_State *L) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int math_exp (lua_State *L) {
|
static int math_exp (lua_State *L) {
|
||||||
lua_pushnumber(L, l_mathop(exp)(luaL_checknumber(L, 1)));
|
lua_pushnumber(L, l_mathop(exp)(luaL_checknumber(L, 1)));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int math_deg (lua_State *L) {
|
static int math_deg (lua_State *L) {
|
||||||
lua_pushnumber(L, luaL_checknumber(L, 1) * (l_mathop(180.0) / PI));
|
lua_pushnumber(L, luaL_checknumber(L, 1) * (l_mathop(180.0) / PI));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int math_rad (lua_State *L) {
|
static int math_rad (lua_State *L) {
|
||||||
lua_pushnumber(L, luaL_checknumber(L, 1) * (PI / l_mathop(180.0)));
|
lua_pushnumber(L, luaL_checknumber(L, 1) * (PI / l_mathop(180.0)));
|
||||||
return 1;
|
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) {
|
static int math_min (lua_State *L) {
|
||||||
int n = lua_gettop(L); /* number of arguments */
|
int n = lua_gettop(L); /* number of arguments */
|
||||||
int imin = 1; /* index of current minimum value */
|
int imin = 1; /* index of current minimum value */
|
||||||
@@ -251,7 +278,7 @@ static int math_type (lua_State *L) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** This code uses lots of shifts. ANSI C does not allow shifts greater
|
** This code uses lots of shifts. ISO C does not allow shifts greater
|
||||||
** than or equal to the width of the type being shifted, so some shifts
|
** than or equal to the width of the type being shifted, so some shifts
|
||||||
** are written in convoluted ways to match that restriction. For
|
** are written in convoluted ways to match that restriction. For
|
||||||
** preprocessor tests, it assumes a width of 32 bits, so the maximum
|
** preprocessor tests, it assumes a width of 32 bits, so the maximum
|
||||||
@@ -666,20 +693,6 @@ static int math_pow (lua_State *L) {
|
|||||||
return 1;
|
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) {
|
static int math_log10 (lua_State *L) {
|
||||||
lua_pushnumber(L, l_mathop(log10)(luaL_checknumber(L, 1)));
|
lua_pushnumber(L, l_mathop(log10)(luaL_checknumber(L, 1)));
|
||||||
return 1;
|
return 1;
|
||||||
@@ -702,7 +715,9 @@ static const luaL_Reg mathlib[] = {
|
|||||||
{"tointeger", math_toint},
|
{"tointeger", math_toint},
|
||||||
{"floor", math_floor},
|
{"floor", math_floor},
|
||||||
{"fmod", math_fmod},
|
{"fmod", math_fmod},
|
||||||
|
{"frexp", math_frexp},
|
||||||
{"ult", math_ult},
|
{"ult", math_ult},
|
||||||
|
{"ldexp", math_ldexp},
|
||||||
{"log", math_log},
|
{"log", math_log},
|
||||||
{"max", math_max},
|
{"max", math_max},
|
||||||
{"min", math_min},
|
{"min", math_min},
|
||||||
@@ -718,8 +733,6 @@ static const luaL_Reg mathlib[] = {
|
|||||||
{"sinh", math_sinh},
|
{"sinh", math_sinh},
|
||||||
{"tanh", math_tanh},
|
{"tanh", math_tanh},
|
||||||
{"pow", math_pow},
|
{"pow", math_pow},
|
||||||
{"frexp", math_frexp},
|
|
||||||
{"ldexp", math_ldexp},
|
|
||||||
{"log10", math_log10},
|
{"log10", math_log10},
|
||||||
#endif
|
#endif
|
||||||
/* placeholders */
|
/* placeholders */
|
||||||
|
|||||||
@@ -306,6 +306,16 @@ 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]
|
** return registry.CLIBS[path]
|
||||||
*/
|
*/
|
||||||
@@ -320,34 +330,41 @@ static void *checkclib (lua_State *L, const char *path) {
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** registry.CLIBS[path] = plib -- for queries
|
** Deallocate function for library strings.
|
||||||
** registry.CLIBS[#CLIBS + 1] = plib -- also keep a list of all libraries
|
** Unload the DLL associated with the string being deallocated.
|
||||||
*/
|
*/
|
||||||
static void addtoclib (lua_State *L, const char *path, void *plib) {
|
static void *freelib (void *ud, void *ptr, size_t osize, size_t nsize) {
|
||||||
lua_getfield(L, LUA_REGISTRYINDEX, CLIBS);
|
/* string itself is irrelevant and static */
|
||||||
lua_pushlightuserdata(L, plib);
|
(void)ptr; (void)osize; (void)nsize;
|
||||||
lua_pushvalue(L, -1);
|
lsys_unloadlib(ud); /* unload library represented by the string */
|
||||||
lua_setfield(L, -3, path); /* CLIBS[path] = plib */
|
return NULL;
|
||||||
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
|
** Create a library string that, when deallocated, will unload 'plib'
|
||||||
** handles in list CLIBS
|
|
||||||
*/
|
*/
|
||||||
static int gctm (lua_State *L) {
|
static void createlibstr (lua_State *L, void *plib) {
|
||||||
lua_Integer n = luaL_len(L, 1);
|
/* common content for all library strings */
|
||||||
for (; n >= 1; n--) { /* for each handle, in reverse order */
|
static const char dummy[] = "01234567890";
|
||||||
lua_rawgeti(L, 1, n); /* get handle CLIBS[n] */
|
lua_pushexternalstring(L, dummy, sizeof(dummy) - 1, freelib, plib);
|
||||||
lsys_unloadlib(lua_touserdata(L, -1));
|
|
||||||
lua_pop(L, 1); /* pop handle */
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** 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.
|
||||||
|
*/
|
||||||
|
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_pop(L, 1); /* pop CLIBS table */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* error codes for 'lookforfunc' */
|
/* error codes for 'lookforfunc' */
|
||||||
#define ERRLIB 1
|
#define ERRLIB 1
|
||||||
@@ -361,8 +378,8 @@ static int gctm (lua_State *L) {
|
|||||||
** Then, if 'sym' is '*', return true (as library has been loaded).
|
** Then, if 'sym' is '*', return true (as library has been loaded).
|
||||||
** Otherwise, look for symbol 'sym' in the library and push a
|
** Otherwise, look for symbol 'sym' in the library and push a
|
||||||
** C function with that symbol.
|
** C function with that symbol.
|
||||||
** Return 0 and 'true' or a function in the stack; in case of
|
** Return 0 with 'true' or a function in the stack; in case of
|
||||||
** errors, return an error code and an error message in the stack.
|
** errors, return an error code with an error message in the stack.
|
||||||
*/
|
*/
|
||||||
static int lookforfunc (lua_State *L, const char *path, const char *sym) {
|
static int lookforfunc (lua_State *L, const char *path, const char *sym) {
|
||||||
void *reg = checkclib(L, path); /* check loaded C libraries */
|
void *reg = checkclib(L, path); /* check loaded C libraries */
|
||||||
@@ -524,7 +541,7 @@ static int searcher_Lua (lua_State *L) {
|
|||||||
const char *name = luaL_checkstring(L, 1);
|
const char *name = luaL_checkstring(L, 1);
|
||||||
filename = findfile(L, name, "path", LUA_LSUBSEP);
|
filename = findfile(L, name, "path", LUA_LSUBSEP);
|
||||||
if (filename == NULL) return 1; /* module not found in this path */
|
if (filename == NULL) return 1; /* module not found in this path */
|
||||||
return checkload(L, (luaL_loadfile(L, filename) == LUA_OK), filename);
|
return checkload(L, (luaL_loadfilex(L, filename, "bt") == LUA_OK), filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -704,21 +721,9 @@ static void createsearcherstable (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_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) {
|
LUAMOD_API int luaopen_package (lua_State *L) {
|
||||||
createclibstable(L);
|
luaL_getsubtable(L, LUA_REGISTRYINDEX, CLIBS); /* create CLIBS table */
|
||||||
|
lua_pop(L, 1); /* will not use it now */
|
||||||
luaL_newlib(L, pk_funcs); /* create 'package' table */
|
luaL_newlib(L, pk_funcs); /* create 'package' table */
|
||||||
createsearcherstable(L);
|
createsearcherstable(L);
|
||||||
/* set paths */
|
/* set paths */
|
||||||
|
|||||||
@@ -31,7 +31,8 @@
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Computes ceil(log2(x))
|
** Computes ceil(log2(x)), which is the smallest integer n such that
|
||||||
|
** x <= (1 << n).
|
||||||
*/
|
*/
|
||||||
lu_byte luaO_ceillog2 (unsigned int x) {
|
lu_byte luaO_ceillog2 (unsigned int x) {
|
||||||
static const lu_byte log_2[256] = { /* log_2[i - 1] = ceil(log2(i)) */
|
static const lu_byte log_2[256] = { /* log_2[i - 1] = ceil(log2(i)) */
|
||||||
@@ -86,7 +87,7 @@ lu_byte luaO_codeparam (unsigned int p) {
|
|||||||
** overflow, so we check which order is best.
|
** overflow, so we check which order is best.
|
||||||
*/
|
*/
|
||||||
l_mem luaO_applyparam (lu_byte p, l_mem x) {
|
l_mem luaO_applyparam (lu_byte p, l_mem x) {
|
||||||
unsigned int m = p & 0xF; /* mantissa */
|
int m = p & 0xF; /* mantissa */
|
||||||
int e = (p >> 4); /* exponent */
|
int e = (p >> 4); /* exponent */
|
||||||
if (e > 0) { /* normalized? */
|
if (e > 0) { /* normalized? */
|
||||||
e--; /* correct exponent */
|
e--; /* correct exponent */
|
||||||
@@ -385,7 +386,7 @@ size_t luaO_str2num (const char *s, TValue *o) {
|
|||||||
int luaO_utf8esc (char *buff, l_uint32 x) {
|
int luaO_utf8esc (char *buff, l_uint32 x) {
|
||||||
int n = 1; /* number of bytes put in buffer (backwards) */
|
int n = 1; /* number of bytes put in buffer (backwards) */
|
||||||
lua_assert(x <= 0x7FFFFFFFu);
|
lua_assert(x <= 0x7FFFFFFFu);
|
||||||
if (x < 0x80) /* ascii? */
|
if (x < 0x80) /* ASCII? */
|
||||||
buff[UTF8BUFFSZ - 1] = cast_char(x);
|
buff[UTF8BUFFSZ - 1] = cast_char(x);
|
||||||
else { /* need continuation bytes */
|
else { /* need continuation bytes */
|
||||||
unsigned int mfb = 0x3f; /* maximum that fits in first byte */
|
unsigned int mfb = 0x3f; /* maximum that fits in first byte */
|
||||||
|
|||||||
@@ -208,7 +208,8 @@ typedef union {
|
|||||||
#define ttisstrictnil(o) checktag((o), LUA_VNIL)
|
#define ttisstrictnil(o) checktag((o), LUA_VNIL)
|
||||||
|
|
||||||
|
|
||||||
#define setnilvalue(obj) settt_(obj, LUA_VNIL)
|
#define setnilvalue(obj) settt_(obj, LUA_VNIL)
|
||||||
|
#define setnilvalue2s(stk) setnilvalue(s2v(stk))
|
||||||
|
|
||||||
|
|
||||||
#define isabstkey(v) checktag((v), LUA_VABSTKEY)
|
#define isabstkey(v) checktag((v), LUA_VABSTKEY)
|
||||||
@@ -418,6 +419,7 @@ typedef struct TString {
|
|||||||
|
|
||||||
|
|
||||||
#define strisshr(ts) ((ts)->shrlen >= 0)
|
#define strisshr(ts) ((ts)->shrlen >= 0)
|
||||||
|
#define isextstr(ts) (ttislngstring(ts) && tsvalue(ts)->shrlen != LSTRREG)
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -582,9 +584,18 @@ typedef struct AbsLineInfo {
|
|||||||
/*
|
/*
|
||||||
** Flags in Prototypes
|
** Flags in Prototypes
|
||||||
*/
|
*/
|
||||||
#define PF_ISVARARG 1
|
#define PF_VAHID 1 /* function has hidden vararg arguments */
|
||||||
#define PF_FIXED 2 /* prototype has parts in fixed memory */
|
#define PF_VATAB 2 /* function has vararg table */
|
||||||
|
#define PF_FIXED 4 /* 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
|
** Function Prototypes
|
||||||
|
|||||||
+11
-18
@@ -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_BANDK */
|
||||||
,opmode(0, 0, 0, 0, 1, iABC) /* OP_BORK */
|
,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_BXORK */
|
||||||
,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_SHLI */
|
||||||
|
,opmode(0, 0, 0, 0, 1, iABC) /* OP_SHRI */
|
||||||
,opmode(0, 0, 0, 0, 1, iABC) /* OP_ADD */
|
,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_SUB */
|
||||||
,opmode(0, 0, 0, 0, 1, iABC) /* OP_MUL */
|
,opmode(0, 0, 0, 0, 1, iABC) /* OP_MUL */
|
||||||
@@ -102,35 +102,28 @@ LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = {
|
|||||||
,opmode(0, 0, 1, 0, 0, ivABC) /* OP_SETLIST */
|
,opmode(0, 0, 1, 0, 0, ivABC) /* OP_SETLIST */
|
||||||
,opmode(0, 0, 0, 0, 1, iABx) /* OP_CLOSURE */
|
,opmode(0, 0, 0, 0, 1, iABx) /* OP_CLOSURE */
|
||||||
,opmode(0, 1, 0, 0, 1, iABC) /* OP_VARARG */
|
,opmode(0, 1, 0, 0, 1, iABC) /* OP_VARARG */
|
||||||
,opmode(0, 0, 1, 0, 1, iABC) /* OP_VARARGPREP */
|
,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, 0, 0, 0, iAx) /* OP_EXTRAARG */
|
,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 from previous instruction, that is,
|
** Check whether instruction uses top. That happens for OP_VARARGPREP
|
||||||
** it accepts multiple results.
|
** and for instructions that use multiple values set by the previous
|
||||||
|
** instruction.
|
||||||
*/
|
*/
|
||||||
int luaP_isIT (Instruction i) {
|
int luaP_isIT (Instruction i) {
|
||||||
OpCode op = GET_OPCODE(i);
|
OpCode op = GET_OPCODE(i);
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case OP_SETLIST:
|
case OP_SETLIST:
|
||||||
return testITMode(GET_OPCODE(i)) && GETARG_vB(i) == 0;
|
return GETARG_vB(i) == 0;
|
||||||
|
case OP_VARARGPREP:
|
||||||
|
return 1;
|
||||||
default:
|
default:
|
||||||
return testITMode(GET_OPCODE(i)) && GETARG_B(i) == 0;
|
return testITMode(GET_OPCODE(i)) && GETARG_B(i) == 0;
|
||||||
}
|
}
|
||||||
|
|||||||
+34
-19
@@ -224,8 +224,8 @@ enum OpMode {iABC, ivABC, iABx, iAsBx, iAx, isJ};
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Grep "ORDER OP" if you change these enums. Opcodes marked with a (*)
|
** Grep "ORDER OP" if you change this enum.
|
||||||
** has extra descriptions in the notes after the enumeration.
|
** See "Notes" below for more information about some instructions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@@ -238,7 +238,7 @@ OP_LOADF,/* A sBx R[A] := (lua_Number)sBx */
|
|||||||
OP_LOADK,/* A Bx R[A] := K[Bx] */
|
OP_LOADK,/* A Bx R[A] := K[Bx] */
|
||||||
OP_LOADKX,/* A R[A] := K[extra arg] */
|
OP_LOADKX,/* A R[A] := K[extra arg] */
|
||||||
OP_LOADFALSE,/* A R[A] := false */
|
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_LOADTRUE,/* A R[A] := true */
|
||||||
OP_LOADNIL,/* A B R[A], R[A+1], ..., R[A+B] := nil */
|
OP_LOADNIL,/* A B R[A], R[A+1], ..., R[A+B] := nil */
|
||||||
OP_GETUPVAL,/* A B R[A] := UpValue[B] */
|
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_BORK,/* A B C R[A] := R[B] | K[C]:integer */
|
||||||
OP_BXORK,/* A B C R[A] := R[B] ~ K[C]:integer */
|
OP_BXORK,/* A B C R[A] := R[B] ~ K[C]:integer */
|
||||||
|
|
||||||
OP_SHRI,/* A B sC R[A] := R[B] >> sC */
|
|
||||||
OP_SHLI,/* A B sC R[A] := sC << R[B] */
|
OP_SHLI,/* A B sC R[A] := sC << R[B] */
|
||||||
|
OP_SHRI,/* A B sC R[A] := R[B] >> sC */
|
||||||
|
|
||||||
OP_ADD,/* A B C R[A] := R[B] + R[C] */
|
OP_ADD,/* A B C R[A] := R[B] + R[C] */
|
||||||
OP_SUB,/* 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_SHL,/* A B C R[A] := R[B] << R[C] */
|
||||||
OP_SHR,/* 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_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] */
|
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_GEI,/* A sB k if ((R[A] >= sB) ~= k) then pc++ */
|
||||||
|
|
||||||
OP_TEST,/* A k if (not R[A] == 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_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_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] (see note) */
|
OP_RETURN,/* A B C k return R[A], ... ,R[A+B-2] */
|
||||||
OP_RETURN0,/* return */
|
OP_RETURN0,/* return */
|
||||||
OP_RETURN1,/* A return R[A] */
|
OP_RETURN1,/* A return R[A] */
|
||||||
|
|
||||||
@@ -336,9 +336,13 @@ 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_CLOSURE,/* A Bx R[A] := closure(KPROTO[Bx]) */
|
||||||
|
|
||||||
OP_VARARG,/* A C R[A], R[A+1], ..., R[A+C-2] = vararg */
|
OP_VARARG,/* A B C k R[A], ..., R[A+C-2] = varargs */
|
||||||
|
|
||||||
OP_VARARGPREP,/*A (adjust vararg parameters) */
|
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_EXTRAARG/* Ax extra (larger) argument for previous opcode */
|
OP_EXTRAARG/* Ax extra (larger) argument for previous opcode */
|
||||||
} OpCode;
|
} OpCode;
|
||||||
@@ -367,7 +371,8 @@ OP_EXTRAARG/* Ax extra (larger) argument for previous opcode */
|
|||||||
OP_RETURN*, OP_SETLIST) may use 'top'.
|
OP_RETURN*, OP_SETLIST) may use 'top'.
|
||||||
|
|
||||||
(*) In OP_VARARG, if (C == 0) then use actual number of varargs and
|
(*) In OP_VARARG, if (C == 0) then use actual number of varargs and
|
||||||
set top (like in OP_CALL with C == 0).
|
set top (like in OP_CALL with C == 0). 'k' means function has a
|
||||||
|
vararg table, which is in R[B].
|
||||||
|
|
||||||
(*) In OP_RETURN, if (B == 0) then return up to 'top'.
|
(*) In OP_RETURN, if (B == 0) then return up to 'top'.
|
||||||
|
|
||||||
@@ -382,18 +387,23 @@ 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
|
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.
|
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
|
(*) For comparisons, k specifies what condition the test should accept
|
||||||
(true or false).
|
(true or false).
|
||||||
|
|
||||||
(*) In OP_MMBINI/OP_MMBINK, k means the arguments were flipped
|
(*) In OP_MMBINI/OP_MMBINK, k means the arguments were flipped
|
||||||
(the constant is the first operand).
|
(the constant is the first operand).
|
||||||
|
|
||||||
(*) All 'skips' (pc++) assume that next instruction is a jump.
|
(*) All comparison and test instructions assume that the instruction
|
||||||
|
being skipped (pc++) is a jump.
|
||||||
|
|
||||||
(*) In instructions OP_RETURN/OP_TAILCALL, 'k' specifies that the
|
(*) In instructions OP_RETURN/OP_TAILCALL, 'k' specifies that the
|
||||||
function builds upvalues, which may need to be closed. C > 0 means
|
function builds upvalues, which may need to be closed. C > 0 means
|
||||||
the function is vararg, so that its 'func' must be corrected before
|
the function has hidden vararg arguments, so that its 'func' must be
|
||||||
returning; in this case, (C - 1) is its number of fixed parameters.
|
corrected before returning; in this case, (C - 1) is its number of
|
||||||
|
fixed parameters.
|
||||||
|
|
||||||
(*) In comparisons with an immediate operand, C signals whether the
|
(*) In comparisons with an immediate operand, C signals whether the
|
||||||
original operand was a float. (It must be corrected in case of
|
original operand was a float. (It must be corrected in case of
|
||||||
@@ -407,8 +417,8 @@ OP_EXTRAARG/* Ax extra (larger) argument for previous opcode */
|
|||||||
** bits 0-2: op mode
|
** bits 0-2: op mode
|
||||||
** bit 3: instruction set register A
|
** bit 3: instruction set register A
|
||||||
** bit 4: operator is a test (next instruction must be a jump)
|
** bit 4: operator is a test (next instruction must be a jump)
|
||||||
** bit 5: instruction uses 'L->top' set by previous instruction (when B == 0)
|
** bit 5: used by 'luaP_isIT'
|
||||||
** bit 6: instruction sets 'L->top' for next instruction (when C == 0)
|
** bit 6: used by 'luaP_isOT'
|
||||||
** bit 7: instruction is an MM instruction (call a metamethod)
|
** bit 7: instruction is an MM instruction (call a metamethod)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -417,12 +427,17 @@ LUAI_DDEC(const lu_byte luaP_opmodes[NUM_OPCODES];)
|
|||||||
#define getOpMode(m) (cast(enum OpMode, luaP_opmodes[m] & 7))
|
#define getOpMode(m) (cast(enum OpMode, luaP_opmodes[m] & 7))
|
||||||
#define testAMode(m) (luaP_opmodes[m] & (1 << 3))
|
#define testAMode(m) (luaP_opmodes[m] & (1 << 3))
|
||||||
#define testTMode(m) (luaP_opmodes[m] & (1 << 4))
|
#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))
|
#define testMMMode(m) (luaP_opmodes[m] & (1 << 7))
|
||||||
|
|
||||||
|
|
||||||
LUAI_FUNC int luaP_isOT (Instruction i);
|
/* 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_isIT (Instruction i);
|
LUAI_FUNC int luaP_isIT (Instruction i);
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+3
-1
@@ -45,8 +45,8 @@ static const char *const opnames[] = {
|
|||||||
"BANDK",
|
"BANDK",
|
||||||
"BORK",
|
"BORK",
|
||||||
"BXORK",
|
"BXORK",
|
||||||
"SHRI",
|
|
||||||
"SHLI",
|
"SHLI",
|
||||||
|
"SHRI",
|
||||||
"ADD",
|
"ADD",
|
||||||
"SUB",
|
"SUB",
|
||||||
"MUL",
|
"MUL",
|
||||||
@@ -94,6 +94,8 @@ static const char *const opnames[] = {
|
|||||||
"SETLIST",
|
"SETLIST",
|
||||||
"CLOSURE",
|
"CLOSURE",
|
||||||
"VARARG",
|
"VARARG",
|
||||||
|
"GETVARG",
|
||||||
|
"ERRNNIL",
|
||||||
"VARARGPREP",
|
"VARARGPREP",
|
||||||
"EXTRAARG",
|
"EXTRAARG",
|
||||||
NULL
|
NULL
|
||||||
|
|||||||
@@ -34,7 +34,7 @@
|
|||||||
#if defined(LUA_USE_WINDOWS)
|
#if defined(LUA_USE_WINDOWS)
|
||||||
#define LUA_STRFTIMEOPTIONS "aAbBcdHIjmMpSUwWxXyYzZ%" \
|
#define LUA_STRFTIMEOPTIONS "aAbBcdHIjmMpSUwWxXyYzZ%" \
|
||||||
"||" "#c#x#d#H#I#j#m#M#S#U#w#W#y#Y" /* two-char options */
|
"||" "#c#x#d#H#I#j#m#M#S#U#w#W#y#Y" /* two-char options */
|
||||||
#elif defined(LUA_USE_C89) /* ANSI C 89 (only 1-char options) */
|
#elif defined(LUA_USE_C89) /* C89 (only 1-char options) */
|
||||||
#define LUA_STRFTIMEOPTIONS "aAbBcdHIjmMpSUwWxXyYZ%"
|
#define LUA_STRFTIMEOPTIONS "aAbBcdHIjmMpSUwWxXyYZ%"
|
||||||
#else /* C99 specification */
|
#else /* C99 specification */
|
||||||
#define LUA_STRFTIMEOPTIONS "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%" \
|
#define LUA_STRFTIMEOPTIONS "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%" \
|
||||||
|
|||||||
@@ -30,7 +30,7 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* maximum number of variable declarationss per function (must be
|
/* maximum number of variable declarations per function (must be
|
||||||
smaller than 250, due to the bytecode format) */
|
smaller than 250, due to the bytecode format) */
|
||||||
#define MAXVARS 200
|
#define MAXVARS 200
|
||||||
|
|
||||||
@@ -197,7 +197,7 @@ static int new_varkind (LexState *ls, TString *name, lu_byte kind) {
|
|||||||
Dyndata *dyd = ls->dyd;
|
Dyndata *dyd = ls->dyd;
|
||||||
Vardesc *var;
|
Vardesc *var;
|
||||||
luaM_growvector(L, dyd->actvar.arr, dyd->actvar.n + 1,
|
luaM_growvector(L, dyd->actvar.arr, dyd->actvar.n + 1,
|
||||||
dyd->actvar.size, Vardesc, SHRT_MAX, "variable declarationss");
|
dyd->actvar.size, Vardesc, SHRT_MAX, "variable declarations");
|
||||||
var = &dyd->actvar.arr[dyd->actvar.n++];
|
var = &dyd->actvar.arr[dyd->actvar.n++];
|
||||||
var->vd.kind = kind; /* default */
|
var->vd.kind = kind; /* default */
|
||||||
var->vd.name = name;
|
var->vd.name = name;
|
||||||
@@ -279,7 +279,9 @@ static void init_var (FuncState *fs, expdesc *e, int vidx) {
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Raises an error if variable described by 'e' is read only
|
** 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.)
|
||||||
*/
|
*/
|
||||||
static void check_readonly (LexState *ls, expdesc *e) {
|
static void check_readonly (LexState *ls, expdesc *e) {
|
||||||
FuncState *fs = ls->fs;
|
FuncState *fs = ls->fs;
|
||||||
@@ -289,7 +291,7 @@ static void check_readonly (LexState *ls, expdesc *e) {
|
|||||||
varname = ls->dyd->actvar.arr[e->u.info].vd.name;
|
varname = ls->dyd->actvar.arr[e->u.info].vd.name;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case VLOCAL: {
|
case VLOCAL: case VVARGVAR: {
|
||||||
Vardesc *vardesc = getlocalvardesc(fs, e->u.var.vidx);
|
Vardesc *vardesc = getlocalvardesc(fs, e->u.var.vidx);
|
||||||
if (vardesc->vd.kind != VDKREG) /* not a regular variable? */
|
if (vardesc->vd.kind != VDKREG) /* not a regular variable? */
|
||||||
varname = vardesc->vd.name;
|
varname = vardesc->vd.name;
|
||||||
@@ -301,6 +303,10 @@ static void check_readonly (LexState *ls, expdesc *e) {
|
|||||||
varname = up->name;
|
varname = up->name;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case VVARGIND: {
|
||||||
|
needvatab(fs->f); /* function will need a vararg table */
|
||||||
|
e->k = VINDEXED;
|
||||||
|
} /* FALLTHROUGH */
|
||||||
case VINDEXUP: case VINDEXSTR: case VINDEXED: { /* global variable */
|
case VINDEXUP: case VINDEXSTR: case VINDEXED: { /* global variable */
|
||||||
if (e->u.ind.ro) /* read-only? */
|
if (e->u.ind.ro) /* read-only? */
|
||||||
varname = tsvalue(&fs->f->k[e->u.ind.keystr]);
|
varname = tsvalue(&fs->f->k[e->u.ind.keystr]);
|
||||||
@@ -426,8 +432,11 @@ static int searchvar (FuncState *fs, TString *n, expdesc *var) {
|
|||||||
else if (eqstr(n, vd->vd.name)) { /* found? */
|
else if (eqstr(n, vd->vd.name)) { /* found? */
|
||||||
if (vd->vd.kind == RDKCTC) /* compile-time constant? */
|
if (vd->vd.kind == RDKCTC) /* compile-time constant? */
|
||||||
init_exp(var, VCONST, fs->firstlocal + i);
|
init_exp(var, VCONST, fs->firstlocal + i);
|
||||||
else /* local variable */
|
else { /* local variable */
|
||||||
init_var(fs, var, i);
|
init_var(fs, var, i);
|
||||||
|
if (vd->vd.kind == RDKVAVAR) /* vararg parameter? */
|
||||||
|
var->k = VVARGVAR;
|
||||||
|
}
|
||||||
return cast_int(var->k);
|
return cast_int(var->k);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -467,8 +476,13 @@ static void marktobeclosed (FuncState *fs) {
|
|||||||
static void singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) {
|
static void singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) {
|
||||||
int v = searchvar(fs, n, var); /* look up variables at current level */
|
int v = searchvar(fs, n, var); /* look up variables at current level */
|
||||||
if (v >= 0) { /* found? */
|
if (v >= 0) { /* found? */
|
||||||
if (v == VLOCAL && !base)
|
if (!base) {
|
||||||
markupval(fs, var->u.var.vidx); /* local will be used as an upval */
|
if (var->k == VVARGVAR) /* vararg parameter? */
|
||||||
|
luaK_vapar2local(fs, var); /* change it to a regular local */
|
||||||
|
if (var->k == VLOCAL)
|
||||||
|
markupval(fs, var->u.var.vidx); /* will be used as an upvalue */
|
||||||
|
}
|
||||||
|
/* else nothing else to be done */
|
||||||
}
|
}
|
||||||
else { /* not found at current level; try upvalues */
|
else { /* not found at current level; try upvalues */
|
||||||
int idx = searchupvalue(fs, n); /* try existing upvalues */
|
int idx = searchupvalue(fs, n); /* try existing upvalues */
|
||||||
@@ -485,6 +499,20 @@ 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
|
** Find a variable with the given name 'n', handling global variables
|
||||||
** too.
|
** too.
|
||||||
@@ -494,18 +522,11 @@ static void buildvar (LexState *ls, TString *varname, expdesc *var) {
|
|||||||
init_exp(var, VGLOBAL, -1); /* global by default */
|
init_exp(var, VGLOBAL, -1); /* global by default */
|
||||||
singlevaraux(fs, varname, var, 1);
|
singlevaraux(fs, varname, var, 1);
|
||||||
if (var->k == VGLOBAL) { /* global name? */
|
if (var->k == VGLOBAL) { /* global name? */
|
||||||
expdesc key;
|
|
||||||
int info = var->u.info;
|
int info = var->u.info;
|
||||||
/* global by default in the scope of a global declaration? */
|
/* global by default in the scope of a global declaration? */
|
||||||
if (info == -2)
|
if (info == -2)
|
||||||
luaK_semerror(ls, "variable '%s' not declared", getstr(varname));
|
luaK_semerror(ls, "variable '%s' not declared", getstr(varname));
|
||||||
singlevaraux(fs, ls->envn, var, 1); /* get environment variable */
|
buildglobal(ls, varname, var);
|
||||||
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)
|
if (info != -1 && ls->dyd->actvar.arr[info].vd.kind == GDKCONST)
|
||||||
var->u.ind.ro = 1; /* mark variable as read-only */
|
var->u.ind.ro = 1; /* mark variable as read-only */
|
||||||
else /* anyway must be a global */
|
else /* anyway must be a global */
|
||||||
@@ -526,6 +547,7 @@ static void singlevar (LexState *ls, expdesc *var) {
|
|||||||
static void adjust_assign (LexState *ls, int nvars, int nexps, expdesc *e) {
|
static void adjust_assign (LexState *ls, int nvars, int nexps, expdesc *e) {
|
||||||
FuncState *fs = ls->fs;
|
FuncState *fs = ls->fs;
|
||||||
int needed = nvars - nexps; /* extra values needed */
|
int needed = nvars - nexps; /* extra values needed */
|
||||||
|
luaK_checkstack(fs, needed);
|
||||||
if (hasmultret(e->k)) { /* last expression has multiple returns? */
|
if (hasmultret(e->k)) { /* last expression has multiple returns? */
|
||||||
int extra = needed + 1; /* discount last expression itself */
|
int extra = needed + 1; /* discount last expression itself */
|
||||||
if (extra < 0)
|
if (extra < 0)
|
||||||
@@ -665,7 +687,7 @@ static void createlabel (LexState *ls, TString *name, int line, int last) {
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Traverse the pending goto's of the finishing block checking whether
|
** Traverse the pending gotos of the finishing block checking whether
|
||||||
** each match some label of that block. Those that do not match are
|
** each match some label of that block. Those that do not match are
|
||||||
** "exported" to the outer block, to be solved there. In particular,
|
** "exported" to the outer block, to be solved there. In particular,
|
||||||
** its 'nactvar' is updated with the level of the inner block,
|
** its 'nactvar' is updated with the level of the inner block,
|
||||||
@@ -799,8 +821,7 @@ static void open_func (LexState *ls, FuncState *fs, BlockCnt *bl) {
|
|||||||
luaC_objbarrier(L, f, f->source);
|
luaC_objbarrier(L, f, f->source);
|
||||||
f->maxstacksize = 2; /* registers 0/1 are always valid */
|
f->maxstacksize = 2; /* registers 0/1 are always valid */
|
||||||
fs->kcache = luaH_new(L); /* create table for function */
|
fs->kcache = luaH_new(L); /* create table for function */
|
||||||
sethvalue2s(L, L->top.p, fs->kcache); /* anchor it */
|
luaD_anchorobj(L, ls->h, obj2gco(fs->kcache)); /* anchor it */
|
||||||
luaD_inctop(L);
|
|
||||||
enterblock(fs, bl, 0);
|
enterblock(fs, bl, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -809,6 +830,7 @@ static void close_func (LexState *ls) {
|
|||||||
lua_State *L = ls->L;
|
lua_State *L = ls->L;
|
||||||
FuncState *fs = ls->fs;
|
FuncState *fs = ls->fs;
|
||||||
Proto *f = fs->f;
|
Proto *f = fs->f;
|
||||||
|
TValue temp;
|
||||||
luaK_ret(fs, luaY_nvarstack(fs), 0); /* final return */
|
luaK_ret(fs, luaY_nvarstack(fs), 0); /* final return */
|
||||||
leaveblock(fs);
|
leaveblock(fs);
|
||||||
lua_assert(fs->bl == NULL);
|
lua_assert(fs->bl == NULL);
|
||||||
@@ -821,8 +843,10 @@ static void close_func (LexState *ls) {
|
|||||||
luaM_shrinkvector(L, f->p, f->sizep, fs->np, Proto *);
|
luaM_shrinkvector(L, f->p, f->sizep, fs->np, Proto *);
|
||||||
luaM_shrinkvector(L, f->locvars, f->sizelocvars, fs->ndebugvars, LocVar);
|
luaM_shrinkvector(L, f->locvars, f->sizelocvars, fs->ndebugvars, LocVar);
|
||||||
luaM_shrinkvector(L, f->upvalues, f->sizeupvalues, fs->nups, Upvaldesc);
|
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;
|
ls->fs = fs->prev;
|
||||||
L->top.p--; /* pop kcache table */
|
|
||||||
luaC_checkGC(L);
|
luaC_checkGC(L);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -898,6 +922,19 @@ typedef struct ConsControl {
|
|||||||
} 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) {
|
static void recfield (LexState *ls, ConsControl *cc) {
|
||||||
/* recfield -> (NAME | '['exp']') = exp */
|
/* recfield -> (NAME | '['exp']') = exp */
|
||||||
FuncState *fs = ls->fs;
|
FuncState *fs = ls->fs;
|
||||||
@@ -918,7 +955,7 @@ static void recfield (LexState *ls, ConsControl *cc) {
|
|||||||
|
|
||||||
|
|
||||||
static void closelistfield (FuncState *fs, ConsControl *cc) {
|
static void closelistfield (FuncState *fs, ConsControl *cc) {
|
||||||
if (cc->v.k == VVOID) return; /* there is no list item */
|
lua_assert(cc->tostore > 0);
|
||||||
luaK_exp2nextreg(fs, &cc->v);
|
luaK_exp2nextreg(fs, &cc->v);
|
||||||
cc->v.k = VVOID;
|
cc->v.k = VVOID;
|
||||||
if (cc->tostore >= cc->maxtostore) {
|
if (cc->tostore >= cc->maxtostore) {
|
||||||
@@ -1006,10 +1043,12 @@ static void constructor (LexState *ls, expdesc *t) {
|
|||||||
checknext(ls, '{' /*}*/);
|
checknext(ls, '{' /*}*/);
|
||||||
cc.maxtostore = maxtostore(fs);
|
cc.maxtostore = maxtostore(fs);
|
||||||
do {
|
do {
|
||||||
lua_assert(cc.v.k == VVOID || cc.tostore > 0);
|
|
||||||
if (ls->t.token == /*{*/ '}') break;
|
if (ls->t.token == /*{*/ '}') break;
|
||||||
closelistfield(fs, &cc);
|
if (cc.v.k != VVOID) /* is there a previous list item? */
|
||||||
|
closelistfield(fs, &cc); /* close it */
|
||||||
field(ls, &cc);
|
field(ls, &cc);
|
||||||
|
luaY_checklimit(fs, cc.tostore + cc.na + cc.nh, MAX_CNST,
|
||||||
|
"items in a constructor");
|
||||||
} while (testnext(ls, ',') || testnext(ls, ';'));
|
} while (testnext(ls, ',') || testnext(ls, ';'));
|
||||||
check_match(ls, /*{*/ '}', '{' /*}*/, line);
|
check_match(ls, /*{*/ '}', '{' /*}*/, line);
|
||||||
lastlistfield(fs, &cc);
|
lastlistfield(fs, &cc);
|
||||||
@@ -1019,9 +1058,9 @@ static void constructor (LexState *ls, expdesc *t) {
|
|||||||
/* }====================================================================== */
|
/* }====================================================================== */
|
||||||
|
|
||||||
|
|
||||||
static void setvararg (FuncState *fs, int nparams) {
|
static void setvararg (FuncState *fs) {
|
||||||
fs->f->flag |= PF_ISVARARG;
|
fs->f->flag |= PF_VAHID; /* by default, use hidden vararg arguments */
|
||||||
luaK_codeABC(fs, OP_VARARGPREP, nparams, 0, 0);
|
luaK_codeABC(fs, OP_VARARGPREP, 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1030,7 +1069,7 @@ static void parlist (LexState *ls) {
|
|||||||
FuncState *fs = ls->fs;
|
FuncState *fs = ls->fs;
|
||||||
Proto *f = fs->f;
|
Proto *f = fs->f;
|
||||||
int nparams = 0;
|
int nparams = 0;
|
||||||
int isvararg = 0;
|
int varargk = 0;
|
||||||
if (ls->t.token != ')') { /* is 'parlist' not empty? */
|
if (ls->t.token != ')') { /* is 'parlist' not empty? */
|
||||||
do {
|
do {
|
||||||
switch (ls->t.token) {
|
switch (ls->t.token) {
|
||||||
@@ -1040,19 +1079,26 @@ static void parlist (LexState *ls) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TK_DOTS: {
|
case TK_DOTS: {
|
||||||
luaX_next(ls);
|
varargk = 1;
|
||||||
isvararg = 1;
|
luaX_next(ls); /* skip '...' */
|
||||||
|
if (ls->t.token == TK_NAME)
|
||||||
|
new_varkind(ls, str_checkname(ls), RDKVAVAR);
|
||||||
|
else
|
||||||
|
new_localvarliteral(ls, "(vararg table)");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: luaX_syntaxerror(ls, "<name> or '...' expected");
|
default: luaX_syntaxerror(ls, "<name> or '...' expected");
|
||||||
}
|
}
|
||||||
} while (!isvararg && testnext(ls, ','));
|
} while (!varargk && testnext(ls, ','));
|
||||||
}
|
}
|
||||||
adjustlocalvars(ls, nparams);
|
adjustlocalvars(ls, nparams);
|
||||||
f->numparams = cast_byte(fs->nactvar);
|
f->numparams = cast_byte(fs->nactvar);
|
||||||
if (isvararg)
|
if (varargk) {
|
||||||
setvararg(fs, f->numparams); /* declared vararg */
|
setvararg(fs); /* declared vararg */
|
||||||
luaK_reserveregs(fs, fs->nactvar); /* reserve registers for parameters */
|
adjustlocalvars(ls, 1); /* vararg parameter */
|
||||||
|
}
|
||||||
|
/* reserve registers for parameters (plus vararg parameter, if present) */
|
||||||
|
luaK_reserveregs(fs, fs->nactvar);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1120,6 +1166,7 @@ static void funcargs (LexState *ls, expdesc *f) {
|
|||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
luaX_syntaxerror(ls, "function arguments expected");
|
luaX_syntaxerror(ls, "function arguments expected");
|
||||||
|
return; /* to avoid warnings */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lua_assert(f->k == VNONRELOC);
|
lua_assert(f->k == VNONRELOC);
|
||||||
@@ -1239,9 +1286,9 @@ static void simpleexp (LexState *ls, expdesc *v) {
|
|||||||
}
|
}
|
||||||
case TK_DOTS: { /* vararg */
|
case TK_DOTS: { /* vararg */
|
||||||
FuncState *fs = ls->fs;
|
FuncState *fs = ls->fs;
|
||||||
check_condition(ls, fs->f->flag & PF_ISVARARG,
|
check_condition(ls, isvararg(fs->f),
|
||||||
"cannot use '...' outside a vararg function");
|
"cannot use '...' outside a vararg function");
|
||||||
init_exp(v, VVARARG, luaK_codeABC(fs, OP_VARARG, 0, 0, 1));
|
init_exp(v, VVARARG, luaK_codeABC(fs, OP_VARARG, 0, fs->f->numparams, 1));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case '{' /*}*/: { /* constructor */
|
case '{' /*}*/: { /* constructor */
|
||||||
@@ -1435,6 +1482,15 @@ 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"
|
** Parse and compile a multiple assignment. The first "variable"
|
||||||
** (a 'suffixedexp') was already read by the caller.
|
** (a 'suffixedexp') was already read by the caller.
|
||||||
@@ -1468,8 +1524,7 @@ static void restassign (LexState *ls, struct LHS_assign *lh, int nvars) {
|
|||||||
return; /* avoid default */
|
return; /* avoid default */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
init_exp(&e, VNONRELOC, ls->fs->freereg-1); /* default assignment */
|
storevartop(ls->fs, &lh->v); /* default assignment */
|
||||||
luaK_storevar(ls->fs, &lh->v, &e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1630,13 +1685,22 @@ static void forbody (LexState *ls, int base, int line, int nvars, int isgen) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Control whether for-loop control variables are read-only
|
||||||
|
*/
|
||||||
|
#if LUA_COMPAT_LOOPVAR
|
||||||
|
#define LOOPVARKIND VDKREG
|
||||||
|
#else /* by default, these variables are read only */
|
||||||
|
#define LOOPVARKIND RDKCONST
|
||||||
|
#endif
|
||||||
|
|
||||||
static void fornum (LexState *ls, TString *varname, int line) {
|
static void fornum (LexState *ls, TString *varname, int line) {
|
||||||
/* fornum -> NAME = exp,exp[,exp] forbody */
|
/* fornum -> NAME = exp,exp[,exp] forbody */
|
||||||
FuncState *fs = ls->fs;
|
FuncState *fs = ls->fs;
|
||||||
int base = fs->freereg;
|
int base = fs->freereg;
|
||||||
new_localvarliteral(ls, "(for state)");
|
new_localvarliteral(ls, "(for state)");
|
||||||
new_localvarliteral(ls, "(for state)");
|
new_localvarliteral(ls, "(for state)");
|
||||||
new_varkind(ls, varname, RDKCONST); /* control variable */
|
new_varkind(ls, varname, LOOPVARKIND); /* control variable */
|
||||||
checknext(ls, '=');
|
checknext(ls, '=');
|
||||||
exp1(ls); /* initial value */
|
exp1(ls); /* initial value */
|
||||||
checknext(ls, ',');
|
checknext(ls, ',');
|
||||||
@@ -1663,7 +1727,7 @@ static void forlist (LexState *ls, TString *indexname) {
|
|||||||
new_localvarliteral(ls, "(for state)"); /* iterator function */
|
new_localvarliteral(ls, "(for state)"); /* iterator function */
|
||||||
new_localvarliteral(ls, "(for state)"); /* state */
|
new_localvarliteral(ls, "(for state)"); /* state */
|
||||||
new_localvarliteral(ls, "(for state)"); /* closing var. (after swap) */
|
new_localvarliteral(ls, "(for state)"); /* closing var. (after swap) */
|
||||||
new_varkind(ls, indexname, RDKCONST); /* control variable */
|
new_varkind(ls, indexname, LOOPVARKIND); /* control variable */
|
||||||
/* other declared variables */
|
/* other declared variables */
|
||||||
while (testnext(ls, ',')) {
|
while (testnext(ls, ',')) {
|
||||||
new_localvar(ls, str_checkname(ls));
|
new_localvar(ls, str_checkname(ls));
|
||||||
@@ -1812,7 +1876,7 @@ static lu_byte getglobalattribute (LexState *ls, lu_byte df) {
|
|||||||
switch (kind) {
|
switch (kind) {
|
||||||
case RDKTOCLOSE:
|
case RDKTOCLOSE:
|
||||||
luaK_semerror(ls, "global variables cannot be to-be-closed");
|
luaK_semerror(ls, "global variables cannot be to-be-closed");
|
||||||
break; /* to avoid warnings */
|
return kind; /* to avoid warnings */
|
||||||
case RDKCONST:
|
case RDKCONST:
|
||||||
return GDKCONST; /* adjust kind for global variable */
|
return GDKCONST; /* adjust kind for global variable */
|
||||||
default:
|
default:
|
||||||
@@ -1821,25 +1885,74 @@ 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) {
|
static void globalstat (LexState *ls) {
|
||||||
/* globalstat -> (GLOBAL) attrib '*'
|
/* globalstat -> (GLOBAL) attrib '*'
|
||||||
globalstat -> (GLOBAL) attrib NAME attrib {',' NAME attrib} */
|
globalstat -> (GLOBAL) attrib NAME attrib {',' NAME attrib} */
|
||||||
FuncState *fs = ls->fs;
|
FuncState *fs = ls->fs;
|
||||||
/* get prefixed attribute (if any); default is regular global variable */
|
/* get prefixed attribute (if any); default is regular global variable */
|
||||||
lu_byte defkind = getglobalattribute(ls, GDKREG);
|
lu_byte defkind = getglobalattribute(ls, GDKREG);
|
||||||
if (testnext(ls, '*')) {
|
if (!testnext(ls, '*'))
|
||||||
|
globalnames(ls, defkind);
|
||||||
|
else {
|
||||||
/* use NULL as name to represent '*' entries */
|
/* use NULL as name to represent '*' entries */
|
||||||
new_varkind(ls, NULL, defkind);
|
new_varkind(ls, NULL, defkind);
|
||||||
fs->nactvar++; /* activate declaration */
|
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, ','));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1850,8 +1963,9 @@ static void globalfunc (LexState *ls, int line) {
|
|||||||
TString *fname = str_checkname(ls);
|
TString *fname = str_checkname(ls);
|
||||||
new_varkind(ls, fname, GDKREG); /* declare global variable */
|
new_varkind(ls, fname, GDKREG); /* declare global variable */
|
||||||
fs->nactvar++; /* enter its scope */
|
fs->nactvar++; /* enter its scope */
|
||||||
buildvar(ls, fname, &var);
|
buildglobal(ls, fname, &var);
|
||||||
body(ls, &b, 0, ls->linenumber); /* compile and return closure in 'b' */
|
body(ls, &b, 0, ls->linenumber); /* compile and return closure in 'b' */
|
||||||
|
checkglobal(ls, fname, line);
|
||||||
luaK_storevar(fs, &var, &b);
|
luaK_storevar(fs, &var, &b);
|
||||||
luaK_fixline(fs, line); /* definition "happens" in the first line */
|
luaK_fixline(fs, line); /* definition "happens" in the first line */
|
||||||
}
|
}
|
||||||
@@ -2009,7 +2123,7 @@ static void statement (LexState *ls) {
|
|||||||
gotostat(ls, line);
|
gotostat(ls, line);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#if defined(LUA_COMPAT_GLOBAL)
|
#if LUA_COMPAT_GLOBAL
|
||||||
case TK_NAME: {
|
case TK_NAME: {
|
||||||
/* compatibility code to parse global keyword when "global"
|
/* compatibility code to parse global keyword when "global"
|
||||||
is not reserved */
|
is not reserved */
|
||||||
@@ -2049,7 +2163,7 @@ static void mainfunc (LexState *ls, FuncState *fs) {
|
|||||||
BlockCnt bl;
|
BlockCnt bl;
|
||||||
Upvaldesc *env;
|
Upvaldesc *env;
|
||||||
open_func(ls, fs, &bl);
|
open_func(ls, fs, &bl);
|
||||||
setvararg(fs, 0); /* main function is always declared vararg */
|
setvararg(fs); /* main function is always vararg */
|
||||||
env = allocupvalue(fs); /* ...set environment upvalue */
|
env = allocupvalue(fs); /* ...set environment upvalue */
|
||||||
env->instack = 1;
|
env->instack = 1;
|
||||||
env->idx = 0;
|
env->idx = 0;
|
||||||
@@ -2063,16 +2177,14 @@ static void mainfunc (LexState *ls, FuncState *fs) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
|
LClosure *luaY_parser (lua_State *L, ZIO *z, Table *anchor, Mbuffer *buff,
|
||||||
Dyndata *dyd, const char *name, int firstchar) {
|
Dyndata *dyd, const char *name, int firstchar) {
|
||||||
LexState lexstate;
|
LexState lexstate;
|
||||||
FuncState funcstate;
|
FuncState funcstate;
|
||||||
LClosure *cl = luaF_newLclosure(L, 1); /* create main closure */
|
LClosure *cl;
|
||||||
setclLvalue2s(L, L->top.p, cl); /* anchor it (to avoid being collected) */
|
lexstate.h = anchor; /* table for scanner */
|
||||||
luaD_inctop(L);
|
cl = luaF_newLclosure(L, 1); /* create main closure */
|
||||||
lexstate.h = luaH_new(L); /* create table for scanner */
|
luaD_anchorobj(L, anchor, obj2gco(cl)); /* anchor it in scanner table */
|
||||||
sethvalue2s(L, L->top.p, lexstate.h); /* anchor it */
|
|
||||||
luaD_inctop(L);
|
|
||||||
funcstate.f = cl->p = luaF_newproto(L);
|
funcstate.f = cl->p = luaF_newproto(L);
|
||||||
luaC_objbarrier(L, cl, cl->p);
|
luaC_objbarrier(L, cl, cl->p);
|
||||||
funcstate.f->source = luaS_new(L, name); /* create and anchor TString */
|
funcstate.f->source = luaS_new(L, name); /* create and anchor TString */
|
||||||
@@ -2085,7 +2197,6 @@ LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
|
|||||||
lua_assert(!funcstate.prev && funcstate.nups == 1 && !lexstate.fs);
|
lua_assert(!funcstate.prev && funcstate.nups == 1 && !lexstate.fs);
|
||||||
/* all scopes should be correctly finished */
|
/* all scopes should be correctly finished */
|
||||||
lua_assert(dyd->actvar.n == 0 && dyd->gt.n == 0 && dyd->label.n == 0);
|
lua_assert(dyd->actvar.n == 0 && dyd->gt.n == 0 && dyd->label.n == 0);
|
||||||
L->top.p--; /* remove scanner's table */
|
return cl;
|
||||||
return cl; /* closure is on the stack, too */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -37,6 +37,8 @@ typedef enum {
|
|||||||
info = result register */
|
info = result register */
|
||||||
VLOCAL, /* local variable; var.ridx = register index;
|
VLOCAL, /* local variable; var.ridx = register index;
|
||||||
var.vidx = relative index in 'actvar.arr' */
|
var.vidx = relative index in 'actvar.arr' */
|
||||||
|
VVARGVAR, /* vararg parameter; var.ridx = register index;
|
||||||
|
var.vidx = relative index in 'actvar.arr' */
|
||||||
VGLOBAL, /* global variable;
|
VGLOBAL, /* global variable;
|
||||||
info = relative index in 'actvar.arr' (or -1 for
|
info = relative index in 'actvar.arr' (or -1 for
|
||||||
implicit declaration) */
|
implicit declaration) */
|
||||||
@@ -49,6 +51,8 @@ typedef enum {
|
|||||||
ind.ro = true if it represents a read-only global;
|
ind.ro = true if it represents a read-only global;
|
||||||
ind.keystr = if key is a string, index in 'k' of that string;
|
ind.keystr = if key is a string, index in 'k' of that string;
|
||||||
-1 if key is not a string */
|
-1 if key is not a string */
|
||||||
|
VVARGIND, /* indexed vararg parameter;
|
||||||
|
ind.* as in VINDEXED */
|
||||||
VINDEXUP, /* indexed upvalue;
|
VINDEXUP, /* indexed upvalue;
|
||||||
ind.idx = key's K index;
|
ind.idx = key's K index;
|
||||||
ind.* as in VINDEXED */
|
ind.* as in VINDEXED */
|
||||||
@@ -97,10 +101,11 @@ typedef struct expdesc {
|
|||||||
/* kinds of variables */
|
/* kinds of variables */
|
||||||
#define VDKREG 0 /* regular local */
|
#define VDKREG 0 /* regular local */
|
||||||
#define RDKCONST 1 /* local constant */
|
#define RDKCONST 1 /* local constant */
|
||||||
#define RDKTOCLOSE 2 /* to-be-closed */
|
#define RDKVAVAR 2 /* vararg parameter */
|
||||||
#define RDKCTC 3 /* local compile-time constant */
|
#define RDKTOCLOSE 3 /* to-be-closed */
|
||||||
#define GDKREG 4 /* regular global */
|
#define RDKCTC 4 /* local compile-time constant */
|
||||||
#define GDKCONST 5 /* global constant */
|
#define GDKREG 5 /* regular global */
|
||||||
|
#define GDKCONST 6 /* global constant */
|
||||||
|
|
||||||
/* variables that live in registers */
|
/* variables that live in registers */
|
||||||
#define varinreg(v) ((v)->vd.kind <= RDKTOCLOSE)
|
#define varinreg(v) ((v)->vd.kind <= RDKTOCLOSE)
|
||||||
@@ -184,8 +189,9 @@ typedef struct FuncState {
|
|||||||
LUAI_FUNC lu_byte luaY_nvarstack (FuncState *fs);
|
LUAI_FUNC lu_byte luaY_nvarstack (FuncState *fs);
|
||||||
LUAI_FUNC void luaY_checklimit (FuncState *fs, int v, int l,
|
LUAI_FUNC void luaY_checklimit (FuncState *fs, int v, int l,
|
||||||
const char *what);
|
const char *what);
|
||||||
LUAI_FUNC LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
|
LUAI_FUNC LClosure *luaY_parser (lua_State *L, ZIO *z, Table *anchor,
|
||||||
Dyndata *dyd, const char *name, int firstchar);
|
Mbuffer *buff, Dyndata *dyd,
|
||||||
|
const char *name, int firstchar);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -68,14 +68,19 @@ void luaE_setdebt (global_State *g, l_mem debt) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
CallInfo *luaE_extendCI (lua_State *L) {
|
CallInfo *luaE_extendCI (lua_State *L, int err) {
|
||||||
CallInfo *ci;
|
CallInfo *ci;
|
||||||
lua_assert(L->ci->next == NULL);
|
ci = luaM_reallocvector(L, NULL, 0, 1, CallInfo);
|
||||||
ci = luaM_new(L, CallInfo);
|
if (l_unlikely(ci == NULL)) { /* allocation failed? */
|
||||||
lua_assert(L->ci->next == NULL);
|
if (err)
|
||||||
L->ci->next = ci;
|
luaM_error(L); /* raise the error */
|
||||||
|
return NULL; /* else only report it */
|
||||||
|
}
|
||||||
|
ci->next = L->ci->next;
|
||||||
ci->previous = L->ci;
|
ci->previous = L->ci;
|
||||||
ci->next = NULL;
|
L->ci->next = ci;
|
||||||
|
if (ci->next)
|
||||||
|
ci->next->previous = ci;
|
||||||
ci->u.l.trap = 0;
|
ci->u.l.trap = 0;
|
||||||
L->nci++;
|
L->nci++;
|
||||||
return ci;
|
return ci;
|
||||||
@@ -146,7 +151,7 @@ LUAI_FUNC void luaE_incCstack (lua_State *L) {
|
|||||||
static void resetCI (lua_State *L) {
|
static void resetCI (lua_State *L) {
|
||||||
CallInfo *ci = L->ci = &L->base_ci;
|
CallInfo *ci = L->ci = &L->base_ci;
|
||||||
ci->func.p = L->stack.p;
|
ci->func.p = L->stack.p;
|
||||||
setnilvalue(s2v(ci->func.p)); /* 'function' entry for basic 'ci' */
|
setnilvalue2s(ci->func.p); /* 'function' entry for basic 'ci' */
|
||||||
ci->top.p = ci->func.p + 1 + LUA_MINSTACK; /* +1 for 'function' entry */
|
ci->top.p = ci->func.p + 1 + LUA_MINSTACK; /* +1 for 'function' entry */
|
||||||
ci->u.c.k = NULL;
|
ci->u.c.k = NULL;
|
||||||
ci->callstatus = CIST_C;
|
ci->callstatus = CIST_C;
|
||||||
@@ -161,7 +166,7 @@ static void stack_init (lua_State *L1, lua_State *L) {
|
|||||||
L1->stack.p = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK, StackValue);
|
L1->stack.p = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK, StackValue);
|
||||||
L1->tbclist.p = L1->stack.p;
|
L1->tbclist.p = L1->stack.p;
|
||||||
for (i = 0; i < BASIC_STACK_SIZE + EXTRA_STACK; i++)
|
for (i = 0; i < BASIC_STACK_SIZE + EXTRA_STACK; i++)
|
||||||
setnilvalue(s2v(L1->stack.p + i)); /* erase new stack */
|
setnilvalue2s(L1->stack.p + i); /* erase new stack */
|
||||||
L1->stack_last.p = L1->stack.p + BASIC_STACK_SIZE;
|
L1->stack_last.p = L1->stack.p + BASIC_STACK_SIZE;
|
||||||
/* initialize first ci */
|
/* initialize first ci */
|
||||||
resetCI(L1);
|
resetCI(L1);
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ typedef struct CallInfo CallInfo;
|
|||||||
** they must be visited again at the end of the cycle), but they are
|
** they must be visited again at the end of the cycle), but they are
|
||||||
** marked black because assignments to them must activate barriers (to
|
** marked black because assignments to them must activate barriers (to
|
||||||
** move them back to TOUCHED1).
|
** move them back to TOUCHED1).
|
||||||
** - Open upvales are kept gray to avoid barriers, but they stay out
|
** - Open upvalues are kept gray to avoid barriers, but they stay out
|
||||||
** of gray lists. (They don't even have a 'gclist' field.)
|
** 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) */
|
/* call is running a C function (still in first 16 bits) */
|
||||||
#define CIST_C (1u << (CIST_RECST + 3))
|
#define CIST_C (1u << (CIST_RECST + 3))
|
||||||
/* call is on a fresh "luaV_execute" frame */
|
/* 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 */
|
/* function is closing tbc variables */
|
||||||
#define CIST_CLSRET (CIST_FRESH << 1)
|
#define CIST_CLSRET (CIST_FRESH << 1)
|
||||||
/* function has tbc variables to close */
|
/* function has tbc variables to close */
|
||||||
@@ -249,10 +249,6 @@ struct CallInfo {
|
|||||||
#define CIST_HOOKYIELD (CIST_TAIL << 1)
|
#define CIST_HOOKYIELD (CIST_TAIL << 1)
|
||||||
/* function "called" a finalizer */
|
/* function "called" a finalizer */
|
||||||
#define CIST_FIN (CIST_HOOKYIELD << 1)
|
#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)
|
#define get_nresults(cs) (cast_int((cs) & CIST_NRESULTS) - 1)
|
||||||
@@ -430,9 +426,9 @@ union GCUnion {
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
** macro to convert a Lua object into a GCObject
|
** 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((v)->tt >= LUA_TSTRING, &(cast_u(v)->gc))
|
#define obj2gco(v) \
|
||||||
|
check_exp(novariant((v)->tt) >= LUA_TSTRING, &(cast_u(v)->gc))
|
||||||
|
|
||||||
|
|
||||||
/* actual number of total memory allocated */
|
/* actual number of total memory allocated */
|
||||||
@@ -442,7 +438,7 @@ union GCUnion {
|
|||||||
LUAI_FUNC void luaE_setdebt (global_State *g, l_mem debt);
|
LUAI_FUNC void luaE_setdebt (global_State *g, l_mem debt);
|
||||||
LUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1);
|
LUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1);
|
||||||
LUAI_FUNC lu_mem luaE_threadsize (lua_State *L);
|
LUAI_FUNC lu_mem luaE_threadsize (lua_State *L);
|
||||||
LUAI_FUNC CallInfo *luaE_extendCI (lua_State *L);
|
LUAI_FUNC CallInfo *luaE_extendCI (lua_State *L, int err);
|
||||||
LUAI_FUNC void luaE_shrinkCI (lua_State *L);
|
LUAI_FUNC void luaE_shrinkCI (lua_State *L);
|
||||||
LUAI_FUNC void luaE_checkcstack (lua_State *L);
|
LUAI_FUNC void luaE_checkcstack (lua_State *L);
|
||||||
LUAI_FUNC void luaE_incCstack (lua_State *L);
|
LUAI_FUNC void luaE_incCstack (lua_State *L);
|
||||||
|
|||||||
@@ -39,18 +39,18 @@
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** equality for long strings
|
** generic equality for strings
|
||||||
*/
|
*/
|
||||||
int luaS_eqlngstr (TString *a, TString *b) {
|
int luaS_eqstr (TString *a, TString *b) {
|
||||||
size_t len = a->u.lnglen;
|
size_t len1, len2;
|
||||||
lua_assert(a->tt == LUA_VLNGSTR && b->tt == LUA_VLNGSTR);
|
const char *s1 = getlstr(a, len1);
|
||||||
return (a == b) || /* same instance or... */
|
const char *s2 = getlstr(b, len2);
|
||||||
((len == b->u.lnglen) && /* equal length and ... */
|
return ((len1 == len2) && /* equal length and ... */
|
||||||
(memcmp(getlngstr(a), getlngstr(b), len) == 0)); /* equal contents */
|
(memcmp(s1, s2, len1) == 0)); /* equal contents */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
unsigned luaS_hash (const char *str, size_t l, unsigned seed) {
|
static unsigned luaS_hash (const char *str, size_t l, unsigned seed) {
|
||||||
unsigned int h = seed ^ cast_uint(l);
|
unsigned int h = seed ^ cast_uint(l);
|
||||||
for (; l > 0; l--)
|
for (; l > 0; l--)
|
||||||
h ^= ((h<<5) + (h>>2) + cast_byte(str[l - 1]));
|
h ^= ((h<<5) + (h>>2) + cast_byte(str[l - 1]));
|
||||||
@@ -315,28 +315,9 @@ 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,
|
TString *luaS_newextlstr (lua_State *L,
|
||||||
const char *s, size_t len, lua_Alloc falloc, void *ud) {
|
const char *s, size_t len, lua_Alloc falloc, void *ud) {
|
||||||
struct NewExt ne;
|
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) {
|
if (!falloc) {
|
||||||
ne.kind = LSTRFIX;
|
ne.kind = LSTRFIX;
|
||||||
f_newext(L, &ne); /* just create header */
|
f_newext(L, &ne); /* just create header */
|
||||||
@@ -357,3 +338,16 @@ 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -54,9 +54,8 @@
|
|||||||
#define eqshrstr(a,b) check_exp((a)->tt == LUA_VSHRSTR, (a) == (b))
|
#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 unsigned luaS_hashlongstr (TString *ts);
|
||||||
LUAI_FUNC int luaS_eqlngstr (TString *a, TString *b);
|
LUAI_FUNC int luaS_eqstr (TString *a, TString *b);
|
||||||
LUAI_FUNC void luaS_resize (lua_State *L, int newsize);
|
LUAI_FUNC void luaS_resize (lua_State *L, int newsize);
|
||||||
LUAI_FUNC void luaS_clearcache (global_State *g);
|
LUAI_FUNC void luaS_clearcache (global_State *g);
|
||||||
LUAI_FUNC void luaS_init (lua_State *L);
|
LUAI_FUNC void luaS_init (lua_State *L);
|
||||||
@@ -69,5 +68,6 @@ LUAI_FUNC TString *luaS_createlngstrobj (lua_State *L, size_t l);
|
|||||||
LUAI_FUNC TString *luaS_newextlstr (lua_State *L,
|
LUAI_FUNC TString *luaS_newextlstr (lua_State *L,
|
||||||
const char *s, size_t len, lua_Alloc falloc, void *ud);
|
const char *s, size_t len, lua_Alloc falloc, void *ud);
|
||||||
LUAI_FUNC size_t luaS_sizelngstr (size_t len, int kind);
|
LUAI_FUNC size_t luaS_sizelngstr (size_t len, int kind);
|
||||||
|
LUAI_FUNC TString *luaS_normstr (lua_State *L, TString *ts);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -132,27 +132,31 @@ 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) {
|
static int str_rep (lua_State *L) {
|
||||||
size_t l, lsep;
|
size_t len, lsep;
|
||||||
const char *s = luaL_checklstring(L, 1, &l);
|
const char *s = luaL_checklstring(L, 1, &len);
|
||||||
lua_Integer n = luaL_checkinteger(L, 2);
|
lua_Integer n = luaL_checkinteger(L, 2);
|
||||||
const char *sep = luaL_optlstring(L, 3, "", &lsep);
|
const char *sep = luaL_optlstring(L, 3, "", &lsep);
|
||||||
if (n <= 0)
|
if (n <= 0 || (len | lsep) == 0)
|
||||||
lua_pushliteral(L, "");
|
lua_pushliteral(L, ""); /* no repetitions or both strings empty */
|
||||||
else if (l_unlikely(l + lsep < l || l + lsep > MAX_SIZE / cast_sizet(n)))
|
else if (l_unlikely(len > MAX_SIZE - lsep ||
|
||||||
|
cast_st2S(len + lsep) > cast_st2S(MAX_SIZE) / n))
|
||||||
return luaL_error(L, "resulting string too large");
|
return luaL_error(L, "resulting string too large");
|
||||||
else {
|
else {
|
||||||
size_t totallen = ((size_t)n * (l + lsep)) - lsep;
|
size_t totallen = (cast_sizet(n) * (len + lsep)) - lsep;
|
||||||
luaL_Buffer b;
|
luaL_Buffer b;
|
||||||
char *p = luaL_buffinitsize(L, &b, totallen);
|
char *p = luaL_buffinitsize(L, &b, totallen);
|
||||||
while (n-- > 1) { /* first n-1 copies (followed by separator) */
|
while (n-- > 1) { /* first n-1 copies (followed by separator) */
|
||||||
memcpy(p, s, l * sizeof(char)); p += l;
|
memcpy(p, s, len * sizeof(char)); p += len;
|
||||||
if (lsep > 0) { /* empty 'memcpy' is not that cheap */
|
if (lsep > 0) { /* empty 'memcpy' is not that cheap */
|
||||||
memcpy(p, sep, lsep * sizeof(char));
|
memcpy(p, sep, lsep * sizeof(char)); p += lsep;
|
||||||
p += lsep;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
memcpy(p, s, l * sizeof(char)); /* last copy (not followed by separator) */
|
memcpy(p, s, len * sizeof(char)); /* last copy without separator */
|
||||||
luaL_pushresultsize(&b, totallen);
|
luaL_pushresultsize(&b, totallen);
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
@@ -265,11 +269,18 @@ static int tonum (lua_State *L, int arg) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void trymt (lua_State *L, const char *mtname) {
|
/*
|
||||||
|
** 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) {
|
||||||
lua_settop(L, 2); /* back to the original arguments */
|
lua_settop(L, 2); /* back to the original arguments */
|
||||||
if (l_unlikely(lua_type(L, 2) == LUA_TSTRING ||
|
if (l_unlikely(lua_type(L, 2) == LUA_TSTRING ||
|
||||||
!luaL_getmetafield(L, 2, mtname)))
|
!luaL_getmetafield(L, 2, mtkey)))
|
||||||
luaL_error(L, "attempt to %s a '%s' with a '%s'", mtname + 2,
|
luaL_error(L, "attempt to %s a '%s' with a '%s'", opname,
|
||||||
luaL_typename(L, -2), luaL_typename(L, -1));
|
luaL_typename(L, -2), luaL_typename(L, -1));
|
||||||
lua_insert(L, -3); /* put metamethod before arguments */
|
lua_insert(L, -3); /* put metamethod before arguments */
|
||||||
lua_call(L, 2, 1); /* call metamethod */
|
lua_call(L, 2, 1); /* call metamethod */
|
||||||
@@ -280,7 +291,7 @@ static int arith (lua_State *L, int op, const char *mtname) {
|
|||||||
if (tonum(L, 1) && tonum(L, 2))
|
if (tonum(L, 1) && tonum(L, 2))
|
||||||
lua_arith(L, op); /* result will be on the top */
|
lua_arith(L, op); /* result will be on the top */
|
||||||
else
|
else
|
||||||
trymt(L, mtname);
|
trymt(L, mtname, mtname + 2);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -746,19 +757,25 @@ 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,
|
static void prepstate (MatchState *ms, lua_State *L,
|
||||||
const char *s, size_t ls, const char *p, size_t lp) {
|
const char *s, size_t ls, const char *p, size_t lp) {
|
||||||
ms->L = L;
|
ms->L = L;
|
||||||
ms->matchdepth = MAXCCALLS;
|
|
||||||
ms->src_init = s;
|
ms->src_init = s;
|
||||||
ms->src_end = s + ls;
|
ms->src_end = s + ls;
|
||||||
ms->p_end = p + lp;
|
ms->p_end = p + lp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** (Re)prepare state for a match, setting fields that change during
|
||||||
|
** each match.
|
||||||
|
*/
|
||||||
static void reprepstate (MatchState *ms) {
|
static void reprepstate (MatchState *ms) {
|
||||||
|
ms->matchdepth = MAXCCALLS;
|
||||||
ms->level = 0;
|
ms->level = 0;
|
||||||
lua_assert(ms->matchdepth == MAXCCALLS);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -957,7 +974,7 @@ static int str_gsub (lua_State *L) {
|
|||||||
reprepstate(&ms); /* (re)prepare state for new match */
|
reprepstate(&ms); /* (re)prepare state for new match */
|
||||||
if ((e = match(&ms, src, p)) != NULL && e != lastmatch) { /* match? */
|
if ((e = match(&ms, src, p)) != NULL && e != lastmatch) { /* match? */
|
||||||
n++;
|
n++;
|
||||||
changed = add_value(&ms, &b, src, e, tr) | changed;
|
changed = add_value(&ms, &b, src, e, tr) || changed;
|
||||||
src = lastmatch = e;
|
src = lastmatch = e;
|
||||||
}
|
}
|
||||||
else if (src < ms.src_end) /* otherwise, skip one character */
|
else if (src < ms.src_end) /* otherwise, skip one character */
|
||||||
@@ -1715,7 +1732,7 @@ static int str_packsize (lua_State *L) {
|
|||||||
luaL_argcheck(L, opt != Kstring && opt != Kzstr, 1,
|
luaL_argcheck(L, opt != Kstring && opt != Kzstr, 1,
|
||||||
"variable-length format");
|
"variable-length format");
|
||||||
size += ntoalign; /* total space used by option */
|
size += ntoalign; /* total space used by option */
|
||||||
luaL_argcheck(L, totalsize <= LUA_MAXINTEGER - size,
|
luaL_argcheck(L, totalsize <= MAX_SIZE - size,
|
||||||
1, "format result too large");
|
1, "format result too large");
|
||||||
totalsize += size;
|
totalsize += size;
|
||||||
}
|
}
|
||||||
@@ -1811,8 +1828,8 @@ static int str_unpack (lua_State *L) {
|
|||||||
lua_Unsigned len = (lua_Unsigned)unpackint(L, data + pos,
|
lua_Unsigned len = (lua_Unsigned)unpackint(L, data + pos,
|
||||||
h.islittle, cast_int(size), 0);
|
h.islittle, cast_int(size), 0);
|
||||||
luaL_argcheck(L, len <= ld - pos - size, 2, "data string too short");
|
luaL_argcheck(L, len <= ld - pos - size, 2, "data string too short");
|
||||||
lua_pushlstring(L, data + pos + size, len);
|
lua_pushlstring(L, data + pos + size, cast_sizet(len));
|
||||||
pos += len; /* skip string */
|
pos += cast_sizet(len); /* skip string */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Kzstr: {
|
case Kzstr: {
|
||||||
|
|||||||
@@ -156,7 +156,7 @@ static Node *hashint (const Table *t, lua_Integer i) {
|
|||||||
** The main computation should be just
|
** The main computation should be just
|
||||||
** n = frexp(n, &i); return (n * INT_MAX) + i
|
** n = frexp(n, &i); return (n * INT_MAX) + i
|
||||||
** but there are some numerical subtleties.
|
** but there are some numerical subtleties.
|
||||||
** In a two-complement representation, INT_MAX does not has an exact
|
** In a two-complement representation, INT_MAX may not have an exact
|
||||||
** representation as a float, but INT_MIN does; because the absolute
|
** representation as a float, but INT_MIN does; because the absolute
|
||||||
** value of 'frexp' is smaller than 1 (unless 'n' is inf/NaN), the
|
** 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
|
** absolute value of the product 'frexp * -INT_MIN' is smaller or equal
|
||||||
@@ -234,41 +234,51 @@ l_sinline Node *mainpositionfromnode (const Table *t, Node *nd) {
|
|||||||
** Check whether key 'k1' is equal to the key in node 'n2'. This
|
** Check whether key 'k1' is equal to the key in node 'n2'. This
|
||||||
** equality is raw, so there are no metamethods. Floats with integer
|
** equality is raw, so there are no metamethods. Floats with integer
|
||||||
** values have been normalized, so integers cannot be equal to
|
** values have been normalized, so integers cannot be equal to
|
||||||
** floats. It is assumed that 'eqshrstr' is simply pointer equality, so
|
** floats. It is assumed that 'eqshrstr' is simply pointer equality,
|
||||||
** that short strings are handled in the default case.
|
** so that short strings are handled in the default case. The flag
|
||||||
** A true 'deadok' means to accept dead keys as equal to their original
|
** 'deadok' means to accept dead keys as equal to their original values.
|
||||||
** values. All dead keys are compared in the default case, by pointer
|
** (Only collectable objects can produce dead keys.) Note that dead
|
||||||
** identity. (Only collectable objects can produce dead keys.) Note that
|
** long strings are also compared by identity. Once a key is dead,
|
||||||
** dead long strings are also compared by identity.
|
** its corresponding value may be collected, and then another value
|
||||||
** Once a key is dead, its corresponding value may be collected, and
|
** can be created with the same address. If this other value is given
|
||||||
** then another value can be created with the same address. If this
|
** to 'next', 'equalkey' will signal a false positive. In a regular
|
||||||
** other value is given to 'next', 'equalkey' will signal a false
|
** traversal, this situation should never happen, as all keys given to
|
||||||
** positive. In a regular traversal, this situation should never happen,
|
** 'next' came from the table itself, and therefore could not have been
|
||||||
** as all keys given to 'next' came from the table itself, and therefore
|
** collected. Outside a regular traversal, we have garbage in, garbage
|
||||||
** could not have been collected. Outside a regular traversal, we
|
** out. What is relevant is that this false positive does not break
|
||||||
** have garbage in, garbage out. What is relevant is that this false
|
** anything. (In particular, 'next' will return some other valid item
|
||||||
** positive does not break anything. (In particular, 'next' will return
|
** on the table or nil.)
|
||||||
** some other valid item on the table or nil.)
|
|
||||||
*/
|
*/
|
||||||
static int equalkey (const TValue *k1, const Node *n2, int deadok) {
|
static int equalkey (const TValue *k1, const Node *n2, int deadok) {
|
||||||
if ((rawtt(k1) != keytt(n2)) && /* not the same variants? */
|
if (rawtt(k1) != keytt(n2)) { /* not the same variants? */
|
||||||
!(deadok && keyisdead(n2) && iscollectable(k1)))
|
if (keyisshrstr(n2) && ttislngstring(k1)) {
|
||||||
return 0; /* cannot be same key */
|
/* an external string can be equal to a short-string key */
|
||||||
switch (keytt(n2)) {
|
return luaS_eqstr(tsvalue(k1), keystrval(n2));
|
||||||
case LUA_VNIL: case LUA_VFALSE: case LUA_VTRUE:
|
}
|
||||||
return 1;
|
else if (deadok && keyisdead(n2) && iscollectable(k1)) {
|
||||||
case LUA_VNUMINT:
|
/* a collectable value can be equal to a dead key */
|
||||||
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));
|
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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -641,10 +651,9 @@ static void reinserthash (lua_State *L, Table *ot, Table *t) {
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Exchange the hash part of 't1' and 't2'. (In 'flags', only the
|
** Exchange the hash part of 't1' and 't2'. (In 'flags', only the dummy
|
||||||
** dummy bit must be exchanged: The 'isrealasize' is not related
|
** bit must be exchanged: The metamethod bits do not change during a
|
||||||
** to the hash part, and the metamethod bits do not change during
|
** resize, so the "real" table can keep their values.)
|
||||||
** a resize, so the "real" table can keep their values.)
|
|
||||||
*/
|
*/
|
||||||
static void exchangehashpart (Table *t1, Table *t2) {
|
static void exchangehashpart (Table *t1, Table *t2) {
|
||||||
lu_byte lsizenode = t1->lsizenode;
|
lu_byte lsizenode = t1->lsizenode;
|
||||||
@@ -1146,19 +1155,28 @@ void luaH_finishset (lua_State *L, Table *t, const TValue *key,
|
|||||||
lua_assert(hres != HOK);
|
lua_assert(hres != HOK);
|
||||||
if (hres == HNOTFOUND) {
|
if (hres == HNOTFOUND) {
|
||||||
TValue aux;
|
TValue aux;
|
||||||
|
const TValue *actk = key; /* actual key to insert */
|
||||||
if (l_unlikely(ttisnil(key)))
|
if (l_unlikely(ttisnil(key)))
|
||||||
luaG_runerror(L, "table index is nil");
|
luaG_runerror(L, "table index is nil");
|
||||||
else if (ttisfloat(key)) {
|
else if (ttisfloat(key)) {
|
||||||
lua_Number f = fltvalue(key);
|
lua_Number f = fltvalue(key);
|
||||||
lua_Integer k;
|
lua_Integer k;
|
||||||
if (luaV_flttointeger(f, &k, F2Ieq)) {
|
if (luaV_flttointeger(f, &k, F2Ieq)) { /* is key equal to an integer? */
|
||||||
setivalue(&aux, k); /* key is equal to an integer */
|
setivalue(&aux, k);
|
||||||
key = &aux; /* insert it as an integer */
|
actk = &aux; /* use the integer as the key */
|
||||||
}
|
}
|
||||||
else if (l_unlikely(luai_numisnan(f)))
|
else if (l_unlikely(luai_numisnan(f)))
|
||||||
luaG_runerror(L, "table index is NaN");
|
luaG_runerror(L, "table index is NaN");
|
||||||
}
|
}
|
||||||
luaH_newkey(L, t, key, value);
|
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);
|
||||||
}
|
}
|
||||||
else if (hres > 0) { /* regular Node? */
|
else if (hres > 0) { /* regular Node? */
|
||||||
setobj2t(L, gval(gnode(t, hres - HFIRSTNODE)), value);
|
setobj2t(L, gval(gnode(t, hres - HFIRSTNODE)), value);
|
||||||
@@ -1202,24 +1220,36 @@ 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
|
** Try to find a boundary in the hash part of table 't'. From the
|
||||||
** caller, we know that 'j' is zero or present and that 'j + 1' is
|
** caller, we know that 'asize + 1' is present. We want to find a larger
|
||||||
** present. We want to find a larger key that is absent from the
|
** key that is absent from the table, so that we can do a binary search
|
||||||
** table, so that we can do a binary search between the two keys to
|
** between the two keys to find a boundary. We keep doubling 'j' until
|
||||||
** find a boundary. We keep doubling 'j' until we get an absent index.
|
** we get an absent index. If the doubling would overflow, we try
|
||||||
** If the doubling would overflow, we try LUA_MAXINTEGER. If it is
|
** LUA_MAXINTEGER. If it is absent, we are ready for the binary search.
|
||||||
** absent, we are ready for the binary search. ('j', being max integer,
|
** ('j', being max integer, is larger or equal to 'i', but it cannot be
|
||||||
** is larger or equal to 'i', but it cannot be equal because it is
|
** equal because it is absent while 'i' is present.) Otherwise, 'j' is a
|
||||||
** 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
|
||||||
** boundary. ('j + 1' cannot be a present integer key because it is
|
** a valid integer in Lua.)
|
||||||
** 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.
|
||||||
*/
|
*/
|
||||||
static lua_Unsigned hash_search (Table *t, lua_Unsigned j) {
|
static lua_Unsigned hash_search (lua_State *L, Table *t, unsigned asize) {
|
||||||
lua_Unsigned i;
|
lua_Unsigned i = asize + 1; /* caller ensures t[i] is present */
|
||||||
if (j == 0) j++; /* the caller ensures 'j + 1' is present */
|
unsigned rnd = G(L)->seed;
|
||||||
do {
|
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] */
|
||||||
i = j; /* 'i' is a present index */
|
i = j; /* 'i' is a present index */
|
||||||
if (j <= l_castS2U(LUA_MAXINTEGER) / 2)
|
if (j <= l_castS2U(LUA_MAXINTEGER)/2 - 1) {
|
||||||
j *= 2;
|
j = j*2 + (rnd & 1); /* try again with 2j or 2j+1 */
|
||||||
|
rnd >>= 1;
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
j = LUA_MAXINTEGER;
|
j = LUA_MAXINTEGER;
|
||||||
if (hashkeyisempty(t, j)) /* t[j] not present? */
|
if (hashkeyisempty(t, j)) /* t[j] not present? */
|
||||||
@@ -1227,7 +1257,7 @@ static lua_Unsigned hash_search (Table *t, lua_Unsigned j) {
|
|||||||
else /* weird case */
|
else /* weird case */
|
||||||
return j; /* well, max integer is a boundary... */
|
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 */
|
/* i < j && t[i] present && t[j] absent */
|
||||||
while (j - i > 1u) { /* do a binary search between them */
|
while (j - i > 1u) { /* do a binary search between them */
|
||||||
lua_Unsigned m = (i + j) / 2;
|
lua_Unsigned m = (i + j) / 2;
|
||||||
@@ -1268,7 +1298,7 @@ static lua_Unsigned newhint (Table *t, unsigned hint) {
|
|||||||
** If there is no array part, or its last element is non empty, the
|
** If there is no array part, or its last element is non empty, the
|
||||||
** border may be in the hash part.
|
** border may be in the hash part.
|
||||||
*/
|
*/
|
||||||
lua_Unsigned luaH_getn (Table *t) {
|
lua_Unsigned luaH_getn (lua_State *L, Table *t) {
|
||||||
unsigned asize = t->asize;
|
unsigned asize = t->asize;
|
||||||
if (asize > 0) { /* is there an array part? */
|
if (asize > 0) { /* is there an array part? */
|
||||||
const unsigned maxvicinity = 4;
|
const unsigned maxvicinity = 4;
|
||||||
@@ -1309,7 +1339,7 @@ lua_Unsigned luaH_getn (Table *t) {
|
|||||||
if (isdummy(t) || hashkeyisempty(t, asize + 1))
|
if (isdummy(t) || hashkeyisempty(t, asize + 1))
|
||||||
return asize; /* 'asize + 1' is empty */
|
return asize; /* 'asize + 1' is empty */
|
||||||
else /* 'asize + 1' is also non empty */
|
else /* 'asize + 1' is also non empty */
|
||||||
return hash_search(t, asize);
|
return hash_search(L, t, asize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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 lu_mem luaH_size (Table *t);
|
||||||
LUAI_FUNC void luaH_free (lua_State *L, 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 int luaH_next (lua_State *L, Table *t, StkId key);
|
||||||
LUAI_FUNC lua_Unsigned luaH_getn (Table *t);
|
LUAI_FUNC lua_Unsigned luaH_getn (lua_State *L, Table *t);
|
||||||
|
|
||||||
|
|
||||||
#if defined(LUA_DEBUG)
|
#if defined(LUA_DEBUG)
|
||||||
|
|||||||
@@ -42,15 +42,17 @@ 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,
|
** 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) {
|
static void checktab (lua_State *L, int arg, int what) {
|
||||||
if (lua_type(L, arg) != LUA_TTABLE) { /* is it not a table? */
|
int tp = lua_type(L, arg);
|
||||||
|
if (tp != LUA_TTABLE) { /* is it not a table? */
|
||||||
int n = 1; /* number of elements to pop */
|
int n = 1; /* number of elements to pop */
|
||||||
if (lua_getmetatable(L, arg) && /* must have metatable */
|
if (lua_getmetatable(L, arg) && /* must have metatable */
|
||||||
(!(what & TAB_R) || checkfield(L, "__index", ++n)) &&
|
(!(what & TAB_R) || checkfield(L, "__index", ++n)) &&
|
||||||
(!(what & TAB_W) || checkfield(L, "__newindex", ++n)) &&
|
(!(what & TAB_W) || checkfield(L, "__newindex", ++n)) &&
|
||||||
(!(what & TAB_L) || checkfield(L, "__len", ++n))) {
|
(!(what & TAB_L) || /* strings don't need '__len' to have a length */
|
||||||
|
tp == LUA_TSTRING || checkfield(L, "__len", ++n))) {
|
||||||
lua_pop(L, n); /* pop metatable and tested metamethods */
|
lua_pop(L, n); /* pop metatable and tested metamethods */
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -204,8 +206,9 @@ static int tpack (lua_State *L) {
|
|||||||
|
|
||||||
static int tunpack (lua_State *L) {
|
static int tunpack (lua_State *L) {
|
||||||
lua_Unsigned n;
|
lua_Unsigned n;
|
||||||
|
lua_Integer len = aux_getn(L, 1, TAB_R);
|
||||||
lua_Integer i = luaL_optinteger(L, 2, 1);
|
lua_Integer i = luaL_optinteger(L, 2, 1);
|
||||||
lua_Integer e = luaL_opt(L, luaL_checkinteger, 3, luaL_len(L, 1));
|
lua_Integer e = luaL_opt(L, luaL_checkinteger, 3, len);
|
||||||
if (i > e) return 0; /* empty range */
|
if (i > e) return 0; /* empty range */
|
||||||
n = l_castS2U(e) - l_castS2U(i); /* number of elements minus 1 */
|
n = l_castS2U(e) - l_castS2U(i); /* number of elements minus 1 */
|
||||||
if (l_unlikely(n >= (unsigned int)INT_MAX ||
|
if (l_unlikely(n >= (unsigned int)INT_MAX ||
|
||||||
|
|||||||
@@ -164,13 +164,13 @@ static void warnf (void *ud, const char *msg, int tocont) {
|
|||||||
|
|
||||||
#define MARK 0x55 /* 01010101 (a nice pattern) */
|
#define MARK 0x55 /* 01010101 (a nice pattern) */
|
||||||
|
|
||||||
typedef union Header {
|
typedef union memHeader {
|
||||||
LUAI_MAXALIGN;
|
LUAI_MAXALIGN;
|
||||||
struct {
|
struct {
|
||||||
size_t size;
|
size_t size;
|
||||||
int type;
|
int type;
|
||||||
} d;
|
} d;
|
||||||
} Header;
|
} memHeader;
|
||||||
|
|
||||||
|
|
||||||
#if !defined(EXTERNMEMCHECK)
|
#if !defined(EXTERNMEMCHECK)
|
||||||
@@ -193,14 +193,14 @@ Memcontrol l_memcontrol =
|
|||||||
{0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL}};
|
{0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL}};
|
||||||
|
|
||||||
|
|
||||||
static void freeblock (Memcontrol *mc, Header *block) {
|
static void freeblock (Memcontrol *mc, memHeader *block) {
|
||||||
if (block) {
|
if (block) {
|
||||||
size_t size = block->d.size;
|
size_t size = block->d.size;
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < MARKSIZE; i++) /* check marks after block */
|
for (i = 0; i < MARKSIZE; i++) /* check marks after block */
|
||||||
lua_assert(*(cast_charp(block + 1) + size + i) == MARK);
|
lua_assert(*(cast_charp(block + 1) + size + i) == MARK);
|
||||||
mc->objcount[block->d.type]--;
|
mc->objcount[block->d.type]--;
|
||||||
fillmem(block, sizeof(Header) + size + MARKSIZE); /* erase block */
|
fillmem(block, sizeof(memHeader) + size + MARKSIZE); /* erase block */
|
||||||
free(block); /* actually free block */
|
free(block); /* actually free block */
|
||||||
mc->numblocks--; /* update counts */
|
mc->numblocks--; /* update counts */
|
||||||
mc->total -= size;
|
mc->total -= size;
|
||||||
@@ -210,7 +210,7 @@ static void freeblock (Memcontrol *mc, Header *block) {
|
|||||||
|
|
||||||
void *debug_realloc (void *ud, void *b, size_t oldsize, size_t size) {
|
void *debug_realloc (void *ud, void *b, size_t oldsize, size_t size) {
|
||||||
Memcontrol *mc = cast(Memcontrol *, ud);
|
Memcontrol *mc = cast(Memcontrol *, ud);
|
||||||
Header *block = cast(Header *, b);
|
memHeader *block = cast(memHeader *, b);
|
||||||
int type;
|
int type;
|
||||||
if (mc->memlimit == 0) { /* first time? */
|
if (mc->memlimit == 0) { /* first time? */
|
||||||
char *limit = getenv("MEMLIMIT"); /* initialize memory limit */
|
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)
|
if (size > oldsize && mc->total+size-oldsize > mc->memlimit)
|
||||||
return NULL; /* fake a memory allocation error */
|
return NULL; /* fake a memory allocation error */
|
||||||
else {
|
else {
|
||||||
Header *newblock;
|
memHeader *newblock;
|
||||||
int i;
|
int i;
|
||||||
size_t commonsize = (oldsize < size) ? oldsize : size;
|
size_t commonsize = (oldsize < size) ? oldsize : size;
|
||||||
size_t realsize = sizeof(Header) + size + MARKSIZE;
|
size_t realsize = sizeof(memHeader) + size + MARKSIZE;
|
||||||
if (realsize < size) return NULL; /* arithmetic overflow! */
|
if (realsize < size) return NULL; /* arithmetic overflow! */
|
||||||
newblock = cast(Header *, malloc(realsize)); /* alloc a new block */
|
newblock = cast(memHeader *, malloc(realsize)); /* alloc a new block */
|
||||||
if (newblock == NULL)
|
if (newblock == NULL)
|
||||||
return NULL; /* really out of memory? */
|
return NULL; /* really out of memory? */
|
||||||
if (block) {
|
if (block) {
|
||||||
@@ -480,7 +480,7 @@ static int lua_checkpc (CallInfo *ci) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void checkstack (global_State *g, lua_State *L1) {
|
static void check_stack (global_State *g, lua_State *L1) {
|
||||||
StkId o;
|
StkId o;
|
||||||
CallInfo *ci;
|
CallInfo *ci;
|
||||||
UpVal *uv;
|
UpVal *uv;
|
||||||
@@ -517,7 +517,7 @@ static void checkrefs (global_State *g, GCObject *o) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case LUA_VTHREAD: {
|
case LUA_VTHREAD: {
|
||||||
checkstack(g, gco2th(o));
|
check_stack(g, gco2th(o));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case LUA_VLCL: {
|
case LUA_VLCL: {
|
||||||
@@ -908,6 +908,17 @@ 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) {
|
static int mem_query (lua_State *L) {
|
||||||
if (lua_isnone(L, 1)) {
|
if (lua_isnone(L, 1)) {
|
||||||
lua_pushinteger(L, cast_Integer(l_memcontrol.total));
|
lua_pushinteger(L, cast_Integer(l_memcontrol.total));
|
||||||
@@ -1066,8 +1077,12 @@ static int tracegc (lua_State *L) {
|
|||||||
|
|
||||||
static int hash_query (lua_State *L) {
|
static int hash_query (lua_State *L) {
|
||||||
if (lua_isnone(L, 2)) {
|
if (lua_isnone(L, 2)) {
|
||||||
|
TString *ts;
|
||||||
luaL_argcheck(L, lua_type(L, 1) == LUA_TSTRING, 1, "string expected");
|
luaL_argcheck(L, lua_type(L, 1) == LUA_TSTRING, 1, "string expected");
|
||||||
lua_pushinteger(L, cast_int(tsvalue(obj_at(L, 1))->hash));
|
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));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
TValue *o = obj_at(L, 1);
|
TValue *o = obj_at(L, 1);
|
||||||
@@ -1091,6 +1106,27 @@ 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) {
|
static int table_query (lua_State *L) {
|
||||||
const Table *t;
|
const Table *t;
|
||||||
int i = cast_int(luaL_optinteger(L, 2, -1));
|
int i = cast_int(luaL_optinteger(L, 2, -1));
|
||||||
@@ -1109,7 +1145,7 @@ static int table_query (lua_State *L) {
|
|||||||
if (!tagisempty(*getArrTag(t, i)))
|
if (!tagisempty(*getArrTag(t, i)))
|
||||||
arr2obj(t, cast_uint(i), s2v(L->top.p));
|
arr2obj(t, cast_uint(i), s2v(L->top.p));
|
||||||
else
|
else
|
||||||
setnilvalue(s2v(L->top.p));
|
setnilvalue2s(L->top.p);
|
||||||
api_incr_top(L);
|
api_incr_top(L);
|
||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
}
|
}
|
||||||
@@ -1266,7 +1302,7 @@ static int doonnewstack (lua_State *L) {
|
|||||||
lua_State *L1 = lua_newthread(L);
|
lua_State *L1 = lua_newthread(L);
|
||||||
size_t l;
|
size_t l;
|
||||||
const char *s = luaL_checklstring(L, 1, &l);
|
const char *s = luaL_checklstring(L, 1, &l);
|
||||||
int status = luaL_loadbuffer(L1, s, l, s);
|
int status = luaL_loadbufferx(L1, s, l, s, "t");
|
||||||
if (status == LUA_OK)
|
if (status == LUA_OK)
|
||||||
status = lua_pcall(L1, 0, 0, 0);
|
status = lua_pcall(L1, 0, 0, 0);
|
||||||
lua_pushinteger(L, status);
|
lua_pushinteger(L, status);
|
||||||
@@ -1346,7 +1382,7 @@ static int doremote (lua_State *L) {
|
|||||||
const char *code = luaL_checklstring(L, 2, &lcode);
|
const char *code = luaL_checklstring(L, 2, &lcode);
|
||||||
int status;
|
int status;
|
||||||
lua_settop(L1, 0);
|
lua_settop(L1, 0);
|
||||||
status = luaL_loadbuffer(L1, code, lcode, code);
|
status = luaL_loadbufferx(L1, code, lcode, code, "t");
|
||||||
if (status == LUA_OK)
|
if (status == LUA_OK)
|
||||||
status = lua_pcall(L1, 0, LUA_MULTRET, 0);
|
status = lua_pcall(L1, 0, LUA_MULTRET, 0);
|
||||||
if (status != LUA_OK) {
|
if (status != LUA_OK) {
|
||||||
@@ -1702,7 +1738,7 @@ static int runC (lua_State *L, lua_State *L1, const char *pc) {
|
|||||||
lua_pushinteger(L1, luaL_len(L1, getindex));
|
lua_pushinteger(L1, luaL_len(L1, getindex));
|
||||||
}
|
}
|
||||||
else if EQ("loadfile") {
|
else if EQ("loadfile") {
|
||||||
luaL_loadfile(L1, luaL_checkstring(L1, getnum));
|
luaL_loadfilex(L1, luaL_checkstring(L1, getnum), "t");
|
||||||
}
|
}
|
||||||
else if EQ("loadstring") {
|
else if EQ("loadstring") {
|
||||||
size_t slen;
|
size_t slen;
|
||||||
@@ -2167,6 +2203,9 @@ static const struct luaL_Reg tests_funcs[] = {
|
|||||||
{"s2d", s2d},
|
{"s2d", s2d},
|
||||||
{"sethook", sethook},
|
{"sethook", sethook},
|
||||||
{"stacklevel", stacklevel},
|
{"stacklevel", stacklevel},
|
||||||
|
{"resetCI", resetCI},
|
||||||
|
{"reallocstack", reallocstack},
|
||||||
|
{"sizes", get_sizes},
|
||||||
{"testC", testC},
|
{"testC", testC},
|
||||||
{"makeCfunc", makeCfunc},
|
{"makeCfunc", makeCfunc},
|
||||||
{"totalmem", mem_query},
|
{"totalmem", mem_query},
|
||||||
|
|||||||
@@ -13,8 +13,8 @@
|
|||||||
|
|
||||||
/* test Lua with compatibility code */
|
/* test Lua with compatibility code */
|
||||||
#define LUA_COMPAT_MATHLIB
|
#define LUA_COMPAT_MATHLIB
|
||||||
#define LUA_COMPAT_LT_LE
|
|
||||||
#undef LUA_COMPAT_GLOBAL
|
#undef LUA_COMPAT_GLOBAL
|
||||||
|
#define LUA_COMPAT_GLOBAL 0
|
||||||
|
|
||||||
|
|
||||||
#define LUA_DEBUG
|
#define LUA_DEBUG
|
||||||
@@ -64,7 +64,7 @@ LUA_API Memcontrol l_memcontrol;
|
|||||||
|
|
||||||
|
|
||||||
#define luai_tracegc(L,f) luai_tracegctest(L, f)
|
#define luai_tracegc(L,f) luai_tracegctest(L, f)
|
||||||
LUAI_FUNC void luai_tracegctest (lua_State *L, int first);
|
extern 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
|
** Function to traverse and check all memory used by Lua
|
||||||
*/
|
*/
|
||||||
LUAI_FUNC int lua_checkmemory (lua_State *L);
|
extern int lua_checkmemory (lua_State *L);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Function to print an object GC-friendly
|
** Function to print an object GC-friendly
|
||||||
*/
|
*/
|
||||||
struct GCObject;
|
struct GCObject;
|
||||||
LUAI_FUNC void lua_printobj (lua_State *L, struct GCObject *o);
|
extern void lua_printobj (lua_State *L, struct GCObject *o);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Function to print a value
|
** Function to print a value
|
||||||
*/
|
*/
|
||||||
struct TValue;
|
struct TValue;
|
||||||
LUAI_FUNC void lua_printvalue (struct TValue *v);
|
extern void lua_printvalue (struct TValue *v);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Function to print the stack
|
** Function to print the stack
|
||||||
*/
|
*/
|
||||||
LUAI_FUNC void lua_printstack (lua_State *L);
|
extern void lua_printstack (lua_State *L);
|
||||||
LUAI_FUNC int lua_printallstack (lua_State *L);
|
extern int lua_printallstack (lua_State *L);
|
||||||
|
|
||||||
|
|
||||||
/* test for lock/unlock */
|
/* 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,
|
LUA_API void *debug_realloc (void *ud, void *block,
|
||||||
size_t osize, size_t nsize);
|
size_t osize, size_t nsize);
|
||||||
|
|
||||||
#if defined(lua_c)
|
|
||||||
#define luaL_newstate() \
|
#define luaL_newstate() \
|
||||||
lua_newstate(debug_realloc, &l_memcontrol, luaL_makeseed(NULL))
|
lua_newstate(debug_realloc, &l_memcontrol, luaL_makeseed(NULL))
|
||||||
#define luai_openlibs(L) \
|
#define luai_openlibs(L) \
|
||||||
{ luaL_openlibs(L); \
|
{ luaL_openlibs(L); \
|
||||||
luaL_requiref(L, "T", luaB_opentests, 1); \
|
luaL_requiref(L, "T", luaB_opentests, 1); \
|
||||||
lua_pop(L, 1); }
|
lua_pop(L, 1); }
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -143,19 +143,13 @@ LUA_API void *debug_realloc (void *ud, void *block,
|
|||||||
#define STRCACHE_N 23
|
#define STRCACHE_N 23
|
||||||
#define STRCACHE_M 5
|
#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.
|
** Reduce maximum stack size to make stack-overflow tests run faster.
|
||||||
** (But value is still large enough to overflow smaller integers.)
|
** (But value is still large enough to overflow smaller integers.)
|
||||||
*/
|
*/
|
||||||
#undef LUAI_MAXSTACK
|
|
||||||
#define LUAI_MAXSTACK 68000
|
#define LUAI_MAXSTACK 68000
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -196,28 +196,12 @@ void luaT_trybiniTM (lua_State *L, const TValue *p1, lua_Integer i2,
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
** Calls an order tag method.
|
** 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,
|
int luaT_callorderTM (lua_State *L, const TValue *p1, const TValue *p2,
|
||||||
TMS event) {
|
TMS event) {
|
||||||
int tag = callbinTM(L, p1, p2, L->top.p, event); /* try original event */
|
int tag = callbinTM(L, p1, p2, L->top.p, event); /* try original event */
|
||||||
if (tag >= 0) /* found tag method? */
|
if (tag >= 0) /* found tag method? */
|
||||||
return !tagisfalse(tag);
|
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 */
|
luaG_ordererror(L, p1, p2); /* no metamethod found */
|
||||||
return 0; /* to avoid warnings */
|
return 0; /* to avoid warnings */
|
||||||
}
|
}
|
||||||
@@ -240,37 +224,141 @@ int luaT_callorderiTM (lua_State *L, const TValue *p1, int v2,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void luaT_adjustvarargs (lua_State *L, int nfixparams, CallInfo *ci,
|
/*
|
||||||
const Proto *p) {
|
** 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) {
|
||||||
int i;
|
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;
|
ci->u.l.nextraargs = nextra;
|
||||||
luaD_checkstack(L, p->maxstacksize + 1);
|
luaD_checkstack(L, p->maxstacksize + 1);
|
||||||
/* copy function to the top of the stack */
|
/* copy function to the top of the stack, after extra arguments */
|
||||||
setobjs2s(L, L->top.p++, ci->func.p);
|
setobjs2s(L, L->top.p++, ci->func.p);
|
||||||
/* move fixed parameters to the top of the stack */
|
/* move fixed parameters to after the copied function */
|
||||||
for (i = 1; i <= nfixparams; i++) {
|
for (i = 1; i <= nfixparams; i++) {
|
||||||
setobjs2s(L, L->top.p++, ci->func.p + i);
|
setobjs2s(L, L->top.p++, ci->func.p + i);
|
||||||
setnilvalue(s2v(ci->func.p + i)); /* erase original parameter (for GC) */
|
setnilvalue2s(ci->func.p + i); /* erase original parameter (for GC) */
|
||||||
}
|
}
|
||||||
ci->func.p += actual + 1;
|
ci->func.p += totalargs + 1; /* 'func' now lives after hidden arguments */
|
||||||
ci->top.p += actual + 1;
|
ci->top.p += totalargs + 1;
|
||||||
lua_assert(L->top.p <= ci->top.p && ci->top.p <= L->stack_last.p);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void luaT_getvarargs (lua_State *L, CallInfo *ci, StkId where, int wanted) {
|
void luaT_adjustvarargs (lua_State *L, CallInfo *ci, const Proto *p) {
|
||||||
int i;
|
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) {
|
||||||
int nextra = ci->u.l.nextraargs;
|
int nextra = ci->u.l.nextraargs;
|
||||||
if (wanted < 0) {
|
lua_Integer n;
|
||||||
wanted = nextra; /* get all extra arguments available */
|
if (tointegerns(rc, &n)) { /* integral value? */
|
||||||
checkstackp(L, nextra, where); /* ensure stack space */
|
if (l_castS2U(n) - 1 < cast_uint(nextra)) {
|
||||||
L->top.p = where + nextra; /* next instruction will need top */
|
StkId slot = ci->func.p - nextra + cast_int(n) - 1;
|
||||||
|
setobjs2s(((lua_State*)NULL), ra, slot);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for (i = 0; i < wanted && i < nextra; i++)
|
else if (ttisstring(rc)) { /* string value? */
|
||||||
setobjs2s(L, where + i, ci->func.p - nextra + i);
|
size_t len;
|
||||||
for (; i < wanted; i++) /* complete required results with nil */
|
const char *s = getlstr(tsvalue(rc), len);
|
||||||
setnilvalue(s2v(where + i));
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (; i < wanted; i++) /* complete required results with nil */
|
||||||
|
setnilvalue2s(where + i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ typedef enum {
|
|||||||
** Mask with 1 in all fast-access methods. A 1 in any of these bits
|
** 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
|
** in the flag of a (meta)table means the metatable does not have the
|
||||||
** corresponding metamethod field. (Bit 6 of the flag indicates that
|
** corresponding metamethod field. (Bit 6 of the flag indicates that
|
||||||
** the table is using the dummy node; bit 7 is used for 'isrealasize'.)
|
** the table is using the dummy node.)
|
||||||
*/
|
*/
|
||||||
#define maskflags cast_byte(~(~0u << (TM_EQ + 1)))
|
#define maskflags cast_byte(~(~0u << (TM_EQ + 1)))
|
||||||
|
|
||||||
@@ -95,10 +95,11 @@ LUAI_FUNC int luaT_callorderTM (lua_State *L, const TValue *p1,
|
|||||||
LUAI_FUNC int luaT_callorderiTM (lua_State *L, const TValue *p1, int v2,
|
LUAI_FUNC int luaT_callorderiTM (lua_State *L, const TValue *p1, int v2,
|
||||||
int inv, int isfloat, TMS event);
|
int inv, int isfloat, TMS event);
|
||||||
|
|
||||||
LUAI_FUNC void luaT_adjustvarargs (lua_State *L, int nfixparams,
|
LUAI_FUNC void luaT_adjustvarargs (lua_State *L, struct CallInfo *ci,
|
||||||
struct CallInfo *ci, const Proto *p);
|
const Proto *p);
|
||||||
LUAI_FUNC void luaT_getvarargs (lua_State *L, struct CallInfo *ci,
|
LUAI_FUNC void luaT_getvararg (CallInfo *ci, StkId ra, TValue *rc);
|
||||||
StkId where, int wanted);
|
LUAI_FUNC void luaT_getvarargs (lua_State *L, struct CallInfo *ci, StkId where,
|
||||||
|
int wanted, int vatab);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -30,6 +30,12 @@
|
|||||||
#define LUA_INIT_VAR "LUA_INIT"
|
#define LUA_INIT_VAR "LUA_INIT"
|
||||||
#endif
|
#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
|
#define LUA_INITVARVERSION LUA_INIT_VAR LUA_VERSUFFIX
|
||||||
|
|
||||||
|
|
||||||
@@ -201,12 +207,12 @@ static int dochunk (lua_State *L, int status) {
|
|||||||
|
|
||||||
|
|
||||||
static int dofile (lua_State *L, const char *name) {
|
static int dofile (lua_State *L, const char *name) {
|
||||||
return dochunk(L, luaL_loadfile(L, name));
|
return dochunk(L, luaL_loadfilex(L, name, "bt"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int dostring (lua_State *L, const char *s, const char *name) {
|
static int dostring (lua_State *L, const char *s, const char *name) {
|
||||||
return dochunk(L, luaL_loadbuffer(L, s, strlen(s), name));
|
return dochunk(L, luaL_loadbufferx(L, s, strlen(s), name, "t"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -260,7 +266,7 @@ static int handle_script (lua_State *L, char **argv) {
|
|||||||
const char *fname = argv[0];
|
const char *fname = argv[0];
|
||||||
if (strcmp(fname, "-") == 0 && strcmp(argv[-1], "--") != 0)
|
if (strcmp(fname, "-") == 0 && strcmp(argv[-1], "--") != 0)
|
||||||
fname = NULL; /* stdin */
|
fname = NULL; /* stdin */
|
||||||
status = luaL_loadfile(L, fname);
|
status = luaL_loadfilex(L, fname, "bt");
|
||||||
if (status == LUA_OK) {
|
if (status == LUA_OK) {
|
||||||
int n = pushargs(L); /* push arguments to script */
|
int n = pushargs(L); /* push arguments to script */
|
||||||
status = docall(L, n, LUA_MULTRET);
|
status = docall(L, n, LUA_MULTRET);
|
||||||
@@ -303,7 +309,8 @@ static int collectargs (char **argv, int *first) {
|
|||||||
case '-': /* '--' */
|
case '-': /* '--' */
|
||||||
if (argv[i][2] != '\0') /* extra characters after '--'? */
|
if (argv[i][2] != '\0') /* extra characters after '--'? */
|
||||||
return has_error; /* invalid option */
|
return has_error; /* invalid option */
|
||||||
*first = i + 1;
|
/* if there is a script name, it comes after '--' */
|
||||||
|
*first = (argv[i + 1] != NULL) ? i + 1 : 0;
|
||||||
return args;
|
return args;
|
||||||
case '\0': /* '-' */
|
case '\0': /* '-' */
|
||||||
return args; /* script "name" is '-' */
|
return args; /* script "name" is '-' */
|
||||||
@@ -348,6 +355,7 @@ static int collectargs (char **argv, int *first) {
|
|||||||
*/
|
*/
|
||||||
static int runargs (lua_State *L, char **argv, int n) {
|
static int runargs (lua_State *L, char **argv, int n) {
|
||||||
int i;
|
int i;
|
||||||
|
lua_warning(L, "@off", 0); /* by default, Lua stand-alone has warnings off */
|
||||||
for (i = 1; i < n; i++) {
|
for (i = 1; i < n; i++) {
|
||||||
int option = argv[i][1];
|
int option = argv[i][1];
|
||||||
lua_assert(argv[i][0] == '-'); /* already checked */
|
lua_assert(argv[i][0] == '-'); /* already checked */
|
||||||
@@ -372,12 +380,21 @@ 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) {
|
static int handle_luainit (lua_State *L) {
|
||||||
const char *name = "=" LUA_INITVARVERSION;
|
const char *name = "=" LUA_INITVARVERSION;
|
||||||
const char *init = getenv(name + 1);
|
const char *init = l_getenv(name + 1);
|
||||||
if (init == NULL) {
|
if (init == NULL) {
|
||||||
name = "=" LUA_INIT_VAR;
|
name = "=" LUA_INIT_VAR;
|
||||||
init = getenv(name + 1); /* try alternative name */
|
init = l_getenv(name + 1); /* try alternative name */
|
||||||
}
|
}
|
||||||
if (init == NULL) return LUA_OK;
|
if (init == NULL) return LUA_OK;
|
||||||
else if (init[0] == '@')
|
else if (init[0] == '@')
|
||||||
@@ -437,13 +454,24 @@ static int handle_luainit (lua_State *L) {
|
|||||||
** the standard input.
|
** the standard input.
|
||||||
** * lua_saveline defines how to "save" a read line in a "history".
|
** * lua_saveline defines how to "save" a read line in a "history".
|
||||||
** * lua_freeline defines how to free a line read by lua_readline.
|
** * 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) /* { */
|
#if !defined(lua_readline) /* { */
|
||||||
|
/* Otherwise, all previously listed functions should be defined. */
|
||||||
|
|
||||||
/* Code to use the readline library, either statically or dynamically linked */
|
#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) */
|
||||||
|
|
||||||
/* pointer to 'readline' function (if any) */
|
/* pointer to 'readline' function (if any) */
|
||||||
typedef char *(*l_readlineT) (const char *prompt);
|
typedef char *(*l_readlineT) (const char *prompt);
|
||||||
@@ -479,43 +507,41 @@ static void lua_freeline (char *line) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#if defined(LUA_USE_READLINE) /* { */
|
#if defined(LUA_USE_DLOPEN) && defined(LUA_READLINELIB) /* { */
|
||||||
|
|
||||||
/* 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 = cast(l_readlineT, readline);
|
|
||||||
l_addhist = cast(l_addhistT, add_history);
|
|
||||||
}
|
|
||||||
|
|
||||||
#elif defined(LUA_USE_DLOPEN) && defined(LUA_READLINELIB) /* }{ */
|
|
||||||
|
|
||||||
/* try to load 'readline' dynamically */
|
/* try to load 'readline' dynamically */
|
||||||
|
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
|
|
||||||
static void lua_initreadline (lua_State *L) {
|
static void lua_initreadline (lua_State *L) {
|
||||||
void *lib = dlopen(LUA_READLINELIB, RTLD_NOW | RTLD_LOCAL);
|
const char *rllib = l_getenv(LUA_RLLIB_VAR); /* name of readline library */
|
||||||
if (lib == NULL)
|
void *lib; /* library handle */
|
||||||
lua_warning(L, "library '" LUA_READLINELIB "' not found", 0);
|
if (rllib == NULL) /* no environment variable? */
|
||||||
else {
|
rllib = LUA_READLINELIB; /* use default name */
|
||||||
|
lib = dlopen(rllib, RTLD_NOW | RTLD_LOCAL);
|
||||||
|
if (lib != NULL) {
|
||||||
const char **name = cast(const char**, dlsym(lib, "rl_readline_name"));
|
const char **name = cast(const char**, dlsym(lib, "rl_readline_name"));
|
||||||
if (name != NULL)
|
if (name != NULL)
|
||||||
*name = "lua";
|
*name = "lua";
|
||||||
l_readline = cast(l_readlineT, cast_func(dlsym(lib, "readline")));
|
l_readline = cast(l_readlineT, cast_func(dlsym(lib, "readline")));
|
||||||
l_addhist = cast(l_addhistT, cast_func(dlsym(lib, "add_history")));
|
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 /* }{ */
|
#else /* }{ */
|
||||||
|
/* no dlopen or LUA_READLINELIB undefined */
|
||||||
|
|
||||||
/* no readline; leave function pointers as NULL */
|
/* Leave pointers with NULL */
|
||||||
#define lua_initreadline(L) cast(void, L)
|
#define lua_initreadline(L) ((void)L)
|
||||||
|
|
||||||
#endif /* } */
|
#endif /* } */
|
||||||
|
|
||||||
|
#endif /* } */
|
||||||
|
|
||||||
#endif /* } */
|
#endif /* } */
|
||||||
|
|
||||||
@@ -583,11 +609,11 @@ static int pushline (lua_State *L, int firstline) {
|
|||||||
static int addreturn (lua_State *L) {
|
static int addreturn (lua_State *L) {
|
||||||
const char *line = lua_tostring(L, -1); /* original line */
|
const char *line = lua_tostring(L, -1); /* original line */
|
||||||
const char *retline = lua_pushfstring(L, "return %s;", line);
|
const char *retline = lua_pushfstring(L, "return %s;", line);
|
||||||
int status = luaL_loadbuffer(L, retline, strlen(retline), "=stdin");
|
int status = luaL_loadbufferx(L, retline, strlen(retline), "=stdin", "t");
|
||||||
if (status == LUA_OK)
|
if (status == LUA_OK)
|
||||||
lua_remove(L, -2); /* remove modified line */
|
lua_remove(L, -2); /* remove modified line */
|
||||||
else
|
else
|
||||||
lua_pop(L, 2); /* pop result from 'luaL_loadbuffer' and modified line */
|
lua_pop(L, 2); /* pop result from 'luaL_loadbufferx' and modified line */
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -614,7 +640,7 @@ static int multiline (lua_State *L) {
|
|||||||
const char *line = lua_tolstring(L, 1, &len); /* get first line */
|
const char *line = lua_tolstring(L, 1, &len); /* get first line */
|
||||||
checklocal(line);
|
checklocal(line);
|
||||||
for (;;) { /* repeat until gets a complete statement */
|
for (;;) { /* repeat until gets a complete statement */
|
||||||
int status = luaL_loadbuffer(L, line, len, "=stdin"); /* try it */
|
int status = luaL_loadbufferx(L, line, len, "=stdin", "t"); /* try it */
|
||||||
if (!incomplete(L, status) || !pushline(L, 0))
|
if (!incomplete(L, status) || !pushline(L, 0))
|
||||||
return status; /* should not or cannot try to add continuation line */
|
return status; /* should not or cannot try to add continuation line */
|
||||||
lua_remove(L, -2); /* remove error message (from incomplete line) */
|
lua_remove(L, -2); /* remove error message (from incomplete line) */
|
||||||
@@ -688,7 +714,13 @@ static void doREPL (lua_State *L) {
|
|||||||
/* }================================================================== */
|
/* }================================================================== */
|
||||||
|
|
||||||
#if !defined(luai_openlibs)
|
#if !defined(luai_openlibs)
|
||||||
#define luai_openlibs(L) luaL_openselectedlibs(L, ~0, 0)
|
#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
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@@ -710,18 +742,19 @@ static int pmain (lua_State *L) {
|
|||||||
if (args & has_v) /* option '-v'? */
|
if (args & has_v) /* option '-v'? */
|
||||||
print_version();
|
print_version();
|
||||||
if (args & has_E) { /* option '-E'? */
|
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_pushboolean(L, 1); /* signal for libraries to ignore env. vars. */
|
||||||
lua_setfield(L, LUA_REGISTRYINDEX, "LUA_NOENV");
|
lua_setfield(L, LUA_REGISTRYINDEX, "LUA_NOENV");
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
l_getenv = &getenv;
|
||||||
luai_openlibs(L); /* open standard libraries */
|
luai_openlibs(L); /* open standard libraries */
|
||||||
createargtable(L, argv, argc, script); /* create table 'arg' */
|
createargtable(L, argv, argc, script); /* create table 'arg' */
|
||||||
lua_gc(L, LUA_GCRESTART); /* start GC... */
|
lua_gc(L, LUA_GCRESTART); /* start GC... */
|
||||||
lua_gc(L, LUA_GCGEN); /* ...in generational mode */
|
lua_gc(L, LUA_GCGEN); /* ...in generational mode */
|
||||||
if (!(args & has_E)) { /* no option '-E'? */
|
if (handle_luainit(L) != LUA_OK) /* run LUA_INIT */
|
||||||
if (handle_luainit(L) != LUA_OK) /* run LUA_INIT */
|
return 0; /* error running LUA_INIT */
|
||||||
return 0; /* error running LUA_INIT */
|
if (!runargs(L, argv, optlim)) /* execute arguments -e, -l, and -W */
|
||||||
}
|
|
||||||
if (!runargs(L, argv, optlim)) /* execute arguments -e and -l */
|
|
||||||
return 0; /* something failed */
|
return 0; /* something failed */
|
||||||
if (script > 0) { /* execute main script (if there is one) */
|
if (script > 0) { /* execute main script (if there is one) */
|
||||||
if (handle_script(L, argv + script) != LUA_OK)
|
if (handle_script(L, argv + script) != LUA_OK)
|
||||||
|
|||||||
@@ -13,13 +13,13 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
|
|
||||||
#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2025 Lua.org, PUC-Rio"
|
#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2026 Lua.org, PUC-Rio"
|
||||||
#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes"
|
#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes"
|
||||||
|
|
||||||
|
|
||||||
#define LUA_VERSION_MAJOR_N 5
|
#define LUA_VERSION_MAJOR_N 5
|
||||||
#define LUA_VERSION_MINOR_N 5
|
#define LUA_VERSION_MINOR_N 5
|
||||||
#define LUA_VERSION_RELEASE_N 0
|
#define LUA_VERSION_RELEASE_N 1
|
||||||
|
|
||||||
#define LUA_VERSION_NUM (LUA_VERSION_MAJOR_N * 100 + LUA_VERSION_MINOR_N)
|
#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)
|
#define LUA_VERSION_RELEASE_NUM (LUA_VERSION_NUM * 100 + LUA_VERSION_RELEASE_N)
|
||||||
@@ -37,10 +37,10 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
** Pseudo-indices
|
** Pseudo-indices
|
||||||
** (-LUAI_MAXSTACK is the minimum valid index; we keep some free empty
|
** (The stack size is limited to INT_MAX/2; we keep some free empty
|
||||||
** space after that to help overflow detection)
|
** space after that to help overflow detection.)
|
||||||
*/
|
*/
|
||||||
#define LUA_REGISTRYINDEX (-LUAI_MAXSTACK - 1000)
|
#define LUA_REGISTRYINDEX (-(INT_MAX/2 + 1000))
|
||||||
#define lua_upvalueindex(i) (LUA_REGISTRYINDEX - (i))
|
#define lua_upvalueindex(i) (LUA_REGISTRYINDEX - (i))
|
||||||
|
|
||||||
|
|
||||||
@@ -432,13 +432,6 @@ LUA_API void (lua_closeslot) (lua_State *L, int idx);
|
|||||||
** compatibility macros
|
** 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_newuserdata(L,s) lua_newuserdatauv(L,s,1)
|
||||||
#define lua_getuservalue(L,idx) lua_getiuservalue(L,idx,1)
|
#define lua_getuservalue(L,idx) lua_getiuservalue(L,idx,1)
|
||||||
@@ -528,7 +521,7 @@ struct lua_Debug {
|
|||||||
|
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* Copyright (C) 1994-2025 Lua.org, PUC-Rio.
|
* Copyright (C) 1994-2026 Lua.org, PUC-Rio.
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
* a copy of this software and associated documentation files (the
|
* a copy of this software and associated documentation files (the
|
||||||
|
|||||||
@@ -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
|
** application will try to dynamically link a 'readline' facility
|
||||||
** for its REPL. In that case, LUA_READLINELIB is the name of the
|
** 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
|
** library it will look for those facilities. If lua.c cannot open
|
||||||
@@ -70,15 +70,19 @@
|
|||||||
#if defined(LUA_USE_LINUX)
|
#if defined(LUA_USE_LINUX)
|
||||||
#define LUA_USE_POSIX
|
#define LUA_USE_POSIX
|
||||||
#define LUA_USE_DLOPEN /* needs an extra library: -ldl */
|
#define LUA_USE_DLOPEN /* needs an extra library: -ldl */
|
||||||
|
#if !defined(LUA_READLINELIB)
|
||||||
#define LUA_READLINELIB "libreadline.so"
|
#define LUA_READLINELIB "libreadline.so"
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#if defined(LUA_USE_MACOSX)
|
#if defined(LUA_USE_MACOSX)
|
||||||
#define LUA_USE_POSIX
|
#define LUA_USE_POSIX
|
||||||
#define LUA_USE_DLOPEN /* MacOS does not need -ldl */
|
#define LUA_USE_DLOPEN /* macOS does not need -ldl */
|
||||||
|
#if !defined(LUA_READLINELIB)
|
||||||
#define LUA_READLINELIB "libedit.dylib"
|
#define LUA_READLINELIB "libedit.dylib"
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#if defined(LUA_USE_IOS)
|
#if defined(LUA_USE_IOS)
|
||||||
@@ -88,7 +92,7 @@
|
|||||||
|
|
||||||
|
|
||||||
#if defined(LUA_USE_C89) && defined(LUA_USE_POSIX)
|
#if defined(LUA_USE_C89) && defined(LUA_USE_POSIX)
|
||||||
#error "Posix is not compatible with C89"
|
#error "POSIX is not compatible with C89"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@@ -138,7 +142,7 @@
|
|||||||
/*
|
/*
|
||||||
@@ LUA_32BITS enables Lua with 32-bit integers and 32-bit floats.
|
@@ LUA_32BITS enables Lua with 32-bit integers and 32-bit floats.
|
||||||
*/
|
*/
|
||||||
#define LUA_32BITS 0
|
/* #define LUA_32BITS */
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -153,7 +157,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#if LUA_32BITS /* { */
|
#if defined(LUA_32BITS) /* { */
|
||||||
/*
|
/*
|
||||||
** 32-bit integers and 'float'
|
** 32-bit integers and 'float'
|
||||||
*/
|
*/
|
||||||
@@ -224,17 +228,17 @@
|
|||||||
|
|
||||||
#if !defined(LUA_PATH_DEFAULT)
|
#if !defined(LUA_PATH_DEFAULT)
|
||||||
#define LUA_PATH_DEFAULT \
|
#define LUA_PATH_DEFAULT \
|
||||||
LUA_LDIR"?.lua;" LUA_LDIR"?\\init.lua;" \
|
LUA_LDIR "?.lua;" LUA_LDIR "?\\init.lua;" \
|
||||||
LUA_CDIR"?.lua;" LUA_CDIR"?\\init.lua;" \
|
LUA_CDIR "?.lua;" LUA_CDIR "?\\init.lua;" \
|
||||||
LUA_SHRDIR"?.lua;" LUA_SHRDIR"?\\init.lua;" \
|
LUA_SHRDIR "?.lua;" LUA_SHRDIR "?\\init.lua;" \
|
||||||
".\\?.lua;" ".\\?\\init.lua"
|
".\\?.lua;" ".\\?\\init.lua"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(LUA_CPATH_DEFAULT)
|
#if !defined(LUA_CPATH_DEFAULT)
|
||||||
#define LUA_CPATH_DEFAULT \
|
#define LUA_CPATH_DEFAULT \
|
||||||
LUA_CDIR"?.dll;" \
|
LUA_CDIR "?.dll;" \
|
||||||
LUA_CDIR"..\\lib\\lua\\" LUA_VDIR "\\?.dll;" \
|
LUA_CDIR "..\\lib\\lua\\" LUA_VDIR "\\?.dll;" \
|
||||||
LUA_CDIR"loadall.dll;" ".\\?.dll"
|
LUA_CDIR "loadall.dll;" ".\\?.dll"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#else /* }{ */
|
#else /* }{ */
|
||||||
@@ -245,14 +249,14 @@
|
|||||||
|
|
||||||
#if !defined(LUA_PATH_DEFAULT)
|
#if !defined(LUA_PATH_DEFAULT)
|
||||||
#define LUA_PATH_DEFAULT \
|
#define LUA_PATH_DEFAULT \
|
||||||
LUA_LDIR"?.lua;" LUA_LDIR"?/init.lua;" \
|
LUA_LDIR "?.lua;" LUA_LDIR "?/init.lua;" \
|
||||||
LUA_CDIR"?.lua;" LUA_CDIR"?/init.lua;" \
|
LUA_CDIR "?.lua;" LUA_CDIR "?/init.lua;" \
|
||||||
"./?.lua;" "./?/init.lua"
|
"./?.lua;" "./?/init.lua"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(LUA_CPATH_DEFAULT)
|
#if !defined(LUA_CPATH_DEFAULT)
|
||||||
#define 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
|
||||||
|
|
||||||
#endif /* } */
|
#endif /* } */
|
||||||
@@ -319,32 +323,13 @@
|
|||||||
** More often than not the libs go together with the core.
|
** More often than not the libs go together with the core.
|
||||||
*/
|
*/
|
||||||
#define LUALIB_API LUA_API
|
#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
|
#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 */
|
|
||||||
|
|
||||||
/* }================================================================== */
|
/* }================================================================== */
|
||||||
|
|
||||||
@@ -358,15 +343,19 @@
|
|||||||
/*
|
/*
|
||||||
@@ LUA_COMPAT_GLOBAL avoids 'global' being a reserved word
|
@@ LUA_COMPAT_GLOBAL avoids 'global' being a reserved word
|
||||||
*/
|
*/
|
||||||
#define LUA_COMPAT_GLOBAL
|
#if !defined(LUA_COMPAT_GLOBAL)
|
||||||
|
#define LUA_COMPAT_GLOBAL 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ LUA_COMPAT_5_3 controls other macros for compatibility with Lua 5.3.
|
@@ LUA_COMPAT_LOOPVAR makes for-loop control variables not read-only,
|
||||||
** You can define it to get all options, or change specific options
|
** as they were in previous versions.
|
||||||
** to fit your specific needs.
|
|
||||||
*/
|
*/
|
||||||
#if defined(LUA_COMPAT_5_3) /* { */
|
#if !defined(LUA_COMPAT_LOOPVAR)
|
||||||
|
#define LUA_COMPAT_LOOPVAR 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ LUA_COMPAT_MATHLIB controls the presence of several deprecated
|
@@ LUA_COMPAT_MATHLIB controls the presence of several deprecated
|
||||||
@@ -374,23 +363,7 @@
|
|||||||
** (These functions were already officially removed in 5.3;
|
** (These functions were already officially removed in 5.3;
|
||||||
** nevertheless they are still available here.)
|
** 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
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -407,8 +380,6 @@
|
|||||||
#define lua_equal(L,idx1,idx2) lua_compare(L,(idx1),(idx2),LUA_OPEQ)
|
#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)
|
#define lua_lessthan(L,idx1,idx2) lua_compare(L,(idx1),(idx2),LUA_OPLT)
|
||||||
|
|
||||||
#endif /* } */
|
|
||||||
|
|
||||||
/* }================================================================== */
|
/* }================================================================== */
|
||||||
|
|
||||||
|
|
||||||
@@ -440,26 +411,11 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
/* The following definitions are good for most cases here */
|
/* The following definition is good for most cases here */
|
||||||
|
|
||||||
#define l_floor(x) (l_mathop(floor)(x))
|
#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 */
|
/* now the variable definitions */
|
||||||
|
|
||||||
#if LUA_FLOAT_TYPE == LUA_FLOAT_FLOAT /* { single float */
|
#if LUA_FLOAT_TYPE == LUA_FLOAT_FLOAT /* { single float */
|
||||||
@@ -708,7 +664,7 @@
|
|||||||
*/
|
*/
|
||||||
#if !defined(luai_likely)
|
#if !defined(luai_likely)
|
||||||
|
|
||||||
#if defined(__GNUC__) && !defined(LUA_NOBUILTIN)
|
#if !defined(LUA_NOBUILTIN) && defined(__GNUC__) && (__GNUC__ >= 3)
|
||||||
#define luai_likely(x) (__builtin_expect(((x) != 0), 1))
|
#define luai_likely(x) (__builtin_expect(((x) != 0), 1))
|
||||||
#define luai_unlikely(x) (__builtin_expect(((x) != 0), 0))
|
#define luai_unlikely(x) (__builtin_expect(((x) != 0), 0))
|
||||||
#else
|
#else
|
||||||
@@ -719,13 +675,6 @@
|
|||||||
#endif
|
#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
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* }================================================================== */
|
/* }================================================================== */
|
||||||
|
|
||||||
@@ -763,20 +712,6 @@
|
|||||||
** =====================================================================
|
** =====================================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
|
||||||
@@ 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
|
@@ LUA_EXTRASPACE defines the size of a raw memory area associated with
|
||||||
** a Lua state with very fast access.
|
** a Lua state with very fast access.
|
||||||
@@ -801,10 +736,17 @@
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ LUAI_MAXALIGN defines fields that, when used in a union, ensure
|
@@ LUAI_MAXALIGN defines fields that ensure proper alignment for
|
||||||
** maximum alignment for the other items in that union.
|
** memory areas offered by Lua (e.g., userdata memory).
|
||||||
|
** Add fields to it if you need alignment for non-ISO objects.
|
||||||
*/
|
*/
|
||||||
|
#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
|
#define LUAI_MAXALIGN lua_Number n; double u; void *s; lua_Integer i; long l
|
||||||
|
#endif
|
||||||
|
|
||||||
/* }================================================================== */
|
/* }================================================================== */
|
||||||
|
|
||||||
@@ -821,7 +763,5 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ static lua_Unsigned loadVarint (LoadState *S, lua_Unsigned limit) {
|
|||||||
|
|
||||||
|
|
||||||
static size_t loadSize (LoadState *S) {
|
static size_t loadSize (LoadState *S) {
|
||||||
return loadVarint(S, MAX_SIZE);
|
return cast_sizet(loadVarint(S, MAX_SIZE));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -147,20 +147,20 @@ static void loadString (LoadState *S, Proto *p, TString **sl) {
|
|||||||
TString *ts;
|
TString *ts;
|
||||||
TValue sv;
|
TValue sv;
|
||||||
size_t size = loadSize(S);
|
size_t size = loadSize(S);
|
||||||
if (size == 0) { /* no string? */
|
if (size == 0) { /* previously saved 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 */
|
lua_Unsigned idx = loadVarint(S, LUA_MAXUNSIGNED); /* get its index */
|
||||||
TValue stv;
|
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)
|
if (novariant(luaH_getint(S->h, l_castU2S(idx), &stv)) != LUA_TSTRING)
|
||||||
error(S, "invalid string index");
|
error(S, "invalid string index");
|
||||||
*sl = ts = tsvalue(&stv); /* get its value */
|
*sl = ts = tsvalue(&stv); /* get its value */
|
||||||
luaC_objbarrier(L, p, ts);
|
luaC_objbarrier(L, p, ts);
|
||||||
return; /* do not save it again */
|
return; /* do not save it again */
|
||||||
}
|
}
|
||||||
else if ((size -= 2) <= LUAI_MAXSHORTLEN) { /* short string? */
|
else if ((size -= 1) <= LUAI_MAXSHORTLEN) { /* short string? */
|
||||||
char buff[LUAI_MAXSHORTLEN + 1]; /* extra space for '\0' */
|
char buff[LUAI_MAXSHORTLEN + 1]; /* extra space for '\0' */
|
||||||
loadVector(S, buff, size + 1); /* load string into buffer */
|
loadVector(S, buff, size + 1); /* load string into buffer */
|
||||||
*sl = ts = luaS_newlstr(L, buff, size); /* create string */
|
*sl = ts = luaS_newlstr(L, buff, size); /* create string */
|
||||||
@@ -327,7 +327,8 @@ static void loadFunction (LoadState *S, Proto *f) {
|
|||||||
f->linedefined = loadInt(S);
|
f->linedefined = loadInt(S);
|
||||||
f->lastlinedefined = loadInt(S);
|
f->lastlinedefined = loadInt(S);
|
||||||
f->numparams = loadByte(S);
|
f->numparams = loadByte(S);
|
||||||
f->flag = loadByte(S) & PF_ISVARARG; /* get only the meaningful flags */
|
/* get only the meaningful flags */
|
||||||
|
f->flag = cast_byte(loadByte(S) & ~PF_FIXED);
|
||||||
if (S->fixed)
|
if (S->fixed)
|
||||||
f->flag |= PF_FIXED; /* signal that code is fixed */
|
f->flag |= PF_FIXED; /* signal that code is fixed */
|
||||||
f->maxstacksize = loadByte(S);
|
f->maxstacksize = loadByte(S);
|
||||||
@@ -391,7 +392,8 @@ static void checkHeader (LoadState *S) {
|
|||||||
/*
|
/*
|
||||||
** Load precompiled chunk.
|
** Load precompiled chunk.
|
||||||
*/
|
*/
|
||||||
LClosure *luaU_undump (lua_State *L, ZIO *Z, const char *name, int fixed) {
|
LClosure *luaU_undump (lua_State *L, ZIO *Z, Table *anchor, const char *name,
|
||||||
|
int fixed) {
|
||||||
LoadState S;
|
LoadState S;
|
||||||
LClosure *cl;
|
LClosure *cl;
|
||||||
if (*name == '@' || *name == '=')
|
if (*name == '@' || *name == '=')
|
||||||
@@ -404,20 +406,16 @@ LClosure *luaU_undump (lua_State *L, ZIO *Z, const char *name, int fixed) {
|
|||||||
S.fixed = cast_byte(fixed);
|
S.fixed = cast_byte(fixed);
|
||||||
S.offset = 1; /* fist byte was already read */
|
S.offset = 1; /* fist byte was already read */
|
||||||
checkHeader(&S);
|
checkHeader(&S);
|
||||||
cl = luaF_newLclosure(L, loadByte(&S));
|
S.h = anchor;
|
||||||
setclLvalue2s(L, L->top.p, cl);
|
|
||||||
luaD_inctop(L);
|
|
||||||
S.h = luaH_new(L); /* create list of saved strings */
|
|
||||||
S.nstr = 0;
|
S.nstr = 0;
|
||||||
sethvalue2s(L, L->top.p, S.h); /* anchor it */
|
cl = luaF_newLclosure(L, loadByte(&S));
|
||||||
luaD_inctop(L);
|
luaD_anchorobj(L, anchor, obj2gco(cl));
|
||||||
cl->p = luaF_newproto(L);
|
cl->p = luaF_newproto(L);
|
||||||
luaC_objbarrier(L, cl, cl->p);
|
luaC_objbarrier(L, cl, cl->p);
|
||||||
loadFunction(&S, cl->p);
|
loadFunction(&S, cl->p);
|
||||||
if (cl->nupvalues != cl->p->sizeupvalues)
|
if (cl->nupvalues != cl->p->sizeupvalues)
|
||||||
error(&S, "corrupted chunk");
|
error(&S, "corrupted chunk");
|
||||||
luai_verifycode(L, cl->p);
|
luai_verifycode(L, cl->p);
|
||||||
L->top.p--; /* pop table */
|
|
||||||
return cl;
|
return cl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,8 +30,8 @@
|
|||||||
|
|
||||||
|
|
||||||
/* load one chunk; from lundump.c */
|
/* load one chunk; from lundump.c */
|
||||||
LUAI_FUNC LClosure* luaU_undump (lua_State* L, ZIO* Z, const char* name,
|
LUAI_FUNC LClosure* luaU_undump (lua_State* L, ZIO* Z, Table *anchor,
|
||||||
int fixed);
|
const char* name, int fixed);
|
||||||
|
|
||||||
/* dump one chunk; from ldump.c */
|
/* dump one chunk; from ldump.c */
|
||||||
LUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Writer w,
|
LUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Writer w,
|
||||||
|
|||||||
+11
-8
@@ -10,7 +10,6 @@
|
|||||||
#include "lprefix.h"
|
#include "lprefix.h"
|
||||||
|
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -47,7 +46,7 @@ static lua_Integer u_posrelat (lua_Integer pos, size_t len) {
|
|||||||
** Decode one UTF-8 sequence, returning NULL if byte sequence is
|
** Decode one UTF-8 sequence, returning NULL if byte sequence is
|
||||||
** invalid. The array 'limits' stores the minimum value for each
|
** invalid. The array 'limits' stores the minimum value for each
|
||||||
** sequence length, to check for overlong representations. Its first
|
** 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).
|
** bytes (count == 0).
|
||||||
*/
|
*/
|
||||||
static const char *utf8_decode (const char *s, l_uint32 *val, int strict) {
|
static const char *utf8_decode (const char *s, l_uint32 *val, int strict) {
|
||||||
@@ -55,8 +54,10 @@ static const char *utf8_decode (const char *s, l_uint32 *val, int strict) {
|
|||||||
{~(l_uint32)0, 0x80, 0x800, 0x10000u, 0x200000u, 0x4000000u};
|
{~(l_uint32)0, 0x80, 0x800, 0x10000u, 0x200000u, 0x4000000u};
|
||||||
unsigned int c = (unsigned char)s[0];
|
unsigned int c = (unsigned char)s[0];
|
||||||
l_uint32 res = 0; /* final result */
|
l_uint32 res = 0; /* final result */
|
||||||
if (c < 0x80) /* ascii? */
|
if (c < 0x80) /* ASCII? */
|
||||||
res = c;
|
res = c;
|
||||||
|
else if (c >= 0xfe) /* c >= 1111 1110b ? */
|
||||||
|
return NULL; /* would need six or more continuation bytes */
|
||||||
else {
|
else {
|
||||||
int count = 0; /* to count number of continuation bytes */
|
int count = 0; /* to count number of continuation bytes */
|
||||||
for (; c & 0x40; c <<= 1) { /* while it needs continuation bytes... */
|
for (; c & 0x40; c <<= 1) { /* while it needs continuation bytes... */
|
||||||
@@ -65,8 +66,9 @@ static const char *utf8_decode (const char *s, l_uint32 *val, int strict) {
|
|||||||
return NULL; /* invalid byte sequence */
|
return NULL; /* invalid byte sequence */
|
||||||
res = (res << 6) | (cc & 0x3F); /* add lower 6 bits from cont. byte */
|
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 */
|
res |= ((l_uint32)(c & 0x7F) << (count * 5)); /* add first byte */
|
||||||
if (count > 5 || res > MAXUTF || res < limits[count])
|
if (res > MAXUTF || res < limits[count])
|
||||||
return NULL; /* invalid byte sequence */
|
return NULL; /* invalid byte sequence */
|
||||||
s += count; /* skip continuation bytes read */
|
s += count; /* skip continuation bytes read */
|
||||||
}
|
}
|
||||||
@@ -147,7 +149,7 @@ static int codepoint (lua_State *L) {
|
|||||||
static void pushutfchar (lua_State *L, int arg) {
|
static void pushutfchar (lua_State *L, int arg) {
|
||||||
lua_Unsigned code = (lua_Unsigned)luaL_checkinteger(L, arg);
|
lua_Unsigned code = (lua_Unsigned)luaL_checkinteger(L, arg);
|
||||||
luaL_argcheck(L, code <= MAXUTF, arg, "value out of range");
|
luaL_argcheck(L, code <= MAXUTF, arg, "value out of range");
|
||||||
lua_pushfstring(L, "%U", (long)code);
|
lua_pushfstring(L, "%U", cast(unsigned long, code));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -215,9 +217,10 @@ static int byteoffset (lua_State *L) {
|
|||||||
}
|
}
|
||||||
lua_pushinteger(L, posi + 1); /* initial position */
|
lua_pushinteger(L, posi + 1); /* initial position */
|
||||||
if ((s[posi] & 0x80) != 0) { /* multi-byte character? */
|
if ((s[posi] & 0x80) != 0) { /* multi-byte character? */
|
||||||
do {
|
if (iscont(s[posi]))
|
||||||
posi++;
|
return luaL_error(L, "initial position is a continuation byte");
|
||||||
} while (iscontp(s + posi + 1)); /* skip to final byte */
|
while (iscontp(s + posi + 1))
|
||||||
|
posi++; /* skip to last continuation byte */
|
||||||
}
|
}
|
||||||
/* else one-byte character: final position is the initial one */
|
/* else one-byte character: final position is the initial one */
|
||||||
lua_pushinteger(L, posi + 1); /* 'posi' now is the final position */
|
lua_pushinteger(L, posi + 1); /* 'posi' now is the final position */
|
||||||
|
|||||||
@@ -268,9 +268,9 @@ static int forprep (lua_State *L, StkId ra) {
|
|||||||
/*
|
/*
|
||||||
** Execute a step of a float numerical for loop, returning
|
** Execute a step of a float numerical for loop, returning
|
||||||
** true iff the loop must continue. (The integer case is
|
** true iff the loop must continue. (The integer case is
|
||||||
** written online with opcode OP_FORLOOP, for performance.)
|
** written inline with opcode OP_FORLOOP, for performance.)
|
||||||
*/
|
*/
|
||||||
static int floatforloop (StkId ra) {
|
static int floatforloop (lua_State *L, StkId ra) {
|
||||||
lua_Number step = fltvalue(s2v(ra + 1));
|
lua_Number step = fltvalue(s2v(ra + 1));
|
||||||
lua_Number limit = fltvalue(s2v(ra));
|
lua_Number limit = fltvalue(s2v(ra));
|
||||||
lua_Number idx = fltvalue(s2v(ra + 2)); /* control variable */
|
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 */
|
else { /* 't' is a table */
|
||||||
tm = fasttm(L, hvalue(t)->metatable, TM_INDEX); /* table's metamethod */
|
tm = fasttm(L, hvalue(t)->metatable, TM_INDEX); /* table's metamethod */
|
||||||
if (tm == NULL) { /* no metamethod? */
|
if (tm == NULL) { /* no metamethod? */
|
||||||
setnilvalue(s2v(val)); /* result is nil */
|
setnilvalue2s(val); /* result is nil */
|
||||||
return LUA_VNIL;
|
return LUA_VNIL;
|
||||||
}
|
}
|
||||||
/* else will try the metamethod */
|
/* else will try the metamethod */
|
||||||
@@ -372,6 +372,14 @@ void luaV_finishset (lua_State *L, const TValue *t, TValue *key,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** 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-
|
** Compare two strings 'ts1' x 'ts2', returning an integer less-equal-
|
||||||
** -greater than zero if 'ts1' is less-equal-greater than 'ts2'.
|
** -greater than zero if 'ts1' is less-equal-greater than 'ts2'.
|
||||||
@@ -386,7 +394,7 @@ static int l_strcmp (const TString *ts1, const TString *ts2) {
|
|||||||
size_t rl2;
|
size_t rl2;
|
||||||
const char *s2 = getlstr(ts2, rl2);
|
const char *s2 = getlstr(ts2, rl2);
|
||||||
for (;;) { /* for each segment */
|
for (;;) { /* for each segment */
|
||||||
int temp = strcoll(s1, s2);
|
int temp = l_strcoll(s1, s2);
|
||||||
if (temp != 0) /* not equal? */
|
if (temp != 0) /* not equal? */
|
||||||
return temp; /* done */
|
return temp; /* done */
|
||||||
else { /* strings are equal up to a '\0' */
|
else { /* strings are equal up to a '\0' */
|
||||||
@@ -573,52 +581,74 @@ int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r) {
|
|||||||
*/
|
*/
|
||||||
int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2) {
|
int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2) {
|
||||||
const TValue *tm;
|
const TValue *tm;
|
||||||
if (ttypetag(t1) != ttypetag(t2)) { /* not the same variant? */
|
if (ttype(t1) != ttype(t2)) /* not the same type? */
|
||||||
if (ttype(t1) != ttype(t2) || ttype(t1) != LUA_TNUMBER)
|
return 0;
|
||||||
return 0; /* only numbers can be equal with different variants */
|
else if (ttypetag(t1) != ttypetag(t2)) {
|
||||||
else { /* two numbers with different variants */
|
switch (ttypetag(t1)) {
|
||||||
/* One of them is an integer. If the other does not have an
|
case LUA_VNUMINT: { /* integer == float? */
|
||||||
integer value, they cannot be equal; otherwise, compare their
|
/* integer and float can only be equal if float has an integer
|
||||||
integer values. */
|
value equal to the integer */
|
||||||
lua_Integer i1, i2;
|
lua_Integer i2;
|
||||||
return (luaV_tointegerns(t1, &i1, F2Ieq) &&
|
return (luaV_flttointeger(fltvalue(t2), &i2, F2Ieq) &&
|
||||||
luaV_tointegerns(t2, &i2, F2Ieq) &&
|
ivalue(t1) == i2);
|
||||||
i1 == 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* values have same type and same variant */
|
else { /* equal variants */
|
||||||
switch (ttypetag(t1)) {
|
switch (ttypetag(t1)) {
|
||||||
case LUA_VNIL: case LUA_VFALSE: case LUA_VTRUE: return 1;
|
case LUA_VNIL: case LUA_VFALSE: case LUA_VTRUE:
|
||||||
case LUA_VNUMINT: return (ivalue(t1) == ivalue(t2));
|
return 1;
|
||||||
case LUA_VNUMFLT: return luai_numeq(fltvalue(t1), fltvalue(t2));
|
case LUA_VNUMINT:
|
||||||
case LUA_VLIGHTUSERDATA: return pvalue(t1) == pvalue(t2);
|
return (ivalue(t1) == ivalue(t2));
|
||||||
case LUA_VLCF: return fvalue(t1) == fvalue(t2);
|
case LUA_VNUMFLT:
|
||||||
case LUA_VSHRSTR: return eqshrstr(tsvalue(t1), tsvalue(t2));
|
return (fltvalue(t1) == fltvalue(t2));
|
||||||
case LUA_VLNGSTR: return luaS_eqlngstr(tsvalue(t1), tsvalue(t2));
|
case LUA_VLIGHTUSERDATA: return pvalue(t1) == pvalue(t2);
|
||||||
case LUA_VUSERDATA: {
|
case LUA_VSHRSTR:
|
||||||
if (uvalue(t1) == uvalue(t2)) return 1;
|
return eqshrstr(tsvalue(t1), tsvalue(t2));
|
||||||
else if (L == NULL) return 0;
|
case LUA_VLNGSTR:
|
||||||
tm = fasttm(L, uvalue(t1)->metatable, TM_EQ);
|
return luaS_eqstr(tsvalue(t1), tsvalue(t2));
|
||||||
if (tm == NULL)
|
case LUA_VUSERDATA: {
|
||||||
tm = fasttm(L, uvalue(t2)->metatable, TM_EQ);
|
if (uvalue(t1) == uvalue(t2)) return 1;
|
||||||
break; /* will try TM */
|
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));
|
||||||
}
|
}
|
||||||
case LUA_VTABLE: {
|
if (tm == NULL) /* no TM? */
|
||||||
if (hvalue(t1) == hvalue(t2)) return 1;
|
return 0; /* objects are different */
|
||||||
else if (L == NULL) return 0;
|
else {
|
||||||
tm = fasttm(L, hvalue(t1)->metatable, TM_EQ);
|
int tag = luaT_callTMres(L, tm, t1, t2, L->top.p); /* call TM */
|
||||||
if (tm == NULL)
|
return !tagisfalse(tag);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -627,6 +657,11 @@ int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2) {
|
|||||||
#define tostring(L,o) \
|
#define tostring(L,o) \
|
||||||
(ttisstring(o) || (cvt2str(o) && (luaO_tostring(L, o), 1)))
|
(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)
|
#define isemptystr(o) (ttisshrstring(o) && tsvalue(o)->shrlen == 0)
|
||||||
|
|
||||||
/* copy strings in stack from top - n up to top - 1 to buffer */
|
/* copy strings in stack from top - n up to top - 1 to buffer */
|
||||||
@@ -661,8 +696,8 @@ void luaV_concat (lua_State *L, int total) {
|
|||||||
setobjs2s(L, top - 2, top - 1); /* result is second op. */
|
setobjs2s(L, top - 2, top - 1); /* result is second op. */
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* at least two non-empty string values; get as many as possible */
|
/* at least two string values; get as many as possible */
|
||||||
size_t tl = tsslen(tsvalue(s2v(top - 1)));
|
size_t tl = tsslen(tsvalue(s2v(top - 1))); /* total length */
|
||||||
TString *ts;
|
TString *ts;
|
||||||
/* collect total length and number of strings */
|
/* collect total length and number of strings */
|
||||||
for (n = 1; n < total && tostring(L, s2v(top - n - 1)); n++) {
|
for (n = 1; n < total && tostring(L, s2v(top - n - 1)); n++) {
|
||||||
@@ -700,7 +735,7 @@ void luaV_objlen (lua_State *L, StkId ra, const TValue *rb) {
|
|||||||
Table *h = hvalue(rb);
|
Table *h = hvalue(rb);
|
||||||
tm = fasttm(L, h->metatable, TM_LEN);
|
tm = fasttm(L, h->metatable, TM_LEN);
|
||||||
if (tm) break; /* metamethod? break switch to call it */
|
if (tm) break; /* metamethod? break switch to call it */
|
||||||
setivalue(s2v(ra), l_castU2S(luaH_getn(h))); /* else primitive len */
|
setivalue(s2v(ra), l_castU2S(luaH_getn(L, h))); /* else primitive len */
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case LUA_VSHRSTR: {
|
case LUA_VSHRSTR: {
|
||||||
@@ -839,12 +874,6 @@ void luaV_finishOp (lua_State *L) {
|
|||||||
case OP_EQ: { /* note that 'OP_EQI'/'OP_EQK' cannot yield */
|
case OP_EQ: { /* note that 'OP_EQI'/'OP_EQK' cannot yield */
|
||||||
int res = !l_isfalse(s2v(L->top.p - 1));
|
int res = !l_isfalse(s2v(L->top.p - 1));
|
||||||
L->top.p--;
|
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);
|
lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_JMP);
|
||||||
if (res != GETARG_k(inst)) /* condition failed? */
|
if (res != GETARG_k(inst)) /* condition failed? */
|
||||||
ci->u.l.savedpc++; /* skip jump instruction */
|
ci->u.l.savedpc++; /* skip jump instruction */
|
||||||
@@ -888,6 +917,10 @@ void luaV_finishOp (lua_State *L) {
|
|||||||
/*
|
/*
|
||||||
** {==================================================================
|
** {==================================================================
|
||||||
** Macros for arithmetic/bitwise/comparison opcodes in 'luaV_execute'
|
** Macros for arithmetic/bitwise/comparison opcodes in 'luaV_execute'
|
||||||
|
**
|
||||||
|
** All these macros are to be used exclusively inside the main
|
||||||
|
** iterpreter loop (function luaV_execute) and may access directly
|
||||||
|
** the local variables of that function (L, i, pc, ci, etc.).
|
||||||
** ===================================================================
|
** ===================================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -909,17 +942,17 @@ void luaV_finishOp (lua_State *L) {
|
|||||||
** operation, 'fop' is the float operation.
|
** operation, 'fop' is the float operation.
|
||||||
*/
|
*/
|
||||||
#define op_arithI(L,iop,fop) { \
|
#define op_arithI(L,iop,fop) { \
|
||||||
StkId ra = RA(i); \
|
TValue *ra = vRA(i); \
|
||||||
TValue *v1 = vRB(i); \
|
TValue *v1 = vRB(i); \
|
||||||
int imm = GETARG_sC(i); \
|
int imm = GETARG_sC(i); \
|
||||||
if (ttisinteger(v1)) { \
|
if (ttisinteger(v1)) { \
|
||||||
lua_Integer iv1 = ivalue(v1); \
|
lua_Integer iv1 = ivalue(v1); \
|
||||||
pc++; setivalue(s2v(ra), iop(L, iv1, imm)); \
|
pc++; setivalue(ra, iop(L, iv1, imm)); \
|
||||||
} \
|
} \
|
||||||
else if (ttisfloat(v1)) { \
|
else if (ttisfloat(v1)) { \
|
||||||
lua_Number nb = fltvalue(v1); \
|
lua_Number nb = fltvalue(v1); \
|
||||||
lua_Number fimm = cast_num(imm); \
|
lua_Number fimm = cast_num(imm); \
|
||||||
pc++; setfltvalue(s2v(ra), fop(L, nb, fimm)); \
|
pc++; setfltvalue(ra, fop(L, nb, fimm)); \
|
||||||
}}
|
}}
|
||||||
|
|
||||||
|
|
||||||
@@ -930,6 +963,7 @@ void luaV_finishOp (lua_State *L) {
|
|||||||
#define op_arithf_aux(L,v1,v2,fop) { \
|
#define op_arithf_aux(L,v1,v2,fop) { \
|
||||||
lua_Number n1; lua_Number n2; \
|
lua_Number n1; lua_Number n2; \
|
||||||
if (tonumberns(v1, n1) && tonumberns(v2, n2)) { \
|
if (tonumberns(v1, n1) && tonumberns(v2, n2)) { \
|
||||||
|
StkId ra = RA(i); \
|
||||||
pc++; setfltvalue(s2v(ra), fop(L, n1, n2)); \
|
pc++; setfltvalue(s2v(ra), fop(L, n1, n2)); \
|
||||||
}}
|
}}
|
||||||
|
|
||||||
@@ -938,7 +972,6 @@ void luaV_finishOp (lua_State *L) {
|
|||||||
** Arithmetic operations over floats and others with register operands.
|
** Arithmetic operations over floats and others with register operands.
|
||||||
*/
|
*/
|
||||||
#define op_arithf(L,fop) { \
|
#define op_arithf(L,fop) { \
|
||||||
StkId ra = RA(i); \
|
|
||||||
TValue *v1 = vRB(i); \
|
TValue *v1 = vRB(i); \
|
||||||
TValue *v2 = vRC(i); \
|
TValue *v2 = vRC(i); \
|
||||||
op_arithf_aux(L, v1, v2, fop); }
|
op_arithf_aux(L, v1, v2, fop); }
|
||||||
@@ -948,7 +981,6 @@ void luaV_finishOp (lua_State *L) {
|
|||||||
** Arithmetic operations with K operands for floats.
|
** Arithmetic operations with K operands for floats.
|
||||||
*/
|
*/
|
||||||
#define op_arithfK(L,fop) { \
|
#define op_arithfK(L,fop) { \
|
||||||
StkId ra = RA(i); \
|
|
||||||
TValue *v1 = vRB(i); \
|
TValue *v1 = vRB(i); \
|
||||||
TValue *v2 = KC(i); lua_assert(ttisnumber(v2)); \
|
TValue *v2 = KC(i); lua_assert(ttisnumber(v2)); \
|
||||||
op_arithf_aux(L, v1, v2, fop); }
|
op_arithf_aux(L, v1, v2, fop); }
|
||||||
@@ -958,8 +990,8 @@ void luaV_finishOp (lua_State *L) {
|
|||||||
** Arithmetic operations over integers and floats.
|
** Arithmetic operations over integers and floats.
|
||||||
*/
|
*/
|
||||||
#define op_arith_aux(L,v1,v2,iop,fop) { \
|
#define op_arith_aux(L,v1,v2,iop,fop) { \
|
||||||
StkId ra = RA(i); \
|
|
||||||
if (ttisinteger(v1) && ttisinteger(v2)) { \
|
if (ttisinteger(v1) && ttisinteger(v2)) { \
|
||||||
|
StkId ra = RA(i); \
|
||||||
lua_Integer i1 = ivalue(v1); lua_Integer i2 = ivalue(v2); \
|
lua_Integer i1 = ivalue(v1); lua_Integer i2 = ivalue(v2); \
|
||||||
pc++; setivalue(s2v(ra), iop(L, i1, i2)); \
|
pc++; setivalue(s2v(ra), iop(L, i1, i2)); \
|
||||||
} \
|
} \
|
||||||
@@ -988,12 +1020,12 @@ void luaV_finishOp (lua_State *L) {
|
|||||||
** Bitwise operations with constant operand.
|
** Bitwise operations with constant operand.
|
||||||
*/
|
*/
|
||||||
#define op_bitwiseK(L,op) { \
|
#define op_bitwiseK(L,op) { \
|
||||||
StkId ra = RA(i); \
|
|
||||||
TValue *v1 = vRB(i); \
|
TValue *v1 = vRB(i); \
|
||||||
TValue *v2 = KC(i); \
|
TValue *v2 = KC(i); \
|
||||||
lua_Integer i1; \
|
lua_Integer i1; \
|
||||||
lua_Integer i2 = ivalue(v2); \
|
lua_Integer i2 = ivalue(v2); \
|
||||||
if (tointegerns(v1, &i1)) { \
|
if (tointegerns(v1, &i1)) { \
|
||||||
|
StkId ra = RA(i); \
|
||||||
pc++; setivalue(s2v(ra), op(i1, i2)); \
|
pc++; setivalue(s2v(ra), op(i1, i2)); \
|
||||||
}}
|
}}
|
||||||
|
|
||||||
@@ -1002,11 +1034,11 @@ void luaV_finishOp (lua_State *L) {
|
|||||||
** Bitwise operations with register operands.
|
** Bitwise operations with register operands.
|
||||||
*/
|
*/
|
||||||
#define op_bitwise(L,op) { \
|
#define op_bitwise(L,op) { \
|
||||||
StkId ra = RA(i); \
|
|
||||||
TValue *v1 = vRB(i); \
|
TValue *v1 = vRB(i); \
|
||||||
TValue *v2 = vRC(i); \
|
TValue *v2 = vRC(i); \
|
||||||
lua_Integer i1; lua_Integer i2; \
|
lua_Integer i1; lua_Integer i2; \
|
||||||
if (tointegerns(v1, &i1) && tointegerns(v2, &i2)) { \
|
if (tointegerns(v1, &i1) && tointegerns(v2, &i2)) { \
|
||||||
|
StkId ra = RA(i); \
|
||||||
pc++; setivalue(s2v(ra), op(i1, i2)); \
|
pc++; setivalue(s2v(ra), op(i1, i2)); \
|
||||||
}}
|
}}
|
||||||
|
|
||||||
@@ -1017,18 +1049,18 @@ void luaV_finishOp (lua_State *L) {
|
|||||||
** integers.
|
** integers.
|
||||||
*/
|
*/
|
||||||
#define op_order(L,opi,opn,other) { \
|
#define op_order(L,opi,opn,other) { \
|
||||||
StkId ra = RA(i); \
|
TValue *ra = vRA(i); \
|
||||||
int cond; \
|
int cond; \
|
||||||
TValue *rb = vRB(i); \
|
TValue *rb = vRB(i); \
|
||||||
if (ttisinteger(s2v(ra)) && ttisinteger(rb)) { \
|
if (ttisinteger(ra) && ttisinteger(rb)) { \
|
||||||
lua_Integer ia = ivalue(s2v(ra)); \
|
lua_Integer ia = ivalue(ra); \
|
||||||
lua_Integer ib = ivalue(rb); \
|
lua_Integer ib = ivalue(rb); \
|
||||||
cond = opi(ia, ib); \
|
cond = opi(ia, ib); \
|
||||||
} \
|
} \
|
||||||
else if (ttisnumber(s2v(ra)) && ttisnumber(rb)) \
|
else if (ttisnumber(ra) && ttisnumber(rb)) \
|
||||||
cond = opn(s2v(ra), rb); \
|
cond = opn(ra, rb); \
|
||||||
else \
|
else \
|
||||||
Protect(cond = other(L, s2v(ra), rb)); \
|
Protect(cond = other(L, ra, rb)); \
|
||||||
docondjump(); }
|
docondjump(); }
|
||||||
|
|
||||||
|
|
||||||
@@ -1037,19 +1069,19 @@ void luaV_finishOp (lua_State *L) {
|
|||||||
** always small enough to have an exact representation as a float.)
|
** always small enough to have an exact representation as a float.)
|
||||||
*/
|
*/
|
||||||
#define op_orderI(L,opi,opf,inv,tm) { \
|
#define op_orderI(L,opi,opf,inv,tm) { \
|
||||||
StkId ra = RA(i); \
|
TValue *ra = vRA(i); \
|
||||||
int cond; \
|
int cond; \
|
||||||
int im = GETARG_sB(i); \
|
int im = GETARG_sB(i); \
|
||||||
if (ttisinteger(s2v(ra))) \
|
if (ttisinteger(ra)) \
|
||||||
cond = opi(ivalue(s2v(ra)), im); \
|
cond = opi(ivalue(ra), im); \
|
||||||
else if (ttisfloat(s2v(ra))) { \
|
else if (ttisfloat(ra)) { \
|
||||||
lua_Number fa = fltvalue(s2v(ra)); \
|
lua_Number fa = fltvalue(ra); \
|
||||||
lua_Number fim = cast_num(im); \
|
lua_Number fim = cast_num(im); \
|
||||||
cond = opf(fa, fim); \
|
cond = opf(fa, fim); \
|
||||||
} \
|
} \
|
||||||
else { \
|
else { \
|
||||||
int isf = GETARG_C(i); \
|
int isf = GETARG_C(i); \
|
||||||
Protect(cond = luaT_callorderiTM(L, s2v(ra), im, inv, isf, tm)); \
|
Protect(cond = luaT_callorderiTM(L, ra, im, inv, isf, tm)); \
|
||||||
} \
|
} \
|
||||||
docondjump(); }
|
docondjump(); }
|
||||||
|
|
||||||
@@ -1068,6 +1100,7 @@ void luaV_finishOp (lua_State *L) {
|
|||||||
|
|
||||||
|
|
||||||
#define RA(i) (base+GETARG_A(i))
|
#define RA(i) (base+GETARG_A(i))
|
||||||
|
#define vRA(i) s2v(RA(i))
|
||||||
#define RB(i) (base+GETARG_B(i))
|
#define RB(i) (base+GETARG_B(i))
|
||||||
#define vRB(i) s2v(RB(i))
|
#define vRB(i) s2v(RB(i))
|
||||||
#define KB(i) (k+GETARG_B(i))
|
#define KB(i) (k+GETARG_B(i))
|
||||||
@@ -1108,14 +1141,14 @@ void luaV_finishOp (lua_State *L) {
|
|||||||
/*
|
/*
|
||||||
** Correct global 'pc'.
|
** Correct global 'pc'.
|
||||||
*/
|
*/
|
||||||
#define savepc(L) (ci->u.l.savedpc = pc)
|
#define savepc(ci) (ci->u.l.savedpc = pc)
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Whenever code can raise errors, the global 'pc' and the global
|
** Whenever code can raise errors, the global 'pc' and the global
|
||||||
** 'top' must be correct to report occasional errors.
|
** 'top' must be correct to report occasional errors.
|
||||||
*/
|
*/
|
||||||
#define savestate(L,ci) (savepc(L), L->top.p = ci->top.p)
|
#define savestate(L,ci) (savepc(ci), L->top.p = ci->top.p)
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1125,7 +1158,7 @@ void luaV_finishOp (lua_State *L) {
|
|||||||
#define Protect(exp) (savestate(L,ci), (exp), updatetrap(ci))
|
#define Protect(exp) (savestate(L,ci), (exp), updatetrap(ci))
|
||||||
|
|
||||||
/* special version that does not change the top */
|
/* special version that does not change the top */
|
||||||
#define ProtectNT(exp) (savepc(L), (exp), updatetrap(ci))
|
#define ProtectNT(exp) (savepc(ci), (exp), updatetrap(ci))
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Protect code that can only raise errors. (That is, it cannot change
|
** Protect code that can only raise errors. (That is, it cannot change
|
||||||
@@ -1143,7 +1176,7 @@ void luaV_finishOp (lua_State *L) {
|
|||||||
|
|
||||||
/* 'c' is the limit of live values in the stack */
|
/* 'c' is the limit of live values in the stack */
|
||||||
#define checkGC(L,c) \
|
#define checkGC(L,c) \
|
||||||
{ luaC_condGC(L, (savepc(L), L->top.p = (c)), \
|
{ luaC_condGC(L, (savepc(ci), L->top.p = (c)), \
|
||||||
updatetrap(ci)); \
|
updatetrap(ci)); \
|
||||||
luai_threadyield(L); }
|
luai_threadyield(L); }
|
||||||
|
|
||||||
@@ -1450,16 +1483,6 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
|
|||||||
op_bitwiseK(L, l_bxor);
|
op_bitwiseK(L, l_bxor);
|
||||||
vmbreak;
|
vmbreak;
|
||||||
}
|
}
|
||||||
vmcase(OP_SHRI) {
|
|
||||||
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(ib, -ic));
|
|
||||||
}
|
|
||||||
vmbreak;
|
|
||||||
}
|
|
||||||
vmcase(OP_SHLI) {
|
vmcase(OP_SHLI) {
|
||||||
StkId ra = RA(i);
|
StkId ra = RA(i);
|
||||||
TValue *rb = vRB(i);
|
TValue *rb = vRB(i);
|
||||||
@@ -1470,6 +1493,16 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
|
|||||||
}
|
}
|
||||||
vmbreak;
|
vmbreak;
|
||||||
}
|
}
|
||||||
|
vmcase(OP_SHRI) {
|
||||||
|
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(ib, -ic));
|
||||||
|
}
|
||||||
|
vmbreak;
|
||||||
|
}
|
||||||
vmcase(OP_ADD) {
|
vmcase(OP_ADD) {
|
||||||
op_arith(L, l_addi, luai_numadd);
|
op_arith(L, l_addi, luai_numadd);
|
||||||
vmbreak;
|
vmbreak;
|
||||||
@@ -1512,14 +1545,14 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
|
|||||||
op_bitwise(L, l_bxor);
|
op_bitwise(L, l_bxor);
|
||||||
vmbreak;
|
vmbreak;
|
||||||
}
|
}
|
||||||
vmcase(OP_SHR) {
|
|
||||||
op_bitwise(L, luaV_shiftr);
|
|
||||||
vmbreak;
|
|
||||||
}
|
|
||||||
vmcase(OP_SHL) {
|
vmcase(OP_SHL) {
|
||||||
op_bitwise(L, luaV_shiftl);
|
op_bitwise(L, luaV_shiftl);
|
||||||
vmbreak;
|
vmbreak;
|
||||||
}
|
}
|
||||||
|
vmcase(OP_SHR) {
|
||||||
|
op_bitwise(L, luaV_shiftr);
|
||||||
|
vmbreak;
|
||||||
|
}
|
||||||
vmcase(OP_MMBIN) {
|
vmcase(OP_MMBIN) {
|
||||||
StkId ra = RA(i);
|
StkId ra = RA(i);
|
||||||
Instruction pi = *(pc - 2); /* original arith. expression */
|
Instruction pi = *(pc - 2); /* original arith. expression */
|
||||||
@@ -1692,7 +1725,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
|
|||||||
if (b != 0) /* fixed number of arguments? */
|
if (b != 0) /* fixed number of arguments? */
|
||||||
L->top.p = ra + b; /* top signals number of arguments */
|
L->top.p = ra + b; /* top signals number of arguments */
|
||||||
/* else previous instruction set top */
|
/* else previous instruction set top */
|
||||||
savepc(L); /* in case of errors */
|
savepc(ci); /* in case of errors */
|
||||||
if ((newci = luaD_precall(L, ra, nresults)) == NULL)
|
if ((newci = luaD_precall(L, ra, nresults)) == NULL)
|
||||||
updatetrap(ci); /* C call; nothing else to be done */
|
updatetrap(ci); /* C call; nothing else to be done */
|
||||||
else { /* Lua call: run function in this same C frame */
|
else { /* Lua call: run function in this same C frame */
|
||||||
@@ -1808,7 +1841,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
|
|||||||
pc -= GETARG_Bx(i); /* jump back */
|
pc -= GETARG_Bx(i); /* jump back */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (floatforloop(ra)) /* float loop */
|
else if (floatforloop(L, ra)) /* float loop */
|
||||||
pc -= GETARG_Bx(i); /* jump back */
|
pc -= GETARG_Bx(i); /* jump back */
|
||||||
updatetrap(ci); /* allows a signal to break the loop */
|
updatetrap(ci); /* allows a signal to break the loop */
|
||||||
vmbreak;
|
vmbreak;
|
||||||
@@ -1868,7 +1901,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
|
|||||||
vmcase(OP_SETLIST) {
|
vmcase(OP_SETLIST) {
|
||||||
StkId ra = RA(i);
|
StkId ra = RA(i);
|
||||||
unsigned n = cast_uint(GETARG_vB(i));
|
unsigned n = cast_uint(GETARG_vB(i));
|
||||||
unsigned int last = cast_uint(GETARG_vC(i));
|
unsigned last = cast_uint(GETARG_vC(i));
|
||||||
Table *h = hvalue(s2v(ra));
|
Table *h = hvalue(s2v(ra));
|
||||||
if (n == 0)
|
if (n == 0)
|
||||||
n = cast_uint(L->top.p - ra) - 1; /* get up to the top */
|
n = cast_uint(L->top.p - ra) - 1; /* get up to the top */
|
||||||
@@ -1902,12 +1935,25 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
|
|||||||
}
|
}
|
||||||
vmcase(OP_VARARG) {
|
vmcase(OP_VARARG) {
|
||||||
StkId ra = RA(i);
|
StkId ra = RA(i);
|
||||||
int n = GETARG_C(i) - 1; /* required results */
|
int n = GETARG_C(i) - 1; /* required results (-1 means all) */
|
||||||
Protect(luaT_getvarargs(L, ci, ra, n));
|
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)));
|
||||||
vmbreak;
|
vmbreak;
|
||||||
}
|
}
|
||||||
vmcase(OP_VARARGPREP) {
|
vmcase(OP_VARARGPREP) {
|
||||||
ProtectNT(luaT_adjustvarargs(L, GETARG_A(i), ci, cl->p));
|
ProtectNT(luaT_adjustvarargs(L, ci, cl->p));
|
||||||
if (l_unlikely(trap)) { /* previous "Protect" updated trap */
|
if (l_unlikely(trap)) { /* previous "Protect" updated trap */
|
||||||
luaD_hookcall(L, ci);
|
luaD_hookcall(L, ci);
|
||||||
L->oldpc = 1; /* next opcode will be seen as a "new" line */
|
L->oldpc = 1; /* next opcode will be seen as a "new" line */
|
||||||
|
|||||||
@@ -15,9 +15,9 @@ CWARNSCPP= \
|
|||||||
-Wdouble-promotion \
|
-Wdouble-promotion \
|
||||||
-Wmissing-declarations \
|
-Wmissing-declarations \
|
||||||
-Wconversion \
|
-Wconversion \
|
||||||
-Wstrict-overflow=2 \
|
|
||||||
# the next warnings might be useful sometimes,
|
# the next warnings might be useful sometimes,
|
||||||
# but usually they generate too much noise
|
# but usually they generate too much noise
|
||||||
|
# -Wstrict-overflow=2 \
|
||||||
# -Werror \
|
# -Werror \
|
||||||
# -pedantic # warns if we use jump tables \
|
# -pedantic # warns if we use jump tables \
|
||||||
# -Wformat=2 \
|
# -Wformat=2 \
|
||||||
@@ -60,10 +60,13 @@ CWARNS= $(CWARNSCPP) $(CWARNSC) $(CWARNGCC)
|
|||||||
# create problems; some are only available in newer gcc versions. To
|
# create problems; some are only available in newer gcc versions. To
|
||||||
# use some of them, we also have to define an environment variable
|
# use some of them, we also have to define an environment variable
|
||||||
# ASAN_OPTIONS="detect_invalid_pointer_pairs=2".
|
# ASAN_OPTIONS="detect_invalid_pointer_pairs=2".
|
||||||
# -fsanitize=undefined
|
# -fsanitize=undefined (you may need to add "-lubsan" to libs)
|
||||||
# -fsanitize=pointer-subtract -fsanitize=address -fsanitize=pointer-compare
|
# -fsanitize=pointer-subtract -fsanitize=address -fsanitize=pointer-compare
|
||||||
# TESTS= -DLUA_USER_H='"ltests.h"' -Og -g
|
|
||||||
|
|
||||||
|
# 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)
|
LOCAL = $(TESTS) $(CWARNS)
|
||||||
|
|
||||||
@@ -71,13 +74,15 @@ LOCAL = $(TESTS) $(CWARNS)
|
|||||||
# To enable Linux goodies, -DLUA_USE_LINUX
|
# To enable Linux goodies, -DLUA_USE_LINUX
|
||||||
# For C89, "-std=c89 -DLUA_USE_C89"
|
# For C89, "-std=c89 -DLUA_USE_C89"
|
||||||
# Note that Linux/Posix options are not compatible with 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
|
MYCFLAGS= $(LOCAL) -std=c99 -DLUA_USE_LINUX
|
||||||
MYLDFLAGS= $(LOCAL) -Wl,-E
|
MYLDFLAGS= -Wl,-E
|
||||||
MYLIBS= -ldl
|
MYLIBS= -ldl
|
||||||
|
|
||||||
|
|
||||||
CC= gcc
|
CC= gcc
|
||||||
CFLAGS= -Wall -O2 $(MYCFLAGS) -fno-stack-protector -fno-common -march=native
|
# (Optionally we can use -march=native -mno-avx512f.)
|
||||||
|
CFLAGS= -Wall -O2 $(MYCFLAGS) -fno-stack-protector -fno-common
|
||||||
AR= ar rc
|
AR= ar rc
|
||||||
RANLIB= ranlib
|
RANLIB= ranlib
|
||||||
RM= rm -f
|
RM= rm -f
|
||||||
@@ -166,8 +171,7 @@ 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 \
|
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
|
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 \
|
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 llex.h lstring.h \
|
llimits.h ltm.h lzio.h lmem.h ldo.h lfunc.h lgc.h lstring.h ltable.h
|
||||||
ltable.h
|
|
||||||
linit.o: linit.c lprefix.h lua.h luaconf.h lualib.h lauxlib.h llimits.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
|
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 \
|
llex.o: llex.c lprefix.h lua.h luaconf.h lctype.h llimits.h ldebug.h \
|
||||||
|
|||||||
+2
-2
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env lua5.3
|
#!/usr/bin/env lua
|
||||||
|
|
||||||
|
|
||||||
-- special marks:
|
-- special marks:
|
||||||
@@ -30,7 +30,7 @@ by Roberto Ierusalimschy, Luiz Henrique de Figueiredo, Waldemar Celes
|
|||||||
<p>
|
<p>
|
||||||
<small>
|
<small>
|
||||||
<a href="http://www.lua.org/copyright.html">Copyright</a>
|
<a href="http://www.lua.org/copyright.html">Copyright</a>
|
||||||
© 2025 Lua.org, PUC-Rio. All rights reserved.
|
© 2026 Lua.org, PUC-Rio. All rights reserved.
|
||||||
</small>
|
</small>
|
||||||
<hr>
|
<hr>
|
||||||
|
|
||||||
|
|||||||
+267
-154
@@ -107,7 +107,7 @@ for small machines and embedded systems.
|
|||||||
|
|
||||||
Unless stated otherwise,
|
Unless stated otherwise,
|
||||||
any overflow when manipulating integer values @def{wrap around},
|
any overflow when manipulating integer values @def{wrap around},
|
||||||
according to the usual rules of two-complement arithmetic.
|
according to the usual rules of two's complement arithmetic.
|
||||||
(In other words,
|
(In other words,
|
||||||
the actual result is the unique representable integer
|
the actual result is the unique representable integer
|
||||||
that is equal modulo @M{2@sp{n}} to the mathematical result,
|
that is equal modulo @M{2@sp{n}} to the mathematical result,
|
||||||
@@ -127,7 +127,8 @@ strings can contain any 8-bit value,
|
|||||||
including @x{embedded zeros} (@Char{\0}).
|
including @x{embedded zeros} (@Char{\0}).
|
||||||
Lua is also encoding-agnostic;
|
Lua is also encoding-agnostic;
|
||||||
it makes no assumptions about the contents of a string.
|
it makes no assumptions about the contents of a string.
|
||||||
The length of any string in Lua must fit in a Lua integer.
|
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}.
|
||||||
|
|
||||||
Lua can call (and manipulate) functions written in Lua and
|
Lua can call (and manipulate) functions written in Lua and
|
||||||
functions written in C @see{functioncall}.
|
functions written in C @see{functioncall}.
|
||||||
@@ -229,7 +230,7 @@ as the following example illustrates:
|
|||||||
@verbatim{
|
@verbatim{
|
||||||
X = 1 -- Ok, global by default
|
X = 1 -- Ok, global by default
|
||||||
do
|
do
|
||||||
global Y -- voids implicit initial declaration
|
global Y -- voids the implicit initial declaration
|
||||||
Y = 1 -- Ok, Y declared as global
|
Y = 1 -- Ok, Y declared as global
|
||||||
X = 1 -- ERROR, X not declared
|
X = 1 -- ERROR, X not declared
|
||||||
end
|
end
|
||||||
@@ -269,7 +270,7 @@ print(x) --> 10 (the global one)
|
|||||||
|
|
||||||
Notice that, in a declaration like @T{local x = x},
|
Notice that, in a declaration like @T{local x = x},
|
||||||
the new @id{x} being declared is not in scope yet,
|
the new @id{x} being declared is not in scope yet,
|
||||||
and so the @id{x} in the left-hand side refers to the outside variable.
|
and so the @id{x} on the right-hand side refers to the outside variable.
|
||||||
|
|
||||||
Because of the @x{lexical scoping} rules,
|
Because of the @x{lexical scoping} rules,
|
||||||
local variables can be freely accessed by functions
|
local variables can be freely accessed by functions
|
||||||
@@ -1555,7 +1556,8 @@ It has the following syntax:
|
|||||||
exp @bnfter{,} exp @bnfopt{@bnfter{,} exp} @Rw{do} block @Rw{end}}
|
exp @bnfter{,} exp @bnfopt{@bnfter{,} exp} @Rw{do} block @Rw{end}}
|
||||||
}
|
}
|
||||||
The given identifier (@bnfNter{Name}) defines the control variable,
|
The given identifier (@bnfNter{Name}) defines the control variable,
|
||||||
which is a new read-only variable local to the loop body (@emph{block}).
|
which is a new read-only (@id{const}) variable local to the loop body
|
||||||
|
(@emph{block}).
|
||||||
|
|
||||||
The loop starts by evaluating once the three control expressions.
|
The loop starts by evaluating once the three control expressions.
|
||||||
Their values are called respectively
|
Their values are called respectively
|
||||||
@@ -1610,7 +1612,7 @@ works as follows.
|
|||||||
|
|
||||||
The names @rep{var_i} declare loop variables local to the loop body.
|
The names @rep{var_i} declare loop variables local to the loop body.
|
||||||
The first of these variables is the @emph{control variable},
|
The first of these variables is the @emph{control variable},
|
||||||
which is a read-only variable.
|
which is a read-only (@id{const}) variable.
|
||||||
|
|
||||||
The loop starts by evaluating @rep{explist}
|
The loop starts by evaluating @rep{explist}
|
||||||
to produce four values:
|
to produce four values:
|
||||||
@@ -1651,15 +1653,22 @@ Function calls are explained in @See{functioncall}.
|
|||||||
|
|
||||||
@sect3{localvar| @title{Variable Declarations}
|
@sect3{localvar| @title{Variable Declarations}
|
||||||
Local and global variables can be declared anywhere inside a block.
|
Local and global variables can be declared anywhere inside a block.
|
||||||
The declaration for locals can include an initialization:
|
The declaration can include an initialization:
|
||||||
@Produc{
|
@Produc{
|
||||||
@producname{stat}@producbody{@Rw{local}
|
@producname{stat}@producbody{@Rw{local}
|
||||||
attnamelist @bnfopt{@bnfter{=} explist}}
|
attnamelist @bnfopt{@bnfter{=} explist}}
|
||||||
@producname{stat}@producbody{@Rw{global} attnamelist}
|
@producname{stat}@producbody{@Rw{global}
|
||||||
|
attnamelist @bnfopt{@bnfter{=} explist}}
|
||||||
}
|
}
|
||||||
If present, an initial assignment has the same semantics
|
If there is no initialization,
|
||||||
|
local variables are initialized with @nil;
|
||||||
|
global variables are left unchanged.
|
||||||
|
Otherwise, the initialization gets the same adjustment
|
||||||
of a multiple assignment @see{assignment}.
|
of a multiple assignment @see{assignment}.
|
||||||
Otherwise, all local variables are initialized with @nil.
|
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.
|
||||||
|
|
||||||
The list of names may be prefixed by an attribute
|
The list of names may be prefixed by an attribute
|
||||||
(a name between angle brackets)
|
(a name between angle brackets)
|
||||||
@@ -1712,7 +1721,8 @@ and a program that starts with any other global declaration
|
|||||||
(e.g., @T{global none}) can only refer to declared variables.
|
(e.g., @T{global none}) can only refer to declared variables.
|
||||||
|
|
||||||
Note that, for global variables,
|
Note that, for global variables,
|
||||||
the effect of any declaration is only syntactical:
|
the effect of any declaration is only syntactical
|
||||||
|
(except for the optional assignment):
|
||||||
@verbatim{
|
@verbatim{
|
||||||
global X <const>, _G
|
global X <const>, _G
|
||||||
X = 1 -- ERROR
|
X = 1 -- ERROR
|
||||||
@@ -2081,12 +2091,12 @@ Note that keys that are not positive integers
|
|||||||
do not interfere with borders.
|
do not interfere with borders.
|
||||||
|
|
||||||
A table with exactly one border is called a @def{sequence}.
|
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).
|
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.
|
and therefore it is not a sequence.
|
||||||
(The @nil at index 4 is called a @emphx{hole}.)
|
(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),
|
has three borders (0, 3, and 6),
|
||||||
so it is not a sequence, too.
|
so it is not a sequence, too.
|
||||||
The table @T{{}} is a sequence with border 0.
|
The table @T{{}} is a sequence with border 0.
|
||||||
@@ -2211,7 +2221,7 @@ The form
|
|||||||
}
|
}
|
||||||
can be used to emulate methods.
|
can be used to emulate methods.
|
||||||
A call @T{v:name(@rep{args})}
|
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.
|
except that @id{v} is evaluated only once.
|
||||||
|
|
||||||
Arguments have the following syntax:
|
Arguments have the following syntax:
|
||||||
@@ -2258,7 +2268,7 @@ return x or f(x) -- results adjusted to 1
|
|||||||
|
|
||||||
@sect3{func-def| @title{Function Definitions}
|
@sect3{func-def| @title{Function Definitions}
|
||||||
|
|
||||||
The syntax for function definition is
|
The syntax for a function definition is
|
||||||
@Produc{
|
@Produc{
|
||||||
@producname{functiondef}@producbody{@Rw{function} funcbody}
|
@producname{functiondef}@producbody{@Rw{function} funcbody}
|
||||||
@producname{funcbody}@producbody{@bnfter{(} @bnfopt{parlist} @bnfter{)} block @Rw{end}}
|
@producname{funcbody}@producbody{@bnfter{(} @bnfopt{parlist} @bnfter{)} block @Rw{end}}
|
||||||
@@ -2308,71 +2318,10 @@ global function f () @rep{body} end
|
|||||||
}
|
}
|
||||||
translates to
|
translates to
|
||||||
@verbatim{
|
@verbatim{
|
||||||
global f; f = function () @rep{body} end
|
global f; global f = function () @rep{body} end
|
||||||
}
|
}
|
||||||
|
The second @Rw{global} makes the assignment an initialization,
|
||||||
A function definition is an executable expression,
|
which will raise an error if that global is already defined.
|
||||||
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
|
The @emphx{colon} syntax
|
||||||
is used to emulate @def{methods},
|
is used to emulate @def{methods},
|
||||||
@@ -2386,10 +2335,104 @@ is syntactic sugar for
|
|||||||
t.a.b.c.f = function (self, @rep{params}) @rep{body} end
|
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}
|
||||||
}
|
}
|
||||||
|
|
||||||
@sect3{multires| @title{Lists of expressions, multiple results,
|
A vararg table in a variadic function can have an optional name,
|
||||||
and adjustment}
|
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}
|
||||||
|
|
||||||
Both function calls and vararg expressions can result in multiple values.
|
Both function calls and vararg expressions can result in multiple values.
|
||||||
These expressions are called @def{multires expressions}.
|
These expressions are called @def{multires expressions}.
|
||||||
@@ -2406,22 +2449,22 @@ These are the places where Lua expects a list of expressions:
|
|||||||
@description{
|
@description{
|
||||||
|
|
||||||
@item{A @rw{return} statement,
|
@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,
|
@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,
|
@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,
|
@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 declaration,
|
@item{A local or global declaration,
|
||||||
for instance @T{local a , b, c = e1, e2, e3} @see{localvar}.}
|
which is similar to a multiple assignment.}
|
||||||
|
|
||||||
@item{The initial values in a generic @rw{for} loop,
|
@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,
|
In the last four cases,
|
||||||
@@ -2429,8 +2472,7 @@ the list of values from the list of expressions
|
|||||||
must be @emph{adjusted} to a specific length:
|
must be @emph{adjusted} to a specific length:
|
||||||
the number of parameters in a call to a non-variadic function
|
the number of parameters in a call to a non-variadic function
|
||||||
@see{func-def},
|
@see{func-def},
|
||||||
the number of variables in a multiple assignment or
|
the number of variables in a multiple assignment or a declaration,
|
||||||
a local declaration,
|
|
||||||
and exactly four values for a generic @rw{for} loop.
|
and exactly four values for a generic @rw{for} loop.
|
||||||
The @def{adjustment} follows these rules:
|
The @def{adjustment} follows these rules:
|
||||||
If there are more values than needed,
|
If there are more values than needed,
|
||||||
@@ -2459,7 +2501,7 @@ we recommend assigning the vararg expression
|
|||||||
to a single variable and using that variable
|
to a single variable and using that variable
|
||||||
in its place.
|
in its place.
|
||||||
|
|
||||||
Here are some examples of uses of mutlres expressions.
|
Here are some examples of uses of multires expressions.
|
||||||
In all cases, when the construction needs
|
In all cases, when the construction needs
|
||||||
@Q{the n-th result} and there is no such result,
|
@Q{the n-th result} and there is no such result,
|
||||||
it uses a @nil.
|
it uses a @nil.
|
||||||
@@ -2648,9 +2690,21 @@ which behaves like a nil value.
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@sect3{constchar|@title{Pointers to strings}
|
@sect3{constchar|@title{Pointers to Strings}
|
||||||
|
|
||||||
Several functions in the API return pointers (@T{const char*})
|
Several functions in the API accept pointers (@T{const char*})
|
||||||
|
to C strings.
|
||||||
|
Some of there 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*})
|
||||||
to Lua strings in the stack.
|
to Lua strings in the stack.
|
||||||
(See @Lid{lua_pushfstring}, @Lid{lua_pushlstring},
|
(See @Lid{lua_pushfstring}, @Lid{lua_pushlstring},
|
||||||
@Lid{lua_pushstring}, and @Lid{lua_tolstring}.
|
@Lid{lua_pushstring}, and @Lid{lua_tolstring}.
|
||||||
@@ -2823,7 +2877,16 @@ status codes to indicate different kinds of errors or other conditions:
|
|||||||
For such errors, Lua does not call the @x{message handler}.
|
For such errors, Lua does not call the @x{message handler}.
|
||||||
}
|
}
|
||||||
|
|
||||||
@item{@defid{LUA_ERRERR}| error while running 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_ERRSYNTAX}| syntax error during precompilation
|
@item{@defid{LUA_ERRSYNTAX}| syntax error during precompilation
|
||||||
or format error in a binary chunk.}
|
or format error in a binary chunk.}
|
||||||
@@ -3004,7 +3067,7 @@ typedef void * (*lua_Alloc) (void *ud,
|
|||||||
size_t osize,
|
size_t osize,
|
||||||
size_t nsize);|
|
size_t nsize);|
|
||||||
|
|
||||||
The type of the @x{memory-allocation function} used by Lua states.
|
The type of the @x{memory-allocator function} used by Lua states.
|
||||||
The allocator function must provide a
|
The allocator function must provide a
|
||||||
functionality similar to @id{realloc},
|
functionality similar to @id{realloc},
|
||||||
but not exactly the same.
|
but not exactly the same.
|
||||||
@@ -3039,11 +3102,12 @@ the allocator must behave like @id{realloc}.
|
|||||||
In particular, the allocator returns @id{NULL}
|
In particular, the allocator returns @id{NULL}
|
||||||
if and only if it cannot fulfill the request.
|
if and only if it cannot fulfill the request.
|
||||||
|
|
||||||
Here is a simple implementation for the @x{allocator function}.
|
Here is a simple implementation for the @x{allocator function},
|
||||||
It is used in the auxiliary library by @Lid{luaL_newstate}.
|
corresponding to the function @Lid{luaL_alloc} from the
|
||||||
|
auxiliary library.
|
||||||
@verbatim{
|
@verbatim{
|
||||||
static void *l_alloc (void *ud, void *ptr, size_t osize,
|
void *luaL_alloc (void *ud, void *ptr, size_t osize,
|
||||||
size_t nsize) {
|
size_t nsize) {
|
||||||
(void)ud; (void)osize; /* not used */
|
(void)ud; (void)osize; /* not used */
|
||||||
if (nsize == 0) {
|
if (nsize == 0) {
|
||||||
free(ptr);
|
free(ptr);
|
||||||
@@ -3470,7 +3534,7 @@ This function should not be called by a finalizer.
|
|||||||
@APIEntry{lua_Alloc lua_getallocf (lua_State *L, void **ud);|
|
@APIEntry{lua_Alloc lua_getallocf (lua_State *L, void **ud);|
|
||||||
@apii{0,0,-}
|
@apii{0,0,-}
|
||||||
|
|
||||||
Returns the @x{memory-allocation function} of a given state.
|
Returns the @x{memory-allocator function} of a given state.
|
||||||
If @id{ud} is not @id{NULL}, Lua stores in @T{*ud} the
|
If @id{ud} is not @id{NULL}, Lua stores in @T{*ud} the
|
||||||
opaque pointer given when the memory-allocator function was set.
|
opaque pointer given when the memory-allocator function was set.
|
||||||
|
|
||||||
@@ -3588,9 +3652,9 @@ because a pseudo-index is not an actual stack position.
|
|||||||
The type of integers in Lua.
|
The type of integers in Lua.
|
||||||
|
|
||||||
By default this type is @id{long long},
|
By default this type is @id{long long},
|
||||||
(usually a 64-bit two-complement integer),
|
(usually a 64-bit two's complement integer),
|
||||||
but that can be changed to @id{long} or @id{int}
|
but that can be changed to @id{long} or @id{int}
|
||||||
(usually a 32-bit two-complement integer).
|
(usually a 32-bit two's complement integer).
|
||||||
(See @id{LUA_INT_TYPE} in @id{luaconf.h}.)
|
(See @id{LUA_INT_TYPE} in @id{luaconf.h}.)
|
||||||
|
|
||||||
Lua also defines the constants
|
Lua also defines the constants
|
||||||
@@ -3827,7 +3891,7 @@ is a seed for the hashing of strings.
|
|||||||
@apii{0,1,m}
|
@apii{0,1,m}
|
||||||
|
|
||||||
Creates a new empty table and pushes it onto the stack.
|
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)}.
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3851,8 +3915,12 @@ like any Lua object.
|
|||||||
This function creates and pushes on the stack a new full userdata,
|
This function creates and pushes on the stack a new full userdata,
|
||||||
with @id{nuvalue} associated Lua values, called @id{user values},
|
with @id{nuvalue} associated Lua values, called @id{user values},
|
||||||
plus an associated block of raw memory with @id{size} bytes.
|
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 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 function returns the address of the block of memory.
|
The function returns the address of the block of memory.
|
||||||
Lua ensures that this address is valid as long as
|
Lua ensures that this address is valid as long as
|
||||||
@@ -3894,8 +3962,8 @@ this confuses the next call to @Lid{lua_next}.
|
|||||||
|
|
||||||
This function may raise an error if the given key
|
This function may raise an error if the given key
|
||||||
is neither @nil nor present in the table.
|
is neither @nil nor present in the table.
|
||||||
See function @Lid{next} for the caveats of modifying
|
|
||||||
the table during its traversal.
|
See function @Lid{next} for more details about the traversal.
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3924,8 +3992,8 @@ This macro may evaluate its arguments more than once.
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@APIEntry{unsigned (lua_numbertocstring) (lua_State *L, int idx,
|
@APIEntry{unsigned lua_numbertocstring (lua_State *L, int idx,
|
||||||
char *buff);|
|
char *buff);|
|
||||||
@apii{0,0,-}
|
@apii{0,0,-}
|
||||||
|
|
||||||
Converts the number at acceptable index @id{idx} to a string
|
Converts the number at acceptable index @id{idx} to a string
|
||||||
@@ -4050,7 +4118,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);|
|
const char *s, size_t len, lua_Alloc falloc, void *ud);|
|
||||||
@apii{0,1,m}
|
@apii{0,1,m}
|
||||||
|
|
||||||
@@ -4073,21 +4141,18 @@ the string @id{s} as the block,
|
|||||||
the length plus one (to account for the ending zero) as the old size,
|
the length plus one (to account for the ending zero) as the old size,
|
||||||
and 0 as the new 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,
|
Even when using an external buffer,
|
||||||
Lua still has to allocate a header for the string.
|
Lua still has to allocate a header for the string.
|
||||||
In case of a memory-allocation error,
|
In case of a memory-allocation error,
|
||||||
Lua will call @id{falloc} before raising the 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, ...);|
|
@APIEntry{const char *lua_pushfstring (lua_State *L, const char *fmt, ...);|
|
||||||
@apii{0,1,m}
|
@apii{0,1,v}
|
||||||
|
|
||||||
Pushes onto the stack a formatted string
|
Pushes onto the stack a formatted string
|
||||||
and returns a pointer to this string @see{constchar}.
|
and returns a pointer to this string @see{constchar}.
|
||||||
@@ -4107,6 +4172,9 @@ A conversion specifier (and its corresponding extra argument) can be
|
|||||||
Every occurrence of @Char{%} in the string @id{fmt}
|
Every occurrence of @Char{%} in the string @id{fmt}
|
||||||
must form a valid conversion specifier.
|
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);|
|
@APIEntry{void lua_pushglobaltable (lua_State *L);|
|
||||||
@@ -4139,7 +4207,7 @@ light userdata with the same @N{C address}.
|
|||||||
}
|
}
|
||||||
|
|
||||||
@APIEntry{const char *lua_pushliteral (lua_State *L, const char *s);|
|
@APIEntry{const char *lua_pushliteral (lua_State *L, const char *s);|
|
||||||
@apii{0,1,m}
|
@apii{0,1,v}
|
||||||
|
|
||||||
This macro is equivalent to @Lid{lua_pushstring},
|
This macro is equivalent to @Lid{lua_pushstring},
|
||||||
but should be used only when @id{s} is a literal string.
|
but should be used only when @id{s} is a literal string.
|
||||||
@@ -4148,7 +4216,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);|
|
@APIEntry{const char *lua_pushlstring (lua_State *L, const char *s, size_t len);|
|
||||||
@apii{0,1,m}
|
@apii{0,1,v}
|
||||||
|
|
||||||
Pushes the string pointed to by @id{s} with size @id{len}
|
Pushes the string pointed to by @id{s} with size @id{len}
|
||||||
onto the stack.
|
onto the stack.
|
||||||
@@ -4160,6 +4228,9 @@ including @x{embedded zeros}.
|
|||||||
|
|
||||||
Returns a pointer to the internal copy of the string @see{constchar}.
|
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);|
|
@APIEntry{void lua_pushnil (lua_State *L);|
|
||||||
@@ -4377,7 +4448,7 @@ Starts and resumes a coroutine in the given thread @id{L}.
|
|||||||
To start a coroutine,
|
To start a coroutine,
|
||||||
you push the main function plus any arguments
|
you push the main function plus any arguments
|
||||||
onto the empty stack of the thread.
|
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.
|
with @id{nargs} being the number of arguments.
|
||||||
The function returns when the coroutine suspends,
|
The function returns when the coroutine suspends,
|
||||||
finishes its execution, or raises an unprotected error.
|
finishes its execution, or raises an unprotected error.
|
||||||
@@ -4557,7 +4628,7 @@ You can resume threads with status @Lid{LUA_OK}
|
|||||||
}
|
}
|
||||||
|
|
||||||
@APIEntry{size_t lua_stringtonumber (lua_State *L, const char *s);|
|
@APIEntry{size_t lua_stringtonumber (lua_State *L, const char *s);|
|
||||||
@apii{0,1,-}
|
@apii{0,0|1,-}
|
||||||
|
|
||||||
Converts the zero-terminated string @id{s} to a number,
|
Converts the zero-terminated string @id{s} to a number,
|
||||||
pushes that number into the stack,
|
pushes that number into the stack,
|
||||||
@@ -4887,7 +4958,7 @@ Lua calls the given @x{continuation function} @id{k} to continue
|
|||||||
the execution of the @N{C function} that yielded @see{continuations}.
|
the execution of the @N{C function} that yielded @see{continuations}.
|
||||||
This continuation function receives the same stack
|
This continuation function receives the same stack
|
||||||
from the previous function,
|
from the previous function,
|
||||||
with the @id{n} results removed and
|
with all the results (@id{nresults}) removed and
|
||||||
replaced by the arguments passed to @Lid{lua_resume}.
|
replaced by the arguments passed to @Lid{lua_resume}.
|
||||||
Moreover,
|
Moreover,
|
||||||
the continuation function receives the value @id{ctx}
|
the continuation function receives the value @id{ctx}
|
||||||
@@ -4977,7 +5048,7 @@ the function was defined in a string where
|
|||||||
}
|
}
|
||||||
|
|
||||||
@item{@id{srclen}|
|
@item{@id{srclen}|
|
||||||
The length of the string @id{source}.
|
the length of the string @id{source}.
|
||||||
}
|
}
|
||||||
|
|
||||||
@item{@id{short_src}|
|
@item{@id{short_src}|
|
||||||
@@ -5019,8 +5090,8 @@ then @id{name} is set to @id{NULL}.
|
|||||||
@item{@id{namewhat}|
|
@item{@id{namewhat}|
|
||||||
explains the @T{name} field.
|
explains the @T{name} field.
|
||||||
The value of @T{namewhat} can be
|
The value of @T{namewhat} can be
|
||||||
@T{"global"}, @T{"local"}, @T{"method"},
|
@T{"global"}, @T{"local"}, @T{"upvalue"},
|
||||||
@T{"field"}, @T{"upvalue"}, or @T{""} (the empty string),
|
@T{"field"}, @T{""} (the empty string), plus some other options,
|
||||||
according to how the function was called.
|
according to how the function was called.
|
||||||
(Lua uses the empty string when no other option seems to apply.)
|
(Lua uses the empty string when no other option seems to apply.)
|
||||||
}
|
}
|
||||||
@@ -5141,7 +5212,7 @@ running at the given level;
|
|||||||
}
|
}
|
||||||
|
|
||||||
@item{@Char{S}|
|
@item{@Char{S}|
|
||||||
fills in the fields @id{source}, @id{short_src},
|
fills in the fields @id{source}, @id{srclen}, @id{short_src},
|
||||||
@id{linedefined}, @id{lastlinedefined}, and @id{what};
|
@id{linedefined}, @id{lastlinedefined}, and @id{what};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5317,7 +5388,9 @@ Returns @id{NULL} (and pops nothing)
|
|||||||
when the index is greater than
|
when the index is greater than
|
||||||
the number of active local variables.
|
the number of active local variables.
|
||||||
|
|
||||||
Parameters @id{ar} and @id{n} are as in the function @Lid{lua_getlocal}.
|
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.
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5384,7 +5457,7 @@ the auxiliary library provides higher-level functions for some
|
|||||||
common tasks.
|
common tasks.
|
||||||
|
|
||||||
All functions and types from the auxiliary library
|
All functions and types from the auxiliary library
|
||||||
are defined in header file @id{lauxlib.h} and
|
are defined in the header file @id{lauxlib.h} and
|
||||||
have a prefix @id{luaL_}.
|
have a prefix @id{luaL_}.
|
||||||
|
|
||||||
All functions in the auxiliary library are built on
|
All functions in the auxiliary library are built on
|
||||||
@@ -5528,7 +5601,7 @@ Its pattern of use is as follows:
|
|||||||
|
|
||||||
@item{First declare a variable @id{b} of type @Lid{luaL_Buffer}.}
|
@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{
|
@item{
|
||||||
Then add string pieces to the buffer calling any of
|
Then add string pieces to the buffer calling any of
|
||||||
@@ -5549,12 +5622,12 @@ you can use the buffer like this:
|
|||||||
@item{First declare a variable @id{b} of type @Lid{luaL_Buffer}.}
|
@item{First declare a variable @id{b} of type @Lid{luaL_Buffer}.}
|
||||||
|
|
||||||
@item{Then initialize it and preallocate a space of
|
@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{Then produce the string into that space.}
|
||||||
|
|
||||||
@item{
|
@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
|
where @id{sz} is the total size of the resulting string
|
||||||
copied into that space (which may be less than or
|
copied into that space (which may be less than or
|
||||||
equal to the preallocated size).
|
equal to the preallocated size).
|
||||||
@@ -5947,9 +6020,8 @@ it does not run it.
|
|||||||
@apii{0,0,-}
|
@apii{0,0,-}
|
||||||
|
|
||||||
Returns a value with a weak attempt for randomness.
|
Returns a value with a weak attempt for randomness.
|
||||||
(It produces that value based on the current date and time
|
The parameter @id{L} can be @id{NULL}
|
||||||
and the address of an internal variable,
|
if there is no Lua state available.
|
||||||
in case the machine has Address Space Layout Randomization.)
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -6005,8 +6077,9 @@ with @id{tname} in the registry.
|
|||||||
@apii{0,0,-}
|
@apii{0,0,-}
|
||||||
|
|
||||||
Creates a new Lua state.
|
Creates a new Lua state.
|
||||||
It calls @Lid{lua_newstate} with an
|
It calls @Lid{lua_newstate} with @Lid{luaL_alloc} as
|
||||||
allocator based on the @N{ISO C} allocation functions
|
the allocator function and the result of @T{luaL_makeseed(NULL)}
|
||||||
|
as the seed,
|
||||||
and then sets a warning function and a panic function @see{C-error}
|
and then sets a warning function and a panic function @see{C-error}
|
||||||
that print messages to the standard error output.
|
that print messages to the standard error output.
|
||||||
|
|
||||||
@@ -6159,7 +6232,7 @@ You should not manually set integer keys in the table
|
|||||||
after the first use of @Lid{luaL_ref}.
|
after the first use of @Lid{luaL_ref}.
|
||||||
|
|
||||||
You can retrieve an object referred by the reference @id{r}
|
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.
|
The function @Lid{luaL_unref} frees a reference.
|
||||||
|
|
||||||
If the object on the top of the stack is @nil,
|
If the object on the top of the stack is @nil,
|
||||||
@@ -6230,6 +6303,15 @@ 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{
|
@APIEntry{
|
||||||
typedef struct luaL_Stream {
|
typedef struct luaL_Stream {
|
||||||
FILE *f;
|
FILE *f;
|
||||||
@@ -6428,7 +6510,7 @@ the host program can call the function @Lid{luaL_openlibs}.
|
|||||||
Alternatively,
|
Alternatively,
|
||||||
the host can select which libraries to open,
|
the host can select which libraries to open,
|
||||||
by using @Lid{luaL_openselectedlibs}.
|
by using @Lid{luaL_openselectedlibs}.
|
||||||
Both functions are defined in the header file @id{lualib.h}.
|
Both functions are declared in the header file @id{lualib.h}.
|
||||||
@index{lualib.h}
|
@index{lualib.h}
|
||||||
|
|
||||||
The stand-alone interpreter @id{lua} @see{lua-sa}
|
The stand-alone interpreter @id{lua} @see{lua-sa}
|
||||||
@@ -6575,7 +6657,7 @@ The call always returns the previous value of the parameter.
|
|||||||
If the call does not give a new value,
|
If the call does not give a new value,
|
||||||
the value is left unchanged.
|
the value is left unchanged.
|
||||||
|
|
||||||
Lua rounds these values before storing them;
|
Lua stores these values in a compressed format,
|
||||||
so, the value returned as the previous value may not be
|
so, the value returned as the previous value may not be
|
||||||
exactly the last value set.
|
exactly the last value set.
|
||||||
}
|
}
|
||||||
@@ -6589,10 +6671,10 @@ This function should not be called by a finalizer.
|
|||||||
}
|
}
|
||||||
|
|
||||||
@LibEntry{dofile ([filename])|
|
@LibEntry{dofile ([filename])|
|
||||||
Opens the named file and executes its content as a Lua chunk.
|
Opens the named file and executes its content as a Lua chunk,
|
||||||
|
returning all values returned by the chunk.
|
||||||
When called without arguments,
|
When called without arguments,
|
||||||
@id{dofile} executes the content of the standard input (@id{stdin}).
|
@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
|
In case of errors, @id{dofile} propagates the error
|
||||||
to its caller.
|
to its caller.
|
||||||
(That is, @id{dofile} does not run in protected mode.)
|
(That is, @id{dofile} does not run in protected mode.)
|
||||||
@@ -6741,19 +6823,18 @@ In particular, you may set existing fields to nil.
|
|||||||
@LibEntry{pairs (t)|
|
@LibEntry{pairs (t)|
|
||||||
|
|
||||||
If @id{t} has a metamethod @idx{__pairs},
|
If @id{t} has a metamethod @idx{__pairs},
|
||||||
calls it with @id{t} as argument and returns the first three
|
calls it with @id{t} as argument and returns the first four
|
||||||
results from the call.
|
results from the call.
|
||||||
|
|
||||||
Otherwise,
|
Otherwise,
|
||||||
returns three values: the @Lid{next} function, the table @id{t}, and @nil,
|
returns the @Lid{next} function, the table @id{t}, plus two @nil values,
|
||||||
so that the construction
|
so that the construction
|
||||||
@verbatim{
|
@verbatim{
|
||||||
for k,v in pairs(t) do @rep{body} end
|
for k,v in pairs(t) do @rep{body} end
|
||||||
}
|
}
|
||||||
will iterate over all key@En{}value pairs of table @id{t}.
|
will iterate over all key@En{}value pairs of table @id{t}.
|
||||||
|
|
||||||
See function @Lid{next} for the caveats of modifying
|
See function @Lid{next} for more details about the traversal.
|
||||||
the table during its traversal.
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -6964,7 +7045,7 @@ in case of error
|
|||||||
(either the original error that stopped the coroutine or
|
(either the original error that stopped the coroutine or
|
||||||
errors in closing methods),
|
errors in closing methods),
|
||||||
this function returns @false plus the error object;
|
this function returns @false plus the error object;
|
||||||
otherwise ir returns @true.
|
otherwise it returns @true.
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -7680,7 +7761,7 @@ If @id{j} is absent, then it is assumed to be equal to @num{-1}
|
|||||||
In particular,
|
In particular,
|
||||||
the call @T{string.sub(s,1,j)} returns a prefix of @id{s}
|
the call @T{string.sub(s,1,j)} returns a prefix of @id{s}
|
||||||
with length @id{j},
|
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}
|
returns a suffix of @id{s}
|
||||||
with length @id{i}.
|
with length @id{i}.
|
||||||
|
|
||||||
@@ -8116,7 +8197,7 @@ the function returns @fail.
|
|||||||
A negative @id{n} gets characters before position @id{i}.
|
A negative @id{n} gets characters before position @id{i}.
|
||||||
The default for @id{i} is 1 when @id{n} is non-negative
|
The default for @id{i} is 1 when @id{n} is non-negative
|
||||||
and @T{#s + 1} otherwise,
|
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.
|
@id{n}-th character from the end of the string.
|
||||||
|
|
||||||
As a special case,
|
As a special case,
|
||||||
@@ -8169,7 +8250,7 @@ the table will have; its default is zero.
|
|||||||
|
|
||||||
Inserts element @id{value} at position @id{pos} in @id{list},
|
Inserts element @id{value} at position @id{pos} in @id{list},
|
||||||
shifting up the elements
|
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},
|
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
|
so that a call @T{table.insert(t,x)} inserts @id{x} at the end
|
||||||
of the list @id{t}.
|
of the list @id{t}.
|
||||||
@@ -8207,7 +8288,7 @@ Removes from @id{list} the element at position @id{pos},
|
|||||||
returning the value of the removed element.
|
returning the value of the removed element.
|
||||||
When @id{pos} is an integer between 1 and @T{#list},
|
When @id{pos} is an integer between 1 and @T{#list},
|
||||||
it shifts down the elements
|
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]};
|
and erases element @T{list[#list]};
|
||||||
The index @id{pos} can also be 0 when @T{#list} is 0,
|
The index @id{pos} can also be 0 when @T{#list} is 0,
|
||||||
or @T{#list + 1}.
|
or @T{#list + 1}.
|
||||||
@@ -8337,6 +8418,17 @@ 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|
|
@LibEntry{math.huge|
|
||||||
|
|
||||||
The float value @idx{HUGE_VAL},
|
The float value @idx{HUGE_VAL},
|
||||||
@@ -8344,6 +8436,12 @@ 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])|
|
@LibEntry{math.log (x [, base])|
|
||||||
|
|
||||||
Returns the logarithm of @id{x} in the given base.
|
Returns the logarithm of @id{x} in the given base.
|
||||||
@@ -8399,7 +8497,7 @@ Converts the angle @id{x} from degrees to radians.
|
|||||||
|
|
||||||
When called without arguments,
|
When called without arguments,
|
||||||
returns a pseudo-random float with uniform distribution
|
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},
|
When called with two integers @id{m} and @id{n},
|
||||||
@id{math.random} returns a pseudo-random integer
|
@id{math.random} returns a pseudo-random integer
|
||||||
with uniform distribution in the range @M{[m, n]}.
|
with uniform distribution in the range @M{[m, n]}.
|
||||||
@@ -9026,6 +9124,7 @@ which automatically removes the file when the program ends.
|
|||||||
|
|
||||||
This library provides
|
This library provides
|
||||||
the functionality of the @link{debugI|debug interface} to Lua programs.
|
the functionality of the @link{debugI|debug interface} to Lua programs.
|
||||||
|
|
||||||
You should exert care when using this library.
|
You should exert care when using this library.
|
||||||
Several of its functions
|
Several of its functions
|
||||||
violate basic assumptions about Lua code
|
violate basic assumptions about Lua code
|
||||||
@@ -9035,6 +9134,8 @@ that userdata metatables cannot be changed by Lua code;
|
|||||||
that Lua programs do not crash)
|
that Lua programs do not crash)
|
||||||
and therefore can compromise otherwise secure code.
|
and therefore can compromise otherwise secure code.
|
||||||
Moreover, some functions in this library may be slow.
|
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
|
All functions in this library are provided
|
||||||
inside the @defid{debug} table.
|
inside the @defid{debug} table.
|
||||||
@@ -9120,6 +9221,10 @@ Compile-time constants may not appear in this listing,
|
|||||||
if they were optimized away by the compiler.
|
if they were optimized away by the compiler.
|
||||||
Negative indices refer to vararg arguments;
|
Negative indices refer to vararg arguments;
|
||||||
@num{-1} is the first vararg argument.
|
@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
|
The function returns @fail
|
||||||
if there is no variable with the given index,
|
if there is no variable with the given index,
|
||||||
and raises an error when called with a level out of range.
|
and raises an error when called with a level out of range.
|
||||||
@@ -9509,12 +9614,18 @@ change between versions.
|
|||||||
@item{
|
@item{
|
||||||
The word @Rw{global} is a reserved word.
|
The word @Rw{global} is a reserved word.
|
||||||
Do not use it as a regular name.
|
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{
|
@item{
|
||||||
The control variable in @Rw{for} loops is read only.
|
The control variable in @Rw{for} loops is read only.
|
||||||
If you need to change it,
|
If you need to change it,
|
||||||
declare a local variable with the same name in the loop body.
|
declare a local variable with the same name in the loop body.
|
||||||
|
|
||||||
|
The compilation option @id{LUA_COMPAT_LOOPVAR} (see @id{luaconf.h})
|
||||||
|
makes these variables regular (writable).
|
||||||
}
|
}
|
||||||
|
|
||||||
@item{
|
@item{
|
||||||
@@ -9640,7 +9751,7 @@ and @bnfNter{LiteralString}, see @See{lexical}.)
|
|||||||
@OrNL @Rw{local} @Rw{function} @bnfNter{Name} funcbody
|
@OrNL @Rw{local} @Rw{function} @bnfNter{Name} funcbody
|
||||||
@OrNL @Rw{global} @Rw{function} @bnfNter{Name} funcbody
|
@OrNL @Rw{global} @Rw{function} @bnfNter{Name} funcbody
|
||||||
@OrNL @Rw{local} attnamelist @bnfopt{@bnfter{=} explist}
|
@OrNL @Rw{local} attnamelist @bnfopt{@bnfter{=} explist}
|
||||||
@OrNL @Rw{global} attnamelist
|
@OrNL @Rw{global} attnamelist @bnfopt{@bnfter{=} explist}
|
||||||
@OrNL @Rw{global} @bnfopt{attrib} @bnfter{*}
|
@OrNL @Rw{global} @bnfopt{attrib} @bnfter{*}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -9702,8 +9813,10 @@ and @bnfNter{LiteralString}, see @See{lexical}.)
|
|||||||
|
|
||||||
@producname{funcbody}@producbody{@bnfter{(} @bnfopt{parlist} @bnfter{)} block @Rw{end}}
|
@producname{funcbody}@producbody{@bnfter{(} @bnfopt{parlist} @bnfter{)} block @Rw{end}}
|
||||||
|
|
||||||
@producname{parlist}@producbody{namelist @bnfopt{@bnfter{,} @bnfter{...}}
|
@producname{parlist}@producbody{namelist @bnfopt{@bnfter{,} varargparam} @Or
|
||||||
@Or @bnfter{...}}
|
varargparam}
|
||||||
|
|
||||||
|
@producname{varargparam}@producbody{@bnfter{...} @bnfopt{@bnfNter{Name}}}
|
||||||
|
|
||||||
@producname{tableconstructor}@producbody{@bnfter{@Open} @bnfopt{fieldlist} @bnfter{@Close}}
|
@producname{tableconstructor}@producbody{@bnfter{@Open} @bnfopt{fieldlist} @bnfter{@Close}}
|
||||||
|
|
||||||
|
|||||||
@@ -5,10 +5,14 @@
|
|||||||
**
|
**
|
||||||
** $ gcc -O2 -std=c99 -o lua onelua.c -lm
|
** $ gcc -O2 -std=c99 -o lua onelua.c -lm
|
||||||
**
|
**
|
||||||
** or
|
** or (for C89)
|
||||||
**
|
**
|
||||||
** $ gcc -O2 -std=c89 -DLUA_USE_C89 -o lua onelua.c -lm
|
** $ 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 */
|
/* default is to build the full interpreter */
|
||||||
@@ -30,7 +34,15 @@
|
|||||||
#define LUA_USE_LINUX
|
#define LUA_USE_LINUX
|
||||||
#define LUA_USE_MACOSX
|
#define LUA_USE_MACOSX
|
||||||
#define LUA_USE_POSIX
|
#define LUA_USE_POSIX
|
||||||
#define LUA_ANSI
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Other specific features
|
||||||
|
*/
|
||||||
|
#if 0
|
||||||
|
#define LUA_32BITS
|
||||||
|
#define LUA_USE_C89
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@@ -54,12 +66,10 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
|
|
||||||
/* setup for luaconf.h */
|
/* setup for luaconf.h */
|
||||||
#define LUA_CORE
|
#define LUA_CORE
|
||||||
#define LUA_LIB
|
#define LUA_LIB
|
||||||
#define ltable_c
|
|
||||||
#define lvm_c
|
|
||||||
#include "luaconf.h"
|
#include "luaconf.h"
|
||||||
|
|
||||||
/* do not export internal symbols */
|
/* do not export internal symbols */
|
||||||
@@ -110,6 +120,11 @@
|
|||||||
#include "linit.c"
|
#include "linit.c"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* test library -- used only for internal development */
|
||||||
|
#if defined(LUA_DEBUG)
|
||||||
|
#include "ltests.c"
|
||||||
|
#endif
|
||||||
|
|
||||||
/* lua */
|
/* lua */
|
||||||
#ifdef MAKE_LUA
|
#ifdef MAKE_LUA
|
||||||
#include "lua.c"
|
#include "lua.c"
|
||||||
|
|||||||
+2
-1
@@ -246,7 +246,8 @@ 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 LE 9 1, return 1"))
|
||||||
assert(not T.testC("compare EQ 9 9, return 1"))
|
assert(not T.testC("compare EQ 9 9, return 1"))
|
||||||
|
|
||||||
local b = {__lt = function (a,b) return a[1] < b[1] end}
|
local b = {__lt = function (a,b) return a[1] < b[1] end,
|
||||||
|
__le = function (a,b) return a[1] <= b[1] end}
|
||||||
local a1,a3,a4 = setmetatable({1}, b),
|
local a1,a3,a4 = setmetatable({1}, b),
|
||||||
setmetatable({3}, b),
|
setmetatable({3}, b),
|
||||||
setmetatable({4}, b)
|
setmetatable({4}, b)
|
||||||
|
|||||||
+22
-2
@@ -308,11 +308,11 @@ else
|
|||||||
_ENV.x, _ENV.y = nil
|
_ENV.x, _ENV.y = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
_ENV = _G
|
_ENV = _G
|
||||||
|
|
||||||
|
|
||||||
-- testing preload
|
-- testing preload
|
||||||
|
|
||||||
do
|
do
|
||||||
local p = package
|
local p = package
|
||||||
package = {}
|
package = {}
|
||||||
@@ -331,6 +331,26 @@ do
|
|||||||
assert(type(package.path) == "string")
|
assert(type(package.path) == "string")
|
||||||
end
|
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('+')
|
print('+')
|
||||||
|
|
||||||
end --]
|
end --]
|
||||||
@@ -447,7 +467,7 @@ do
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- test of large float/integer indices
|
-- test of large float/integer indices
|
||||||
|
|
||||||
-- compute maximum integer where all bits fit in a float
|
-- compute maximum integer where all bits fit in a float
|
||||||
local maxint = math.maxinteger
|
local maxint = math.maxinteger
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ local strsub = string.sub
|
|||||||
|
|
||||||
local print = print
|
local print = print
|
||||||
|
|
||||||
_ENV = nil
|
global none
|
||||||
|
|
||||||
-- Try to convert a value to an integer, without assuming any coercion.
|
-- Try to convert a value to an integer, without assuming any coercion.
|
||||||
local function toint (x)
|
local function toint (x)
|
||||||
|
|||||||
+28
-2
@@ -24,7 +24,7 @@ assert(not pcall(type))
|
|||||||
|
|
||||||
|
|
||||||
-- testing local-function recursion
|
-- testing local-function recursion
|
||||||
global fact; fact = false
|
global fact = false
|
||||||
do
|
do
|
||||||
local res = 1
|
local res = 1
|
||||||
local function fact (n)
|
local function fact (n)
|
||||||
@@ -65,7 +65,7 @@ a.b.c:f2('k', 12); assert(a.b.c.k == 12)
|
|||||||
|
|
||||||
print('+')
|
print('+')
|
||||||
|
|
||||||
global t; t = nil -- 'declare' t
|
global t = nil -- 'declare' t
|
||||||
function f(a,b,c) local d = 'a'; t={a,b,c,d} end
|
function f(a,b,c) local d = 'a'; t={a,b,c,d} end
|
||||||
|
|
||||||
f( -- this line change must be valid
|
f( -- this line change must be valid
|
||||||
@@ -372,6 +372,32 @@ do -- another bug (in 5.4.0)
|
|||||||
end
|
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"))
|
x = string.dump(load("x = 1; return x"))
|
||||||
a = assert(load(read1(x), nil, "b"))
|
a = assert(load(read1(x), nil, "b"))
|
||||||
assert(a() == 1 and _G.x == 1)
|
assert(a() == 1 and _G.x == 1)
|
||||||
|
|||||||
@@ -702,7 +702,9 @@ else
|
|||||||
assert(t.currentline == t.linedefined + 2)
|
assert(t.currentline == t.linedefined + 2)
|
||||||
assert(not debug.getinfo(c, 1)) -- no other level
|
assert(not debug.getinfo(c, 1)) -- no other level
|
||||||
assert(coroutine.resume(c)) -- run next line
|
assert(coroutine.resume(c)) -- run next line
|
||||||
local n,v = debug.getlocal(c, 0, 2) -- check next local
|
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
|
||||||
assert(n == "b" and v == 10)
|
assert(n == "b" and v == 10)
|
||||||
v = {coroutine.resume(c)} -- finish coroutine
|
v = {coroutine.resume(c)} -- finish coroutine
|
||||||
assert(v[1] == true and v[2] == 2 and v[3] == 3 and v[4] == undef)
|
assert(v[1] == true and v[2] == 2 and v[3] == 3 and v[4] == undef)
|
||||||
|
|||||||
+8
-4
@@ -356,8 +356,8 @@ function f(a,b)
|
|||||||
global assert, g, string
|
global assert, g, string
|
||||||
local _, y = debug.getlocal(1, 2)
|
local _, y = debug.getlocal(1, 2)
|
||||||
assert(x == a and y == b)
|
assert(x == a and y == b)
|
||||||
assert(debug.setlocal(2, 3, "pera") == "AA".."AA")
|
assert(debug.setlocal(2, 4, "pera") == "AA".."AA")
|
||||||
assert(debug.setlocal(2, 4, "manga") == "B")
|
assert(debug.setlocal(2, 5, "manga") == "B")
|
||||||
x = debug.getinfo(2)
|
x = debug.getinfo(2)
|
||||||
assert(x.func == g and x.what == "Lua" and x.name == 'g' and
|
assert(x.func == g and x.what == "Lua" and x.name == 'g' and
|
||||||
x.nups == 2 and string.find(x.source, "^@.*db%.lua$"))
|
x.nups == 2 and string.find(x.source, "^@.*db%.lua$"))
|
||||||
@@ -392,7 +392,7 @@ function g (...)
|
|||||||
global *
|
global *
|
||||||
local B = 13
|
local B = 13
|
||||||
global<const> assert
|
global<const> assert
|
||||||
local x,y = debug.getlocal(1,5)
|
local x,y = debug.getlocal(1,6)
|
||||||
assert(x == 'B' and y == 13)
|
assert(x == 'B' and y == 13)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -458,7 +458,8 @@ local function collectlocals (level)
|
|||||||
local tab = {}
|
local tab = {}
|
||||||
for i = 1, math.huge do
|
for i = 1, math.huge do
|
||||||
local n, v = debug.getlocal(level + 1, i)
|
local n, v = debug.getlocal(level + 1, i)
|
||||||
if not (n and string.find(n, "^[a-zA-Z0-9_]+$")) then
|
if not (n and string.find(n, "^[a-zA-Z0-9_]+$") or
|
||||||
|
n == "(vararg table)") then
|
||||||
break -- consider only real variables
|
break -- consider only real variables
|
||||||
end
|
end
|
||||||
tab[n] = v
|
tab[n] = v
|
||||||
@@ -725,6 +726,9 @@ assert(t.isvararg == false and t.nparams == 3 and t.nups == 0)
|
|||||||
t = debug.getinfo(function (a,b,...) return t[a] end, "u")
|
t = debug.getinfo(function (a,b,...) return t[a] end, "u")
|
||||||
assert(t.isvararg == true and t.nparams == 2 and t.nups == 1)
|
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
|
t = debug.getinfo(1) -- main
|
||||||
assert(t.isvararg == true and t.nparams == 0 and t.nups == 1 and
|
assert(t.isvararg == true and t.nparams == 0 and t.nups == 1 and
|
||||||
debug.getupvalue(t.func, 1) == "_ENV")
|
debug.getupvalue(t.func, 1) == "_ENV")
|
||||||
|
|||||||
+57
-29
@@ -159,6 +159,9 @@ 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={13}; local bbbb=1; aaa[bbbb](3)", "number")
|
||||||
checkmessage("aaa=(1)..{}", "a table value")
|
checkmessage("aaa=(1)..{}", "a table value")
|
||||||
|
|
||||||
|
checkmessage("local function foo (...t) return t.xx + 1 end; foo()",
|
||||||
|
"field 'xx'")
|
||||||
|
|
||||||
-- bug in 5.4.6
|
-- bug in 5.4.6
|
||||||
checkmessage("a = {_ENV = {}}; print(a._ENV.x + 1)", "field 'x'")
|
checkmessage("a = {_ENV = {}}; print(a._ENV.x + 1)", "field 'x'")
|
||||||
|
|
||||||
@@ -418,28 +421,28 @@ end
|
|||||||
|
|
||||||
-- testing line error
|
-- testing line error
|
||||||
|
|
||||||
local function lineerror (s, l)
|
local function lineerror (s, l, w)
|
||||||
local err,msg = pcall(load(s))
|
local err,msg = pcall(load(s))
|
||||||
local line = tonumber(string.match(msg, ":(%d+):"))
|
local line = tonumber(string.match(msg, ":(%d+):"))
|
||||||
assert(line == l or (not line and not l))
|
assert((line == l or (not line and not l)) and string.find(msg, w))
|
||||||
end
|
end
|
||||||
|
|
||||||
lineerror("local a\n for i=1,'a' do \n print(i) \n end", 2)
|
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)
|
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)
|
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)
|
lineerror("function a.x.y ()\na=a+1\nend", 1, "index")
|
||||||
|
|
||||||
lineerror("a = \na\n+\n{}", 3)
|
lineerror("a = \na\n+\n{}", 3, "arithmetic")
|
||||||
lineerror("a = \n3\n+\n(\n4\n/\nprint)", 6)
|
lineerror("a = \n3\n+\n(\n4\n/\nprint)", 6, "arithmetic")
|
||||||
lineerror("a = \nprint\n+\n(\n4\n/\n7)", 3)
|
lineerror("a = \nprint\n+\n(\n4\n/\n7)", 3, "arithmetic")
|
||||||
|
|
||||||
lineerror("a\n=\n-\n\nprint\n;", 3)
|
lineerror("a\n=\n-\n\nprint\n;", 3, "arithmetic")
|
||||||
|
|
||||||
lineerror([[
|
lineerror([[
|
||||||
a
|
a
|
||||||
( -- <<
|
( -- <<
|
||||||
23)
|
23)
|
||||||
]], 2)
|
]], 2, "call")
|
||||||
|
|
||||||
lineerror([[
|
lineerror([[
|
||||||
local a = {x = 13}
|
local a = {x = 13}
|
||||||
@@ -449,7 +452,7 @@ x
|
|||||||
( -- <<
|
( -- <<
|
||||||
23
|
23
|
||||||
)
|
)
|
||||||
]], 5)
|
]], 5, "call")
|
||||||
|
|
||||||
lineerror([[
|
lineerror([[
|
||||||
local a = {x = 13}
|
local a = {x = 13}
|
||||||
@@ -459,17 +462,17 @@ x
|
|||||||
(
|
(
|
||||||
23 + a
|
23 + a
|
||||||
)
|
)
|
||||||
]], 6)
|
]], 6, "arithmetic")
|
||||||
|
|
||||||
local p = [[
|
local p = [[
|
||||||
function g() f() end
|
function g() f() end
|
||||||
function f(x) error('a', XX) end
|
function f(x) error('a', XX) end
|
||||||
g()
|
g()
|
||||||
]]
|
]]
|
||||||
XX=3;lineerror((p), 3)
|
XX=3;lineerror((p), 3, "a")
|
||||||
XX=0;lineerror((p), false)
|
XX=0;lineerror((p), false, "a")
|
||||||
XX=1;lineerror((p), 2)
|
XX=1;lineerror((p), 2, "a")
|
||||||
XX=2;lineerror((p), 1)
|
XX=2;lineerror((p), 1, "a")
|
||||||
_G.XX, _G.g, _G.f = nil
|
_G.XX, _G.g, _G.f = nil
|
||||||
|
|
||||||
|
|
||||||
@@ -477,7 +480,7 @@ lineerror([[
|
|||||||
local b = false
|
local b = false
|
||||||
if not b then
|
if not b then
|
||||||
error 'test'
|
error 'test'
|
||||||
end]], 3)
|
end]], 3, "test")
|
||||||
|
|
||||||
lineerror([[
|
lineerror([[
|
||||||
local b = false
|
local b = false
|
||||||
@@ -487,7 +490,7 @@ if not b then
|
|||||||
error 'test'
|
error 'test'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end]], 5)
|
end]], 5, "test")
|
||||||
|
|
||||||
lineerror([[
|
lineerror([[
|
||||||
_ENV = 1
|
_ENV = 1
|
||||||
@@ -495,7 +498,7 @@ global function foo ()
|
|||||||
local a = 10
|
local a = 10
|
||||||
return a
|
return a
|
||||||
end
|
end
|
||||||
]], 2)
|
]], 2, "index")
|
||||||
|
|
||||||
|
|
||||||
-- bug in 5.4.0
|
-- bug in 5.4.0
|
||||||
@@ -503,17 +506,37 @@ lineerror([[
|
|||||||
local a = 0
|
local a = 0
|
||||||
local b = 1
|
local b = 1
|
||||||
local c = b % a
|
local c = b % a
|
||||||
]], 3)
|
]], 3, "perform")
|
||||||
|
|
||||||
do
|
do
|
||||||
-- Force a negative estimate for base line. Error in instruction 2
|
-- Force a negative estimate for base line. Error in instruction 2
|
||||||
-- (after VARARGPREP, GETGLOBAL), with first absolute line information
|
-- (after VARARGPREP, GETGLOBAL), with first absolute line information
|
||||||
-- (forced by too many lines) in instruction 0.
|
-- (forced by too many lines) in instruction 0.
|
||||||
local s = string.format("%s return __A.x", string.rep("\n", 300))
|
local s = string.format("%s return __A.x", string.rep("\n", 300))
|
||||||
lineerror(s, 301)
|
lineerror(s, 301, "index")
|
||||||
end
|
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
|
if not _soft then
|
||||||
-- several tests that exhaust the Lua stack
|
-- several tests that exhaust the Lua stack
|
||||||
collectgarbage()
|
collectgarbage()
|
||||||
@@ -689,21 +712,26 @@ end
|
|||||||
-- testing syntax limits
|
-- testing syntax limits
|
||||||
|
|
||||||
local function testrep (init, rep, close, repc, finalresult)
|
local function testrep (init, rep, close, repc, finalresult)
|
||||||
local s = init .. string.rep(rep, 100) .. close .. string.rep(repc, 100)
|
local function gencode (n)
|
||||||
local res, msg = load(s)
|
return init .. string.rep(rep, n) .. close .. string.rep(repc, n)
|
||||||
assert(res) -- 100 levels is OK
|
end
|
||||||
|
local res, msg = load(gencode(100)) -- 100 levels is OK
|
||||||
|
assert(res)
|
||||||
if (finalresult) then
|
if (finalresult) then
|
||||||
assert(res() == finalresult)
|
assert(res() == finalresult)
|
||||||
end
|
end
|
||||||
s = init .. string.rep(rep, 500)
|
local res, msg = load(gencode(500)) -- 500 levels not ok
|
||||||
local res, msg = load(s) -- 500 levels not ok
|
|
||||||
assert(not res and (string.find(msg, "too many") or
|
assert(not res and (string.find(msg, "too many") or
|
||||||
string.find(msg, "overflow")))
|
string.find(msg, "overflow")))
|
||||||
end
|
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", ",a", "= 1", ",1") -- multiple assignment
|
||||||
testrep("local a; a=", "{", "0", "}")
|
testrep("local a; a=", "{", "0", "}") -- constructors
|
||||||
testrep("return ", "(", "2", ")", 2)
|
testrep("return ", "(", "2", ")", 2) -- parentheses
|
||||||
|
-- nested calls (a(a(a(a(...)))))
|
||||||
testrep("local function a (x) return x end; return ", "a(", "2.2", ")", 2.2)
|
testrep("local function a (x) return x end; return ", "a(", "2.2", ")", 2.2)
|
||||||
testrep("", "do ", "", " end")
|
testrep("", "do ", "", " end")
|
||||||
testrep("", "while a do ", "", " end")
|
testrep("", "while a do ", "", " end")
|
||||||
|
|||||||
+2
-2
@@ -715,7 +715,7 @@ do
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
if T and T.nonblock then
|
if T and T.nonblock and not _port then
|
||||||
print("testing failed write")
|
print("testing failed write")
|
||||||
|
|
||||||
-- unable to write anything to /dev/full
|
-- unable to write anything to /dev/full
|
||||||
@@ -840,7 +840,7 @@ assert(os.date("!\0\0") == "\0\0")
|
|||||||
local x = string.rep("a", 10000)
|
local x = string.rep("a", 10000)
|
||||||
assert(os.date(x) == x)
|
assert(os.date(x) == x)
|
||||||
local t = os.time()
|
local t = os.time()
|
||||||
global D; D = os.date("*t", t)
|
global D = os.date("*t", t)
|
||||||
assert(os.date(string.rep("%d", 1000), t) ==
|
assert(os.date(string.rep("%d", 1000), t) ==
|
||||||
string.rep(os.date("%d", t), 1000))
|
string.rep(os.date("%d", t), 1000))
|
||||||
assert(os.date(string.rep("%", 200)) == string.rep("%", 100))
|
assert(os.date(string.rep("%", 200)) == string.rep("%", 100))
|
||||||
|
|||||||
@@ -707,4 +707,46 @@ end
|
|||||||
|
|
||||||
collectgarbage(oldmode)
|
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')
|
print('OK')
|
||||||
|
|||||||
@@ -176,6 +176,20 @@ do print"testing stop-the-world collection"
|
|||||||
assert(collectgarbage("param", "stepsize") == step)
|
assert(collectgarbage("param", "stepsize") == step)
|
||||||
end
|
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)
|
collectgarbage(oldmode)
|
||||||
|
|
||||||
print('OK')
|
print('OK')
|
||||||
|
|||||||
+63
-1
@@ -293,6 +293,7 @@ end
|
|||||||
foo()
|
foo()
|
||||||
--------------------------------------------------------------------------
|
--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
-- check for compilation errors
|
||||||
local function checkerr (code, err)
|
local function checkerr (code, err)
|
||||||
local st, msg = load(code)
|
local st, msg = load(code)
|
||||||
assert(not st and string.find(msg, err))
|
assert(not st and string.find(msg, err))
|
||||||
@@ -380,7 +381,7 @@ do
|
|||||||
global *
|
global *
|
||||||
Y = x + Y
|
Y = x + Y
|
||||||
assert(_ENV.Y == 20)
|
assert(_ENV.Y == 20)
|
||||||
|
Y = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
@@ -411,5 +412,66 @@ do -- mixing lots of global/local declarations
|
|||||||
_ENV.x200 = nil
|
_ENV.x200 = nil
|
||||||
end
|
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'
|
print'OK'
|
||||||
|
|
||||||
|
|||||||
+10
-8
@@ -1,6 +1,8 @@
|
|||||||
-- $Id: testes/heavy.lua,v $
|
-- $Id: testes/heavy.lua,v $
|
||||||
-- See Copyright Notice in file lua.h
|
-- See Copyright Notice in file lua.h
|
||||||
|
|
||||||
|
global <const> *
|
||||||
|
|
||||||
local function teststring ()
|
local function teststring ()
|
||||||
print("creating a string too long")
|
print("creating a string too long")
|
||||||
do
|
do
|
||||||
@@ -47,9 +49,9 @@ local function loadrep (x, what)
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function controlstruct ()
|
local function controlstruct ()
|
||||||
print("control structure too long")
|
print("control structure too long")
|
||||||
local lim = ((1 << 24) - 2) // 3
|
local lim = ((1 << 24) - 2) // 4
|
||||||
local s = string.rep("a = a + 1\n", lim)
|
local s = string.rep("a = a + 1\n", lim)
|
||||||
s = "while true do " .. s .. "end"
|
s = "while true do " .. s .. "end"
|
||||||
assert(load(s))
|
assert(load(s))
|
||||||
@@ -63,7 +65,7 @@ function controlstruct ()
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function manylines ()
|
local function manylines ()
|
||||||
print("loading chunk with too many lines")
|
print("loading chunk with too many lines")
|
||||||
local st, msg = loadrep("\n", "lines")
|
local st, msg = loadrep("\n", "lines")
|
||||||
assert(not st and string.find(msg, "too many lines"))
|
assert(not st and string.find(msg, "too many lines"))
|
||||||
@@ -71,7 +73,7 @@ function manylines ()
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function hugeid ()
|
local function hugeid ()
|
||||||
print("loading chunk with huge identifier")
|
print("loading chunk with huge identifier")
|
||||||
local st, msg = loadrep("a", "chars")
|
local st, msg = loadrep("a", "chars")
|
||||||
assert(not st and
|
assert(not st and
|
||||||
@@ -80,7 +82,7 @@ function hugeid ()
|
|||||||
print('+')
|
print('+')
|
||||||
end
|
end
|
||||||
|
|
||||||
function toomanyinst ()
|
local function toomanyinst ()
|
||||||
print("loading chunk with too many instructions")
|
print("loading chunk with too many instructions")
|
||||||
local st, msg = loadrep("a = 10; ", "instructions")
|
local st, msg = loadrep("a = 10; ", "instructions")
|
||||||
print('+')
|
print('+')
|
||||||
@@ -107,7 +109,7 @@ local function loadrepfunc (prefix, f)
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function toomanyconst ()
|
local function toomanyconst ()
|
||||||
print("loading function with too many constants")
|
print("loading function with too many constants")
|
||||||
loadrepfunc("function foo () return {0,",
|
loadrepfunc("function foo () return {0,",
|
||||||
function (n)
|
function (n)
|
||||||
@@ -126,7 +128,7 @@ function toomanyconst ()
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function toomanystr ()
|
local function toomanystr ()
|
||||||
local a = {}
|
local a = {}
|
||||||
local st, msg = pcall(function ()
|
local st, msg = pcall(function ()
|
||||||
for i = 1, math.huge do
|
for i = 1, math.huge do
|
||||||
@@ -144,7 +146,7 @@ function toomanystr ()
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function toomanyidx ()
|
local function toomanyidx ()
|
||||||
local a = {}
|
local a = {}
|
||||||
local st, msg = pcall(function ()
|
local st, msg = pcall(function ()
|
||||||
for i = 1, math.huge do
|
for i = 1, math.huge do
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
#include "lua.h"
|
#include "lua.h"
|
||||||
|
|
||||||
/* function from lib1.c */
|
/* function from lib1.c */
|
||||||
int lib1_export (lua_State *L);
|
LUAMOD_API int lib1_export (lua_State *L);
|
||||||
|
|
||||||
LUAMOD_API int luaopen_lib11 (lua_State *L) {
|
LUAMOD_API int luaopen_lib11 (lua_State *L) {
|
||||||
return lib1_export(L);
|
return lib1_export(L);
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
|
/* implementation for lib2-v2 */
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include "lua.h"
|
#include "lua.h"
|
||||||
#include "lauxlib.h"
|
#include "lauxlib.h"
|
||||||
|
|
||||||
@@ -8,8 +12,54 @@ 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[] = {
|
static const struct luaL_Reg funcs[] = {
|
||||||
{"id", id},
|
{"id", id},
|
||||||
|
{"newstr", newstr},
|
||||||
{NULL, NULL}
|
{NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -18,6 +68,7 @@ LUAMOD_API int luaopen_lib2 (lua_State *L) {
|
|||||||
lua_settop(L, 2);
|
lua_settop(L, 2);
|
||||||
lua_setglobal(L, "y"); /* y gets 2nd parameter */
|
lua_setglobal(L, "y"); /* y gets 2nd parameter */
|
||||||
lua_setglobal(L, "x"); /* x gets 1st parameter */
|
lua_setglobal(L, "x"); /* x gets 1st parameter */
|
||||||
|
initstr(L);
|
||||||
luaL_newlib(L, funcs);
|
luaL_newlib(L, funcs);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ LUA_DIR = ../../
|
|||||||
CC = gcc
|
CC = gcc
|
||||||
|
|
||||||
# compilation should generate Dynamic-Link Libraries
|
# compilation should generate Dynamic-Link Libraries
|
||||||
CFLAGS = -Wall -std=c99 -O2 -I$(LUA_DIR) -fPIC -shared
|
CFLAGS = -Wall -O2 -I$(LUA_DIR) -fPIC -shared
|
||||||
|
|
||||||
# libraries used by the tests
|
# libraries used by the tests
|
||||||
all: lib1.so lib11.so lib2.so lib21.so lib2-v2.so
|
all: lib1.so lib11.so lib2.so lib21.so lib2-v2.so
|
||||||
|
|||||||
+2
-4
@@ -310,8 +310,7 @@ do -- testing presence of second argument
|
|||||||
local function foo (howtoclose, obj, n)
|
local function foo (howtoclose, obj, n)
|
||||||
local ca -- copy of 'a' visible inside its close metamethod
|
local ca -- copy of 'a' visible inside its close metamethod
|
||||||
do
|
do
|
||||||
local a <close> = func2close(function (...)
|
local a <close> = func2close(function (...t)
|
||||||
local t = table.pack(...)
|
|
||||||
assert(select("#", ...) == n)
|
assert(select("#", ...) == n)
|
||||||
assert(t.n == n and t[1] == ca and (t.n < 2 or t[2] == obj))
|
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"
|
ca = 15 -- final value to be returned if howtoclose=="scope"
|
||||||
@@ -911,8 +910,7 @@ do
|
|||||||
|
|
||||||
local extrares -- result from extra yield (if any)
|
local extrares -- result from extra yield (if any)
|
||||||
|
|
||||||
local function check (body, extra, ...)
|
local function check (body, extra, ...t)
|
||||||
local t = table.pack(...) -- expected returns
|
|
||||||
local co = coroutine.wrap(body)
|
local co = coroutine.wrap(body)
|
||||||
if extra then
|
if extra then
|
||||||
extrares = co() -- runs until first (extra) yield
|
extrares = co() -- runs until first (extra) yield
|
||||||
|
|||||||
+27
-5
@@ -78,6 +78,9 @@ end
|
|||||||
|
|
||||||
RUN('lua -v')
|
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))
|
print(string.format("(temporary program file used in these tests: %s)", prog))
|
||||||
|
|
||||||
-- running stdin as a file
|
-- running stdin as a file
|
||||||
@@ -90,7 +93,7 @@ prepfile[[
|
|||||||
1, a
|
1, a
|
||||||
)
|
)
|
||||||
]]
|
]]
|
||||||
RUN('lua - < %s > %s', prog, out)
|
RUN('lua - -- < %s > %s', prog, out)
|
||||||
checkout("1\tnil\n")
|
checkout("1\tnil\n")
|
||||||
|
|
||||||
RUN('echo "print(10)\nprint(2)\n" | lua > %s', out)
|
RUN('echo "print(10)\nprint(2)\n" | lua > %s', out)
|
||||||
@@ -133,7 +136,7 @@ checkout("-h\n")
|
|||||||
prepfile("print(package.path)")
|
prepfile("print(package.path)")
|
||||||
|
|
||||||
-- test LUA_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")
|
checkout("x\n")
|
||||||
|
|
||||||
-- test LUA_PATH_version
|
-- test LUA_PATH_version
|
||||||
@@ -167,7 +170,9 @@ checkout("10\n11\n")
|
|||||||
-- test errors in LUA_INIT
|
-- test errors in LUA_INIT
|
||||||
NoRun('LUA_INIT:1: msg', 'env LUA_INIT="error(\'msg\')" lua')
|
NoRun('LUA_INIT:1: msg', 'env LUA_INIT="error(\'msg\')" lua')
|
||||||
|
|
||||||
-- test option '-E'
|
|
||||||
|
print("testing option '-E'")
|
||||||
|
|
||||||
local defaultpath, defaultCpath
|
local defaultpath, defaultCpath
|
||||||
|
|
||||||
do
|
do
|
||||||
@@ -192,6 +197,22 @@ assert(not string.find(defaultpath, "xxx") and
|
|||||||
string.find(defaultCpath, "lua"))
|
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
|
-- test replacement of ';;' to default path
|
||||||
local function convert (p)
|
local function convert (p)
|
||||||
prepfile("print(package.path)")
|
prepfile("print(package.path)")
|
||||||
@@ -358,7 +379,7 @@ RUN([[lua -e"_PROMPT='' _PROMPT2=''" -i < %s > %s]], prog, out)
|
|||||||
checkprogout("6\n10\n10\n\n")
|
checkprogout("6\n10\n10\n\n")
|
||||||
|
|
||||||
prepfile("a = [[b\nc\nd\ne]]\na")
|
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")
|
checkprogout("b\nc\nd\ne\n\n")
|
||||||
|
|
||||||
-- input interrupted in continuation line
|
-- input interrupted in continuation line
|
||||||
@@ -488,12 +509,13 @@ assert(not os.remove(out))
|
|||||||
-- invalid options
|
-- invalid options
|
||||||
NoRun("unrecognized option '-h'", "lua -h")
|
NoRun("unrecognized option '-h'", "lua -h")
|
||||||
NoRun("unrecognized option '---'", "lua ---")
|
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 '-vv'", "lua -vv")
|
||||||
NoRun("unrecognized option '-iv'", "lua -iv")
|
NoRun("unrecognized option '-iv'", "lua -iv")
|
||||||
NoRun("'-e' needs argument", "lua -e")
|
NoRun("'-e' needs argument", "lua -e")
|
||||||
NoRun("syntax error", "lua -e a")
|
NoRun("syntax error", "lua -e a")
|
||||||
NoRun("'-l' needs argument", "lua -l")
|
NoRun("'-l' needs argument", "lua -l")
|
||||||
|
NoRun("-i", "lua -- -i") -- handles -i as a script name
|
||||||
|
|
||||||
|
|
||||||
if T then -- test library?
|
if T then -- test library?
|
||||||
|
|||||||
@@ -685,6 +685,18 @@ assert(eq(math.exp(0), 1))
|
|||||||
assert(eq(math.sin(10), math.sin(10%(2*math.pi))))
|
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.3e-2 ') == 1.3e-2)
|
||||||
assert(tonumber(' -1.00000000000001 ') == -1.00000000000001)
|
assert(tonumber(' -1.00000000000001 ') == -1.00000000000001)
|
||||||
|
|
||||||
|
|||||||
+54
-11
@@ -42,8 +42,12 @@ checkerr(MEMERRMSG, f)
|
|||||||
T.alloccount() -- remove limit
|
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,
|
-- test memory errors; increase limit for maximum memory by steps,
|
||||||
-- o that we get memory errors in all allocations of a given
|
-- so that we get memory errors in all allocations of a given
|
||||||
-- task, until there is enough memory to complete the task without
|
-- task, until there is enough memory to complete the task without
|
||||||
-- errors.
|
-- errors.
|
||||||
local function testbytes (s, f)
|
local function testbytes (s, f)
|
||||||
@@ -53,6 +57,7 @@ local function testbytes (s, f)
|
|||||||
local a,b = nil
|
local a,b = nil
|
||||||
while true do
|
while true do
|
||||||
collectgarbage(); collectgarbage()
|
collectgarbage(); collectgarbage()
|
||||||
|
deep(4)
|
||||||
T.totalmem(M)
|
T.totalmem(M)
|
||||||
a, b = T.testC("pcall 0 1 0; pushstatus; return 2", f)
|
a, b = T.testC("pcall 0 1 0; pushstatus; return 2", f)
|
||||||
T.totalmem(0) -- remove limit
|
T.totalmem(0) -- remove limit
|
||||||
@@ -77,6 +82,7 @@ local function testalloc (s, f)
|
|||||||
local a,b = nil
|
local a,b = nil
|
||||||
while true do
|
while true do
|
||||||
collectgarbage(); collectgarbage()
|
collectgarbage(); collectgarbage()
|
||||||
|
deep(4)
|
||||||
T.alloccount(M)
|
T.alloccount(M)
|
||||||
a, b = T.testC("pcall 0 1 0; pushstatus; return 2", f)
|
a, b = T.testC("pcall 0 1 0; pushstatus; return 2", f)
|
||||||
T.alloccount() -- remove limit
|
T.alloccount() -- remove limit
|
||||||
@@ -87,21 +93,19 @@ local function testalloc (s, f)
|
|||||||
M = M + 1 -- increase allocation limit
|
M = M + 1 -- increase allocation limit
|
||||||
end
|
end
|
||||||
print(string.format("minimum allocations for %s: %d allocations", s, M))
|
print(string.format("minimum allocations for %s: %d allocations", s, M))
|
||||||
return a
|
return M
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
local function testamem (s, f)
|
local function testamem (s, f)
|
||||||
testalloc(s, f)
|
local aloc = testalloc(s, f)
|
||||||
return testbytes(s, f)
|
local res = testbytes(s, f)
|
||||||
|
return {aloc = aloc, res = res}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- doing nothing
|
local b = testamem("function call", function () return 10 end)
|
||||||
b = testamem("doing nothing", function () return 10 end)
|
assert(b.res == 10 and b.aloc == 0)
|
||||||
assert(b == 10)
|
|
||||||
|
|
||||||
-- testing memory errors when creating a new state
|
|
||||||
|
|
||||||
testamem("state creation", function ()
|
testamem("state creation", function ()
|
||||||
local st = T.newstate()
|
local st = T.newstate()
|
||||||
@@ -121,6 +125,18 @@ testamem("coroutine creation", function()
|
|||||||
return coroutine.create(print)
|
return coroutine.create(print)
|
||||||
end)
|
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
|
-- testing to-be-closed variables
|
||||||
testamem("to-be-closed variables", function()
|
testamem("to-be-closed variables", function()
|
||||||
@@ -150,9 +166,9 @@ local function expand (n,s)
|
|||||||
e, s, expand(n-1,s), e)
|
e, s, expand(n-1,s), e)
|
||||||
end
|
end
|
||||||
|
|
||||||
G=0; collectgarbage(); a =collectgarbage("count")
|
G=0; collectgarbage()
|
||||||
load(expand(20,"G=G+1"))()
|
load(expand(20,"G=G+1"))()
|
||||||
assert(G==20); collectgarbage(); -- assert(gcinfo() <= a+1)
|
assert(G==20); collectgarbage()
|
||||||
G = nil
|
G = nil
|
||||||
|
|
||||||
testamem("running code on new thread", function ()
|
testamem("running code on new thread", function ()
|
||||||
@@ -160,6 +176,14 @@ testamem("running code on new thread", function ()
|
|||||||
end)
|
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
|
-- testing memory x compiler
|
||||||
|
|
||||||
testamem("loadstring", function ()
|
testamem("loadstring", function ()
|
||||||
@@ -258,6 +282,25 @@ testamem("growing stack", function ()
|
|||||||
return foo(100)
|
return foo(100)
|
||||||
end)
|
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)
|
||||||
|
|
||||||
-- }==================================================================
|
-- }==================================================================
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+18
-1
@@ -345,6 +345,18 @@ do
|
|||||||
end
|
end
|
||||||
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 = {}
|
local nofind = {}
|
||||||
|
|
||||||
|
|
||||||
@@ -893,13 +905,18 @@ local function foo1 (e,i)
|
|||||||
if i <= e.n then return i,a[i] end
|
if i <= e.n then return i,a[i] end
|
||||||
end
|
end
|
||||||
|
|
||||||
setmetatable(a, {__pairs = function (x) return foo, x, 0 end})
|
local closed = false
|
||||||
|
setmetatable(a, {__pairs = function (x)
|
||||||
|
local tbc = setmetatable({}, {__close = function () closed = true end})
|
||||||
|
return foo, x, 0, tbc
|
||||||
|
end})
|
||||||
|
|
||||||
local i = 0
|
local i = 0
|
||||||
for k,v in pairs(a) do
|
for k,v in pairs(a) do
|
||||||
i = i + 1
|
i = i + 1
|
||||||
assert(k == i and v == k+1)
|
assert(k == i and v == k+1)
|
||||||
end
|
end
|
||||||
|
assert(closed) -- 'tbc' has been closed
|
||||||
|
|
||||||
a.n = 5
|
a.n = 5
|
||||||
a[3] = 30
|
a[3] = 30
|
||||||
|
|||||||
@@ -347,6 +347,16 @@ do -- init parameter in gmatch
|
|||||||
end
|
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')
|
-- tests for `%f' (`frontiers')
|
||||||
|
|
||||||
assert(string.gsub("aaa aa a aaa a", "%f[%w]a", "x") == "xaa xa x xaa x")
|
assert(string.gsub("aaa aa a aaa a", "%f[%w]a", "x") == "xaa xa x xaa x")
|
||||||
|
|||||||
@@ -72,6 +72,19 @@ assert(a==1 and x==nil)
|
|||||||
a,x = unpack({1,2}, 1, 1)
|
a,x = unpack({1,2}, 1, 1)
|
||||||
assert(a==1 and x==nil)
|
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
|
do
|
||||||
local maxi = (1 << 31) - 1 -- maximum value for an int (usually)
|
local maxi = (1 << 31) - 1 -- maximum value for an int (usually)
|
||||||
local mini = -(1 << 31) -- minimum value for an int (usually)
|
local mini = -(1 << 31) -- minimum value for an int (usually)
|
||||||
|
|||||||
@@ -540,6 +540,23 @@ else
|
|||||||
assert(y == x)
|
assert(y == x)
|
||||||
local z = T.externstr(x) -- external allocated long string
|
local z = T.externstr(x) -- external allocated long string
|
||||||
assert(z == y)
|
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
|
end
|
||||||
|
|
||||||
print('OK')
|
print('OK')
|
||||||
|
|||||||
+8
-3
@@ -1,12 +1,17 @@
|
|||||||
-- track collections
|
-- track collections
|
||||||
|
|
||||||
|
|
||||||
local M = {}
|
local M = {}
|
||||||
|
|
||||||
-- import list
|
-- import list
|
||||||
local setmetatable, stderr, collectgarbage =
|
local stderr, collectgarbage = io.stderr, collectgarbage
|
||||||
setmetatable, io.stderr, collectgarbage
|
|
||||||
|
|
||||||
_ENV = nil
|
-- 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
|
||||||
|
|
||||||
local active = false
|
local active = false
|
||||||
|
|
||||||
|
|||||||
+22
-1
@@ -152,11 +152,20 @@ 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, "𦧺", 1, 2)
|
checkerror("continuation byte", utf8.offset, "𦧺", 1, 2)
|
||||||
checkerror("continuation byte", utf8.offset, "\x80", 1)
|
checkerror("continuation byte", utf8.offset, "\x80", 1)
|
||||||
|
checkerror("continuation byte", utf8.offset, "\x9c", -1)
|
||||||
|
|
||||||
-- error in indices for len
|
-- error in indices for len
|
||||||
checkerror("out of bounds", utf8.len, "abc", 0, 2)
|
checkerror("out of bounds", utf8.len, "abc", 0, 2)
|
||||||
checkerror("out of bounds", utf8.len, "abc", 1, 4)
|
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 s = "hello World"
|
||||||
local t = {string.byte(s, 1, -1)}
|
local t = {string.byte(s, 1, -1)}
|
||||||
@@ -229,10 +238,18 @@ s = "\0 \x7F\z
|
|||||||
s = string.gsub(s, " ", "")
|
s = string.gsub(s, " ", "")
|
||||||
check(s, {0,0x7F, 0x80,0x7FF, 0x800,0xFFFF, 0x10000,0x10FFFF})
|
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
|
do
|
||||||
-- original UTF-8 values
|
-- original UTF-8 values
|
||||||
local s = "\u{4000000}\u{7FFFFFFF}"
|
local s = "\u{4000000}\u{7FFFFFFF}"
|
||||||
assert(#s == 12)
|
assert(s == "\xFC\x84\x80\x80\x80\x80\xFD\xBF\xBF\xBF\xBF\xBF")
|
||||||
check(s, {0x4000000, 0x7FFFFFFF}, true)
|
check(s, {0x4000000, 0x7FFFFFFF}, true)
|
||||||
|
|
||||||
s = "\u{200000}\u{3FFFFFF}"
|
s = "\u{200000}\u{3FFFFFF}"
|
||||||
@@ -248,6 +265,10 @@ local x = "日本語a-4\0éó"
|
|||||||
check(x, {26085, 26412, 35486, 97, 45, 52, 0, 233, 243})
|
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
|
-- Supplementary Characters
|
||||||
check("𣲷𠜎𠱓𡁻𠵼ab𠺢",
|
check("𣲷𠜎𠱓𡁻𠵼ab𠺢",
|
||||||
{0x23CB7, 0x2070E, 0x20C53, 0x2107B, 0x20D7C, 0x61, 0x62, 0x20EA2,})
|
{0x23CB7, 0x2070E, 0x20C53, 0x2107B, 0x20D7C, 0x61, 0x62, 0x20EA2,})
|
||||||
|
|||||||
+113
-4
@@ -3,9 +3,12 @@
|
|||||||
|
|
||||||
print('testing vararg')
|
print('testing vararg')
|
||||||
|
|
||||||
local function f (a, ...)
|
local function f (a, ...t)
|
||||||
local x = {n = select('#', ...), ...}
|
local x = {n = select('#', ...), ...}
|
||||||
for i = 1, x.n do assert(a[i] == x[i]) end
|
assert(x.n == t.n)
|
||||||
|
for i = 1, x.n do
|
||||||
|
assert(a[i] == x[i] and x[i] == t[i])
|
||||||
|
end
|
||||||
return x.n
|
return x.n
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -17,7 +20,7 @@ local function c12 (...)
|
|||||||
return res, 2
|
return res, 2
|
||||||
end
|
end
|
||||||
|
|
||||||
local function vararg (...) return {n = select('#', ...), ...} end
|
local function vararg (... t) return t end
|
||||||
|
|
||||||
local call = function (f, args) return f(table.unpack(args, 1, args.n)) end
|
local call = function (f, args) return f(table.unpack(args, 1, args.n)) end
|
||||||
|
|
||||||
@@ -98,8 +101,40 @@ a,b,c,d,e = f(4)
|
|||||||
assert(a==nil and b==nil and c==nil and d==nil and e==nil)
|
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
|
-- varargs for main chunks
|
||||||
local f = load[[ return {...} ]]
|
local f = assert(load[[ return {...} ]])
|
||||||
local x = f(2,3)
|
local x = f(2,3)
|
||||||
assert(x[1] == 2 and x[2] == 3 and x[3] == undef)
|
assert(x[1] == 2 and x[2] == 3 and x[3] == undef)
|
||||||
|
|
||||||
@@ -147,5 +182,79 @@ do
|
|||||||
local a, b = g()
|
local a, b = g()
|
||||||
assert(a == nil and b == 2)
|
assert(a == nil and b == 2)
|
||||||
end
|
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')
|
print('OK')
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user