Update LUA

This commit is contained in:
Andrew Pamment 2016-12-10 07:31:44 +10:00
parent 12f874c015
commit 3237c6de14
28 changed files with 975 additions and 594 deletions

View File

@ -26,7 +26,7 @@ MYOBJS=
# == END OF USER SETTINGS -- NO NEED TO CHANGE ANYTHING BELOW THIS LINE ======= # == END OF USER SETTINGS -- NO NEED TO CHANGE ANYTHING BELOW THIS LINE =======
PLATS= aix bsd c89 freebsd generic linux macosx mingw posix solaris minix PLATS= aix bsd c89 freebsd generic linux macosx mingw posix solaris
LUA_A= liblua.a LUA_A= liblua.a
CORE_O= lapi.o lcode.o lctype.o ldebug.o ldo.o ldump.o lfunc.o lgc.o llex.o \ CORE_O= lapi.o lcode.o lctype.o ldebug.o ldo.o ldump.o lfunc.o lgc.o llex.o \
@ -101,11 +101,8 @@ c89:
@echo '' @echo ''
minix:
$(MAKE) $(ALL) CC="clang" SYSCFLAGS="-DLUA_USE_LINUX" SYSLIBS="-L/usr/pkg/lib -Wl,-E -lreadline"
freebsd: freebsd:
$(MAKE) $(ALL) CC="cc" SYSCFLAGS="-DLUA_USE_LINUX -I/usr/local/include" SYSLIBS="-Wl,-E -L/usr/local/lib -lreadline" $(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_LINUX" SYSLIBS="-Wl,-E -lreadline"
generic: $(ALL) generic: $(ALL)

View File

@ -1,5 +1,5 @@
/* /*
** $Id: lapi.c,v 2.257 2015/11/02 18:48:07 roberto Exp $ ** $Id: lapi.c,v 2.259 2016/02/29 14:27:14 roberto Exp $
** Lua API ** Lua API
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -378,9 +378,9 @@ LUA_API const char *lua_tolstring (lua_State *L, int idx, size_t *len) {
return NULL; return NULL;
} }
lua_lock(L); /* 'luaO_tostring' may create a new string */ lua_lock(L); /* 'luaO_tostring' may create a new string */
luaO_tostring(L, o);
luaC_checkGC(L); luaC_checkGC(L);
o = index2addr(L, idx); /* previous call may reallocate the stack */ o = index2addr(L, idx); /* previous call may reallocate the stack */
luaO_tostring(L, o);
lua_unlock(L); lua_unlock(L);
} }
if (len != NULL) if (len != NULL)
@ -479,10 +479,10 @@ LUA_API void lua_pushinteger (lua_State *L, lua_Integer n) {
LUA_API const char *lua_pushlstring (lua_State *L, const char *s, size_t len) { LUA_API const char *lua_pushlstring (lua_State *L, const char *s, size_t len) {
TString *ts; TString *ts;
lua_lock(L); lua_lock(L);
luaC_checkGC(L);
ts = (len == 0) ? luaS_new(L, "") : luaS_newlstr(L, s, len); ts = (len == 0) ? luaS_new(L, "") : luaS_newlstr(L, s, len);
setsvalue2s(L, L->top, ts); setsvalue2s(L, L->top, ts);
api_incr_top(L); api_incr_top(L);
luaC_checkGC(L);
lua_unlock(L); lua_unlock(L);
return getstr(ts); return getstr(ts);
} }
@ -494,12 +494,12 @@ LUA_API const char *lua_pushstring (lua_State *L, const char *s) {
setnilvalue(L->top); setnilvalue(L->top);
else { else {
TString *ts; TString *ts;
luaC_checkGC(L);
ts = luaS_new(L, s); ts = luaS_new(L, s);
setsvalue2s(L, L->top, ts); setsvalue2s(L, L->top, ts);
s = getstr(ts); /* internal copy's address */ s = getstr(ts); /* internal copy's address */
} }
api_incr_top(L); api_incr_top(L);
luaC_checkGC(L);
lua_unlock(L); lua_unlock(L);
return s; return s;
} }
@ -509,8 +509,8 @@ LUA_API const char *lua_pushvfstring (lua_State *L, const char *fmt,
va_list argp) { va_list argp) {
const char *ret; const char *ret;
lua_lock(L); lua_lock(L);
luaC_checkGC(L);
ret = luaO_pushvfstring(L, fmt, argp); ret = luaO_pushvfstring(L, fmt, argp);
luaC_checkGC(L);
lua_unlock(L); lua_unlock(L);
return ret; return ret;
} }
@ -520,10 +520,10 @@ LUA_API const char *lua_pushfstring (lua_State *L, const char *fmt, ...) {
const char *ret; const char *ret;
va_list argp; va_list argp;
lua_lock(L); lua_lock(L);
luaC_checkGC(L);
va_start(argp, fmt); va_start(argp, fmt);
ret = luaO_pushvfstring(L, fmt, argp); ret = luaO_pushvfstring(L, fmt, argp);
va_end(argp); va_end(argp);
luaC_checkGC(L);
lua_unlock(L); lua_unlock(L);
return ret; return ret;
} }
@ -538,7 +538,6 @@ LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
CClosure *cl; CClosure *cl;
api_checknelems(L, n); api_checknelems(L, n);
api_check(L, n <= MAXUPVAL, "upvalue index too large"); api_check(L, n <= MAXUPVAL, "upvalue index too large");
luaC_checkGC(L);
cl = luaF_newCclosure(L, n); cl = luaF_newCclosure(L, n);
cl->f = fn; cl->f = fn;
L->top -= n; L->top -= n;
@ -549,6 +548,7 @@ LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
setclCvalue(L, L->top, cl); setclCvalue(L, L->top, cl);
} }
api_incr_top(L); api_incr_top(L);
luaC_checkGC(L);
lua_unlock(L); lua_unlock(L);
} }
@ -585,16 +585,16 @@ LUA_API int lua_pushthread (lua_State *L) {
static int auxgetstr (lua_State *L, const TValue *t, const char *k) { static int auxgetstr (lua_State *L, const TValue *t, const char *k) {
const TValue *aux; const TValue *slot;
TString *str = luaS_new(L, k); TString *str = luaS_new(L, k);
if (luaV_fastget(L, t, str, aux, luaH_getstr)) { if (luaV_fastget(L, t, str, slot, luaH_getstr)) {
setobj2s(L, L->top, aux); setobj2s(L, L->top, slot);
api_incr_top(L); api_incr_top(L);
} }
else { else {
setsvalue2s(L, L->top, str); setsvalue2s(L, L->top, str);
api_incr_top(L); api_incr_top(L);
luaV_finishget(L, t, L->top - 1, L->top - 1, aux); luaV_finishget(L, t, L->top - 1, L->top - 1, slot);
} }
lua_unlock(L); lua_unlock(L);
return ttnov(L->top - 1); return ttnov(L->top - 1);
@ -626,17 +626,17 @@ LUA_API int lua_getfield (lua_State *L, int idx, const char *k) {
LUA_API int lua_geti (lua_State *L, int idx, lua_Integer n) { LUA_API int lua_geti (lua_State *L, int idx, lua_Integer n) {
StkId t; StkId t;
const TValue *aux; const TValue *slot;
lua_lock(L); lua_lock(L);
t = index2addr(L, idx); t = index2addr(L, idx);
if (luaV_fastget(L, t, n, aux, luaH_getint)) { if (luaV_fastget(L, t, n, slot, luaH_getint)) {
setobj2s(L, L->top, aux); setobj2s(L, L->top, slot);
api_incr_top(L); api_incr_top(L);
} }
else { else {
setivalue(L->top, n); setivalue(L->top, n);
api_incr_top(L); api_incr_top(L);
luaV_finishget(L, t, L->top - 1, L->top - 1, aux); luaV_finishget(L, t, L->top - 1, L->top - 1, slot);
} }
lua_unlock(L); lua_unlock(L);
return ttnov(L->top - 1); return ttnov(L->top - 1);
@ -683,12 +683,12 @@ LUA_API int lua_rawgetp (lua_State *L, int idx, const void *p) {
LUA_API void lua_createtable (lua_State *L, int narray, int nrec) { LUA_API void lua_createtable (lua_State *L, int narray, int nrec) {
Table *t; Table *t;
lua_lock(L); lua_lock(L);
luaC_checkGC(L);
t = luaH_new(L); t = luaH_new(L);
sethvalue(L, L->top, t); sethvalue(L, L->top, t);
api_incr_top(L); api_incr_top(L);
if (narray > 0 || nrec > 0) if (narray > 0 || nrec > 0)
luaH_resize(L, t, narray, nrec); luaH_resize(L, t, narray, nrec);
luaC_checkGC(L);
lua_unlock(L); lua_unlock(L);
} }
@ -740,15 +740,15 @@ LUA_API int lua_getuservalue (lua_State *L, int idx) {
** t[k] = value at the top of the stack (where 'k' is a string) ** t[k] = value at the top of the stack (where 'k' is a string)
*/ */
static void auxsetstr (lua_State *L, const TValue *t, const char *k) { static void auxsetstr (lua_State *L, const TValue *t, const char *k) {
const TValue *aux; const TValue *slot;
TString *str = luaS_new(L, k); TString *str = luaS_new(L, k);
api_checknelems(L, 1); api_checknelems(L, 1);
if (luaV_fastset(L, t, str, aux, luaH_getstr, L->top - 1)) if (luaV_fastset(L, t, str, slot, luaH_getstr, L->top - 1))
L->top--; /* pop value */ L->top--; /* pop value */
else { else {
setsvalue2s(L, L->top, str); /* push 'str' (to make it a TValue) */ setsvalue2s(L, L->top, str); /* push 'str' (to make it a TValue) */
api_incr_top(L); api_incr_top(L);
luaV_finishset(L, t, L->top - 1, L->top - 2, aux); luaV_finishset(L, t, L->top - 1, L->top - 2, slot);
L->top -= 2; /* pop value and key */ L->top -= 2; /* pop value and key */
} }
lua_unlock(L); /* lock done by caller */ lua_unlock(L); /* lock done by caller */
@ -781,16 +781,16 @@ LUA_API void lua_setfield (lua_State *L, int idx, const char *k) {
LUA_API void lua_seti (lua_State *L, int idx, lua_Integer n) { LUA_API void lua_seti (lua_State *L, int idx, lua_Integer n) {
StkId t; StkId t;
const TValue *aux; const TValue *slot;
lua_lock(L); lua_lock(L);
api_checknelems(L, 1); api_checknelems(L, 1);
t = index2addr(L, idx); t = index2addr(L, idx);
if (luaV_fastset(L, t, n, aux, luaH_getint, L->top - 1)) if (luaV_fastset(L, t, n, slot, luaH_getint, L->top - 1))
L->top--; /* pop value */ L->top--; /* pop value */
else { else {
setivalue(L->top, n); setivalue(L->top, n);
api_incr_top(L); api_incr_top(L);
luaV_finishset(L, t, L->top - 1, L->top - 2, aux); luaV_finishset(L, t, L->top - 1, L->top - 2, slot);
L->top -= 2; /* pop value and key */ L->top -= 2; /* pop value and key */
} }
lua_unlock(L); lua_unlock(L);
@ -1140,7 +1140,6 @@ LUA_API void lua_concat (lua_State *L, int n) {
lua_lock(L); lua_lock(L);
api_checknelems(L, n); api_checknelems(L, n);
if (n >= 2) { if (n >= 2) {
luaC_checkGC(L);
luaV_concat(L, n); luaV_concat(L, n);
} }
else if (n == 0) { /* push empty string */ else if (n == 0) { /* push empty string */
@ -1148,6 +1147,7 @@ LUA_API void lua_concat (lua_State *L, int n) {
api_incr_top(L); api_incr_top(L);
} }
/* else n == 1; nothing to do */ /* else n == 1; nothing to do */
luaC_checkGC(L);
lua_unlock(L); lua_unlock(L);
} }
@ -1183,10 +1183,10 @@ LUA_API void lua_setallocf (lua_State *L, lua_Alloc f, void *ud) {
LUA_API void *lua_newuserdata (lua_State *L, size_t size) { LUA_API void *lua_newuserdata (lua_State *L, size_t size) {
Udata *u; Udata *u;
lua_lock(L); lua_lock(L);
luaC_checkGC(L);
u = luaS_newudata(L, size); u = luaS_newudata(L, size);
setuvalue(L, L->top, u); setuvalue(L, L->top, u);
api_incr_top(L); api_incr_top(L);
luaC_checkGC(L);
lua_unlock(L); lua_unlock(L);
return getudatamem(u); return getudatamem(u);
} }

View File

@ -1,5 +1,5 @@
/* /*
** $Id: lauxlib.c,v 1.284 2015/11/19 19:16:22 roberto Exp $ ** $Id: lauxlib.c,v 1.286 2016/01/08 15:33:09 roberto Exp $
** Auxiliary functions for building Lua libraries ** Auxiliary functions for building Lua libraries
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -17,7 +17,8 @@
#include <string.h> #include <string.h>
/* This file uses only the official API of Lua. /*
** This file uses only the official API of Lua.
** Any function declared here could be written as an application function. ** Any function declared here could be written as an application function.
*/ */
@ -198,6 +199,10 @@ static void tag_error (lua_State *L, int arg, int tag) {
} }
/*
** The use of 'lua_pushfstring' ensures this function does not
** need reserved stack space when called.
*/
LUALIB_API void luaL_where (lua_State *L, int level) { LUALIB_API void luaL_where (lua_State *L, int level) {
lua_Debug ar; lua_Debug ar;
if (lua_getstack(L, level, &ar)) { /* check function at level */ if (lua_getstack(L, level, &ar)) { /* check function at level */
@ -207,10 +212,15 @@ LUALIB_API void luaL_where (lua_State *L, int level) {
return; return;
} }
} }
lua_pushliteral(L, ""); /* else, no information available... */ lua_pushfstring(L, ""); /* else, no information available... */
} }
/*
** Again, the use of 'lua_pushvfstring' ensures this function does
** not need reserved stack space when called. (At worst, it generates
** an error with "stack overflow" instead of the given message.)
*/
LUALIB_API int luaL_error (lua_State *L, const char *fmt, ...) { LUALIB_API int luaL_error (lua_State *L, const char *fmt, ...) {
va_list argp; va_list argp;
va_start(argp, fmt); va_start(argp, fmt);
@ -349,10 +359,15 @@ LUALIB_API int luaL_checkoption (lua_State *L, int arg, const char *def,
} }
/*
** Ensures the stack has at least 'space' extra slots, raising an error
** if it cannot fulfill the request. (The error handling needs a few
** extra slots to format the error message. In case of an error without
** this extra space, Lua will generate the same 'stack overflow' error,
** but without 'msg'.)
*/
LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *msg) { LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *msg) {
/* keep some extra space to run error routines, if needed */ if (!lua_checkstack(L, space)) {
const int extra = LUA_MINSTACK;
if (!lua_checkstack(L, space + extra)) {
if (msg) if (msg)
luaL_error(L, "stack overflow (%s)", msg); luaL_error(L, "stack overflow (%s)", msg);
else else

View File

@ -1,5 +1,5 @@
/* /*
** $Id: lbaselib.c,v 1.312 2015/10/29 15:21:04 roberto Exp $ ** $Id: lbaselib.c,v 1.313 2016/04/11 19:18:40 roberto Exp $
** Basic library ** Basic library
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -102,8 +102,8 @@ static int luaB_tonumber (lua_State *L) {
static int luaB_error (lua_State *L) { static int luaB_error (lua_State *L) {
int level = (int)luaL_optinteger(L, 2, 1); int level = (int)luaL_optinteger(L, 2, 1);
lua_settop(L, 1); lua_settop(L, 1);
if (lua_isstring(L, 1) && level > 0) { /* add extra information? */ if (lua_type(L, 1) == LUA_TSTRING && level > 0) {
luaL_where(L, level); luaL_where(L, level); /* add extra information */
lua_pushvalue(L, 1); lua_pushvalue(L, 1);
lua_concat(L, 2); lua_concat(L, 2);
} }
@ -251,9 +251,8 @@ static int ipairsaux (lua_State *L) {
/* /*
** This function will use either 'ipairsaux' or 'ipairsaux_raw' to ** 'ipairs' function. Returns 'ipairsaux', given "table", 0.
** traverse a table, depending on whether the table has metamethods ** (The given "table" may not be a table.)
** that can affect the traversal.
*/ */
static int luaB_ipairs (lua_State *L) { static int luaB_ipairs (lua_State *L) {
#if defined(LUA_COMPAT_IPAIRS) #if defined(LUA_COMPAT_IPAIRS)

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
/* /*
** $Id: lcode.h,v 1.63 2013/12/30 20:47:58 roberto Exp $ ** $Id: lcode.h,v 1.64 2016/01/05 16:22:37 roberto Exp $
** Code generator for Lua ** Code generator for Lua
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -40,7 +40,8 @@ typedef enum BinOpr {
typedef enum UnOpr { OPR_MINUS, OPR_BNOT, OPR_NOT, OPR_LEN, OPR_NOUNOPR } UnOpr; typedef enum UnOpr { OPR_MINUS, OPR_BNOT, OPR_NOT, OPR_LEN, OPR_NOUNOPR } UnOpr;
#define getcode(fs,e) ((fs)->f->code[(e)->u.info]) /* get (pointer to) instruction of given 'expdesc' */
#define getinstruction(fs,e) ((fs)->f->code[(e)->u.info])
#define luaK_codeAsBx(fs,o,A,sBx) luaK_codeABx(fs,o,A,(sBx)+MAXARG_sBx) #define luaK_codeAsBx(fs,o,A,sBx) luaK_codeABx(fs,o,A,(sBx)+MAXARG_sBx)

View File

@ -1,5 +1,5 @@
/* /*
** $Id: lcorolib.c,v 1.9 2014/11/02 19:19:04 roberto Exp $ ** $Id: lcorolib.c,v 1.10 2016/04/11 19:19:55 roberto Exp $
** Coroutine Library ** Coroutine Library
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -75,7 +75,7 @@ static int luaB_auxwrap (lua_State *L) {
lua_State *co = lua_tothread(L, lua_upvalueindex(1)); lua_State *co = lua_tothread(L, lua_upvalueindex(1));
int r = auxresume(L, co, lua_gettop(L)); int r = auxresume(L, co, lua_gettop(L));
if (r < 0) { if (r < 0) {
if (lua_isstring(L, -1)) { /* error object is a string? */ if (lua_type(L, -1) == LUA_TSTRING) { /* error object is a string? */
luaL_where(L, 1); /* add extra info */ luaL_where(L, 1); /* add extra info */
lua_insert(L, -2); lua_insert(L, -2);
lua_concat(L, 2); lua_concat(L, 2);

View File

@ -1,5 +1,5 @@
/* /*
** $Id: ldebug.c,v 2.117 2015/11/02 18:48:07 roberto Exp $ ** $Id: ldebug.c,v 2.120 2016/03/31 19:01:21 roberto Exp $
** Debug Interface ** Debug Interface
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -69,7 +69,13 @@ static void swapextra (lua_State *L) {
/* /*
** this function can be called asynchronous (e.g. during a signal) ** This function can be called asynchronously (e.g. during a signal).
** Fields 'oldpc', 'basehookcount', and 'hookcount' (set by
** 'resethookcount') are for debug only, and it is no problem if they
** get arbitrary values (causes at most one wrong hook call). 'hookmask'
** is an atomic value. We assume that pointers are atomic too (e.g., gcc
** ensures that for all platforms where it runs). Moreover, 'hook' is
** always checked before being called (see 'luaD_hook').
*/ */
LUA_API void lua_sethook (lua_State *L, lua_Hook func, int mask, int count) { LUA_API void lua_sethook (lua_State *L, lua_Hook func, int mask, int count) {
if (func == NULL || mask == 0) { /* turn off hooks? */ if (func == NULL || mask == 0) { /* turn off hooks? */
@ -558,7 +564,7 @@ static const char *varinfo (lua_State *L, const TValue *o) {
l_noret luaG_typeerror (lua_State *L, const TValue *o, const char *op) { l_noret luaG_typeerror (lua_State *L, const TValue *o, const char *op) {
const char *t = objtypename(o); const char *t = luaT_objtypename(L, o);
luaG_runerror(L, "attempt to %s a %s value%s", op, t, varinfo(L, o)); luaG_runerror(L, "attempt to %s a %s value%s", op, t, varinfo(L, o));
} }
@ -590,9 +596,9 @@ l_noret luaG_tointerror (lua_State *L, const TValue *p1, const TValue *p2) {
l_noret luaG_ordererror (lua_State *L, const TValue *p1, const TValue *p2) { l_noret luaG_ordererror (lua_State *L, const TValue *p1, const TValue *p2) {
const char *t1 = objtypename(p1); const char *t1 = luaT_objtypename(L, p1);
const char *t2 = objtypename(p2); const char *t2 = luaT_objtypename(L, p2);
if (t1 == t2) if (strcmp(t1, t2) == 0)
luaG_runerror(L, "attempt to compare two %s values", t1); luaG_runerror(L, "attempt to compare two %s values", t1);
else else
luaG_runerror(L, "attempt to compare %s with %s", t1, t2); luaG_runerror(L, "attempt to compare %s with %s", t1, t2);

View File

@ -1,5 +1,5 @@
/* /*
** $Id: ldo.c,v 2.150 2015/11/19 19:16:22 roberto Exp $ ** $Id: ldo.c,v 2.151 2015/12/16 16:40:07 roberto Exp $
** Stack and Call structure of Lua ** Stack and Call structure of Lua
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -242,9 +242,14 @@ void luaD_inctop (lua_State *L) {
/* }================================================================== */ /* }================================================================== */
/*
** Call a hook for the given event. Make sure there is a hook to be
** called. (Both 'L->hook' and 'L->hookmask', which triggers this
** function, can be changed asynchronously by signals.)
*/
void luaD_hook (lua_State *L, int event, int line) { void luaD_hook (lua_State *L, int event, int line) {
lua_Hook hook = L->hook; lua_Hook hook = L->hook;
if (hook && L->allowhook) { if (hook && L->allowhook) { /* make sure there is a hook */
CallInfo *ci = L->ci; CallInfo *ci = L->ci;
ptrdiff_t top = savestack(L, L->top); ptrdiff_t top = savestack(L, L->top);
ptrdiff_t ci_top = savestack(L, ci->top); ptrdiff_t ci_top = savestack(L, ci->top);

View File

@ -1,5 +1,5 @@
/* /*
** $Id: ldo.h,v 2.28 2015/11/23 11:29:43 roberto Exp $ ** $Id: ldo.h,v 2.29 2015/12/21 13:02:14 roberto Exp $
** Stack and Call structure of Lua ** Stack and Call structure of Lua
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -25,7 +25,7 @@
{ pre; luaD_growstack(L, n); pos; } else { condmovestack(L,pre,pos); } { pre; luaD_growstack(L, n); pos; } else { condmovestack(L,pre,pos); }
/* In general, 'pre'/'pos' are empty (nothing to save) */ /* In general, 'pre'/'pos' are empty (nothing to save) */
#define luaD_checkstack(L,n) luaD_checkstackaux(L,n,,) #define luaD_checkstack(L,n) luaD_checkstackaux(L,n,(void)0,(void)0)

View File

@ -1,5 +1,5 @@
/* /*
** $Id: lgc.c,v 2.210 2015/11/03 18:10:44 roberto Exp $ ** $Id: lgc.c,v 2.212 2016/03/31 19:02:03 roberto Exp $
** Garbage Collector ** Garbage Collector
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -754,14 +754,11 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) {
/* /*
** sweep a list until a live object (or end of list) ** sweep a list until a live object (or end of list)
*/ */
static GCObject **sweeptolive (lua_State *L, GCObject **p, int *n) { static GCObject **sweeptolive (lua_State *L, GCObject **p) {
GCObject **old = p; GCObject **old = p;
int i = 0;
do { do {
i++;
p = sweeplist(L, p, 1); p = sweeplist(L, p, 1);
} while (p == old); } while (p == old);
if (n) *n += i;
return p; return p;
} }
@ -856,10 +853,10 @@ static int runafewfinalizers (lua_State *L) {
/* /*
** call all pending finalizers ** call all pending finalizers
*/ */
static void callallpendingfinalizers (lua_State *L, int propagateerrors) { static void callallpendingfinalizers (lua_State *L) {
global_State *g = G(L); global_State *g = G(L);
while (g->tobefnz) while (g->tobefnz)
GCTM(L, propagateerrors); GCTM(L, 0);
} }
@ -909,7 +906,7 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) {
if (issweepphase(g)) { if (issweepphase(g)) {
makewhite(g, o); /* "sweep" object 'o' */ makewhite(g, o); /* "sweep" object 'o' */
if (g->sweepgc == &o->next) /* should not remove 'sweepgc' object */ if (g->sweepgc == &o->next) /* should not remove 'sweepgc' object */
g->sweepgc = sweeptolive(L, g->sweepgc, NULL); /* change 'sweepgc' */ g->sweepgc = sweeptolive(L, g->sweepgc); /* change 'sweepgc' */
} }
/* search for pointer pointing to 'o' */ /* search for pointer pointing to 'o' */
for (p = &g->allgc; *p != o; p = &(*p)->next) { /* empty */ } for (p = &g->allgc; *p != o; p = &(*p)->next) { /* empty */ }
@ -951,19 +948,16 @@ static void setpause (global_State *g) {
/* /*
** Enter first sweep phase. ** Enter first sweep phase.
** The call to 'sweeptolive' makes pointer point to an object inside ** The call to 'sweeplist' tries to make pointer point to an object
** the list (instead of to the header), so that the real sweep do not ** inside the list (instead of to the header), so that the real sweep do
** need to skip objects created between "now" and the start of the real ** not need to skip objects created between "now" and the start of the
** sweep. ** real sweep.
** Returns how many objects it swept.
*/ */
static int entersweep (lua_State *L) { static void entersweep (lua_State *L) {
global_State *g = G(L); global_State *g = G(L);
int n = 0;
g->gcstate = GCSswpallgc; g->gcstate = GCSswpallgc;
lua_assert(g->sweepgc == NULL); lua_assert(g->sweepgc == NULL);
g->sweepgc = sweeptolive(L, &g->allgc, &n); g->sweepgc = sweeplist(L, &g->allgc, 1);
return n;
} }
@ -971,7 +965,7 @@ void luaC_freeallobjects (lua_State *L) {
global_State *g = G(L); global_State *g = G(L);
separatetobefnz(g, 1); /* separate all objects with finalizers */ separatetobefnz(g, 1); /* separate all objects with finalizers */
lua_assert(g->finobj == NULL); lua_assert(g->finobj == NULL);
callallpendingfinalizers(L, 0); callallpendingfinalizers(L);
lua_assert(g->tobefnz == NULL); lua_assert(g->tobefnz == NULL);
g->currentwhite = WHITEBITS; /* this "white" makes all objects look dead */ g->currentwhite = WHITEBITS; /* this "white" makes all objects look dead */
g->gckind = KGC_NORMAL; g->gckind = KGC_NORMAL;
@ -1064,12 +1058,11 @@ static lu_mem singlestep (lua_State *L) {
} }
case GCSatomic: { case GCSatomic: {
lu_mem work; lu_mem work;
int sw;
propagateall(g); /* make sure gray list is empty */ propagateall(g); /* make sure gray list is empty */
work = atomic(L); /* work is what was traversed by 'atomic' */ work = atomic(L); /* work is what was traversed by 'atomic' */
sw = entersweep(L); entersweep(L);
g->GCestimate = gettotalbytes(g); /* first estimate */; g->GCestimate = gettotalbytes(g); /* first estimate */;
return work + sw * GCSWEEPCOST; return work;
} }
case GCSswpallgc: { /* sweep "regular" objects */ case GCSswpallgc: { /* sweep "regular" objects */
return sweepstep(L, g, GCSswpfinobj, &g->finobj); return sweepstep(L, g, GCSswpfinobj, &g->finobj);

View File

@ -1,5 +1,5 @@
/* /*
** $Id: lgc.h,v 2.90 2015/10/21 18:15:15 roberto Exp $ ** $Id: lgc.h,v 2.91 2015/12/21 13:02:14 roberto Exp $
** Garbage Collector ** Garbage Collector
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -112,7 +112,7 @@
condchangemem(L,pre,pos); } condchangemem(L,pre,pos); }
/* more often than not, 'pre'/'pos' are empty */ /* more often than not, 'pre'/'pos' are empty */
#define luaC_checkGC(L) luaC_condGC(L,,) #define luaC_checkGC(L) luaC_condGC(L,(void)0,(void)0)
#define luaC_barrier(L,p,v) ( \ #define luaC_barrier(L,p,v) ( \

View File

@ -1,5 +1,5 @@
/* /*
** $Id: liolib.c,v 2.148 2015/11/23 11:36:11 roberto Exp $ ** $Id: liolib.c,v 2.149 2016/05/02 14:03:19 roberto Exp $
** Standard I/O (and system) library ** Standard I/O (and system) library
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -375,14 +375,17 @@ static int io_lines (lua_State *L) {
/* maximum length of a numeral */ /* maximum length of a numeral */
#define MAXRN 200 #if !defined (L_MAXLENNUM)
#define L_MAXLENNUM 200
#endif
/* auxiliary structure used by 'read_number' */ /* auxiliary structure used by 'read_number' */
typedef struct { typedef struct {
FILE *f; /* file being read */ FILE *f; /* file being read */
int c; /* current character (look ahead) */ int c; /* current character (look ahead) */
int n; /* number of elements in buffer 'buff' */ int n; /* number of elements in buffer 'buff' */
char buff[MAXRN + 1]; /* +1 for ending '\0' */ char buff[L_MAXLENNUM + 1]; /* +1 for ending '\0' */
} RN; } RN;
@ -390,7 +393,7 @@ typedef struct {
** Add current char to buffer (if not out of space) and read next one ** Add current char to buffer (if not out of space) and read next one
*/ */
static int nextc (RN *rn) { static int nextc (RN *rn) {
if (rn->n >= MAXRN) { /* buffer overflow? */ if (rn->n >= L_MAXLENNUM) { /* buffer overflow? */
rn->buff[0] = '\0'; /* invalidate result */ rn->buff[0] = '\0'; /* invalidate result */
return 0; /* fail */ return 0; /* fail */
} }
@ -403,10 +406,10 @@ static int nextc (RN *rn) {
/* /*
** Accept current char if it is in 'set' (of size 1 or 2) ** Accept current char if it is in 'set' (of size 2)
*/ */
static int test2 (RN *rn, const char *set) { static int test2 (RN *rn, const char *set) {
if (rn->c == set[0] || (rn->c == set[1] && rn->c != '\0')) if (rn->c == set[0] || rn->c == set[1])
return nextc(rn); return nextc(rn);
else return 0; else return 0;
} }
@ -435,11 +438,11 @@ static int read_number (lua_State *L, FILE *f) {
char decp[2]; char decp[2];
rn.f = f; rn.n = 0; rn.f = f; rn.n = 0;
decp[0] = lua_getlocaledecpoint(); /* get decimal point from locale */ decp[0] = lua_getlocaledecpoint(); /* get decimal point from locale */
decp[1] = '\0'; decp[1] = '.'; /* always accept a dot */
l_lockfile(rn.f); l_lockfile(rn.f);
do { rn.c = l_getc(rn.f); } while (isspace(rn.c)); /* skip spaces */ do { rn.c = l_getc(rn.f); } while (isspace(rn.c)); /* skip spaces */
test2(&rn, "-+"); /* optional signal */ test2(&rn, "-+"); /* optional signal */
if (test2(&rn, "0")) { if (test2(&rn, "00")) {
if (test2(&rn, "xX")) hex = 1; /* numeral is hexadecimal */ if (test2(&rn, "xX")) hex = 1; /* numeral is hexadecimal */
else count = 1; /* count initial '0' as a valid digit */ else count = 1; /* count initial '0' as a valid digit */
} }

View File

@ -1,5 +1,5 @@
/* /*
** $Id: llex.c,v 2.95 2015/11/19 19:16:22 roberto Exp $ ** $Id: llex.c,v 2.96 2016/05/02 14:02:12 roberto Exp $
** Lexical Analyzer ** Lexical Analyzer
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -162,7 +162,6 @@ static void inclinenumber (LexState *ls) {
void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source, void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source,
int firstchar) { int firstchar) {
ls->t.token = 0; ls->t.token = 0;
ls->decpoint = '.';
ls->L = L; ls->L = L;
ls->current = firstchar; ls->current = firstchar;
ls->lookahead.token = TK_EOS; /* no look-ahead token */ ls->lookahead.token = TK_EOS; /* no look-ahead token */
@ -207,35 +206,6 @@ static int check_next2 (LexState *ls, const char *set) {
} }
/*
** change all characters 'from' in buffer to 'to'
*/
static void buffreplace (LexState *ls, char from, char to) {
if (from != to) {
size_t n = luaZ_bufflen(ls->buff);
char *p = luaZ_buffer(ls->buff);
while (n--)
if (p[n] == from) p[n] = to;
}
}
/*
** in case of format error, try to change decimal point separator to
** the one defined in the current locale and check again
*/
static void trydecpoint (LexState *ls, TValue *o) {
char old = ls->decpoint;
ls->decpoint = lua_getlocaledecpoint();
buffreplace(ls, old, ls->decpoint); /* try new decimal separator */
if (luaO_str2num(luaZ_buffer(ls->buff), o) == 0) {
/* format error with correct decimal point: no more options */
buffreplace(ls, ls->decpoint, '.'); /* undo change (for error message) */
lexerror(ls, "malformed number", TK_FLT);
}
}
/* LUA_NUMBER */ /* LUA_NUMBER */
/* /*
** this function is quite liberal in what it accepts, as 'luaO_str2num' ** this function is quite liberal in what it accepts, as 'luaO_str2num'
@ -259,9 +229,8 @@ static int read_numeral (LexState *ls, SemInfo *seminfo) {
else break; else break;
} }
save(ls, '\0'); save(ls, '\0');
buffreplace(ls, '.', ls->decpoint); /* follow locale for decimal point */
if (luaO_str2num(luaZ_buffer(ls->buff), &obj) == 0) /* format error? */ if (luaO_str2num(luaZ_buffer(ls->buff), &obj) == 0) /* format error? */
trydecpoint(ls, &obj); /* try to update decimal point separator */ lexerror(ls, "malformed number", TK_FLT);
if (ttisinteger(&obj)) { if (ttisinteger(&obj)) {
seminfo->i = ivalue(&obj); seminfo->i = ivalue(&obj);
return TK_INT; return TK_INT;

View File

@ -1,5 +1,5 @@
/* /*
** $Id: llex.h,v 1.78 2014/10/29 15:38:24 roberto Exp $ ** $Id: llex.h,v 1.79 2016/05/02 14:02:12 roberto Exp $
** Lexical Analyzer ** Lexical Analyzer
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -69,7 +69,6 @@ typedef struct LexState {
struct Dyndata *dyd; /* dynamic structures used by the parser */ struct Dyndata *dyd; /* dynamic structures used by the parser */
TString *source; /* current source name */ TString *source; /* current source name */
TString *envn; /* environment variable name */ TString *envn; /* environment variable name */
char decpoint; /* locale decimal point */
} LexState; } LexState;

View File

@ -1,5 +1,5 @@
/* /*
** $Id: lobject.c,v 2.108 2015/11/02 16:09:30 roberto Exp $ ** $Id: lobject.c,v 2.111 2016/05/20 14:07:48 roberto Exp $
** Some generic functions over Lua objects ** Some generic functions over Lua objects
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -243,20 +243,59 @@ static lua_Number lua_strx2number (const char *s, char **endptr) {
/* }====================================================== */ /* }====================================================== */
static const char *l_str2d (const char *s, lua_Number *result) { /* maximum length of a numeral */
#if !defined (L_MAXLENNUM)
#define L_MAXLENNUM 200
#endif
static const char *l_str2dloc (const char *s, lua_Number *result, int mode) {
char *endptr; char *endptr;
if (strpbrk(s, "nN")) /* reject 'inf' and 'nan' */ *result = (mode == 'x') ? lua_strx2number(s, &endptr) /* try to convert */
return NULL; : lua_str2number(s, &endptr);
else if (strpbrk(s, "xX")) /* hex? */ if (endptr == s) return NULL; /* nothing recognized? */
*result = lua_strx2number(s, &endptr); while (lisspace(cast_uchar(*endptr))) endptr++; /* skip trailing spaces */
else return (*endptr == '\0') ? endptr : NULL; /* OK if no trailing characters */
*result = lua_str2number(s, &endptr);
if (endptr == s) return NULL; /* nothing recognized */
while (lisspace(cast_uchar(*endptr))) endptr++;
return (*endptr == '\0' ? endptr : NULL); /* OK if no trailing characters */
} }
/*
** Convert string 's' to a Lua number (put in 'result'). Return NULL
** on fail or the address of the ending '\0' on success.
** 'pmode' points to (and 'mode' contains) special things in the string:
** - 'x'/'X' means an hexadecimal numeral
** - 'n'/'N' means 'inf' or 'nan' (which should be rejected)
** - '.' just optimizes the search for the common case (nothing special)
** This function accepts both the current locale or a dot as the radix
** mark. If the convertion fails, it may mean number has a dot but
** locale accepts something else. In that case, the code copies 's'
** to a buffer (because 's' is read-only), changes the dot to the
** current locale radix mark, and tries to convert again.
*/
static const char *l_str2d (const char *s, lua_Number *result) {
const char *endptr;
const char *pmode = strpbrk(s, ".xXnN");
int mode = pmode ? ltolower(cast_uchar(*pmode)) : 0;
if (mode == 'n') /* reject 'inf' and 'nan' */
return NULL;
endptr = l_str2dloc(s, result, mode); /* try to convert */
if (endptr == NULL) { /* failed? may be a different locale */
char buff[L_MAXLENNUM + 1];
char *pdot = strchr(s, '.');
if (strlen(s) > L_MAXLENNUM || pdot == NULL)
return NULL; /* string too long or no dot; fail */
strcpy(buff, s); /* copy string to buffer */
buff[pdot - s] = lua_getlocaledecpoint(); /* correct decimal point */
endptr = l_str2dloc(buff, result, mode); /* try again */
if (endptr != NULL)
endptr = s + (endptr - buff); /* make relative to 's' */
}
return endptr;
}
#define MAXBY10 cast(lua_Unsigned, LUA_MAXINTEGER / 10)
#define MAXLASTD cast_int(LUA_MAXINTEGER % 10)
static const char *l_str2int (const char *s, lua_Integer *result) { static const char *l_str2int (const char *s, lua_Integer *result) {
lua_Unsigned a = 0; lua_Unsigned a = 0;
int empty = 1; int empty = 1;
@ -273,7 +312,10 @@ static const char *l_str2int (const char *s, lua_Integer *result) {
} }
else { /* decimal */ else { /* decimal */
for (; lisdigit(cast_uchar(*s)); s++) { for (; lisdigit(cast_uchar(*s)); s++) {
a = a * 10 + *s - '0'; int d = *s - '0';
if (a >= MAXBY10 && (a > MAXBY10 || d > MAXLASTD + neg)) /* overflow? */
return NULL; /* do not accept it (as integer) */
a = a * 10 + d;
empty = 0; empty = 0;
} }
} }
@ -351,8 +393,10 @@ static void pushstr (lua_State *L, const char *str, size_t l) {
} }
/* this function handles only '%d', '%c', '%f', '%p', and '%s' /*
conventional formats, plus Lua-specific '%I' and '%U' */ ** this function handles only '%d', '%c', '%f', '%p', and '%s'
conventional formats, plus Lua-specific '%I' and '%U'
*/
const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) { const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {
int n = 0; int n = 0;
for (;;) { for (;;) {
@ -360,13 +404,13 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {
if (e == NULL) break; if (e == NULL) break;
pushstr(L, fmt, e - fmt); pushstr(L, fmt, e - fmt);
switch (*(e+1)) { switch (*(e+1)) {
case 's': { case 's': { /* zero-terminated string */
const char *s = va_arg(argp, char *); const char *s = va_arg(argp, char *);
if (s == NULL) s = "(null)"; if (s == NULL) s = "(null)";
pushstr(L, s, strlen(s)); pushstr(L, s, strlen(s));
break; break;
} }
case 'c': { case 'c': { /* an 'int' as a character */
char buff = cast(char, va_arg(argp, int)); char buff = cast(char, va_arg(argp, int));
if (lisprint(cast_uchar(buff))) if (lisprint(cast_uchar(buff)))
pushstr(L, &buff, 1); pushstr(L, &buff, 1);
@ -374,28 +418,28 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {
luaO_pushfstring(L, "<\\%d>", cast_uchar(buff)); luaO_pushfstring(L, "<\\%d>", cast_uchar(buff));
break; break;
} }
case 'd': { case 'd': { /* an 'int' */
setivalue(L->top, va_arg(argp, int)); setivalue(L->top, va_arg(argp, int));
goto top2str; goto top2str;
} }
case 'I': { case 'I': { /* a 'lua_Integer' */
setivalue(L->top, cast(lua_Integer, va_arg(argp, l_uacInt))); setivalue(L->top, cast(lua_Integer, va_arg(argp, l_uacInt)));
goto top2str; goto top2str;
} }
case 'f': { case 'f': { /* a 'lua_Number' */
setfltvalue(L->top, cast_num(va_arg(argp, l_uacNumber))); setfltvalue(L->top, cast_num(va_arg(argp, l_uacNumber)));
top2str: top2str: /* convert the top element to a string */
luaD_inctop(L); luaD_inctop(L);
luaO_tostring(L, L->top - 1); luaO_tostring(L, L->top - 1);
break; break;
} }
case 'p': { case 'p': { /* a pointer */
char buff[4*sizeof(void *) + 8]; /* should be enough space for a '%p' */ char buff[4*sizeof(void *) + 8]; /* should be enough space for a '%p' */
int l = l_sprintf(buff, sizeof(buff), "%p", va_arg(argp, void *)); int l = l_sprintf(buff, sizeof(buff), "%p", va_arg(argp, void *));
pushstr(L, buff, l); pushstr(L, buff, l);
break; break;
} }
case 'U': { case 'U': { /* an 'int' as a UTF-8 sequence */
char buff[UTF8BUFFSZ]; char buff[UTF8BUFFSZ];
int l = luaO_utf8esc(buff, cast(long, va_arg(argp, long))); int l = luaO_utf8esc(buff, cast(long, va_arg(argp, long)));
pushstr(L, buff + UTF8BUFFSZ - l, l); pushstr(L, buff + UTF8BUFFSZ - l, l);

View File

@ -1,5 +1,5 @@
/* /*
** $Id: loslib.c,v 1.60 2015/11/19 19:16:22 roberto Exp $ ** $Id: loslib.c,v 1.64 2016/04/18 13:06:55 roberto Exp $
** Standard Operating System library ** Standard Operating System library
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -24,18 +24,29 @@
/* /*
** {================================================================== ** {==================================================================
** list of valid conversion specifiers for the 'strftime' function ** List of valid conversion specifiers for the 'strftime' function;
** options are grouped by length; group of length 2 start with '||'.
** =================================================================== ** ===================================================================
*/ */
#if !defined(LUA_STRFTIMEOPTIONS) /* { */ #if !defined(LUA_STRFTIMEOPTIONS) /* { */
#if defined(LUA_USE_C89) /* options for ANSI C 89 */
#define LUA_STRFTIMEOPTIONS { "aAbBcdHIjmMpSUwWxXyYz%", "" } #define L_STRFTIMEC89 "aAbBcdHIjmMpSUwWxXyYZ%"
/* options for ISO C 99 and POSIX */
#define L_STRFTIMEC99 "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%" \
"||" "EcECExEXEyEY" "OdOeOHOIOmOMOSOuOUOVOwOWOy"
/* options for Windows */
#define L_STRFTIMEWIN "aAbBcdHIjmMpSUwWxXyYzZ%" \
"||" "#c#x#d#H#I#j#m#M#S#U#w#W#y#Y"
#if defined(LUA_USE_WINDOWS)
#define LUA_STRFTIMEOPTIONS L_STRFTIMEWIN
#elif defined(LUA_USE_C89)
#define LUA_STRFTIMEOPTIONS L_STRFTIMEC89
#else /* C99 specification */ #else /* C99 specification */
#define LUA_STRFTIMEOPTIONS \ #define LUA_STRFTIMEOPTIONS L_STRFTIMEC99
{ "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%", "", \
"E", "cCxXyY", \
"O", "deHImMSuUVwWy" }
#endif #endif
#endif /* } */ #endif /* } */
@ -195,6 +206,23 @@ static void setboolfield (lua_State *L, const char *key, int value) {
lua_setfield(L, -2, key); lua_setfield(L, -2, key);
} }
/*
** Set all fields from structure 'tm' in the table on top of the stack
*/
static void setallfields (lua_State *L, struct tm *stm) {
setfield(L, "sec", stm->tm_sec);
setfield(L, "min", stm->tm_min);
setfield(L, "hour", stm->tm_hour);
setfield(L, "day", stm->tm_mday);
setfield(L, "month", stm->tm_mon + 1);
setfield(L, "year", stm->tm_year + 1900);
setfield(L, "wday", stm->tm_wday + 1);
setfield(L, "yday", stm->tm_yday + 1);
setboolfield(L, "isdst", stm->tm_isdst);
}
static int getboolfield (lua_State *L, const char *key) { static int getboolfield (lua_State *L, const char *key) {
int res; int res;
res = (lua_getfield(L, -1, key) == LUA_TNIL) ? -1 : lua_toboolean(L, -1); res = (lua_getfield(L, -1, key) == LUA_TNIL) ? -1 : lua_toboolean(L, -1);
@ -210,18 +238,18 @@ static int getboolfield (lua_State *L, const char *key) {
static int getfield (lua_State *L, const char *key, int d, int delta) { static int getfield (lua_State *L, const char *key, int d, int delta) {
int isnum; int isnum;
int t = lua_getfield(L, -1, key); int t = lua_getfield(L, -1, key); /* get field and its type */
lua_Integer res = lua_tointegerx(L, -1, &isnum); lua_Integer res = lua_tointegerx(L, -1, &isnum);
if (!isnum) { /* field is not a number? */ if (!isnum) { /* field is not an integer? */
if (t != LUA_TNIL) /* some other value? */ if (t != LUA_TNIL) /* some other value? */
return luaL_error(L, "field '%s' not an integer", key); return luaL_error(L, "field '%s' is not an integer", key);
else if (d < 0) /* absent field; no default? */ else if (d < 0) /* absent field; no default? */
return luaL_error(L, "field '%s' missing in date table", key); return luaL_error(L, "field '%s' missing in date table", key);
res = d; res = d;
} }
else { else {
if (!(-L_MAXDATEFIELD <= res && res <= L_MAXDATEFIELD)) if (!(-L_MAXDATEFIELD <= res && res <= L_MAXDATEFIELD))
return luaL_error(L, "field '%s' out-of-bounds", key); return luaL_error(L, "field '%s' is out-of-bound", key);
res -= delta; res -= delta;
} }
lua_pop(L, 1); lua_pop(L, 1);
@ -230,21 +258,15 @@ static int getfield (lua_State *L, const char *key, int d, int delta) {
static const char *checkoption (lua_State *L, const char *conv, char *buff) { static const char *checkoption (lua_State *L, const char *conv, char *buff) {
static const char *const options[] = LUA_STRFTIMEOPTIONS; const char *option;
unsigned int i; int oplen = 1;
for (i = 0; i < sizeof(options)/sizeof(options[0]); i += 2) { for (option = LUA_STRFTIMEOPTIONS; *option != '\0'; option += oplen) {
if (*conv != '\0' && strchr(options[i], *conv) != NULL) { if (*option == '|') /* next block? */
buff[1] = *conv; oplen++; /* next length */
if (*options[i + 1] == '\0') { /* one-char conversion specifier? */ else if (memcmp(conv, option, oplen) == 0) { /* match? */
buff[2] = '\0'; /* end buffer */ memcpy(buff, conv, oplen); /* copy valid option to buffer */
return conv + 1; buff[oplen] = '\0';
} return conv + oplen; /* return next item */
else if (*(conv + 1) != '\0' &&
strchr(options[i + 1], *(conv + 1)) != NULL) {
buff[2] = *(conv + 1); /* valid two-char conversion specifier */
buff[3] = '\0'; /* end buffer */
return conv + 2;
}
} }
} }
luaL_argerror(L, 1, luaL_argerror(L, 1,
@ -271,18 +293,10 @@ static int os_date (lua_State *L) {
luaL_error(L, "time result cannot be represented in this installation"); luaL_error(L, "time result cannot be represented in this installation");
if (strcmp(s, "*t") == 0) { if (strcmp(s, "*t") == 0) {
lua_createtable(L, 0, 9); /* 9 = number of fields */ lua_createtable(L, 0, 9); /* 9 = number of fields */
setfield(L, "sec", stm->tm_sec); setallfields(L, stm);
setfield(L, "min", stm->tm_min);
setfield(L, "hour", stm->tm_hour);
setfield(L, "day", stm->tm_mday);
setfield(L, "month", stm->tm_mon+1);
setfield(L, "year", stm->tm_year+1900);
setfield(L, "wday", stm->tm_wday+1);
setfield(L, "yday", stm->tm_yday+1);
setboolfield(L, "isdst", stm->tm_isdst);
} }
else { else {
char cc[4]; char cc[4]; /* buffer for individual conversion specifiers */
luaL_Buffer b; luaL_Buffer b;
cc[0] = '%'; cc[0] = '%';
luaL_buffinit(L, &b); luaL_buffinit(L, &b);
@ -292,7 +306,7 @@ static int os_date (lua_State *L) {
else { else {
size_t reslen; size_t reslen;
char *buff = luaL_prepbuffsize(&b, SIZETIMEFMT); char *buff = luaL_prepbuffsize(&b, SIZETIMEFMT);
s = checkoption(L, s + 1, cc); s = checkoption(L, s + 1, cc + 1); /* copy specifier to 'cc' */
reslen = strftime(buff, SIZETIMEFMT, cc, stm); reslen = strftime(buff, SIZETIMEFMT, cc, stm);
luaL_addsize(&b, reslen); luaL_addsize(&b, reslen);
} }
@ -319,6 +333,7 @@ static int os_time (lua_State *L) {
ts.tm_year = getfield(L, "year", -1, 1900); ts.tm_year = getfield(L, "year", -1, 1900);
ts.tm_isdst = getboolfield(L, "isdst"); ts.tm_isdst = getboolfield(L, "isdst");
t = mktime(&ts); t = mktime(&ts);
setallfields(L, &ts); /* update fields with normalized values */
} }
if (t != (time_t)(l_timet)t || t == (time_t)(-1)) if (t != (time_t)(l_timet)t || t == (time_t)(-1))
luaL_error(L, "time result cannot be represented in this installation"); luaL_error(L, "time result cannot be represented in this installation");

View File

@ -1,5 +1,5 @@
/* /*
** $Id: lparser.c,v 2.149 2015/11/02 16:09:30 roberto Exp $ ** $Id: lparser.c,v 2.153 2016/05/13 19:10:16 roberto Exp $
** Lua Parser ** Lua Parser
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -164,7 +164,8 @@ static int registerlocalvar (LexState *ls, TString *varname) {
int oldsize = f->sizelocvars; int oldsize = f->sizelocvars;
luaM_growvector(ls->L, f->locvars, fs->nlocvars, f->sizelocvars, luaM_growvector(ls->L, f->locvars, fs->nlocvars, f->sizelocvars,
LocVar, SHRT_MAX, "local variables"); LocVar, SHRT_MAX, "local variables");
while (oldsize < f->sizelocvars) f->locvars[oldsize++].varname = NULL; while (oldsize < f->sizelocvars)
f->locvars[oldsize++].varname = NULL;
f->locvars[fs->nlocvars].varname = varname; f->locvars[fs->nlocvars].varname = varname;
luaC_objbarrier(ls->L, f, varname); luaC_objbarrier(ls->L, f, varname);
return fs->nlocvars++; return fs->nlocvars++;
@ -230,7 +231,8 @@ static int newupvalue (FuncState *fs, TString *name, expdesc *v) {
checklimit(fs, fs->nups + 1, MAXUPVAL, "upvalues"); checklimit(fs, fs->nups + 1, MAXUPVAL, "upvalues");
luaM_growvector(fs->ls->L, f->upvalues, fs->nups, f->sizeupvalues, luaM_growvector(fs->ls->L, f->upvalues, fs->nups, f->sizeupvalues,
Upvaldesc, MAXUPVAL, "upvalues"); Upvaldesc, MAXUPVAL, "upvalues");
while (oldsize < f->sizeupvalues) f->upvalues[oldsize++].name = NULL; while (oldsize < f->sizeupvalues)
f->upvalues[oldsize++].name = NULL;
f->upvalues[fs->nups].instack = (v->k == VLOCAL); f->upvalues[fs->nups].instack = (v->k == VLOCAL);
f->upvalues[fs->nups].idx = cast_byte(v->u.info); f->upvalues[fs->nups].idx = cast_byte(v->u.info);
f->upvalues[fs->nups].name = name; f->upvalues[fs->nups].name = name;
@ -255,7 +257,8 @@ static int searchvar (FuncState *fs, TString *n) {
*/ */
static void markupval (FuncState *fs, int level) { static void markupval (FuncState *fs, int level) {
BlockCnt *bl = fs->bl; BlockCnt *bl = fs->bl;
while (bl->nactvar > level) bl = bl->previous; while (bl->nactvar > level)
bl = bl->previous;
bl->upval = 1; bl->upval = 1;
} }
@ -264,27 +267,26 @@ static void markupval (FuncState *fs, int level) {
Find variable with given name 'n'. If it is an upvalue, add this Find variable with given name 'n'. If it is an upvalue, add this
upvalue into all intermediate functions. upvalue into all intermediate functions.
*/ */
static int singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) { static void singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) {
if (fs == NULL) /* no more levels? */ if (fs == NULL) /* no more levels? */
return VVOID; /* default is global */ init_exp(var, VVOID, 0); /* default is global */
else { else {
int v = searchvar(fs, n); /* look up locals at current level */ int v = searchvar(fs, n); /* look up locals at current level */
if (v >= 0) { /* found? */ if (v >= 0) { /* found? */
init_exp(var, VLOCAL, v); /* variable is local */ init_exp(var, VLOCAL, v); /* variable is local */
if (!base) if (!base)
markupval(fs, v); /* local will be used as an upval */ markupval(fs, v); /* local will be used as an upval */
return VLOCAL;
} }
else { /* not found as local at current level; try upvalues */ else { /* not found as local at current level; try upvalues */
int idx = searchupvalue(fs, n); /* try existing upvalues */ int idx = searchupvalue(fs, n); /* try existing upvalues */
if (idx < 0) { /* not found? */ if (idx < 0) { /* not found? */
if (singlevaraux(fs->prev, n, var, 0) == VVOID) /* try upper levels */ singlevaraux(fs->prev, n, var, 0); /* try upper levels */
return VVOID; /* not found; is a global */ if (var->k == VVOID) /* not found? */
return; /* it is a global */
/* else was LOCAL or UPVAL */ /* else was LOCAL or UPVAL */
idx = newupvalue(fs, n, var); /* will be a new upvalue */ idx = newupvalue(fs, n, var); /* will be a new upvalue */
} }
init_exp(var, VUPVAL, idx); init_exp(var, VUPVAL, idx); /* new or old upvalue */
return VUPVAL;
} }
} }
} }
@ -293,10 +295,11 @@ static int singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) {
static void singlevar (LexState *ls, expdesc *var) { static void singlevar (LexState *ls, expdesc *var) {
TString *varname = str_checkname(ls); TString *varname = str_checkname(ls);
FuncState *fs = ls->fs; FuncState *fs = ls->fs;
if (singlevaraux(fs, varname, var, 1) == VVOID) { /* global name? */ singlevaraux(fs, varname, var, 1);
if (var->k == VVOID) { /* global name? */
expdesc key; expdesc key;
singlevaraux(fs, ls->envn, var, 1); /* get environment variable */ singlevaraux(fs, ls->envn, var, 1); /* get environment variable */
lua_assert(var->k == VLOCAL || var->k == VUPVAL); lua_assert(var->k != VVOID); /* this one must exist */
codestring(ls, &key, varname); /* key is variable name */ codestring(ls, &key, varname); /* key is variable name */
luaK_indexed(fs, var, &key); /* env[varname] */ luaK_indexed(fs, var, &key); /* env[varname] */
} }
@ -499,7 +502,8 @@ static Proto *addprototype (LexState *ls) {
if (fs->np >= f->sizep) { if (fs->np >= f->sizep) {
int oldsize = f->sizep; int oldsize = f->sizep;
luaM_growvector(L, f->p, fs->np, f->sizep, Proto *, MAXARG_Bx, "functions"); luaM_growvector(L, f->p, fs->np, f->sizep, Proto *, MAXARG_Bx, "functions");
while (oldsize < f->sizep) f->p[oldsize++] = NULL; while (oldsize < f->sizep)
f->p[oldsize++] = NULL;
} }
f->p[fs->np++] = clp = luaF_newproto(L); f->p[fs->np++] = clp = luaF_newproto(L);
luaC_objbarrier(L, f, clp); luaC_objbarrier(L, f, clp);
@ -1226,7 +1230,7 @@ static void labelstat (LexState *ls, TString *label, int line) {
checkrepeated(fs, ll, label); /* check for repeated labels */ checkrepeated(fs, ll, label); /* check for repeated labels */
checknext(ls, TK_DBCOLON); /* skip double colon */ checknext(ls, TK_DBCOLON); /* skip double colon */
/* create new entry for this label */ /* create new entry for this label */
l = newlabelentry(ls, ll, label, line, fs->pc); l = newlabelentry(ls, ll, label, line, luaK_getlabel(fs));
skipnoopstat(ls); /* skip other no-op statements */ skipnoopstat(ls); /* skip other no-op statements */
if (block_follow(ls, 0)) { /* label is last no-op statement in the block? */ if (block_follow(ls, 0)) { /* label is last no-op statement in the block? */
/* assume that locals are already out of scope */ /* assume that locals are already out of scope */
@ -1494,7 +1498,7 @@ static void exprstat (LexState *ls) {
} }
else { /* stat -> func */ else { /* stat -> func */
check_condition(ls, v.v.k == VCALL, "syntax error"); check_condition(ls, v.v.k == VCALL, "syntax error");
SETARG_C(getcode(fs, &v.v), 1); /* call statement uses no results */ SETARG_C(getinstruction(fs, &v.v), 1); /* call statement uses no results */
} }
} }
@ -1511,8 +1515,8 @@ static void retstat (LexState *ls) {
if (hasmultret(e.k)) { if (hasmultret(e.k)) {
luaK_setmultret(fs, &e); luaK_setmultret(fs, &e);
if (e.k == VCALL && nret == 1) { /* tail call? */ if (e.k == VCALL && nret == 1) { /* tail call? */
SET_OPCODE(getcode(fs,&e), OP_TAILCALL); SET_OPCODE(getinstruction(fs,&e), OP_TAILCALL);
lua_assert(GETARG_A(getcode(fs,&e)) == fs->nactvar); lua_assert(GETARG_A(getinstruction(fs,&e)) == fs->nactvar);
} }
first = fs->nactvar; first = fs->nactvar;
nret = LUA_MULTRET; /* return all values */ nret = LUA_MULTRET; /* return all values */

View File

@ -1,5 +1,5 @@
/* /*
** $Id: lparser.h,v 1.74 2014/10/25 11:50:46 roberto Exp $ ** $Id: lparser.h,v 1.76 2015/12/30 18:16:13 roberto Exp $
** Lua Parser ** Lua Parser
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -13,25 +13,38 @@
/* /*
** Expression descriptor ** Expression and variable descriptor.
** Code generation for variables and expressions can be delayed to allow
** optimizations; An 'expdesc' structure describes a potentially-delayed
** variable/expression. It has a description of its "main" value plus a
** list of conditional jumps that can also produce its value (generated
** by short-circuit operators 'and'/'or').
*/ */
/* kinds of variables/expressions */
typedef enum { typedef enum {
VVOID, /* no value */ VVOID, /* when 'expdesc' describes the last expression a list,
VNIL, this kind means an empty list (so, no expression) */
VTRUE, VNIL, /* constant nil */
VFALSE, VTRUE, /* constant true */
VK, /* info = index of constant in 'k' */ VFALSE, /* constant false */
VKFLT, /* nval = numerical float value */ VK, /* constant in 'k'; info = index of constant in 'k' */
VKINT, /* nval = numerical integer value */ VKFLT, /* floating constant; nval = numerical float value */
VNONRELOC, /* info = result register */ VKINT, /* integer constant; nval = numerical integer value */
VLOCAL, /* info = local register */ VNONRELOC, /* expression has its value in a fixed register;
VUPVAL, /* info = index of upvalue in 'upvalues' */ info = result register */
VINDEXED, /* t = table register/upvalue; idx = index R/K */ VLOCAL, /* local variable; info = local register */
VJMP, /* info = instruction pc */ VUPVAL, /* upvalue variable; info = index of upvalue in 'upvalues' */
VRELOCABLE, /* info = instruction pc */ VINDEXED, /* indexed variable;
VCALL, /* info = instruction pc */ ind.vt = whether 't' is register or upvalue;
VVARARG /* info = instruction pc */ ind.t = table register or upvalue;
ind.idx = key's R/K index */
VJMP, /* expression is a test/comparison;
info = pc of corresponding jump instruction */
VRELOCABLE, /* expression can put result in any register;
info = instruction pc */
VCALL, /* expression is a function call; info = instruction pc */
VVARARG /* vararg expression; info = instruction pc */
} expkind; } expkind;
@ -41,14 +54,14 @@ typedef enum {
typedef struct expdesc { typedef struct expdesc {
expkind k; expkind k;
union { union {
lua_Integer ival; /* for VKINT */
lua_Number nval; /* for VKFLT */
int info; /* for generic use */
struct { /* for indexed variables (VINDEXED) */ struct { /* for indexed variables (VINDEXED) */
short idx; /* index (R/K) */ short idx; /* index (R/K) */
lu_byte t; /* table (register or upvalue) */ lu_byte t; /* table (register or upvalue) */
lu_byte vt; /* whether 't' is register (VLOCAL) or upvalue (VUPVAL) */ lu_byte vt; /* whether 't' is register (VLOCAL) or upvalue (VUPVAL) */
} ind; } ind;
int info; /* for generic use */
lua_Number nval; /* for VKFLT */
lua_Integer ival; /* for VKINT */
} u; } u;
int t; /* patch list of 'exit when true' */ int t; /* patch list of 'exit when true' */
int f; /* patch list of 'exit when false' */ int f; /* patch list of 'exit when false' */

View File

@ -1,5 +1,5 @@
/* /*
** $Id: lstate.h,v 2.128 2015/11/13 12:16:51 roberto Exp $ ** $Id: lstate.h,v 2.130 2015/12/16 16:39:38 roberto Exp $
** Global State ** Global State
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -33,6 +33,15 @@
struct lua_longjmp; /* defined in ldo.c */ struct lua_longjmp; /* defined in ldo.c */
/*
** Atomic type (relative to signals) to better ensure that 'lua_sethook'
** is thread safe
*/
#if !defined(l_signalT)
#include <signal.h>
#define l_signalT sig_atomic_t
#endif
/* extra stack space to handle TM calls and some other extras */ /* extra stack space to handle TM calls and some other extras */
#define EXTRA_STACK 5 #define EXTRA_STACK 5
@ -162,14 +171,14 @@ struct lua_State {
struct lua_State *twups; /* list of threads with open upvalues */ struct lua_State *twups; /* list of threads with open upvalues */
struct lua_longjmp *errorJmp; /* current error recover point */ struct lua_longjmp *errorJmp; /* current error recover point */
CallInfo base_ci; /* CallInfo for first level (C calling Lua) */ CallInfo base_ci; /* CallInfo for first level (C calling Lua) */
lua_Hook hook; volatile lua_Hook hook;
ptrdiff_t errfunc; /* current error handling function (stack index) */ ptrdiff_t errfunc; /* current error handling function (stack index) */
int stacksize; int stacksize;
int basehookcount; int basehookcount;
int hookcount; int hookcount;
unsigned short nny; /* number of non-yieldable calls in stack */ unsigned short nny; /* number of non-yieldable calls in stack */
unsigned short nCcalls; /* number of nested C calls */ unsigned short nCcalls; /* number of nested C calls */
lu_byte hookmask; l_signalT hookmask;
lu_byte allowhook; lu_byte allowhook;
}; };

View File

@ -1,5 +1,5 @@
/* /*
** $Id: lstrlib.c,v 1.239 2015/11/25 16:28:17 roberto Exp $ ** $Id: lstrlib.c,v 1.251 2016/05/20 14:13:21 roberto Exp $
** Standard library for string operations and pattern-matching ** Standard library for string operations and pattern-matching
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -13,6 +13,7 @@
#include <ctype.h> #include <ctype.h>
#include <float.h> #include <float.h>
#include <limits.h> #include <limits.h>
#include <locale.h>
#include <stddef.h> #include <stddef.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -26,7 +27,8 @@
/* /*
** maximum number of captures that a pattern can do during ** maximum number of captures that a pattern can do during
** pattern-matching. This limit is arbitrary. ** pattern-matching. This limit is arbitrary, but must fit in
** an unsigned char.
*/ */
#if !defined(LUA_MAXCAPTURES) #if !defined(LUA_MAXCAPTURES)
#define LUA_MAXCAPTURES 32 #define LUA_MAXCAPTURES 32
@ -214,9 +216,8 @@ typedef struct MatchState {
const char *src_end; /* end ('\0') of source string */ const char *src_end; /* end ('\0') of source string */
const char *p_end; /* end ('\0') of pattern */ const char *p_end; /* end ('\0') of pattern */
lua_State *L; lua_State *L;
size_t nrep; /* limit to avoid non-linear complexity */
int matchdepth; /* control for recursive depth (to avoid C stack overflow) */ int matchdepth; /* control for recursive depth (to avoid C stack overflow) */
int level; /* total number of captures (finished or unfinished) */ unsigned char level; /* total number of captures (finished or unfinished) */
struct { struct {
const char *init; const char *init;
ptrdiff_t len; ptrdiff_t len;
@ -234,17 +235,6 @@ static const char *match (MatchState *ms, const char *s, const char *p);
#endif #endif
/*
** parameters to control the maximum number of operators handled in
** a match (to avoid non-linear complexity). The maximum will be:
** (subject length) * A_REPS + B_REPS
*/
#if !defined(A_REPS)
#define A_REPS 4
#define B_REPS 100000
#endif
#define L_ESC '%' #define L_ESC '%'
#define SPECIALS "^$*+?.([%-" #define SPECIALS "^$*+?.([%-"
@ -502,8 +492,6 @@ static const char *match (MatchState *ms, const char *s, const char *p) {
s = NULL; /* fail */ s = NULL; /* fail */
} }
else { /* matched once */ else { /* matched once */
if (ms->nrep-- == 0)
luaL_error(ms->L, "pattern too complex");
switch (*ep) { /* handle optional suffix */ switch (*ep) { /* handle optional suffix */
case '?': { /* optional */ case '?': { /* optional */
const char *res; const char *res;
@ -607,10 +595,6 @@ static void prepstate (MatchState *ms, lua_State *L,
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;
if (ls < (MAX_SIZET - B_REPS) / A_REPS)
ms->nrep = A_REPS * ls + B_REPS;
else /* overflow (very long subject) */
ms->nrep = MAX_SIZET; /* no limit */
} }
@ -681,6 +665,7 @@ static int str_match (lua_State *L) {
typedef struct GMatchState { typedef struct GMatchState {
const char *src; /* current position */ const char *src; /* current position */
const char *p; /* pattern */ const char *p; /* pattern */
const char *lastmatch; /* end of last match */
MatchState ms; /* match state */ MatchState ms; /* match state */
} GMatchState; } GMatchState;
@ -688,14 +673,12 @@ typedef struct GMatchState {
static int gmatch_aux (lua_State *L) { static int gmatch_aux (lua_State *L) {
GMatchState *gm = (GMatchState *)lua_touserdata(L, lua_upvalueindex(3)); GMatchState *gm = (GMatchState *)lua_touserdata(L, lua_upvalueindex(3));
const char *src; const char *src;
gm->ms.L = L;
for (src = gm->src; src <= gm->ms.src_end; src++) { for (src = gm->src; src <= gm->ms.src_end; src++) {
const char *e; const char *e;
reprepstate(&gm->ms); reprepstate(&gm->ms);
if ((e = match(&gm->ms, src, gm->p)) != NULL) { if ((e = match(&gm->ms, src, gm->p)) != NULL && e != gm->lastmatch) {
if (e == src) /* empty match? */ gm->src = gm->lastmatch = e;
gm->src =src + 1; /* go at least one position */
else
gm->src = e;
return push_captures(&gm->ms, src, e); return push_captures(&gm->ms, src, e);
} }
} }
@ -711,7 +694,7 @@ static int gmatch (lua_State *L) {
lua_settop(L, 2); /* keep them on closure to avoid being collected */ lua_settop(L, 2); /* keep them on closure to avoid being collected */
gm = (GMatchState *)lua_newuserdata(L, sizeof(GMatchState)); gm = (GMatchState *)lua_newuserdata(L, sizeof(GMatchState));
prepstate(&gm->ms, L, s, ls, p, lp); prepstate(&gm->ms, L, s, ls, p, lp);
gm->src = s; gm->p = p; gm->src = s; gm->p = p; gm->lastmatch = NULL;
lua_pushcclosure(L, gmatch_aux, 3); lua_pushcclosure(L, gmatch_aux, 3);
return 1; return 1;
} }
@ -778,12 +761,13 @@ static void add_value (MatchState *ms, luaL_Buffer *b, const char *s,
static int str_gsub (lua_State *L) { static int str_gsub (lua_State *L) {
size_t srcl, lp; size_t srcl, lp;
const char *src = luaL_checklstring(L, 1, &srcl); const char *src = luaL_checklstring(L, 1, &srcl); /* subject */
const char *p = luaL_checklstring(L, 2, &lp); const char *p = luaL_checklstring(L, 2, &lp); /* pattern */
int tr = lua_type(L, 3); const char *lastmatch = NULL; /* end of last match */
lua_Integer max_s = luaL_optinteger(L, 4, srcl + 1); int tr = lua_type(L, 3); /* replacement type */
lua_Integer max_s = luaL_optinteger(L, 4, srcl + 1); /* max replacements */
int anchor = (*p == '^'); int anchor = (*p == '^');
lua_Integer n = 0; lua_Integer n = 0; /* replacement count */
MatchState ms; MatchState ms;
luaL_Buffer b; luaL_Buffer b;
luaL_argcheck(L, tr == LUA_TNUMBER || tr == LUA_TSTRING || luaL_argcheck(L, tr == LUA_TNUMBER || tr == LUA_TSTRING ||
@ -796,16 +780,15 @@ static int str_gsub (lua_State *L) {
prepstate(&ms, L, src, srcl, p, lp); prepstate(&ms, L, src, srcl, p, lp);
while (n < max_s) { while (n < max_s) {
const char *e; const char *e;
reprepstate(&ms); reprepstate(&ms); /* (re)prepare state for new match */
if ((e = match(&ms, src, p)) != NULL) { if ((e = match(&ms, src, p)) != NULL && e != lastmatch) { /* match? */
n++; n++;
add_value(&ms, &b, src, e, tr); add_value(&ms, &b, src, e, tr); /* add replacement to buffer */
src = lastmatch = e;
} }
if (e && e>src) /* non empty match? */ else if (src < ms.src_end) /* otherwise, skip one character */
src = e; /* skip it */
else if (src < ms.src_end)
luaL_addchar(&b, *src++); luaL_addchar(&b, *src++);
else break; else break; /* end of subject */
if (anchor) break; if (anchor) break;
} }
luaL_addlstring(&b, src, ms.src_end-src); luaL_addlstring(&b, src, ms.src_end-src);
@ -830,7 +813,6 @@ static int str_gsub (lua_State *L) {
** Hexadecimal floating-point formatter ** Hexadecimal floating-point formatter
*/ */
#include <locale.h>
#include <math.h> #include <math.h>
#define SIZELENMOD (sizeof(LUA_NUMBER_FRMLEN)/sizeof(char)) #define SIZELENMOD (sizeof(LUA_NUMBER_FRMLEN)/sizeof(char))
@ -922,16 +904,14 @@ static int lua_number2strx (lua_State *L, char *buff, int sz,
#define MAX_FORMAT 32 #define MAX_FORMAT 32
static void addquoted (lua_State *L, luaL_Buffer *b, int arg) { static void addquoted (luaL_Buffer *b, const char *s, size_t len) {
size_t l;
const char *s = luaL_checklstring(L, arg, &l);
luaL_addchar(b, '"'); luaL_addchar(b, '"');
while (l--) { while (len--) {
if (*s == '"' || *s == '\\' || *s == '\n') { if (*s == '"' || *s == '\\' || *s == '\n') {
luaL_addchar(b, '\\'); luaL_addchar(b, '\\');
luaL_addchar(b, *s); luaL_addchar(b, *s);
} }
else if (*s == '\0' || iscntrl(uchar(*s))) { else if (iscntrl(uchar(*s))) {
char buff[10]; char buff[10];
if (!isdigit(uchar(*(s+1)))) if (!isdigit(uchar(*(s+1))))
l_sprintf(buff, sizeof(buff), "\\%d", (int)uchar(*s)); l_sprintf(buff, sizeof(buff), "\\%d", (int)uchar(*s));
@ -946,6 +926,57 @@ static void addquoted (lua_State *L, luaL_Buffer *b, int arg) {
luaL_addchar(b, '"'); luaL_addchar(b, '"');
} }
/*
** Ensures the 'buff' string uses a dot as the radix character.
*/
static void checkdp (char *buff, int nb) {
if (memchr(buff, '.', nb) == NULL) { /* no dot? */
char point = lua_getlocaledecpoint(); /* try locale point */
char *ppoint = memchr(buff, point, nb);
if (ppoint) *ppoint = '.'; /* change it to a dot */
}
}
static void addliteral (lua_State *L, luaL_Buffer *b, int arg) {
switch (lua_type(L, arg)) {
case LUA_TSTRING: {
size_t len;
const char *s = lua_tolstring(L, arg, &len);
addquoted(b, s, len);
break;
}
case LUA_TNUMBER: {
char *buff = luaL_prepbuffsize(b, MAX_ITEM);
int nb;
if (!lua_isinteger(L, arg)) { /* float? */
lua_Number n = lua_tonumber(L, arg); /* write as hexa ('%a') */
nb = lua_number2strx(L, buff, MAX_ITEM, "%" LUA_NUMBER_FRMLEN "a", n);
checkdp(buff, nb); /* ensure it uses a dot */
}
else { /* integers */
lua_Integer n = lua_tointeger(L, arg);
const char *format = (n == LUA_MININTEGER) /* corner case? */
? "0x%" LUA_INTEGER_FRMLEN "x" /* use hexa */
: LUA_INTEGER_FMT; /* else use default format */
nb = l_sprintf(buff, MAX_ITEM, format, n);
}
luaL_addsize(b, nb);
break;
}
case LUA_TNIL: case LUA_TBOOLEAN: {
luaL_tolstring(L, arg, NULL);
luaL_addvalue(b);
break;
}
default: {
luaL_argerror(L, arg, "value has no literal form");
}
}
}
static const char *scanformat (lua_State *L, const char *strfrmt, char *form) { static const char *scanformat (lua_State *L, const char *strfrmt, char *form) {
const char *p = strfrmt; const char *p = strfrmt;
while (*p != '\0' && strchr(FLAGS, *p) != NULL) p++; /* skip flags */ while (*p != '\0' && strchr(FLAGS, *p) != NULL) p++; /* skip flags */
@ -1025,7 +1056,7 @@ static int str_format (lua_State *L) {
break; break;
} }
case 'q': { case 'q': {
addquoted(L, &b, arg); addliteral(L, &b, arg);
break; break;
} }
case 's': { case 's': {
@ -1070,8 +1101,8 @@ static int str_format (lua_State *L) {
/* value used for padding */ /* value used for padding */
#if !defined(LUA_PACKPADBYTE) #if !defined(LUAL_PACKPADBYTE)
#define LUA_PACKPADBYTE 0x00 #define LUAL_PACKPADBYTE 0x00
#endif #endif
/* maximum size for the binary representation of an integer */ /* maximum size for the binary representation of an integer */
@ -1308,7 +1339,7 @@ static int str_pack (lua_State *L) {
KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign); KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign);
totalsize += ntoalign + size; totalsize += ntoalign + size;
while (ntoalign-- > 0) while (ntoalign-- > 0)
luaL_addchar(&b, LUA_PACKPADBYTE); /* fill alignment */ luaL_addchar(&b, LUAL_PACKPADBYTE); /* fill alignment */
arg++; arg++;
switch (opt) { switch (opt) {
case Kint: { /* signed integers */ case Kint: { /* signed integers */
@ -1343,13 +1374,11 @@ static int str_pack (lua_State *L) {
case Kchar: { /* fixed-size string */ case Kchar: { /* fixed-size string */
size_t len; size_t len;
const char *s = luaL_checklstring(L, arg, &len); const char *s = luaL_checklstring(L, arg, &len);
if ((size_t)size <= len) /* string larger than (or equal to) needed? */ luaL_argcheck(L, len <= (size_t)size, arg,
luaL_addlstring(&b, s, size); /* truncate string to asked size */ "string longer than given size");
else { /* string smaller than needed */ luaL_addlstring(&b, s, len); /* add string */
luaL_addlstring(&b, s, len); /* add it all */
while (len++ < (size_t)size) /* pad extra space */ while (len++ < (size_t)size) /* pad extra space */
luaL_addchar(&b, LUA_PACKPADBYTE); luaL_addchar(&b, LUAL_PACKPADBYTE);
}
break; break;
} }
case Kstring: { /* strings with length count */ case Kstring: { /* strings with length count */
@ -1372,7 +1401,7 @@ static int str_pack (lua_State *L) {
totalsize += len + 1; totalsize += len + 1;
break; break;
} }
case Kpadding: luaL_addchar(&b, LUA_PACKPADBYTE); /* FALLTHROUGH */ case Kpadding: luaL_addchar(&b, LUAL_PACKPADBYTE); /* FALLTHROUGH */
case Kpaddalign: case Knop: case Kpaddalign: case Knop:
arg--; /* undo increment */ arg--; /* undo increment */
break; break;

View File

@ -1,5 +1,5 @@
/* /*
** $Id: ltablib.c,v 1.90 2015/11/25 12:48:57 roberto Exp $ ** $Id: ltablib.c,v 1.93 2016/02/25 19:41:54 roberto Exp $
** Library for Table Manipulation ** Library for Table Manipulation
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -53,7 +53,7 @@ static void checktab (lua_State *L, int arg, int what) {
lua_pop(L, n); /* pop metatable and tested metamethods */ lua_pop(L, n); /* pop metatable and tested metamethods */
} }
else else
luaL_argerror(L, arg, "table expected"); /* force an error */ luaL_checktype(L, arg, LUA_TTABLE); /* force an error */
} }
} }
@ -139,7 +139,7 @@ static int tmove (lua_State *L) {
n = e - f + 1; /* number of elements to move */ n = e - f + 1; /* number of elements to move */
luaL_argcheck(L, t <= LUA_MAXINTEGER - n + 1, 4, luaL_argcheck(L, t <= LUA_MAXINTEGER - n + 1, 4,
"destination wrap around"); "destination wrap around");
if (t > e || t <= f || tt != 1) { if (t > e || t <= f || (tt != 1 && !lua_compare(L, 1, tt, LUA_OPEQ))) {
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
lua_geti(L, 1, f + i); lua_geti(L, 1, f + i);
lua_seti(L, tt, t + i); lua_seti(L, tt, t + i);
@ -152,7 +152,7 @@ static int tmove (lua_State *L) {
} }
} }
} }
lua_pushvalue(L, tt); /* return "to table" */ lua_pushvalue(L, tt); /* return destination table */
return 1; return 1;
} }
@ -172,7 +172,7 @@ static int tconcat (lua_State *L) {
size_t lsep; size_t lsep;
const char *sep = luaL_optlstring(L, 2, "", &lsep); const char *sep = luaL_optlstring(L, 2, "", &lsep);
lua_Integer i = luaL_optinteger(L, 3, 1); lua_Integer i = luaL_optinteger(L, 3, 1);
last = luaL_opt(L, luaL_checkinteger, 4, last); last = luaL_optinteger(L, 4, last);
luaL_buffinit(L, &b); luaL_buffinit(L, &b);
for (; i < last; i++) { for (; i < last; i++) {
addfield(L, &b, i); addfield(L, &b, i);
@ -232,6 +232,10 @@ static int unpack (lua_State *L) {
*/ */
/* type for array indices */
typedef unsigned int IdxT;
/* /*
** Produce a "random" 'unsigned int' to randomize pivot choice. This ** Produce a "random" 'unsigned int' to randomize pivot choice. This
** macro is used only when 'sort' detects a big imbalance in the result ** macro is used only when 'sort' detects a big imbalance in the result
@ -270,7 +274,7 @@ static unsigned int l_randomizePivot (void) {
#define RANLIMIT 100u #define RANLIMIT 100u
static void set2 (lua_State *L, unsigned int i, unsigned int j) { static void set2 (lua_State *L, IdxT i, IdxT j) {
lua_seti(L, 1, i); lua_seti(L, 1, i);
lua_seti(L, 1, j); lua_seti(L, 1, j);
} }
@ -303,10 +307,9 @@ static int sort_comp (lua_State *L, int a, int b) {
** Pos-condition: a[lo .. i - 1] <= a[i] == P <= a[i + 1 .. up] ** Pos-condition: a[lo .. i - 1] <= a[i] == P <= a[i + 1 .. up]
** returns 'i'. ** returns 'i'.
*/ */
static unsigned int partition (lua_State *L, unsigned int lo, static IdxT partition (lua_State *L, IdxT lo, IdxT up) {
unsigned int up) { IdxT i = lo; /* will be incremented before first use */
unsigned int i = lo; /* will be incremented before first use */ IdxT j = up - 1; /* will be decremented before first use */
unsigned int j = up - 1; /* will be decremented before first use */
/* loop invariant: a[lo .. i] <= P <= a[j .. up] */ /* loop invariant: a[lo .. i] <= P <= a[j .. up] */
for (;;) { for (;;) {
/* next loop: repeat ++i while a[i] < P */ /* next loop: repeat ++i while a[i] < P */
@ -340,10 +343,9 @@ static unsigned int partition (lua_State *L, unsigned int lo,
** Choose an element in the middle (2nd-3th quarters) of [lo,up] ** Choose an element in the middle (2nd-3th quarters) of [lo,up]
** "randomized" by 'rnd' ** "randomized" by 'rnd'
*/ */
static unsigned int choosePivot (unsigned int lo, unsigned int up, static IdxT choosePivot (IdxT lo, IdxT up, unsigned int rnd) {
unsigned int rnd) { IdxT r4 = (up - lo) / 4; /* range/4 */
unsigned int r4 = (unsigned int)(up - lo) / 4u; /* range/4 */ IdxT p = rnd % (r4 * 2) + (lo + r4);
unsigned int p = rnd % (r4 * 2) + (lo + r4);
lua_assert(lo + r4 <= p && p <= up - r4); lua_assert(lo + r4 <= p && p <= up - r4);
return p; return p;
} }
@ -352,11 +354,11 @@ static unsigned int choosePivot (unsigned int lo, unsigned int up,
/* /*
** QuickSort algorithm (recursive function) ** QuickSort algorithm (recursive function)
*/ */
static void auxsort (lua_State *L, unsigned int lo, unsigned int up, static void auxsort (lua_State *L, IdxT lo, IdxT up,
unsigned int rnd) { unsigned int rnd) {
while (lo < up) { /* loop for tail recursion */ while (lo < up) { /* loop for tail recursion */
unsigned int p; /* Pivot index */ IdxT p; /* Pivot index */
unsigned int n; /* to be used later */ IdxT n; /* to be used later */
/* sort elements 'lo', 'p', and 'up' */ /* sort elements 'lo', 'p', and 'up' */
lua_geti(L, 1, lo); lua_geti(L, 1, lo);
lua_geti(L, 1, up); lua_geti(L, 1, up);
@ -400,7 +402,7 @@ static void auxsort (lua_State *L, unsigned int lo, unsigned int up,
n = up - p; /* size of smaller interval */ n = up - p; /* size of smaller interval */
up = p - 1; /* tail call for [lo .. p - 1] (lower interval) */ up = p - 1; /* tail call for [lo .. p - 1] (lower interval) */
} }
if ((up - lo) / 128u > n) /* partition too imbalanced? */ if ((up - lo) / 128 > n) /* partition too imbalanced? */
rnd = l_randomizePivot(); /* try a new randomization */ rnd = l_randomizePivot(); /* try a new randomization */
} /* tail call auxsort(L, lo, up, rnd) */ } /* tail call auxsort(L, lo, up, rnd) */
} }
@ -410,11 +412,10 @@ static int sort (lua_State *L) {
lua_Integer n = aux_getn(L, 1, TAB_RW); lua_Integer n = aux_getn(L, 1, TAB_RW);
if (n > 1) { /* non-trivial interval? */ if (n > 1) { /* non-trivial interval? */
luaL_argcheck(L, n < INT_MAX, 1, "array too big"); luaL_argcheck(L, n < INT_MAX, 1, "array too big");
luaL_checkstack(L, 40, ""); /* assume array is smaller than 2^40 */
if (!lua_isnoneornil(L, 2)) /* is there a 2nd argument? */ if (!lua_isnoneornil(L, 2)) /* is there a 2nd argument? */
luaL_checktype(L, 2, LUA_TFUNCTION); /* must be a function */ luaL_checktype(L, 2, LUA_TFUNCTION); /* must be a function */
lua_settop(L, 2); /* make sure there are two arguments */ lua_settop(L, 2); /* make sure there are two arguments */
auxsort(L, 1, (unsigned int)n, 0u); auxsort(L, 1, (IdxT)n, 0);
} }
return 0; return 0;
} }

View File

@ -1,5 +1,5 @@
/* /*
** $Id: ltm.c,v 2.36 2015/11/03 15:47:30 roberto Exp $ ** $Id: ltm.c,v 2.37 2016/02/26 19:20:15 roberto Exp $
** Tag methods ** Tag methods
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -83,6 +83,22 @@ const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o, TMS event) {
} }
/*
** Return the name of the type of an object. For tables and userdata
** with metatable, use their '__name' metafield, if present.
*/
const char *luaT_objtypename (lua_State *L, const TValue *o) {
Table *mt;
if ((ttistable(o) && (mt = hvalue(o)->metatable) != NULL) ||
(ttisfulluserdata(o) && (mt = uvalue(o)->metatable) != NULL)) {
const TValue *name = luaH_getshortstr(mt, luaS_new(L, "__name"));
if (ttisstring(name)) /* is '__name' a string? */
return getstr(tsvalue(name)); /* use it as type name */
}
return ttypename(ttnov(o)); /* else use standard type name */
}
void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1, void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1,
const TValue *p2, TValue *p3, int hasres) { const TValue *p2, TValue *p3, int hasres) {
ptrdiff_t result = savestack(L, p3); ptrdiff_t result = savestack(L, p3);

View File

@ -1,5 +1,5 @@
/* /*
** $Id: ltm.h,v 2.21 2014/10/25 11:50:46 roberto Exp $ ** $Id: ltm.h,v 2.22 2016/02/26 19:20:15 roberto Exp $
** Tag methods ** Tag methods
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -51,11 +51,12 @@ typedef enum {
#define fasttm(l,et,e) gfasttm(G(l), et, e) #define fasttm(l,et,e) gfasttm(G(l), et, e)
#define ttypename(x) luaT_typenames_[(x) + 1] #define ttypename(x) luaT_typenames_[(x) + 1]
#define objtypename(x) ttypename(ttnov(x))
LUAI_DDEC const char *const luaT_typenames_[LUA_TOTALTAGS]; LUAI_DDEC const char *const luaT_typenames_[LUA_TOTALTAGS];
LUAI_FUNC const char *luaT_objtypename (lua_State *L, const TValue *o);
LUAI_FUNC const TValue *luaT_gettm (Table *events, TMS event, TString *ename); LUAI_FUNC const TValue *luaT_gettm (Table *events, TMS event, TString *ename);
LUAI_FUNC const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o, LUAI_FUNC const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o,
TMS event); TMS event);

View File

@ -1,5 +1,5 @@
/* /*
** $Id: lua.h,v 1.329 2015/11/13 17:18:42 roberto Exp $ ** $Id: lua.h,v 1.331 2016/05/30 15:53:28 roberto Exp $
** Lua - A Scripting Language ** Lua - A Scripting Language
** Lua.org, PUC-Rio, Brazil (http://www.lua.org) ** Lua.org, PUC-Rio, Brazil (http://www.lua.org)
** See Copyright Notice at the end of this file ** See Copyright Notice at the end of this file
@ -19,11 +19,11 @@
#define LUA_VERSION_MAJOR "5" #define LUA_VERSION_MAJOR "5"
#define LUA_VERSION_MINOR "3" #define LUA_VERSION_MINOR "3"
#define LUA_VERSION_NUM 503 #define LUA_VERSION_NUM 503
#define LUA_VERSION_RELEASE "2" #define LUA_VERSION_RELEASE "3"
#define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR #define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR
#define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE #define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE
#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2015 Lua.org, PUC-Rio" #define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2016 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"
@ -361,7 +361,7 @@ LUA_API void (lua_setallocf) (lua_State *L, lua_Alloc f, void *ud);
#define lua_pushliteral(L, s) lua_pushstring(L, "" s) #define lua_pushliteral(L, s) lua_pushstring(L, "" s)
#define lua_pushglobaltable(L) \ #define lua_pushglobaltable(L) \
lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS) ((void)lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS))
#define lua_tostring(L,i) lua_tolstring(L, (i), NULL) #define lua_tostring(L,i) lua_tolstring(L, (i), NULL)
@ -460,7 +460,7 @@ struct lua_Debug {
/****************************************************************************** /******************************************************************************
* Copyright (C) 1994-2015 Lua.org, PUC-Rio. * Copyright (C) 1994-2016 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

View File

@ -1,5 +1,5 @@
/* /*
** $Id: luaconf.h,v 1.254 2015/10/21 18:17:40 roberto Exp $ ** $Id: luaconf.h,v 1.255 2016/05/01 20:06:09 roberto Exp $
** Configuration file for Lua ** Configuration file for Lua
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -612,7 +612,7 @@
** provide its own implementation. ** provide its own implementation.
*/ */
#if !defined(LUA_USE_C89) #if !defined(LUA_USE_C89)
#define lua_number2strx(L,b,sz,f,n) l_sprintf(b,sz,f,n) #define lua_number2strx(L,b,sz,f,n) ((void)L, l_sprintf(b,sz,f,n))
#endif #endif

105
lua/lvm.c
View File

@ -1,5 +1,5 @@
/* /*
** $Id: lvm.c,v 2.265 2015/11/23 11:30:45 roberto Exp $ ** $Id: lvm.c,v 2.268 2016/02/05 19:59:14 roberto Exp $
** Lua virtual machine ** Lua virtual machine
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -153,55 +153,69 @@ static int forlimit (const TValue *obj, lua_Integer *p, lua_Integer step,
/* /*
** Complete a table access: if 't' is a table, 'tm' has its metamethod; ** Finish the table access 'val = t[key]'.
** otherwise, 'tm' is NULL. ** if 'slot' is NULL, 't' is not a table; otherwise, 'slot' points to
** t[k] entry (which must be nil).
*/ */
void luaV_finishget (lua_State *L, const TValue *t, TValue *key, StkId val, void luaV_finishget (lua_State *L, const TValue *t, TValue *key, StkId val,
const TValue *tm) { const TValue *slot) {
int loop; /* counter to avoid infinite loops */ int loop; /* counter to avoid infinite loops */
lua_assert(tm != NULL || !ttistable(t)); const TValue *tm; /* metamethod */
for (loop = 0; loop < MAXTAGLOOP; loop++) { for (loop = 0; loop < MAXTAGLOOP; loop++) {
if (tm == NULL) { /* no metamethod (from a table)? */ if (slot == NULL) { /* 't' is not a table? */
if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_INDEX))) lua_assert(!ttistable(t));
tm = luaT_gettmbyobj(L, t, TM_INDEX);
if (ttisnil(tm))
luaG_typeerror(L, t, "index"); /* no metamethod */ luaG_typeerror(L, t, "index"); /* no metamethod */
/* else will try the metamethod */
} }
if (ttisfunction(tm)) { /* metamethod is a function */ else { /* 't' is a table */
lua_assert(ttisnil(slot));
tm = fasttm(L, hvalue(t)->metatable, TM_INDEX); /* table's metamethod */
if (tm == NULL) { /* no metamethod? */
setnilvalue(val); /* result is nil */
return;
}
/* else will try the metamethod */
}
if (ttisfunction(tm)) { /* is metamethod a function? */
luaT_callTM(L, tm, t, key, val, 1); /* call it */ luaT_callTM(L, tm, t, key, val, 1); /* call it */
return; return;
} }
t = tm; /* else repeat access over 'tm' */ t = tm; /* else try to access 'tm[key]' */
if (luaV_fastget(L,t,key,tm,luaH_get)) { /* try fast track */ if (luaV_fastget(L,t,key,slot,luaH_get)) { /* fast track? */
setobj2s(L, val, tm); /* done */ setobj2s(L, val, slot); /* done */
return; return;
} }
/* else repeat */ /* else repeat (tail call 'luaV_finishget') */
} }
luaG_runerror(L, "gettable chain too long; possible loop"); luaG_runerror(L, "'__index' chain too long; possible loop");
} }
/* /*
** Main function for table assignment (invoking metamethods if needed). ** Finish a table assignment 't[key] = val'.
** Compute 't[key] = val' ** If 'slot' is NULL, 't' is not a table. Otherwise, 'slot' points
** to the entry 't[key]', or to 'luaO_nilobject' if there is no such
** entry. (The value at 'slot' must be nil, otherwise 'luaV_fastset'
** would have done the job.)
*/ */
void luaV_finishset (lua_State *L, const TValue *t, TValue *key, void luaV_finishset (lua_State *L, const TValue *t, TValue *key,
StkId val, const TValue *oldval) { StkId val, const TValue *slot) {
int loop; /* counter to avoid infinite loops */ int loop; /* counter to avoid infinite loops */
for (loop = 0; loop < MAXTAGLOOP; loop++) { for (loop = 0; loop < MAXTAGLOOP; loop++) {
const TValue *tm; const TValue *tm; /* '__newindex' metamethod */
if (oldval != NULL) { if (slot != NULL) { /* is 't' a table? */
lua_assert(ttistable(t) && ttisnil(oldval)); Table *h = hvalue(t); /* save 't' table */
/* must check the metamethod */ lua_assert(ttisnil(slot)); /* old value must be nil */
if ((tm = fasttm(L, hvalue(t)->metatable, TM_NEWINDEX)) == NULL && tm = fasttm(L, h->metatable, TM_NEWINDEX); /* get metamethod */
/* no metamethod; is there a previous entry in the table? */ if (tm == NULL) { /* no metamethod? */
(oldval != luaO_nilobject || if (slot == luaO_nilobject) /* no previous entry? */
/* no previous entry; must create one. (The next test is slot = luaH_newkey(L, h, key); /* create one */
always true; we only need the assignment.) */
(oldval = luaH_newkey(L, hvalue(t), key), 1))) {
/* no metamethod and (now) there is an entry with given key */ /* no metamethod and (now) there is an entry with given key */
setobj2t(L, cast(TValue *, oldval), val); setobj2t(L, cast(TValue *, slot), val); /* set its new value */
invalidateTMcache(hvalue(t)); invalidateTMcache(h);
luaC_barrierback(L, hvalue(t), val); luaC_barrierback(L, h, val);
return; return;
} }
/* else will try the metamethod */ /* else will try the metamethod */
@ -216,11 +230,11 @@ void luaV_finishset (lua_State *L, const TValue *t, TValue *key,
return; return;
} }
t = tm; /* else repeat assignment over 'tm' */ t = tm; /* else repeat assignment over 'tm' */
if (luaV_fastset(L, t, key, oldval, luaH_get, val)) if (luaV_fastset(L, t, key, slot, luaH_get, val))
return; /* done */ return; /* done */
/* else loop */ /* else loop */
} }
luaG_runerror(L, "settable chain too long; possible loop"); luaG_runerror(L, "'__newindex' chain too long; possible loop");
} }
@ -738,18 +752,28 @@ void luaV_finishOp (lua_State *L) {
luai_threadyield(L); } luai_threadyield(L); }
/* fetch an instruction and prepare its execution */
#define vmfetch() { \
i = *(ci->u.l.savedpc++); \
if (L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) \
Protect(luaG_traceexec(L)); \
ra = RA(i); /* WARNING: any stack reallocation invalidates 'ra' */ \
lua_assert(base == ci->u.l.base); \
lua_assert(base <= L->top && L->top < L->stack + L->stacksize); \
}
#define vmdispatch(o) switch(o) #define vmdispatch(o) switch(o)
#define vmcase(l) case l: #define vmcase(l) case l:
#define vmbreak break #define vmbreak break
/* /*
** copy of 'luaV_gettable', but protecting call to potential metamethod ** copy of 'luaV_gettable', but protecting the call to potential
** (which can reallocate the stack) ** metamethod (which can reallocate the stack)
*/ */
#define gettableProtected(L,t,k,v) { const TValue *aux; \ #define gettableProtected(L,t,k,v) { const TValue *slot; \
if (luaV_fastget(L,t,k,aux,luaH_get)) { setobj2s(L, v, aux); } \ if (luaV_fastget(L,t,k,slot,luaH_get)) { setobj2s(L, v, slot); } \
else Protect(luaV_finishget(L,t,k,v,aux)); } else Protect(luaV_finishget(L,t,k,v,slot)); }
/* same for 'luaV_settable' */ /* same for 'luaV_settable' */
@ -772,14 +796,9 @@ void luaV_execute (lua_State *L) {
base = ci->u.l.base; /* local copy of function's base */ base = ci->u.l.base; /* local copy of function's base */
/* main loop of interpreter */ /* main loop of interpreter */
for (;;) { for (;;) {
Instruction i = *(ci->u.l.savedpc++); Instruction i;
StkId ra; StkId ra;
if (L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) vmfetch();
Protect(luaG_traceexec(L));
/* WARNING: several calls may realloc the stack and invalidate 'ra' */
ra = RA(i);
lua_assert(base == ci->u.l.base);
lua_assert(base <= L->top && L->top < L->stack + L->stacksize);
vmdispatch (GET_OPCODE(i)) { vmdispatch (GET_OPCODE(i)) {
vmcase(OP_MOVE) { vmcase(OP_MOVE) {
setobjs2s(L, ra, RB(i)); setobjs2s(L, ra, RB(i));

View File

@ -1,5 +1,5 @@
/* /*
** $Id: lvm.h,v 2.39 2015/09/09 13:44:07 roberto Exp $ ** $Id: lvm.h,v 2.40 2016/01/05 16:07:21 roberto Exp $
** Lua virtual machine ** Lua virtual machine
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -49,25 +49,24 @@
/* /*
** fast track for 'gettable': 1 means 'aux' points to resulted value; ** fast track for 'gettable': if 't' is a table and 't[k]' is not nil,
** 0 means 'aux' is metamethod (if 't' is a table) or NULL. 'f' is ** return 1 with 'slot' pointing to 't[k]' (final result). Otherwise,
** the raw get function to use. ** return 0 (meaning it will have to check metamethod) with 'slot'
** pointing to a nil 't[k]' (if 't' is a table) or NULL (otherwise).
** 'f' is the raw get function to use.
*/ */
#define luaV_fastget(L,t,k,aux,f) \ #define luaV_fastget(L,t,k,slot,f) \
(!ttistable(t) \ (!ttistable(t) \
? (aux = NULL, 0) /* not a table; 'aux' is NULL and result is 0 */ \ ? (slot = NULL, 0) /* not a table; 'slot' is NULL and result is 0 */ \
: (aux = f(hvalue(t), k), /* else, do raw access */ \ : (slot = f(hvalue(t), k), /* else, do raw access */ \
!ttisnil(aux) ? 1 /* result not nil? 'aux' has it */ \ !ttisnil(slot))) /* result not nil? */
: (aux = fasttm(L, hvalue(t)->metatable, TM_INDEX), /* get metamethod */\
aux != NULL ? 0 /* has metamethod? must call it */ \
: (aux = luaO_nilobject, 1)))) /* else, final result is nil */
/* /*
** standard implementation for 'gettable' ** standard implementation for 'gettable'
*/ */
#define luaV_gettable(L,t,k,v) { const TValue *aux; \ #define luaV_gettable(L,t,k,v) { const TValue *slot; \
if (luaV_fastget(L,t,k,aux,luaH_get)) { setobj2s(L, v, aux); } \ if (luaV_fastget(L,t,k,slot,luaH_get)) { setobj2s(L, v, slot); } \
else luaV_finishget(L,t,k,v,aux); } else luaV_finishget(L,t,k,v,slot); }
/* /*
@ -100,9 +99,9 @@ LUAI_FUNC int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r);
LUAI_FUNC int luaV_tonumber_ (const TValue *obj, lua_Number *n); LUAI_FUNC int luaV_tonumber_ (const TValue *obj, lua_Number *n);
LUAI_FUNC int luaV_tointeger (const TValue *obj, lua_Integer *p, int mode); LUAI_FUNC int luaV_tointeger (const TValue *obj, lua_Integer *p, int mode);
LUAI_FUNC void luaV_finishget (lua_State *L, const TValue *t, TValue *key, LUAI_FUNC void luaV_finishget (lua_State *L, const TValue *t, TValue *key,
StkId val, const TValue *tm); StkId val, const TValue *slot);
LUAI_FUNC void luaV_finishset (lua_State *L, const TValue *t, TValue *key, LUAI_FUNC void luaV_finishset (lua_State *L, const TValue *t, TValue *key,
StkId val, const TValue *oldval); StkId val, const TValue *slot);
LUAI_FUNC void luaV_finishOp (lua_State *L); LUAI_FUNC void luaV_finishOp (lua_State *L);
LUAI_FUNC void luaV_execute (lua_State *L); LUAI_FUNC void luaV_execute (lua_State *L);
LUAI_FUNC void luaV_concat (lua_State *L, int total); LUAI_FUNC void luaV_concat (lua_State *L, int total);