diff options
Diffstat (limited to 'lib/lua/src')
-rw-r--r-- | lib/lua/src/LuaLib/lauxlib.c | 316 | ||||
-rw-r--r-- | lib/lua/src/LuaLib/lbaselib.c | 436 | ||||
-rw-r--r-- | lib/lua/src/LuaLib/ldblib.c | 324 | ||||
-rw-r--r-- | lib/lua/src/LuaLib/liolib.c | 534 | ||||
-rw-r--r-- | lib/lua/src/LuaLib/lmathlib.c | 105 | ||||
-rw-r--r-- | lib/lua/src/LuaLib/loadlib.c | 765 | ||||
-rw-r--r-- | lib/lua/src/LuaLib/lstrlib.c | 420 | ||||
-rw-r--r-- | lib/lua/src/LuaLib/ltablib.c | 130 | ||||
-rw-r--r-- | lib/lua/src/lapi.c | 648 | ||||
-rw-r--r-- | lib/lua/src/lcode.c | 469 | ||||
-rw-r--r-- | lib/lua/src/ldebug.c | 335 | ||||
-rw-r--r-- | lib/lua/src/ldo.c | 375 | ||||
-rw-r--r-- | lib/lua/src/ldump.c | 164 | ||||
-rw-r--r-- | lib/lua/src/lfunc.c | 107 | ||||
-rw-r--r-- | lib/lua/src/lgc.c | 778 | ||||
-rw-r--r-- | lib/lua/src/llex.c | 559 | ||||
-rw-r--r-- | lib/lua/src/lmem.c | 97 | ||||
-rw-r--r-- | lib/lua/src/lobject.c | 134 | ||||
-rw-r--r-- | lib/lua/src/lopcodes.c | 102 | ||||
-rw-r--r-- | lib/lua/src/lparser.c | 622 | ||||
-rw-r--r-- | lib/lua/src/lstate.c | 207 | ||||
-rw-r--r-- | lib/lua/src/lstring.c | 63 | ||||
-rw-r--r-- | lib/lua/src/ltable.c | 493 | ||||
-rw-r--r-- | lib/lua/src/ltm.c | 29 | ||||
-rw-r--r-- | lib/lua/src/luacomp.c | 45 | ||||
-rw-r--r-- | lib/lua/src/lundump.c | 287 | ||||
-rw-r--r-- | lib/lua/src/lvm.c | 829 | ||||
-rw-r--r-- | lib/lua/src/lzio.c | 37 |
28 files changed, 5261 insertions, 4149 deletions
diff --git a/lib/lua/src/LuaLib/lauxlib.c b/lib/lua/src/LuaLib/lauxlib.c index 2088b9e..9df860c 100644 --- a/lib/lua/src/LuaLib/lauxlib.c +++ b/lib/lua/src/LuaLib/lauxlib.c @@ -1,5 +1,5 @@ /* -** $Id: lauxlib.c,v 1.4 2004-11-27 21:46:10 pixel Exp $ +** $Id: lauxlib.c,v 1.5 2007-07-27 10:05:55 pixel Exp $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice in lua.h */ @@ -9,6 +9,7 @@ #include <errno.h> #include <stdarg.h> #include <stdio.h> +#include <stdlib.h> #include <string.h> @@ -17,18 +18,14 @@ */ #define lauxlib_c +#define LUA_LIB #include "lua.h" #include "lauxlib.h" -/* number of prereserved references (for internal use) */ -#define RESERVED_REFS 2 - -/* reserved references */ -#define FREELIST_REF 1 /* free list of references */ -#define ARRAYSIZE_REF 2 /* array sizes */ +#define FREELIST_REF 0 /* free list of references */ /* convert a stack index to positive */ @@ -45,36 +42,38 @@ LUALIB_API int luaL_argerror (lua_State *L, int narg, const char *extramsg) { lua_Debug ar; - lua_getstack(L, 0, &ar); + if (!lua_getstack(L, 0, &ar)) /* no stack frame? */ + return luaL_error(L, "bad argument #%d (%s)", narg, extramsg); lua_getinfo(L, "n", &ar); if (strcmp(ar.namewhat, "method") == 0) { narg--; /* do not count `self' */ if (narg == 0) /* error is in the self argument itself? */ - return luaL_error(L, "calling `%s' on bad self (%s)", ar.name, extramsg); + return luaL_error(L, "calling " LUA_QS " on bad self (%s)", + ar.name, extramsg); } if (ar.name == NULL) ar.name = "?"; - return luaL_error(L, "bad argument #%d to `%s' (%s)", + return luaL_error(L, "bad argument #%d to " LUA_QS " (%s)", narg, ar.name, extramsg); } LUALIB_API int luaL_typerror (lua_State *L, int narg, const char *tname) { const char *msg = lua_pushfstring(L, "%s expected, got %s", - tname, lua_typename(L, lua_type(L,narg))); + tname, luaL_typename(L, narg)); return luaL_argerror(L, narg, msg); } static void tag_error (lua_State *L, int narg, int tag) { - luaL_typerror(L, narg, lua_typename(L, tag)); + luaL_typerror(L, narg, lua_typename(L, tag)); } LUALIB_API void luaL_where (lua_State *L, int level) { lua_Debug ar; if (lua_getstack(L, level, &ar)) { /* check function at level */ - lua_getinfo(L, "Snl", &ar); /* get info about it */ + lua_getinfo(L, "Sl", &ar); /* get info about it */ if (ar.currentline > 0) { /* is there info? */ lua_pushfstring(L, "%s:%d: ", ar.short_src, ar.currentline); return; @@ -97,51 +96,44 @@ LUALIB_API int luaL_error (lua_State *L, const char *fmt, ...) { /* }====================================================== */ -LUALIB_API int luaL_findstring (const char *name, const char *const list[]) { +LUALIB_API int luaL_checkoption (lua_State *L, int narg, const char *def, + const char *const lst[]) { + const char *name = (def) ? luaL_optstring(L, narg, def) : + luaL_checkstring(L, narg); int i; - for (i=0; list[i]; i++) - if (strcmp(list[i], name) == 0) + for (i=0; lst[i]; i++) + if (strcmp(lst[i], name) == 0) return i; - return -1; /* name not found */ + return luaL_argerror(L, narg, + lua_pushfstring(L, "invalid option " LUA_QS, name)); } LUALIB_API int luaL_newmetatable (lua_State *L, const char *tname) { - lua_pushstring(L, tname); - lua_rawget(L, LUA_REGISTRYINDEX); /* get registry.name */ + lua_getfield(L, LUA_REGISTRYINDEX, tname); /* get registry.name */ if (!lua_isnil(L, -1)) /* name already in use? */ return 0; /* leave previous value on top, but return 0 */ lua_pop(L, 1); lua_newtable(L); /* create metatable */ - lua_pushstring(L, tname); - lua_pushvalue(L, -2); - lua_rawset(L, LUA_REGISTRYINDEX); /* registry.name = metatable */ lua_pushvalue(L, -1); - lua_pushstring(L, tname); - lua_rawset(L, LUA_REGISTRYINDEX); /* registry[metatable] = name */ + lua_setfield(L, LUA_REGISTRYINDEX, tname); /* registry.name = metatable */ return 1; } -LUALIB_API void luaL_getmetatable (lua_State *L, const char *tname) { - lua_pushstring(L, tname); - lua_rawget(L, LUA_REGISTRYINDEX); -} - - LUALIB_API void *luaL_checkudata (lua_State *L, int ud, const char *tname) { - const char *tn; - if (!lua_getmetatable(L, ud)) return NULL; /* no metatable? */ - lua_rawget(L, LUA_REGISTRYINDEX); /* get registry[metatable] */ - tn = lua_tostring(L, -1); - if (tn && (strcmp(tn, tname) == 0)) { - lua_pop(L, 1); - return lua_touserdata(L, ud); - } - else { - lua_pop(L, 1); - return NULL; + void *p = lua_touserdata(L, ud); + if (p != NULL) { /* value is a userdata? */ + if (lua_getmetatable(L, ud)) { /* does it have a metatable? */ + lua_getfield(L, LUA_REGISTRYINDEX, tname); /* get correct metatable */ + if (lua_rawequal(L, -1, -2)) { /* does it have the correct mt? */ + lua_pop(L, 2); /* remove both metatables */ + return p; + } + } } + luaL_typerror(L, ud, tname); /* else error */ + return NULL; /* to avoid warnings */ } @@ -164,9 +156,8 @@ LUALIB_API void luaL_checkany (lua_State *L, int narg) { LUALIB_API const char *luaL_checklstring (lua_State *L, int narg, size_t *len) { - const char *s = lua_tostring(L, narg); + const char *s = lua_tolstring(L, narg, len); if (!s) tag_error(L, narg, LUA_TSTRING); - if (len) *len = lua_strlen(L, narg); return s; } @@ -191,8 +182,21 @@ LUALIB_API lua_Number luaL_checknumber (lua_State *L, int narg) { LUALIB_API lua_Number luaL_optnumber (lua_State *L, int narg, lua_Number def) { - if (lua_isnoneornil(L, narg)) return def; - else return luaL_checknumber(L, narg); + return luaL_opt(L, luaL_checknumber, narg, def); +} + + +LUALIB_API lua_Integer luaL_checkinteger (lua_State *L, int narg) { + lua_Integer d = lua_tointeger(L, narg); + if (d == 0 && !lua_isnumber(L, narg)) /* avoid extra test when d is not 0 */ + tag_error(L, narg, LUA_TNUMBER); + return d; +} + + +LUALIB_API lua_Integer luaL_optinteger (lua_State *L, int narg, + lua_Integer def) { + return luaL_opt(L, luaL_checkinteger, narg, def); } @@ -222,27 +226,43 @@ LUALIB_API int luaL_callmeta (lua_State *L, int obj, const char *event) { } -LUALIB_API void luaL_openlib (lua_State *L, const char *libname, - const luaL_reg *l, int nup) { +LUALIB_API void (luaL_register) (lua_State *L, const char *libname, + const luaL_Reg *l) { + luaI_openlib(L, libname, l, 0); +} + + +static int libsize (const luaL_Reg *l) { + int size = 0; + for (; l->name; l++) size++; + return size; +} + + +LUALIB_API void luaI_openlib (lua_State *L, const char *libname, + const luaL_Reg *l, int nup) { if (libname) { - lua_pushstring(L, libname); - lua_gettable(L, LUA_GLOBALSINDEX); /* check whether lib already exists */ - if (lua_isnil(L, -1)) { /* no? */ - lua_pop(L, 1); - lua_newtable(L); /* create it */ - lua_pushstring(L, libname); - lua_pushvalue(L, -2); - lua_settable(L, LUA_GLOBALSINDEX); /* register it with given name */ + int size = libsize(l); + /* check whether lib already exists */ + luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", size); + lua_getfield(L, -1, libname); /* get _LOADED[libname] */ + if (!lua_istable(L, -1)) { /* not found? */ + lua_pop(L, 1); /* remove previous result */ + /* try global variable (and create one if it does not exist) */ + if (luaL_findtable(L, LUA_GLOBALSINDEX, libname, size) != NULL) + luaL_error(L, "name conflict for module " LUA_QS, libname); + lua_pushvalue(L, -1); + lua_setfield(L, -3, libname); /* _LOADED[libname] = new table */ } + lua_remove(L, -2); /* remove _LOADED table */ lua_insert(L, -(nup+1)); /* move library table to below upvalues */ } for (; l->name; l++) { int i; - lua_pushstring(L, l->name); for (i=0; i<nup; i++) /* copy upvalues to the top */ - lua_pushvalue(L, -(nup+1)); + lua_pushvalue(L, -nup); lua_pushcclosure(L, l->func, nup); - lua_settable(L, -(nup+3)); + lua_setfield(L, -(nup+2), l->name); } lua_pop(L, nup); /* remove upvalues */ } @@ -255,50 +275,50 @@ LUALIB_API void luaL_openlib (lua_State *L, const char *libname, ** ======================================================= */ +#if defined(LUA_COMPAT_GETN) + static int checkint (lua_State *L, int topop) { - int n = (int)lua_tonumber(L, -1); - if (n == 0 && !lua_isnumber(L, -1)) n = -1; + int n = (lua_type(L, -1) == LUA_TNUMBER) ? lua_tointeger(L, -1) : -1; lua_pop(L, topop); return n; } static void getsizes (lua_State *L) { - lua_rawgeti(L, LUA_REGISTRYINDEX, ARRAYSIZE_REF); + lua_getfield(L, LUA_REGISTRYINDEX, "LUA_SIZES"); if (lua_isnil(L, -1)) { /* no `size' table? */ lua_pop(L, 1); /* remove nil */ lua_newtable(L); /* create it */ lua_pushvalue(L, -1); /* `size' will be its own metatable */ lua_setmetatable(L, -2); - lua_pushliteral(L, "__mode"); - lua_pushliteral(L, "k"); - lua_rawset(L, -3); /* metatable(N).__mode = "k" */ + lua_pushliteral(L, "kv"); + lua_setfield(L, -2, "__mode"); /* metatable(N).__mode = "kv" */ lua_pushvalue(L, -1); - lua_rawseti(L, LUA_REGISTRYINDEX, ARRAYSIZE_REF); /* store in register */ + lua_setfield(L, LUA_REGISTRYINDEX, "LUA_SIZES"); /* store in register */ } } -void luaL_setn (lua_State *L, int t, int n) { +LUALIB_API void luaL_setn (lua_State *L, int t, int n) { t = abs_index(L, t); lua_pushliteral(L, "n"); lua_rawget(L, t); if (checkint(L, 1) >= 0) { /* is there a numeric field `n'? */ lua_pushliteral(L, "n"); /* use it */ - lua_pushnumber(L, (lua_Number)n); + lua_pushinteger(L, n); lua_rawset(L, t); } else { /* use `sizes' */ getsizes(L); lua_pushvalue(L, t); - lua_pushnumber(L, (lua_Number)n); + lua_pushinteger(L, n); lua_rawset(L, -3); /* sizes[t] = n */ lua_pop(L, 1); /* remove `sizes' */ } } -int luaL_getn (lua_State *L, int t) { +LUALIB_API int luaL_getn (lua_State *L, int t) { int n; t = abs_index(L, t); lua_pushliteral(L, "n"); /* try t.n */ @@ -308,19 +328,60 @@ int luaL_getn (lua_State *L, int t) { lua_pushvalue(L, t); lua_rawget(L, -2); if ((n = checkint(L, 2)) >= 0) return n; - for (n = 1; ; n++) { /* else must count elements */ - lua_rawgeti(L, t, n); - if (lua_isnil(L, -1)) break; - lua_pop(L, 1); - } - lua_pop(L, 1); - return n - 1; + return (int)lua_objlen(L, t); } +#endif + /* }====================================================== */ +LUALIB_API const char *luaL_gsub (lua_State *L, const char *s, const char *p, + const char *r) { + const char *wild; + size_t l = strlen(p); + luaL_Buffer b; + luaL_buffinit(L, &b); + while ((wild = strstr(s, p)) != NULL) { + luaL_addlstring(&b, s, wild - s); /* push prefix */ + luaL_addstring(&b, r); /* push replacement in place of pattern */ + s = wild + l; /* continue after `p' */ + } + luaL_addstring(&b, s); /* push last suffix */ + luaL_pushresult(&b); + return lua_tostring(L, -1); +} + + +LUALIB_API const char *luaL_findtable (lua_State *L, int idx, + const char *fname, int szhint) { + const char *e; + lua_pushvalue(L, idx); + do { + e = strchr(fname, '.'); + if (e == NULL) e = fname + strlen(fname); + lua_pushlstring(L, fname, e - fname); + lua_rawget(L, -2); + if (lua_isnil(L, -1)) { /* no such field? */ + lua_pop(L, 1); /* remove this nil */ + lua_createtable(L, 0, (*e == '.' ? 1 : szhint)); /* new table for field */ + lua_pushlstring(L, fname, e - fname); + lua_pushvalue(L, -2); + lua_settable(L, -4); /* set new table into field */ + } + else if (!lua_istable(L, -1)) { /* field has a non-table value? */ + lua_pop(L, 2); /* remove table and value */ + return fname; /* return problematic part of the name */ + } + lua_remove(L, -2); /* remove previous table */ + fname = e + 1; + } while (*e == '.'); + return NULL; +} + + + /* ** {====================================================== ** Generic Buffer manipulation @@ -374,7 +435,7 @@ LUALIB_API char *luaL_prepbuffer (luaL_Buffer *B) { LUALIB_API void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l) { while (l--) - luaL_putchar(B, *s++); + luaL_addchar(B, *s++); } @@ -392,9 +453,10 @@ LUALIB_API void luaL_pushresult (luaL_Buffer *B) { LUALIB_API void luaL_addvalue (luaL_Buffer *B) { lua_State *L = B->L; - size_t vl = lua_strlen(L, -1); + size_t vl; + const char *s = lua_tolstring(L, -1, &vl); if (vl <= bufffree(B)) { /* fit into buffer? */ - memcpy(B->p, lua_tostring(L, -1), vl); /* put it there */ + memcpy(B->p, s, vl); /* put it there */ B->p += vl; lua_pop(L, 1); /* remove from stack */ } @@ -424,18 +486,15 @@ LUALIB_API int luaL_ref (lua_State *L, int t) { return LUA_REFNIL; /* `nil' has a unique fixed reference */ } lua_rawgeti(L, t, FREELIST_REF); /* get first free element */ - ref = (int)lua_tonumber(L, -1); /* ref = t[FREELIST_REF] */ + ref = (int)lua_tointeger(L, -1); /* ref = t[FREELIST_REF] */ lua_pop(L, 1); /* remove it from stack */ if (ref != 0) { /* any free element? */ lua_rawgeti(L, t, ref); /* remove it from list */ lua_rawseti(L, t, FREELIST_REF); /* (t[FREELIST_REF] = t[ref]) */ } else { /* no free elements */ - ref = luaL_getn(L, t); - if (ref < RESERVED_REFS) - ref = RESERVED_REFS; /* skip reserved references */ + ref = (int)lua_objlen(L, t); ref++; /* create new reference */ - luaL_setn(L, t, ref); } lua_rawseti(L, t, ref); return ref; @@ -447,7 +506,7 @@ LUALIB_API void luaL_unref (lua_State *L, int t, int ref) { t = abs_index(L, t); lua_rawgeti(L, t, FREELIST_REF); lua_rawseti(L, t, ref); /* t[ref] = t[FREELIST_REF] */ - lua_pushnumber(L, (lua_Number)ref); + lua_pushinteger(L, ref); lua_rawseti(L, t, FREELIST_REF); /* t[FREELIST_REF] = ref */ } } @@ -461,6 +520,7 @@ LUALIB_API void luaL_unref (lua_State *L, int t, int ref) { */ typedef struct LoadF { + int extraline; FILE *f; char buff[LUAL_BUFFERSIZE]; } LoadF; @@ -469,15 +529,21 @@ typedef struct LoadF { static const char *getF (lua_State *L, void *ud, size_t *size) { LoadF *lf = (LoadF *)ud; (void)L; + if (lf->extraline) { + lf->extraline = 0; + *size = 1; + return "\n"; + } if (feof(lf->f)) return NULL; *size = fread(lf->buff, 1, LUAL_BUFFERSIZE, lf->f); return (*size > 0) ? lf->buff : NULL; } -static int errfile (lua_State *L, int fnameindex) { +static int errfile (lua_State *L, const char *what, int fnameindex) { + const char *serr = strerror(errno); const char *filename = lua_tostring(L, fnameindex) + 1; - lua_pushfstring(L, "cannot read %s: %s", filename, strerror(errno)); + lua_pushfstring(L, "cannot %s %s: %s", what, filename, serr); lua_remove(L, fnameindex); return LUA_ERRFILE; } @@ -488,6 +554,7 @@ LUALIB_API int luaL_loadfile (lua_State *L, const char *filename) { int status, readstatus; int c; int fnameindex = lua_gettop(L) + 1; /* index of filename on the stack */ + lf.extraline = 0; if (filename == NULL) { lua_pushliteral(L, "=stdin"); lf.f = stdin; @@ -495,20 +562,29 @@ LUALIB_API int luaL_loadfile (lua_State *L, const char *filename) { else { lua_pushfstring(L, "@%s", filename); lf.f = fopen(filename, "r"); + if (lf.f == NULL) return errfile(L, "open", fnameindex); + } + c = getc(lf.f); + if (c == '#') { /* Unix exec. file? */ + lf.extraline = 1; + while ((c = getc(lf.f)) != EOF && c != '\n') ; /* skip first line */ + if (c == '\n') c = getc(lf.f); } - if (lf.f == NULL) return errfile(L, fnameindex); /* unable to open file */ - c = ungetc(getc(lf.f), lf.f); - if (!(isspace(c) || isprint(c)) && lf.f != stdin) { /* binary file? */ + if (c == LUA_SIGNATURE[0] && lf.f != stdin) { /* binary file? */ fclose(lf.f); lf.f = fopen(filename, "rb"); /* reopen in binary mode */ - if (lf.f == NULL) return errfile(L, fnameindex); /* unable to reopen file */ + if (lf.f == NULL) return errfile(L, "reopen", fnameindex); + /* skip eventual `#!...' */ + while ((c = getc(lf.f)) != EOF && c != LUA_SIGNATURE[0]) ; + lf.extraline = 0; } + ungetc(c, lf.f); status = lua_load(L, getF, &lf, lua_tostring(L, -1)); readstatus = ferror(lf.f); if (lf.f != stdin) fclose(lf.f); /* close file (even in case of errors) */ if (readstatus) { lua_settop(L, fnameindex); /* ignore results from `lua_load' */ - return errfile(L, fnameindex); + return errfile(L, "read", fnameindex); } lua_remove(L, fnameindex); return status; @@ -539,53 +615,39 @@ LUALIB_API int luaL_loadbuffer (lua_State *L, const char *buff, size_t size, return lua_load(L, getS, &ls, name); } -/* }====================================================== */ +LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s) { + return luaL_loadbuffer(L, s, strlen(s), s); +} -/* -** {====================================================== -** compatibility code -** ======================================================= -*/ -static void callalert (lua_State *L, int status) { - if (status != 0) { - lua_getglobal(L, "_ALERT"); - if (lua_isfunction(L, -1)) { - lua_insert(L, -2); - lua_call(L, 1, 0); - } - else { /* no _ALERT function; print it on stderr */ - fprintf(stderr, "%s\n", lua_tostring(L, -2)); - lua_pop(L, 2); /* remove error message and _ALERT */ - } - } -} +/* }====================================================== */ -static int aux_do (lua_State *L, int status) { - if (status == 0) { /* parse OK? */ - status = lua_pcall(L, 0, LUA_MULTRET, 0); /* call main */ +static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) { + (void)ud; + (void)osize; + if (nsize == 0) { + free(ptr); + return NULL; } - callalert(L, status); - return status; + else + return realloc(ptr, nsize); } -LUALIB_API int lua_dofile (lua_State *L, const char *filename) { - return aux_do(L, luaL_loadfile(L, filename)); +static int panic (lua_State *L) { + (void)L; /* to avoid warnings */ + fprintf(stderr, "PANIC: unprotected error in call to Lua API (%s)\n", + lua_tostring(L, -1)); + return 0; } -LUALIB_API int lua_dobuffer (lua_State *L, const char *buff, size_t size, - const char *name) { - return aux_do(L, luaL_loadbuffer(L, buff, size, name)); +LUALIB_API lua_State *luaL_newstate (void) { + lua_State *L = lua_newstate(l_alloc, NULL); + if (L) lua_atpanic(L, &panic); + return L; } - -LUALIB_API int lua_dostring (lua_State *L, const char *str) { - return lua_dobuffer(L, str, strlen(str), str); -} - -/* }====================================================== */ diff --git a/lib/lua/src/LuaLib/lbaselib.c b/lib/lua/src/LuaLib/lbaselib.c index 9a173a4..846f26f 100644 --- a/lib/lua/src/LuaLib/lbaselib.c +++ b/lib/lua/src/LuaLib/lbaselib.c @@ -1,5 +1,5 @@ /* -** $Id: lbaselib.c,v 1.7 2007-07-25 16:54:33 pixel Exp $ +** $Id: lbaselib.c,v 1.8 2007-07-27 10:05:55 pixel Exp $ ** Basic library ** See Copyright Notice in lua.h */ @@ -12,6 +12,7 @@ #include <string.h> #define lbaselib_c +#define LUA_LIB #include "lua.h" @@ -38,7 +39,8 @@ static int luaB_print (lua_State *L) { lua_call(L, 1, 1); s = lua_tostring(L, -1); /* get result */ if (s == NULL) - return luaL_error(L, "`tostring' must return a string to `print'"); + return luaL_error(L, LUA_QL("tostring") " must return a string to " + LUA_QL("print")); if (i>1) fputs("\t", stdout); fputs(s, stdout); lua_pop(L, 1); /* pop result */ @@ -78,10 +80,8 @@ static int luaB_tonumber (lua_State *L) { static int luaB_error (lua_State *L) { int level = luaL_optint(L, 2, 1); - luaL_checkany(L, 1); - if (!lua_isstring(L, 1) || level == 0) - lua_pushvalue(L, 1); /* propagate error message without changes */ - else { /* add extra information */ + lua_settop(L, 1); + if (lua_isstring(L, 1) && level > 0) { /* add extra information? */ luaL_where(L, level); lua_pushvalue(L, 1); lua_concat(L, 2); @@ -114,11 +114,11 @@ static int luaB_setmetatable (lua_State *L) { } -static void getfunc (lua_State *L) { +static void getfunc (lua_State *L, int opt) { if (lua_isfunction(L, 1)) lua_pushvalue(L, 1); else { lua_Debug ar; - int level = luaL_optint(L, 1, 1); + int level = opt ? luaL_optint(L, 1, 1) : luaL_checkint(L, 1); luaL_argcheck(L, level >= 0, 1, "level must be non-negative"); if (lua_getstack(L, level, &ar) == 0) luaL_argerror(L, 1, "invalid level"); @@ -130,35 +130,31 @@ static void getfunc (lua_State *L) { } -static int aux_getfenv (lua_State *L) { - lua_getfenv(L, -1); - lua_pushliteral(L, "__fenv"); - lua_rawget(L, -2); - return !lua_isnil(L, -1); -} - - static int luaB_getfenv (lua_State *L) { - getfunc(L); - if (!aux_getfenv(L)) /* __fenv not defined? */ - lua_pop(L, 1); /* remove it, to return real environment */ + getfunc(L, 1); + if (lua_iscfunction(L, -1)) /* is a C function? */ + lua_pushvalue(L, LUA_GLOBALSINDEX); /* return the thread's global env. */ + else + lua_getfenv(L, -1); return 1; } static int luaB_setfenv (lua_State *L) { luaL_checktype(L, 2, LUA_TTABLE); - getfunc(L); - if (aux_getfenv(L)) /* __fenv defined? */ - luaL_error(L, "`setfenv' cannot change a protected environment"); - else - lua_pop(L, 2); /* remove __fenv and real environment table */ + getfunc(L, 0); lua_pushvalue(L, 2); - if (lua_isnumber(L, 1) && lua_tonumber(L, 1) == 0) - lua_replace(L, LUA_GLOBALSINDEX); - else if (lua_setfenv(L, -2) == 0) - luaL_error(L, "`setfenv' cannot change environment of given function"); - return 0; + if (lua_isnumber(L, 1) && lua_tonumber(L, 1) == 0) { + /* change environment of current thread */ + lua_pushthread(L); + lua_insert(L, -2); + lua_setfenv(L, -2); + return 0; + } + else if (lua_iscfunction(L, -2) || lua_setfenv(L, -2) == 0) + luaL_error(L, + LUA_QL("setfenv") " cannot change environment of given object"); + return 1; } @@ -189,21 +185,40 @@ static int luaB_rawset (lua_State *L) { static int luaB_gcinfo (lua_State *L) { - lua_pushnumber(L, (lua_Number)lua_getgccount(L)); - lua_pushnumber(L, (lua_Number)lua_getgcthreshold(L)); - return 2; + lua_pushinteger(L, lua_getgccount(L)); + return 1; } static int luaB_collectgarbage (lua_State *L) { - lua_setgcthreshold(L, luaL_optint(L, 1, 0)); - return 0; + static const char *const opts[] = {"stop", "restart", "collect", + "count", "step", "setpause", "setstepmul", NULL}; + static const int optsnum[] = {LUA_GCSTOP, LUA_GCRESTART, LUA_GCCOLLECT, + LUA_GCCOUNT, LUA_GCSTEP, LUA_GCSETPAUSE, LUA_GCSETSTEPMUL}; + int o = luaL_checkoption(L, 1, "collect", opts); + int ex = luaL_optint(L, 2, 0); + int res = lua_gc(L, optsnum[o], ex); + switch (optsnum[o]) { + case LUA_GCCOUNT: { + int b = lua_gc(L, LUA_GCCOUNTB, 0); + lua_pushnumber(L, res + ((lua_Number)b/1024)); + return 1; + } + case LUA_GCSTEP: { + lua_pushboolean(L, res); + return 1; + } + default: { + lua_pushnumber(L, res); + return 1; + } + } } static int luaB_type (lua_State *L) { luaL_checkany(L, 1); - lua_pushstring(L, lua_typename(L, lua_type(L, 1))); + lua_pushstring(L, luaL_typename(L, 1)); return 1; } @@ -222,30 +237,29 @@ static int luaB_next (lua_State *L) { static int luaB_pairs (lua_State *L) { luaL_checktype(L, 1, LUA_TTABLE); - lua_pushliteral(L, "next"); - lua_rawget(L, LUA_GLOBALSINDEX); /* return generator, */ + lua_pushvalue(L, lua_upvalueindex(1)); /* return generator, */ lua_pushvalue(L, 1); /* state, */ lua_pushnil(L); /* and initial value */ return 3; } +static int ipairsaux (lua_State *L) { + int i = luaL_checkint(L, 2); + luaL_checktype(L, 1, LUA_TTABLE); + i++; /* next value */ + lua_pushinteger(L, i); + lua_rawgeti(L, 1, i); + return (lua_isnil(L, -1)) ? 0 : 2; +} + + static int luaB_ipairs (lua_State *L) { - lua_Number i = lua_tonumber(L, 2); luaL_checktype(L, 1, LUA_TTABLE); - if (i == 0 && lua_isnone(L, 2)) { /* `for' start? */ - lua_pushliteral(L, "ipairs"); - lua_rawget(L, LUA_GLOBALSINDEX); /* return generator, */ - lua_pushvalue(L, 1); /* state, */ - lua_pushnumber(L, 0); /* and initial value */ - return 3; - } - else { /* `for' step */ - i++; /* next value */ - lua_pushnumber(L, i); - lua_rawgeti(L, 1, (int)i); - return (lua_isnil(L, -1)) ? 0 : 2; - } + lua_pushvalue(L, lua_upvalueindex(1)); /* return generator, */ + lua_pushvalue(L, 1); /* state, */ + lua_pushinteger(L, 0); /* and initial value */ + return 3; } @@ -274,11 +288,44 @@ static int luaB_loadfile (lua_State *L) { } +/* +** 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) { + (void)ud; /* to avoid warnings */ + luaL_checkstack(L, 2, "too many nested functions"); + lua_pushvalue(L, 1); /* get function */ + lua_call(L, 0, 1); /* call it */ + if (lua_isnil(L, -1)) { + *size = 0; + return NULL; + } + else if (lua_isstring(L, -1)) { + lua_replace(L, 3); /* save string in a reserved stack slot */ + return lua_tolstring(L, 3, size); + } + else luaL_error(L, "reader function must return a string"); + return NULL; /* to avoid warnings */ +} + + +static int luaB_load (lua_State *L) { + int status; + const char *cname = luaL_optstring(L, 2, "=(load)"); + luaL_checktype(L, 1, LUA_TFUNCTION); + lua_settop(L, 3); /* function, eventual name, plus one reserved slot */ + status = lua_load(L, generic_reader, NULL, cname); + return load_aux(L, status); +} + + static int luaB_dofile (lua_State *L) { const char *fname = luaL_optstring(L, 1, NULL); int n = lua_gettop(L); - int status = luaL_loadfile(L, fname); - if (status != 0) lua_error(L); + if (luaL_loadfile(L, fname) != 0) lua_error(L); lua_call(L, 0, LUA_MULTRET); return lua_gettop(L) - n; } @@ -288,22 +335,40 @@ static int luaB_assert (lua_State *L) { luaL_checkany(L, 1); if (!lua_toboolean(L, 1)) return luaL_error(L, "%s", luaL_optstring(L, 2, "assertion failed!")); - lua_settop(L, 1); - return 1; + return lua_gettop(L); } static int luaB_unpack (lua_State *L) { - int n, i; + int i, e, n; luaL_checktype(L, 1, LUA_TTABLE); - n = luaL_getn(L, 1); + i = luaL_optint(L, 2, 1); + e = luaL_opt(L, luaL_checkint, 3, luaL_getn(L, 1)); + n = e - i + 1; /* number of elements */ + if (n <= 0) return 0; /* empty range */ luaL_checkstack(L, n, "table too big to unpack"); - for (i=1; i<=n; i++) /* push arg[1...n] */ + for (; i<=e; i++) /* push arg[i...e] */ lua_rawgeti(L, 1, i); return n; } +static int luaB_select (lua_State *L) { + int n = lua_gettop(L); + if (lua_type(L, 1) == LUA_TSTRING && *lua_tostring(L, 1) == '#') { + lua_pushinteger(L, n-1); + return 1; + } + else { + int i = luaL_checkint(L, 1); + if (i < 0) i = n + i; + else if (i > n) i = n; + luaL_argcheck(L, 1 <= i, 1, "index out of range"); + return n - i; + } +} + + static int luaB_pcall (lua_State *L) { int status; luaL_checkany(L, 1); @@ -327,38 +392,26 @@ static int luaB_xpcall (lua_State *L) { static int luaB_tostring (lua_State *L) { - char buff[128]; luaL_checkany(L, 1); if (luaL_callmeta(L, 1, "__tostring")) /* is there a metafield? */ return 1; /* use its value */ switch (lua_type(L, 1)) { case LUA_TNUMBER: lua_pushstring(L, lua_tostring(L, 1)); - return 1; + break; case LUA_TSTRING: lua_pushvalue(L, 1); - return 1; + break; case LUA_TBOOLEAN: lua_pushstring(L, (lua_toboolean(L, 1) ? "true" : "false")); - return 1; - case LUA_TTABLE: - sprintf(buff, "table: %p", lua_topointer(L, 1)); - break; - case LUA_TFUNCTION: - sprintf(buff, "function: %p", lua_topointer(L, 1)); - break; - case LUA_TUSERDATA: - case LUA_TLIGHTUSERDATA: - sprintf(buff, "userdata: %p", lua_touserdata(L, 1)); - break; - case LUA_TTHREAD: - sprintf(buff, "thread: %p", (void *)lua_tothread(L, 1)); break; case LUA_TNIL: lua_pushliteral(L, "nil"); - return 1; + break; + default: + lua_pushfstring(L, "%s: %p", luaL_typename(L, 1), lua_topointer(L, 1)); + break; } - lua_pushstring(L, buff); return 1; } @@ -389,150 +442,31 @@ static int luaB_newproxy (lua_State *L) { } -/* -** {====================================================== -** `require' function -** ======================================================= -*/ - - -/* name of global that holds table with loaded packages */ -#define REQTAB "_LOADED" - -/* name of global that holds the search path for packages */ -#define LUA_PATH "LUA_PATH" - -#ifndef LUA_PATH_SEP -#define LUA_PATH_SEP ';' -#endif - -#ifndef LUA_PATH_MARK -#define LUA_PATH_MARK '?' -#endif - -#ifndef LUA_PATH_DEFAULT -#define LUA_PATH_DEFAULT "?;?.lua" -#endif - - -static const char *getpath (lua_State *L) { - const char *path; - lua_getglobal(L, LUA_PATH); /* try global variable */ - path = lua_tostring(L, -1); - lua_pop(L, 1); - if (path) return path; - path = getenv(LUA_PATH); /* else try environment variable */ - if (path) return path; - return LUA_PATH_DEFAULT; /* else use default */ -} - - -static const char *pushnextpath (lua_State *L, const char *path) { - const char *l; - if (*path == '\0') return NULL; /* no more paths */ - if (*path == LUA_PATH_SEP) path++; /* skip separator */ - l = strchr(path, LUA_PATH_SEP); /* find next separator */ - if (l == NULL) l = path+strlen(path); - lua_pushlstring(L, path, l - path); /* directory name */ - return l; -} - - -static void pushcomposename (lua_State *L) { - const char *path = lua_tostring(L, -1); - const char *wild; - int n = 1; - while ((wild = strchr(path, LUA_PATH_MARK)) != NULL) { - /* is there stack space for prefix, name, and eventual last sufix? */ - luaL_checkstack(L, 3, "too many marks in a path component"); - lua_pushlstring(L, path, wild - path); /* push prefix */ - lua_pushvalue(L, 1); /* push package name (in place of MARK) */ - path = wild + 1; /* continue after MARK */ - n += 2; - } - lua_pushstring(L, path); /* push last sufix (`n' already includes this) */ - lua_concat(L, n); -} - - -static int luaB_require (lua_State *L) { - const char *path; - int status = LUA_ERRFILE; /* not found (yet) */ - luaL_checkstring(L, 1); - lua_settop(L, 1); - lua_getglobal(L, REQTAB); - if (!lua_istable(L, 2)) return luaL_error(L, "`" REQTAB "' is not a table"); - path = getpath(L); - lua_pushvalue(L, 1); /* check package's name in book-keeping table */ - lua_rawget(L, 2); - if (lua_toboolean(L, -1)) /* is it there? */ - return 1; /* package is already loaded; return its result */ - else { /* must load it */ - while (status == LUA_ERRFILE) { - lua_settop(L, 3); /* reset stack position */ - if ((path = pushnextpath(L, path)) == NULL) break; - pushcomposename(L); - status = luaL_loadfile(L, lua_tostring(L, -1)); /* try to load it */ - } - } - switch (status) { - case 0: { - lua_getglobal(L, "_REQUIREDNAME"); /* save previous name */ - lua_insert(L, -2); /* put it below function */ - lua_pushvalue(L, 1); - lua_setglobal(L, "_REQUIREDNAME"); /* set new name */ - lua_call(L, 0, 1); /* run loaded module */ - lua_insert(L, -2); /* put result below previous name */ - lua_setglobal(L, "_REQUIREDNAME"); /* reset to previous name */ - if (lua_isnil(L, -1)) { /* no/nil return? */ - lua_pushboolean(L, 1); - lua_replace(L, -2); /* replace to true */ - } - lua_pushvalue(L, 1); - lua_pushvalue(L, -2); - lua_rawset(L, 2); /* mark it as loaded */ - return 1; /* return value */ - } - case LUA_ERRFILE: { /* file not found */ - return luaL_error(L, "could not load package `%s' from path `%s'", - lua_tostring(L, 1), getpath(L)); - } - default: { - return luaL_error(L, "error loading package `%s' (%s)", - lua_tostring(L, 1), lua_tostring(L, -1)); - } - } -} - -/* }====================================================== */ - - -static const luaL_reg base_funcs[] = { +static const luaL_Reg base_funcs[] = { + {"assert", luaB_assert}, + {"collectgarbage", luaB_collectgarbage}, + {"dofile", luaB_dofile}, {"error", luaB_error}, - {"getmetatable", luaB_getmetatable}, - {"setmetatable", luaB_setmetatable}, + {"gcinfo", luaB_gcinfo}, {"getfenv", luaB_getfenv}, - {"setfenv", luaB_setfenv}, + {"getmetatable", luaB_getmetatable}, + {"loadfile", luaB_loadfile}, + {"load", luaB_load}, + {"loadstring", luaB_loadstring}, {"next", luaB_next}, - {"ipairs", luaB_ipairs}, - {"pairs", luaB_pairs}, + {"pcall", luaB_pcall}, // {"print", luaB_print}, + {"rawequal", luaB_rawequal}, + {"rawget", luaB_rawget}, + {"rawset", luaB_rawset}, + {"select", luaB_select}, + {"setfenv", luaB_setfenv}, + {"setmetatable", luaB_setmetatable}, {"tonumber", luaB_tonumber}, {"tostring", luaB_tostring}, {"type", luaB_type}, - {"assert", luaB_assert}, {"unpack", luaB_unpack}, - {"rawequal", luaB_rawequal}, - {"rawget", luaB_rawget}, - {"rawset", luaB_rawset}, - {"pcall", luaB_pcall}, {"xpcall", luaB_xpcall}, - {"collectgarbage", luaB_collectgarbage}, - {"gcinfo", luaB_gcinfo}, - {"loadfile", luaB_loadfile}, - {"dofile", luaB_dofile}, - {"loadstring", luaB_loadstring}, - {"require", luaB_require}, {NULL, NULL} }; @@ -547,9 +481,13 @@ static int auxresume (lua_State *L, lua_State *co, int narg) { int status; if (!lua_checkstack(co, narg)) luaL_error(L, "too many arguments to resume"); + if (lua_status(co) == 0 && lua_gettop(co) == 0) { + lua_pushliteral(L, "cannot resume dead coroutine"); + return -1; /* error flag */ + } lua_xmove(L, co, narg); status = lua_resume(co, narg); - if (status == 0) { + if (status == 0 || status == LUA_YIELD) { int nres = lua_gettop(co); if (!lua_checkstack(L, nres)) luaL_error(L, "too many results to resume"); @@ -623,55 +561,83 @@ static int luaB_costatus (lua_State *L) { luaL_argcheck(L, co, 1, "coroutine expected"); if (L == co) lua_pushliteral(L, "running"); else { - lua_Debug ar; - if (lua_getstack(co, 0, &ar) == 0 && lua_gettop(co) == 0) - lua_pushliteral(L, "dead"); - else - lua_pushliteral(L, "suspended"); + switch (lua_status(co)) { + case LUA_YIELD: + lua_pushliteral(L, "suspended"); + break; + case 0: { + lua_Debug ar; + if (lua_getstack(co, 0, &ar) > 0) /* does it have frames? */ + lua_pushliteral(L, "normal"); /* it is running */ + else if (lua_gettop(co) == 0) + lua_pushliteral(L, "dead"); + else + lua_pushliteral(L, "suspended"); /* initial state */ + break; + } + default: /* some error occured */ + lua_pushliteral(L, "dead"); + break; + } } return 1; } -static const luaL_reg co_funcs[] = { +static int luaB_corunning (lua_State *L) { + if (lua_pushthread(L)) + return 0; /* main thread is not a coroutine */ + else + return 1; +} + + +static const luaL_Reg co_funcs[] = { {"create", luaB_cocreate}, - {"wrap", luaB_cowrap}, {"resume", luaB_coresume}, - {"yield", luaB_yield}, + {"running", luaB_corunning}, {"status", luaB_costatus}, + {"wrap", luaB_cowrap}, + {"yield", luaB_yield}, {NULL, NULL} }; /* }====================================================== */ +static void auxopen (lua_State *L, const char *name, + lua_CFunction f, lua_CFunction u) { + lua_pushcfunction(L, u); + lua_pushcclosure(L, f, 1); + lua_setfield(L, -2, name); +} + static void base_open (lua_State *L) { - lua_pushliteral(L, "_G"); + /* set global _G */ lua_pushvalue(L, LUA_GLOBALSINDEX); - luaL_openlib(L, NULL, base_funcs, 0); /* open lib into global table */ - lua_pushliteral(L, "_VERSION"); + lua_setglobal(L, "_G"); + /* open lib into global table */ + luaL_register(L, "_G", base_funcs); lua_pushliteral(L, LUA_VERSION); - lua_rawset(L, -3); /* set global _VERSION */ + lua_setglobal(L, "_VERSION"); /* set global _VERSION */ + /* `ipairs' and `pairs' need auxliliary functions as upvalues */ + auxopen(L, "ipairs", luaB_ipairs, ipairsaux); + auxopen(L, "pairs", luaB_pairs, luaB_next); /* `newproxy' needs a weaktable as upvalue */ - lua_pushliteral(L, "newproxy"); - lua_newtable(L); /* new table `w' */ + lua_createtable(L, 0, 1); /* new table `w' */ lua_pushvalue(L, -1); /* `w' will be its own metatable */ lua_setmetatable(L, -2); - lua_pushliteral(L, "__mode"); - lua_pushliteral(L, "k"); - lua_rawset(L, -3); /* metatable(w).__mode = "k" */ + lua_pushliteral(L, "kv"); + lua_setfield(L, -2, "__mode"); /* metatable(w).__mode = "kv" */ lua_pushcclosure(L, luaB_newproxy, 1); - lua_rawset(L, -3); /* set global `newproxy' */ - lua_rawset(L, -1); /* set global _G */ + lua_setglobal(L, "newproxy"); /* set global `newproxy' */ } LUALIB_API int luaopen_base (lua_State *L) { base_open(L); - luaL_openlib(L, LUA_COLIBNAME, co_funcs, 0); - lua_newtable(L); - lua_setglobal(L, REQTAB); - return 0; + luaL_register(L, LUA_COLIBNAME, co_funcs); + return 2; } diff --git a/lib/lua/src/LuaLib/ldblib.c b/lib/lua/src/LuaLib/ldblib.c index 2449b90..076ddac 100644 --- a/lib/lua/src/LuaLib/ldblib.c +++ b/lib/lua/src/LuaLib/ldblib.c @@ -1,5 +1,5 @@ /* -** $Id: ldblib.c,v 1.4 2004-11-27 21:46:10 pixel Exp $ +** $Id: ldblib.c,v 1.5 2007-07-27 10:05:55 pixel Exp $ ** Interface from Lua to its debug API ** See Copyright Notice in lua.h */ @@ -10,6 +10,7 @@ #include <string.h> #define ldblib_c +#define LUA_LIB #include "lua.h" @@ -18,75 +19,137 @@ +static int db_getregistry (lua_State *L) { + lua_pushvalue(L, LUA_REGISTRYINDEX); + return 1; +} + + +static int db_getmetatable (lua_State *L) { + luaL_checkany(L, 1); + if (!lua_getmetatable(L, 1)) { + lua_pushnil(L); /* no metatable */ + } + return 1; +} + + +static int db_setmetatable (lua_State *L) { + int t = lua_type(L, 2); + luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2, + "nil or table expected"); + lua_settop(L, 2); + lua_pushboolean(L, lua_setmetatable(L, 1)); + return 1; +} + + +static int db_getfenv (lua_State *L) { + lua_getfenv(L, 1); + return 1; +} + + +static int db_setfenv (lua_State *L) { + luaL_checktype(L, 2, LUA_TTABLE); + lua_settop(L, 2); + if (lua_setfenv(L, 1) == 0) + luaL_error(L, LUA_QL("setfenv") + " cannot change environment of given object"); + return 1; +} + + static void settabss (lua_State *L, const char *i, const char *v) { - lua_pushstring(L, i); lua_pushstring(L, v); - lua_rawset(L, -3); + lua_setfield(L, -2, i); } static void settabsi (lua_State *L, const char *i, int v) { - lua_pushstring(L, i); - lua_pushnumber(L, (lua_Number)v); - lua_rawset(L, -3); + lua_pushinteger(L, v); + lua_setfield(L, -2, i); } -static int getinfo (lua_State *L) { +static lua_State *getthread (lua_State *L, int *arg) { + if (lua_isthread(L, 1)) { + *arg = 1; + return lua_tothread(L, 1); + } + else { + *arg = 0; + return L; + } +} + + +static void treatstackoption (lua_State *L, lua_State *L1, const char *fname) { + if (L == L1) { + lua_pushvalue(L, -2); + lua_remove(L, -3); + } + else + lua_xmove(L1, L, 1); + lua_setfield(L, -2, fname); +} + + +static int db_getinfo (lua_State *L) { lua_Debug ar; - const char *options = luaL_optstring(L, 2, "flnSu"); - if (lua_isnumber(L, 1)) { - if (!lua_getstack(L, (int)(lua_tonumber(L, 1)), &ar)) { + int arg; + lua_State *L1 = getthread(L, &arg); + const char *options = luaL_optstring(L, arg+2, "flnSu"); + if (lua_isnumber(L, arg+1)) { + if (!lua_getstack(L1, (int)lua_tointeger(L, arg+1), &ar)) { lua_pushnil(L); /* level out of range */ return 1; } } - else if (lua_isfunction(L, 1)) { + else if (lua_isfunction(L, arg+1)) { lua_pushfstring(L, ">%s", options); options = lua_tostring(L, -1); - lua_pushvalue(L, 1); + lua_pushvalue(L, arg+1); + lua_xmove(L, L1, 1); } else - return luaL_argerror(L, 1, "function or level expected"); - if (!lua_getinfo(L, options, &ar)) - return luaL_argerror(L, 2, "invalid option"); - lua_newtable(L); - for (; *options; options++) { - switch (*options) { - case 'S': - settabss(L, "source", ar.source); - settabss(L, "short_src", ar.short_src); - settabsi(L, "linedefined", ar.linedefined); - settabss(L, "what", ar.what); - break; - case 'l': - settabsi(L, "currentline", ar.currentline); - break; - case 'u': - settabsi(L, "nups", ar.nups); - break; - case 'n': - settabss(L, "name", ar.name); - settabss(L, "namewhat", ar.namewhat); - break; - case 'f': - lua_pushliteral(L, "func"); - lua_pushvalue(L, -3); - lua_rawset(L, -3); - break; - } + return luaL_argerror(L, arg+1, "function or level expected"); + if (!lua_getinfo(L1, options, &ar)) + return luaL_argerror(L, arg+2, "invalid option"); + lua_createtable(L, 0, 2); + if (strchr(options, 'S')) { + settabss(L, "source", ar.source); + settabss(L, "short_src", ar.short_src); + settabsi(L, "linedefined", ar.linedefined); + settabsi(L, "lastlinedefined", ar.lastlinedefined); + settabss(L, "what", ar.what); + } + if (strchr(options, 'l')) + settabsi(L, "currentline", ar.currentline); + if (strchr(options, 'u')) + settabsi(L, "nups", ar.nups); + if (strchr(options, 'n')) { + settabss(L, "name", ar.name); + settabss(L, "namewhat", ar.namewhat); } + if (strchr(options, 'L')) + treatstackoption(L, L1, "activelines"); + if (strchr(options, 'f')) + treatstackoption(L, L1, "func"); return 1; /* return table */ } -static int getlocal (lua_State *L) { +static int db_getlocal (lua_State *L) { + int arg; + lua_State *L1 = getthread(L, &arg); lua_Debug ar; const char *name; - if (!lua_getstack(L, luaL_checkint(L, 1), &ar)) /* level out of range? */ - return luaL_argerror(L, 1, "level out of range"); - name = lua_getlocal(L, &ar, luaL_checkint(L, 2)); + if (!lua_getstack(L1, luaL_checkint(L, arg+1), &ar)) /* out of range? */ + return luaL_argerror(L, arg+1, "level out of range"); + name = lua_getlocal(L1, &ar, luaL_checkint(L, arg+2)); if (name) { + lua_xmove(L1, L, 1); lua_pushstring(L, name); lua_pushvalue(L, -2); return 2; @@ -98,12 +161,16 @@ static int getlocal (lua_State *L) { } -static int setlocal (lua_State *L) { +static int db_setlocal (lua_State *L) { + int arg; + lua_State *L1 = getthread(L, &arg); lua_Debug ar; - if (!lua_getstack(L, luaL_checkint(L, 1), &ar)) /* level out of range? */ - return luaL_argerror(L, 1, "level out of range"); - luaL_checkany(L, 3); - lua_pushstring(L, lua_setlocal(L, &ar, luaL_checkint(L, 2))); + if (!lua_getstack(L1, luaL_checkint(L, arg+1), &ar)) /* out of range? */ + return luaL_argerror(L, arg+1, "level out of range"); + luaL_checkany(L, arg+3); + lua_settop(L, arg+3); + lua_xmove(L, L1, 1); + lua_pushstring(L, lua_setlocal(L1, &ar, luaL_checkint(L, arg+2))); return 1; } @@ -121,12 +188,12 @@ static int auxupvalue (lua_State *L, int get) { } -static int getupvalue (lua_State *L) { +static int db_getupvalue (lua_State *L) { return auxupvalue(L, 1); } -static int setupvalue (lua_State *L) { +static int db_setupvalue (lua_State *L) { luaL_checkany(L, 3); return auxupvalue(L, 0); } @@ -141,16 +208,16 @@ static void hookf (lua_State *L, lua_Debug *ar) { {"call", "return", "line", "count", "tail return"}; lua_pushlightuserdata(L, (void *)&KEY_HOOK); lua_rawget(L, LUA_REGISTRYINDEX); + lua_pushlightuserdata(L, L); + lua_rawget(L, -2); if (lua_isfunction(L, -1)) { lua_pushstring(L, hooknames[(int)ar->event]); if (ar->currentline >= 0) - lua_pushnumber(L, (lua_Number)ar->currentline); + lua_pushinteger(L, ar->currentline); else lua_pushnil(L); lua_assert(lua_getinfo(L, "lS", ar)); lua_call(L, 2, 0); } - else - lua_pop(L, 1); /* pop result from gettable */ } @@ -174,48 +241,75 @@ static char *unmakemask (int mask, char *smask) { } -static int sethook (lua_State *L) { - if (lua_isnoneornil(L, 1)) { - lua_settop(L, 1); - lua_sethook(L, NULL, 0, 0); /* turn off hooks */ +static void gethooktable (lua_State *L) { + lua_pushlightuserdata(L, (void *)&KEY_HOOK); + lua_rawget(L, LUA_REGISTRYINDEX); + if (!lua_istable(L, -1)) { + lua_pop(L, 1); + lua_createtable(L, 0, 1); + lua_pushlightuserdata(L, (void *)&KEY_HOOK); + lua_pushvalue(L, -2); + lua_rawset(L, LUA_REGISTRYINDEX); + } +} + + +static int db_sethook (lua_State *L) { + int arg; + lua_State *L1 = getthread(L, &arg); + if (lua_isnoneornil(L, arg+1)) { + lua_settop(L, arg+1); + lua_sethook(L1, NULL, 0, 0); /* turn off hooks */ } else { - const char *smask = luaL_checkstring(L, 2); - int count = luaL_optint(L, 3, 0); - luaL_checktype(L, 1, LUA_TFUNCTION); - lua_sethook(L, hookf, makemask(smask, count), count); + const char *smask = luaL_checkstring(L, arg+2); + int count = luaL_optint(L, arg+3, 0); + luaL_checktype(L, arg+1, LUA_TFUNCTION); + lua_sethook(L1, hookf, makemask(smask, count), count); } - lua_pushlightuserdata(L, (void *)&KEY_HOOK); - lua_pushvalue(L, 1); - lua_rawset(L, LUA_REGISTRYINDEX); /* set new hook */ + gethooktable(L1); + lua_pushlightuserdata(L1, L1); + lua_pushvalue(L, arg+1); + lua_xmove(L, L1, 1); + lua_rawset(L1, -3); /* set new hook */ + lua_pop(L1, 1); /* remove hook table */ return 0; } -static int gethook (lua_State *L) { +static int db_gethook (lua_State *L) { + int arg; + lua_State *L1 = getthread(L, &arg); char buff[5]; - int mask = lua_gethookmask(L); - lua_Hook hook = lua_gethook(L); + int mask = lua_gethookmask(L1); + lua_Hook hook = lua_gethook(L1); if (hook != NULL && hook != hookf) /* external hook? */ lua_pushliteral(L, "external hook"); else { - lua_pushlightuserdata(L, (void *)&KEY_HOOK); - lua_rawget(L, LUA_REGISTRYINDEX); /* get hook */ + gethooktable(L1); + lua_pushlightuserdata(L1, L1); + lua_rawget(L1, -2); /* get hook */ + lua_remove(L1, -2); /* remove hook table */ + lua_xmove(L1, L, 1); } lua_pushstring(L, unmakemask(mask, buff)); - lua_pushnumber(L, (lua_Number)lua_gethookcount(L)); + lua_pushinteger(L, lua_gethookcount(L1)); return 3; } -static int debug (lua_State *L) { +static int db_debug (lua_State *L) { for (;;) { char buffer[250]; fputs("lua_debug> ", stderr); if (fgets(buffer, sizeof(buffer), stdin) == 0 || strcmp(buffer, "cont\n") == 0) return 0; - lua_dostring(L, buffer); + if (luaL_loadbuffer(L, buffer, strlen(buffer), "=(debug command)") || + lua_pcall(L, 0, 0, 0)) { + fputs(lua_tostring(L, -1), stderr); + fputs("\n", stderr); + } lua_settop(L, 0); /* remove eventual returns */ } } @@ -224,76 +318,80 @@ static int debug (lua_State *L) { #define LEVELS1 12 /* size of the first part of the stack */ #define LEVELS2 10 /* size of the second part of the stack */ -static int errorfb (lua_State *L) { - int level = 1; /* skip level 0 (it's this function) */ +static int db_errorfb (lua_State *L) { + int level; int firstpart = 1; /* still before eventual `...' */ + int arg; + lua_State *L1 = getthread(L, &arg); lua_Debug ar; - if (lua_gettop(L) == 0) + if (lua_isnumber(L, arg+2)) { + level = (int)lua_tointeger(L, arg+2); + lua_pop(L, 1); + } + else + level = (L == L1) ? 1 : 0; /* level 0 may be this own function */ + if (lua_gettop(L) == arg) lua_pushliteral(L, ""); - else if (!lua_isstring(L, 1)) return 1; /* no string message */ + else if (!lua_isstring(L, arg+1)) return 1; /* message is not a string */ else lua_pushliteral(L, "\n"); lua_pushliteral(L, "stack traceback:"); - while (lua_getstack(L, level++, &ar)) { + while (lua_getstack(L1, level++, &ar)) { if (level > LEVELS1 && firstpart) { /* no more than `LEVELS2' more levels? */ - if (!lua_getstack(L, level+LEVELS2, &ar)) + if (!lua_getstack(L1, level+LEVELS2, &ar)) level--; /* keep going */ else { lua_pushliteral(L, "\n\t..."); /* too many levels */ - while (lua_getstack(L, level+LEVELS2, &ar)) /* find last levels */ + while (lua_getstack(L1, level+LEVELS2, &ar)) /* find last levels */ level++; } firstpart = 0; continue; } lua_pushliteral(L, "\n\t"); - lua_getinfo(L, "Snl", &ar); + lua_getinfo(L1, "Snl", &ar); lua_pushfstring(L, "%s:", ar.short_src); if (ar.currentline > 0) lua_pushfstring(L, "%d:", ar.currentline); - switch (*ar.namewhat) { - case 'g': /* global */ - case 'l': /* local */ - case 'f': /* field */ - case 'm': /* method */ - lua_pushfstring(L, " in function `%s'", ar.name); - break; - default: { - if (*ar.what == 'm') /* main? */ - lua_pushfstring(L, " in main chunk"); - else if (*ar.what == 'C' || *ar.what == 't') - lua_pushliteral(L, " ?"); /* C function or tail call */ - else - lua_pushfstring(L, " in function <%s:%d>", - ar.short_src, ar.linedefined); - } + if (*ar.namewhat != '\0') /* is there a name? */ + lua_pushfstring(L, " in function " LUA_QS, ar.name); + else { + if (*ar.what == 'm') /* main? */ + lua_pushfstring(L, " in main chunk"); + else if (*ar.what == 'C' || *ar.what == 't') + lua_pushliteral(L, " ?"); /* C function or tail call */ + else + lua_pushfstring(L, " in function <%s:%d>", + ar.short_src, ar.linedefined); } - lua_concat(L, lua_gettop(L)); + lua_concat(L, lua_gettop(L) - arg); } - lua_concat(L, lua_gettop(L)); + lua_concat(L, lua_gettop(L) - arg); return 1; } -static const luaL_reg dblib[] = { - {"getlocal", getlocal}, - {"getinfo", getinfo}, - {"gethook", gethook}, - {"getupvalue", getupvalue}, - {"sethook", sethook}, - {"setlocal", setlocal}, - {"setupvalue", setupvalue}, - {"debug", debug}, - {"traceback", errorfb}, +static const luaL_Reg dblib[] = { + {"debug", db_debug}, + {"getfenv", db_getfenv}, + {"gethook", db_gethook}, + {"getinfo", db_getinfo}, + {"getlocal", db_getlocal}, + {"getregistry", db_getregistry}, + {"getmetatable", db_getmetatable}, + {"getupvalue", db_getupvalue}, + {"setfenv", db_setfenv}, + {"sethook", db_sethook}, + {"setlocal", db_setlocal}, + {"setmetatable", db_setmetatable}, + {"setupvalue", db_setupvalue}, + {"traceback", db_errorfb}, {NULL, NULL} }; LUALIB_API int luaopen_debug (lua_State *L) { - luaL_openlib(L, LUA_DBLIBNAME, dblib, 0); - lua_pushliteral(L, "_TRACEBACK"); - lua_pushcfunction(L, errorfb); - lua_settable(L, LUA_GLOBALSINDEX); + luaL_register(L, LUA_DBLIBNAME, dblib); return 1; } diff --git a/lib/lua/src/LuaLib/liolib.c b/lib/lua/src/LuaLib/liolib.c index bd3b2ed..f9866c3 100644 --- a/lib/lua/src/LuaLib/liolib.c +++ b/lib/lua/src/LuaLib/liolib.c @@ -1,18 +1,17 @@ /* -** $Id: liolib.c,v 1.6 2007-07-25 16:54:33 pixel Exp $ +** $Id: liolib.c,v 1.7 2007-07-27 10:05:55 pixel Exp $ ** Standard I/O (and system) library ** See Copyright Notice in lua.h */ #include <errno.h> -#include <locale.h> #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <time.h> #define liolib_c +#define LUA_LIB #include "lua.h" @@ -20,62 +19,16 @@ #include "lualib.h" -typedef struct FileHandle { - FILE *f; - int ispipe; -} FileHandle; - - - -/* -** by default, gcc does not get `tmpname' -*/ -#ifndef USE_TMPNAME -#ifdef __GNUC__ -#define USE_TMPNAME 0 -#else -#define USE_TMPNAME 1 -#endif -#endif - - -/* -** by default, posix systems get `popen' -*/ -#ifndef USE_POPEN -#ifdef _POSIX_C_SOURCE -#if _POSIX_C_SOURCE >= 2 -#define USE_POPEN 1 -#endif -#endif -#endif - -#ifndef USE_POPEN -#define USE_POPEN 0 -#endif - - - - -/* -** {====================================================== -** FILE Operations -** ======================================================= -*/ - -#if !USE_POPEN -#define pclose(f) (-1) -#endif +#define IO_INPUT 1 +#define IO_OUTPUT 2 -#define FILEHANDLE "FILE*" - -#define IO_INPUT "_input" -#define IO_OUTPUT "_output" +static const char *const fnames[] = {"input", "output"}; static int pushresult (lua_State *L, int i, const char *filename) { + int en = errno; /* calls to Lua API may change this value */ if (i) { lua_pushboolean(L, 1); return 1; @@ -83,26 +36,32 @@ static int pushresult (lua_State *L, int i, const char *filename) { else { lua_pushnil(L); if (filename) - lua_pushfstring(L, "%s: %s", filename, strerror(errno)); + lua_pushfstring(L, "%s: %s", filename, strerror(en)); else - lua_pushfstring(L, "%s", strerror(errno)); - lua_pushnumber(L, errno); + lua_pushfstring(L, "%s", strerror(en)); + lua_pushinteger(L, en); return 3; } } -static FileHandle *topfile (lua_State *L, int findex) { - FileHandle *fh = (FileHandle *)luaL_checkudata(L, findex, FILEHANDLE); - if (fh == NULL) luaL_argerror(L, findex, "bad file"); - return fh; +static void fileerror (lua_State *L, int arg, const char *filename) { + lua_pushfstring(L, "%s: %s", filename, strerror(errno)); + luaL_argerror(L, arg, lua_tostring(L, -1)); } +#define topfile(L) ((FILE **)luaL_checkudata(L, 1, LUA_FILEHANDLE)) + + static int io_type (lua_State *L) { - FileHandle *fh = (FileHandle *)luaL_checkudata(L, 1, FILEHANDLE); - if (fh == NULL) lua_pushnil(L); - else if (fh->f == NULL) + void *ud; + luaL_checkany(L, 1); + ud = lua_touserdata(L, 1); + lua_getfield(L, LUA_REGISTRYINDEX, LUA_FILEHANDLE); + if (ud == NULL || !lua_getmetatable(L, 1) || !lua_rawequal(L, -2, -1)) + lua_pushnil(L); /* not a file */ + else if (*((FILE **)ud) == NULL) lua_pushliteral(L, "closed file"); else lua_pushliteral(L, "file"); @@ -110,89 +69,79 @@ static int io_type (lua_State *L) { } -#define tofile(L,i) (tofileh(L,i)->f) - -static FileHandle *tofileh (lua_State *L, int findex) { - FileHandle *fh = topfile(L, findex); - if (fh->f == NULL) +static FILE *tofile (lua_State *L) { + FILE **f = topfile(L); + if (*f == NULL) luaL_error(L, "attempt to use a closed file"); - return fh; + return *f; } -#define newfile(L) (&(newfileh(L)->f)) - /* ** When creating file handles, always creates a `closed' file handle ** before opening the actual file; so, if there is a memory error, the ** file is not left opened. */ -static FileHandle *newfileh (lua_State *L) { - FileHandle *fh = (FileHandle *)lua_newuserdata(L, sizeof(FileHandle)); - fh->f = NULL; /* file handle is currently `closed' */ - fh->ispipe = 0; - luaL_getmetatable(L, FILEHANDLE); +static FILE **newfile (lua_State *L) { + FILE **pf = (FILE **)lua_newuserdata(L, sizeof(FILE *)); + *pf = NULL; /* file handle is currently `closed' */ + luaL_getmetatable(L, LUA_FILEHANDLE); lua_setmetatable(L, -2); - return fh; + return pf; } /* -** assumes that top of the stack is the `io' library, and next is -** the `io' metatable +** this function has a separated environment, which defines the +** correct __close for 'popen' files */ -static void registerfile (lua_State *L, FILE *f, const char *name, - const char *impname) { - lua_pushstring(L, name); - *newfile(L) = f; - if (impname) { - lua_pushstring(L, impname); - lua_pushvalue(L, -2); - lua_settable(L, -6); /* metatable[impname] = file */ - } - lua_settable(L, -3); /* io[name] = file */ +static int io_pclose (lua_State *L) { + FILE **p = topfile(L); + int ok = lua_pclose(L, *p); + *p = NULL; + return pushresult(L, ok, NULL); +} + + +static int io_fclose (lua_State *L) { + FILE **p = topfile(L); + int ok = (fclose(*p) == 0); + *p = NULL; + return pushresult(L, ok, NULL); } static int aux_close (lua_State *L) { - FileHandle *fh = tofileh(L, 1); - FILE *f = fh->f; - if (f == stdin || f == stdout || f == stderr) - return 0; /* file cannot be closed */ - else { - int ok = fh->ispipe ? (pclose(f) != -1) : (fclose(f) == 0); - fh->f = NULL; /* mark file as closed */ - return ok; - } + lua_getfenv(L, 1); + lua_getfield(L, -1, "__close"); + return (lua_tocfunction(L, -1))(L); } static int io_close (lua_State *L) { - if (lua_isnone(L, 1) && lua_type(L, lua_upvalueindex(1)) == LUA_TTABLE) { - lua_pushstring(L, IO_OUTPUT); - lua_rawget(L, lua_upvalueindex(1)); - } - return pushresult(L, aux_close(L), NULL); + if (lua_isnone(L, 1)) + lua_rawgeti(L, LUA_ENVIRONINDEX, IO_OUTPUT); + tofile(L); /* make sure argument is a file */ + return aux_close(L); } static int io_gc (lua_State *L) { - FileHandle *fh = topfile(L, 1); - if (fh->f != NULL) /* ignore closed files */ + FILE *f = *topfile(L); + /* ignore closed files and standard files */ + if (f != NULL && f != stdin && f != stdout && f != stderr) aux_close(L); return 0; } static int io_tostring (lua_State *L) { - char buff[128]; - FileHandle *fh = topfile(L, 1); - if (fh->f == NULL) - strcpy(buff, "closed"); + FILE *f = *topfile(L); + if (f == NULL) + lua_pushstring(L, "file (closed)"); else - sprintf(buff, "%p", lua_touserdata(L, 1)); - lua_pushfstring(L, "file (%s)", buff); + lua_pushfstring(L, "file (%p)", f); return 1; } @@ -207,17 +156,11 @@ static int io_open (lua_State *L) { static int io_popen (lua_State *L) { -#if !USE_POPEN - luaL_error(L, "`popen' not supported"); - return 0; -#else const char *filename = luaL_checkstring(L, 1); const char *mode = luaL_optstring(L, 2, "r"); - FileHandle *fh = newfileh(L); - fh->f = popen(filename, mode); - fh->ispipe = 1; - return (fh->f == NULL) ? pushresult(L, 0, filename) : 1; -#endif + FILE **pf = newfile(L); + *pf = lua_popen(L, filename, mode); + return (*pf == NULL) ? pushresult(L, 0, filename) : 1; } @@ -228,34 +171,33 @@ static int io_tmpfile (lua_State *L) { } -static FILE *getiofile (lua_State *L, const char *name) { - lua_pushstring(L, name); - lua_rawget(L, lua_upvalueindex(1)); - return tofile(L, -1); +static FILE *getiofile (lua_State *L, int findex) { + FILE *f; + lua_rawgeti(L, LUA_ENVIRONINDEX, findex); + f = *(FILE **)lua_touserdata(L, -1); + if (f == NULL) + luaL_error(L, "standard %s file is closed", fnames[findex - 1]); + return f; } -static int g_iofile (lua_State *L, const char *name, const char *mode) { +static int g_iofile (lua_State *L, int f, const char *mode) { if (!lua_isnoneornil(L, 1)) { const char *filename = lua_tostring(L, 1); - lua_pushstring(L, name); if (filename) { FILE **pf = newfile(L); *pf = fopen(filename, mode); - if (*pf == NULL) { - lua_pushfstring(L, "%s: %s", filename, strerror(errno)); - luaL_argerror(L, 1, lua_tostring(L, -1)); - } + if (*pf == NULL) + fileerror(L, 1, filename); } else { - tofile(L, 1); /* check that it's a valid file handle */ + tofile(L); /* check that it's a valid file handle */ lua_pushvalue(L, 1); } - lua_rawset(L, lua_upvalueindex(1)); + lua_rawseti(L, LUA_ENVIRONINDEX, f); } /* return current value */ - lua_pushstring(L, name); - lua_rawget(L, lua_upvalueindex(1)); + lua_rawgeti(L, LUA_ENVIRONINDEX, f); return 1; } @@ -273,17 +215,15 @@ static int io_output (lua_State *L) { static int io_readline (lua_State *L); -static void aux_lines (lua_State *L, int idx, int close) { - lua_pushliteral(L, FILEHANDLE); - lua_rawget(L, LUA_REGISTRYINDEX); +static void aux_lines (lua_State *L, int idx, int toclose) { lua_pushvalue(L, idx); - lua_pushboolean(L, close); /* close/not close file when finished */ - lua_pushcclosure(L, io_readline, 3); + lua_pushboolean(L, toclose); /* close/not close file when finished */ + lua_pushcclosure(L, io_readline, 2); } static int f_lines (lua_State *L) { - tofile(L, 1); /* check that it's a valid file handle */ + tofile(L); /* check that it's a valid file handle */ aux_lines(L, 1, 0); return 1; } @@ -291,15 +231,16 @@ static int f_lines (lua_State *L) { static int io_lines (lua_State *L) { if (lua_isnoneornil(L, 1)) { /* no arguments? */ - lua_pushstring(L, IO_INPUT); - lua_rawget(L, lua_upvalueindex(1)); /* will iterate over default input */ + /* will iterate over default input */ + lua_rawgeti(L, LUA_ENVIRONINDEX, IO_INPUT); return f_lines(L); } else { const char *filename = luaL_checkstring(L, 1); FILE **pf = newfile(L); *pf = fopen(filename, "r"); - luaL_argcheck(L, *pf, 1, strerror(errno)); + if (*pf == NULL) + fileerror(L, 1, filename); aux_lines(L, lua_gettop(L), 1); return 1; } @@ -342,7 +283,7 @@ static int read_line (lua_State *L, FILE *f) { return (lua_strlen(L, -1) > 0); /* check whether read something */ } l = strlen(p); - if (p[l-1] != '\n') + if (l == 0 || p[l-1] != '\n') luaL_addsize(&b, l); else { luaL_addsize(&b, l - 1); /* do not include `eol' */ @@ -375,6 +316,7 @@ static int g_read (lua_State *L, FILE *f, int first) { int nargs = lua_gettop(L) - 1; int success; int n; + clearerr(f); if (nargs == 0) { /* no arguments? */ success = read_line(L, f); n = first+1; /* to return 1 result */ @@ -384,7 +326,7 @@ static int g_read (lua_State *L, FILE *f, int first) { success = 1; for (n = first; nargs-- && success; n++) { if (lua_type(L, n) == LUA_TNUMBER) { - size_t l = (size_t)lua_tonumber(L, n); + size_t l = (size_t)lua_tointeger(L, n); success = (l == 0) ? test_eof(L, f) : read_chars(L, f, l); } else { @@ -401,14 +343,14 @@ static int g_read (lua_State *L, FILE *f, int first) { read_chars(L, f, ~((size_t)0)); /* read MAX_SIZE_T chars */ success = 1; /* always success */ break; - case 'w': /* word */ - return luaL_error(L, "obsolete option `*w' to `read'"); default: return luaL_argerror(L, n, "invalid format"); } } } } + if (ferror(f)) + return pushresult(L, 0, NULL); if (!success) { lua_pop(L, 1); /* remove last result */ lua_pushnil(L); /* push nil instead */ @@ -423,19 +365,23 @@ static int io_read (lua_State *L) { static int f_read (lua_State *L) { - return g_read(L, tofile(L, 1), 2); + return g_read(L, tofile(L), 2); } static int io_readline (lua_State *L) { - FILE *f = *(FILE **)lua_touserdata(L, lua_upvalueindex(2)); + FILE *f = *(FILE **)lua_touserdata(L, lua_upvalueindex(1)); + int sucess; if (f == NULL) /* file is already closed? */ luaL_error(L, "file is already closed"); - if (read_line(L, f)) return 1; + sucess = read_line(L, f); + if (ferror(f)) + return luaL_error(L, "%s", strerror(errno)); + if (sucess) return 1; else { /* EOF */ - if (lua_toboolean(L, lua_upvalueindex(3))) { /* generator created file? */ + if (lua_toboolean(L, lua_upvalueindex(2))) { /* generator created file? */ lua_settop(L, 0); - lua_pushvalue(L, lua_upvalueindex(2)); + lua_pushvalue(L, lua_upvalueindex(1)); aux_close(L); /* close it */ } return 0; @@ -470,44 +416,55 @@ static int io_write (lua_State *L) { static int f_write (lua_State *L) { - return g_write(L, tofile(L, 1), 2); + return g_write(L, tofile(L), 2); } static int f_seek (lua_State *L) { static const int mode[] = {SEEK_SET, SEEK_CUR, SEEK_END}; static const char *const modenames[] = {"set", "cur", "end", NULL}; - FILE *f = tofile(L, 1); - int op = luaL_findstring(luaL_optstring(L, 2, "cur"), modenames); + FILE *f = tofile(L); + int op = luaL_checkoption(L, 2, "cur", modenames); long offset = luaL_optlong(L, 3, 0); - luaL_argcheck(L, op != -1, 2, "invalid mode"); op = fseek(f, offset, mode[op]); if (op) return pushresult(L, 0, NULL); /* error */ else { - lua_pushnumber(L, ftell(f)); + lua_pushinteger(L, ftell(f)); return 1; } } +static int f_setvbuf (lua_State *L) { + static const int mode[] = {_IONBF, _IOFBF, _IOLBF}; + static const char *const modenames[] = {"no", "full", "line", NULL}; + FILE *f = tofile(L); + int op = luaL_checkoption(L, 2, NULL, modenames); + lua_Integer sz = luaL_optinteger(L, 3, LUAL_BUFFERSIZE); + int res = setvbuf(f, NULL, mode[op], sz); + return pushresult(L, res == 0, NULL); +} + + + static int io_flush (lua_State *L) { return pushresult(L, fflush(getiofile(L, IO_OUTPUT)) == 0, NULL); } static int f_flush (lua_State *L) { - return pushresult(L, fflush(tofile(L, 1)) == 0, NULL); + return pushresult(L, fflush(tofile(L)) == 0, NULL); } -static const luaL_reg iolib[] = { - {"input", io_input}, - {"output", io_output}, - {"lines", io_lines}, +static const luaL_Reg iolib[] = { {"close", io_close}, {"flush", io_flush}, + {"input", io_input}, + {"lines", io_lines}, {"open", io_open}, + {"output", io_output}, {"popen", io_popen}, {"read", io_read}, {"tmpfile", io_tmpfile}, @@ -517,13 +474,14 @@ static const luaL_reg iolib[] = { }; -static const luaL_reg flib[] = { +static const luaL_Reg flib[] = { + {"close", io_close}, {"flush", f_flush}, - {"read", f_read}, {"lines", f_lines}, + {"read", f_read}, {"seek", f_seek}, + {"setvbuf", f_setvbuf}, {"write", f_write}, - {"close", io_close}, {"__gc", io_gc}, {"__tostring", io_tostring}, {NULL, NULL} @@ -531,232 +489,44 @@ static const luaL_reg flib[] = { static void createmeta (lua_State *L) { - luaL_newmetatable(L, FILEHANDLE); /* create new metatable for file handles */ - /* file methods */ - lua_pushliteral(L, "__index"); - lua_pushvalue(L, -2); /* push metatable */ - lua_rawset(L, -3); /* metatable.__index = metatable */ - luaL_openlib(L, NULL, flib, 0); -} - -/* }====================================================== */ - - -/* -** {====================================================== -** Other O.S. Operations -** ======================================================= -*/ - -static int io_execute (lua_State *L) { - lua_pushnumber(L, system(luaL_checkstring(L, 1))); - return 1; -} - - -static int io_remove (lua_State *L) { - const char *filename = luaL_checkstring(L, 1); - return pushresult(L, remove(filename) == 0, filename); + luaL_newmetatable(L, LUA_FILEHANDLE); /* create metatable for file handles */ + lua_pushvalue(L, -1); /* push metatable */ + lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */ + luaL_register(L, NULL, flib); /* file methods */ } -static int io_rename (lua_State *L) { - const char *fromname = luaL_checkstring(L, 1); - const char *toname = luaL_checkstring(L, 2); - return pushresult(L, rename(fromname, toname) == 0, fromname); -} - - -static int io_tmpname (lua_State *L) { -#if !USE_TMPNAME - luaL_error(L, "`tmpname' not supported"); - return 0; -#else - char buff[L_tmpnam]; - if (tmpnam(buff) != buff) - return luaL_error(L, "unable to generate a unique filename in `tmpname'"); - lua_pushstring(L, buff); - return 1; -#endif -} - - -static int io_getenv (lua_State *L) { - lua_pushstring(L, getenv(luaL_checkstring(L, 1))); /* if NULL push nil */ - return 1; -} - - -static int io_clock (lua_State *L) { - lua_pushnumber(L, ((lua_Number)clock())/(lua_Number)CLOCKS_PER_SEC); - return 1; -} - - -/* -** {====================================================== -** Time/Date operations -** { year=%Y, month=%m, day=%d, hour=%H, min=%M, sec=%S, -** wday=%w+1, yday=%j, isdst=? } -** ======================================================= -*/ - -static void setfield (lua_State *L, const char *key, int value) { - lua_pushstring(L, key); - lua_pushnumber(L, value); - lua_rawset(L, -3); -} - -static void setboolfield (lua_State *L, const char *key, int value) { - lua_pushstring(L, key); - lua_pushboolean(L, value); - lua_rawset(L, -3); -} - -static int getboolfield (lua_State *L, const char *key) { - int res; - lua_pushstring(L, key); - lua_gettable(L, -2); - res = lua_toboolean(L, -1); - lua_pop(L, 1); - return res; -} - - -static int getfield (lua_State *L, const char *key, int d) { - int res; - lua_pushstring(L, key); - lua_gettable(L, -2); - if (lua_isnumber(L, -1)) - res = (int)(lua_tonumber(L, -1)); - else { - if (d == -2) - return luaL_error(L, "field `%s' missing in date table", key); - res = d; - } - lua_pop(L, 1); - return res; -} - - -static int io_date (lua_State *L) { - const char *s = luaL_optstring(L, 1, "%c"); - time_t t = (time_t)(luaL_optnumber(L, 2, -1)); - struct tm *stm; - if (t == (time_t)(-1)) /* no time given? */ - t = time(NULL); /* use current time */ - if (*s == '!') { /* UTC? */ - stm = gmtime(&t); - s++; /* skip `!' */ - } - else - stm = localtime(&t); - if (stm == NULL) /* invalid date? */ - lua_pushnil(L); - else if (strcmp(s, "*t") == 0) { - lua_newtable(L); - 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); - } - else { - char b[256]; - if (strftime(b, sizeof(b), s, stm)) - lua_pushstring(L, b); - else - return luaL_error(L, "`date' format too long"); - } - return 1; -} - - -static int io_time (lua_State *L) { - if (lua_isnoneornil(L, 1)) /* called without args? */ - lua_pushnumber(L, time(NULL)); /* return current time */ - else { - time_t t; - struct tm ts; - luaL_checktype(L, 1, LUA_TTABLE); - lua_settop(L, 1); /* make sure table is at the top */ - ts.tm_sec = getfield(L, "sec", 0); - ts.tm_min = getfield(L, "min", 0); - ts.tm_hour = getfield(L, "hour", 12); - ts.tm_mday = getfield(L, "day", -2); - ts.tm_mon = getfield(L, "month", -2) - 1; - ts.tm_year = getfield(L, "year", -2) - 1900; - ts.tm_isdst = getboolfield(L, "isdst"); - t = mktime(&ts); - if (t == (time_t)(-1)) - lua_pushnil(L); - else - lua_pushnumber(L, t); +static void createstdfile (lua_State *L, FILE *f, int k, const char *fname) { + *newfile(L) = f; + if (k > 0) { + lua_pushvalue(L, -1); + lua_rawseti(L, LUA_ENVIRONINDEX, k); } - return 1; + lua_setfield(L, -2, fname); } -static int io_difftime (lua_State *L) { - lua_pushnumber(L, difftime((time_t)(luaL_checknumber(L, 1)), - (time_t)(luaL_optnumber(L, 2, 0)))); - return 1; -} - -/* }====================================================== */ - - -static int io_setloc (lua_State *L) { - static const int cat[] = {LC_ALL, LC_COLLATE, LC_CTYPE, LC_MONETARY, - LC_NUMERIC, LC_TIME}; - static const char *const catnames[] = {"all", "collate", "ctype", "monetary", - "numeric", "time", NULL}; - const char *l = lua_tostring(L, 1); - int op = luaL_findstring(luaL_optstring(L, 2, "all"), catnames); - luaL_argcheck(L, l || lua_isnoneornil(L, 1), 1, "string expected"); - luaL_argcheck(L, op != -1, 2, "invalid option"); - lua_pushstring(L, setlocale(cat[op], l)); - return 1; -} - - -static int io_exit (lua_State *L) { - exit(luaL_optint(L, 1, EXIT_SUCCESS)); - return 0; /* to avoid warnings */ -} - -static const luaL_reg syslib[] = { - {"clock", io_clock}, - {"date", io_date}, - {"difftime", io_difftime}, - {"execute", io_execute}, - {"exit", io_exit}, - {"getenv", io_getenv}, - {"remove", io_remove}, - {"rename", io_rename}, - {"setlocale", io_setloc}, - {"time", io_time}, - {"tmpname", io_tmpname}, - {NULL, NULL} -}; - -/* }====================================================== */ - - - LUALIB_API int luaopen_io (lua_State *L) { - luaL_openlib(L, LUA_OSLIBNAME, syslib, 0); createmeta(L); - lua_pushvalue(L, -1); - luaL_openlib(L, LUA_IOLIBNAME, iolib, 1); - /* put predefined file handles into `io' table */ - registerfile(L, stdin, "stdin", IO_INPUT); - registerfile(L, stdout, "stdout", IO_OUTPUT); - registerfile(L, stderr, "stderr", NULL); + /* create (private) environment (with fields IO_INPUT, IO_OUTPUT, __close) */ + lua_createtable(L, 2, 1); + lua_replace(L, LUA_ENVIRONINDEX); + /* open library */ + luaL_register(L, LUA_IOLIBNAME, iolib); + /* create (and set) default files */ + createstdfile(L, stdin, IO_INPUT, "stdin"); + createstdfile(L, stdout, IO_OUTPUT, "stdout"); + createstdfile(L, stderr, 0, "stderr"); + /* create environment for 'popen' */ + lua_getfield(L, -1, "popen"); + lua_createtable(L, 0, 1); + lua_pushcfunction(L, io_pclose); + lua_setfield(L, -2, "__close"); + lua_setfenv(L, -2); + lua_pop(L, 1); /* pop 'popen' */ + /* set default close function */ + lua_pushcfunction(L, io_fclose); + lua_setfield(L, LUA_ENVIRONINDEX, "__close"); return 1; } diff --git a/lib/lua/src/LuaLib/lmathlib.c b/lib/lua/src/LuaLib/lmathlib.c index 998c46c..417fdca 100644 --- a/lib/lua/src/LuaLib/lmathlib.c +++ b/lib/lua/src/LuaLib/lmathlib.c @@ -1,5 +1,5 @@ /* -** $Id: lmathlib.c,v 1.4 2004-11-27 21:46:10 pixel Exp $ +** $Id: lmathlib.c,v 1.5 2007-07-27 10:05:55 pixel Exp $ ** Standard mathematical library ** See Copyright Notice in lua.h */ @@ -9,6 +9,7 @@ #include <math.h> #define lmathlib_c +#define LUA_LIB #include "lua.h" @@ -22,56 +23,58 @@ -/* -** If you want Lua to operate in degrees (instead of radians), -** define USE_DEGREES -*/ -#ifdef USE_DEGREES -#define FROMRAD(a) ((a)/RADIANS_PER_DEGREE) -#define TORAD(a) ((a)*RADIANS_PER_DEGREE) -#else -#define FROMRAD(a) (a) -#define TORAD(a) (a) -#endif - - static int math_abs (lua_State *L) { lua_pushnumber(L, fabs(luaL_checknumber(L, 1))); return 1; } static int math_sin (lua_State *L) { - lua_pushnumber(L, sin(TORAD(luaL_checknumber(L, 1)))); + lua_pushnumber(L, sin(luaL_checknumber(L, 1))); + return 1; +} + +static int math_sinh (lua_State *L) { + lua_pushnumber(L, sinh(luaL_checknumber(L, 1))); return 1; } static int math_cos (lua_State *L) { - lua_pushnumber(L, cos(TORAD(luaL_checknumber(L, 1)))); + lua_pushnumber(L, cos(luaL_checknumber(L, 1))); + return 1; +} + +static int math_cosh (lua_State *L) { + lua_pushnumber(L, cosh(luaL_checknumber(L, 1))); return 1; } static int math_tan (lua_State *L) { - lua_pushnumber(L, tan(TORAD(luaL_checknumber(L, 1)))); + lua_pushnumber(L, tan(luaL_checknumber(L, 1))); + return 1; +} + +static int math_tanh (lua_State *L) { + lua_pushnumber(L, tanh(luaL_checknumber(L, 1))); return 1; } static int math_asin (lua_State *L) { - lua_pushnumber(L, FROMRAD(asin(luaL_checknumber(L, 1)))); + lua_pushnumber(L, asin(luaL_checknumber(L, 1))); return 1; } static int math_acos (lua_State *L) { - lua_pushnumber(L, FROMRAD(acos(luaL_checknumber(L, 1)))); + lua_pushnumber(L, acos(luaL_checknumber(L, 1))); return 1; } static int math_atan (lua_State *L) { - lua_pushnumber(L, FROMRAD(atan(luaL_checknumber(L, 1)))); + lua_pushnumber(L, atan(luaL_checknumber(L, 1))); return 1; } static int math_atan2 (lua_State *L) { - lua_pushnumber(L, FROMRAD(atan2(luaL_checknumber(L, 1), luaL_checknumber(L, 2)))); + lua_pushnumber(L, atan2(luaL_checknumber(L, 1), luaL_checknumber(L, 2))); return 1; } @@ -85,11 +88,19 @@ static int math_floor (lua_State *L) { return 1; } -static int math_mod (lua_State *L) { +static int math_fmod (lua_State *L) { lua_pushnumber(L, fmod(luaL_checknumber(L, 1), luaL_checknumber(L, 2))); return 1; } +static int math_modf (lua_State *L) { + double ip; + double fp = modf(luaL_checknumber(L, 1), &ip); + lua_pushnumber(L, ip); + lua_pushnumber(L, fp); + return 2; +} + static int math_sqrt (lua_State *L) { lua_pushnumber(L, sqrt(luaL_checknumber(L, 1))); return 1; @@ -128,7 +139,7 @@ static int math_rad (lua_State *L) { static int math_frexp (lua_State *L) { int e; lua_pushnumber(L, frexp(luaL_checknumber(L, 1), &e)); - lua_pushnumber(L, e); + lua_pushinteger(L, e); return 2; } @@ -179,14 +190,14 @@ static int math_random (lua_State *L) { case 1: { /* only upper limit */ int u = luaL_checkint(L, 1); luaL_argcheck(L, 1<=u, 1, "interval is empty"); - lua_pushnumber(L, (int)floor(r*u)+1); /* int between 1 and `u' */ + lua_pushnumber(L, floor(r*u)+1); /* int between 1 and `u' */ break; } case 2: { /* lower and upper limits */ int l = luaL_checkint(L, 1); int u = luaL_checkint(L, 2); luaL_argcheck(L, l<=u, 2, "interval is empty"); - lua_pushnumber(L, (int)floor(r*(u-l+1))+l); /* int between `l' and `u' */ + lua_pushnumber(L, floor(r*(u-l+1))+l); /* int between `l' and `u' */ break; } default: return luaL_error(L, "wrong number of arguments"); @@ -201,31 +212,35 @@ static int math_randomseed (lua_State *L) { } -static const luaL_reg mathlib[] = { +static const luaL_Reg mathlib[] = { {"abs", math_abs}, - {"sin", math_sin}, - {"cos", math_cos}, - {"tan", math_tan}, - {"asin", math_asin}, {"acos", math_acos}, - {"atan", math_atan}, + {"asin", math_asin}, {"atan2", math_atan2}, + {"atan", math_atan}, {"ceil", math_ceil}, + {"cosh", math_cosh}, + {"cos", math_cos}, + {"deg", math_deg}, + {"exp", math_exp}, {"floor", math_floor}, - {"mod", math_mod}, + {"fmod", math_fmod}, {"frexp", math_frexp}, {"ldexp", math_ldexp}, - {"sqrt", math_sqrt}, - {"min", math_min}, - {"max", math_max}, - {"log", math_log}, {"log10", math_log10}, - {"exp", math_exp}, - {"deg", math_deg}, + {"log", math_log}, + {"max", math_max}, + {"min", math_min}, + {"modf", math_modf}, {"pow", math_pow}, {"rad", math_rad}, {"random", math_random}, {"randomseed", math_randomseed}, + {"sinh", math_sinh}, + {"sin", math_sin}, + {"sqrt", math_sqrt}, + {"tanh", math_tanh}, + {"tan", math_tan}, {NULL, NULL} }; @@ -234,13 +249,15 @@ static const luaL_reg mathlib[] = { ** Open math library */ LUALIB_API int luaopen_math (lua_State *L) { - luaL_openlib(L, LUA_MATHLIBNAME, mathlib, 0); - lua_pushliteral(L, "pi"); + luaL_register(L, LUA_MATHLIBNAME, mathlib); lua_pushnumber(L, PI); - lua_settable(L, -3); - lua_pushliteral(L, "__pow"); - lua_pushcfunction(L, math_pow); - lua_settable(L, LUA_GLOBALSINDEX); + lua_setfield(L, -2, "pi"); + lua_pushnumber(L, HUGE_VAL); + lua_setfield(L, -2, "huge"); +#if defined(LUA_COMPAT_MOD) + lua_getfield(L, -1, "fmod"); + lua_setfield(L, -2, "mod"); +#endif return 1; } diff --git a/lib/lua/src/LuaLib/loadlib.c b/lib/lua/src/LuaLib/loadlib.c index 8756205..5c6019f 100644 --- a/lib/lua/src/LuaLib/loadlib.c +++ b/lib/lua/src/LuaLib/loadlib.c @@ -1,205 +1,664 @@ /* -** $Id: loadlib.c,v 1.4 2004-11-27 21:46:10 pixel Exp $ +** $Id: loadlib.c,v 1.5 2007-07-27 10:05:55 pixel Exp $ ** Dynamic library loader for Lua ** See Copyright Notice in lua.h -* -* This Lua library exports a single function, called loadlib, which is -* called from Lua as loadlib(lib,init), where lib is the full name of the -* library to be loaded (including the complete path) and init is the name -* of a function to be called after the library is loaded. Typically, this -* function will register other functions, thus making the complete library -* available to Lua. The init function is *not* automatically called by -* loadlib. Instead, loadlib returns the init function as a Lua function -* that the client can call when it thinks is appropriate. In the case of -* errors, loadlib returns nil and two strings describing the error. -* The first string is supplied by the operating system; it should be -* informative and useful for error messages. The second string is "open", -* "init", or "absent" to identify the error and is meant to be used for -* making decisions without having to look into the first string (whose -* format is system-dependent). -* -* This module contains an implementation of loadlib for Unix systems that -* have dlfcn, an implementation for Windows, and a stub for other systems. -* See the list at the end of this file for some links to available -* implementations of dlfcn and interfaces to other native dynamic loaders -* on top of which loadlib could be implemented. -* +** +** This module contains an implementation of loadlib for Unix systems +** that have dlfcn, an implementation for Darwin (Mac OS X), an +** implementation for Windows, and a stub for other systems. */ + +#include <stdlib.h> +#include <string.h> + + +#define loadlib_c +#define LUA_LIB + #include "lua.h" + #include "lauxlib.h" #include "lualib.h" -#undef LOADLIB +/* prefix for open functions in C libraries */ +#define LUA_POF "luaopen_" + +/* separator for open functions in C libraries */ +#define LUA_OFSEP "_" + + +#define LIBPREFIX "LOADLIB: " + +#define POF LUA_POF +#define LIB_FAIL "open" + + +/* error codes for ll_loadfunc */ +#define ERRLIB 1 +#define ERRFUNC 2 +#define setprogdir(L) ((void)0) -#ifdef USE_DLOPEN -#define LOADLIB + +static void ll_unloadlib (void *lib); +static void *ll_load (lua_State *L, const char *path); +static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym); + + + +#if defined(LUA_DL_DLOPEN) /* -* This is an implementation of loadlib based on the dlfcn interface. -* The dlfcn interface is available in Linux, SunOS, Solaris, IRIX, FreeBSD, -* NetBSD, AIX 4.2, HPUX 11, and probably most other Unix flavors, at least -* as an emulation layer on top of native functions. +** {======================================================================== +** This is an implementation of loadlib based on the dlfcn interface. +** The dlfcn interface is available in Linux, SunOS, Solaris, IRIX, FreeBSD, +** NetBSD, AIX 4.2, HPUX 11, and probably most other Unix flavors, at least +** as an emulation layer on top of native functions. +** ========================================================================= */ #include <dlfcn.h> -static int loadlib(lua_State *L) -{ - const char *path=luaL_checkstring(L,1); - const char *init=luaL_checkstring(L,2); - void *lib=dlopen(path,RTLD_NOW); - if (lib!=NULL) - { - lua_CFunction f=(lua_CFunction) dlsym(lib,init); - if (f!=NULL) - { - lua_pushlightuserdata(L,lib); - lua_pushcclosure(L,f,1); - return 1; - } - } - /* else return appropriate error messages */ - lua_pushnil(L); - lua_pushstring(L,dlerror()); - lua_pushstring(L,(lib!=NULL) ? "init" : "open"); - if (lib!=NULL) dlclose(lib); - return 3; +static void ll_unloadlib (void *lib) { + dlclose(lib); } -#endif + +static void *ll_load (lua_State *L, const char *path) { + void *lib = dlopen(path, RTLD_NOW); + if (lib == NULL) lua_pushstring(L, dlerror()); + return lib; +} + + +static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { + lua_CFunction f = (lua_CFunction)dlsym(lib, sym); + if (f == NULL) lua_pushstring(L, dlerror()); + return f; +} + +/* }====================================================== */ + + + +#elif defined(LUA_DL_DLL) +/* +** {====================================================================== +** This is an implementation of loadlib for Windows using native functions. +** ======================================================================= +*/ + +#include <windows.h> + + +#undef setprogdir + +static void setprogdir (lua_State *L) { + char buff[MAX_PATH + 1]; + char *lb; + DWORD nsize = sizeof(buff)/sizeof(char); + DWORD n = GetModuleFileNameA(NULL, buff, nsize); + if (n == 0 || n == nsize || (lb = strrchr(buff, '\\')) == NULL) + luaL_error(L, "unable to get ModuleFileName"); + else { + *lb = '\0'; + luaL_gsub(L, lua_tostring(L, -1), LUA_EXECDIR, buff); + lua_remove(L, -2); /* remove original string */ + } +} + + +static void pusherror (lua_State *L) { + int error = GetLastError(); + char buffer[128]; + if (FormatMessageA(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM, + NULL, error, 0, buffer, sizeof(buffer), NULL)) + lua_pushstring(L, buffer); + else + lua_pushfstring(L, "system error %d\n", error); +} + +static void ll_unloadlib (void *lib) { + FreeLibrary((HINSTANCE)lib); +} + + +static void *ll_load (lua_State *L, const char *path) { + HINSTANCE lib = LoadLibraryA(path); + if (lib == NULL) pusherror(L); + return lib; +} + + +static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { + lua_CFunction f = (lua_CFunction)GetProcAddress((HINSTANCE)lib, sym); + if (f == NULL) pusherror(L); + return f; +} + +/* }====================================================== */ +#elif defined(LUA_DL_DYLD) /* -** In Windows, default is to use dll; otherwise, default is not to use dll +** {====================================================================== +** Native Mac OS X / Darwin Implementation +** ======================================================================= */ -#ifndef USE_DLL -#ifdef _WIN32 -#define USE_DLL 1 + +#include <mach-o/dyld.h> + + +/* Mac appends a `_' before C function names */ +#undef POF +#define POF "_" LUA_POF + + +static void pusherror (lua_State *L) { + const char *err_str; + const char *err_file; + NSLinkEditErrors err; + int err_num; + NSLinkEditError(&err, &err_num, &err_file, &err_str); + lua_pushstring(L, err_str); +} + + +static const char *errorfromcode (NSObjectFileImageReturnCode ret) { + switch (ret) { + case NSObjectFileImageInappropriateFile: + return "file is not a bundle"; + case NSObjectFileImageArch: + return "library is for wrong CPU type"; + case NSObjectFileImageFormat: + return "bad format"; + case NSObjectFileImageAccess: + return "cannot access file"; + case NSObjectFileImageFailure: + default: + return "unable to load library"; + } +} + + +static void ll_unloadlib (void *lib) { + NSUnLinkModule((NSModule)lib, NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES); +} + + +static void *ll_load (lua_State *L, const char *path) { + NSObjectFileImage img; + NSObjectFileImageReturnCode ret; + /* this would be a rare case, but prevents crashing if it happens */ + if(!_dyld_present()) { + lua_pushliteral(L, "dyld not present"); + return NULL; + } + ret = NSCreateObjectFileImageFromFile(path, &img); + if (ret == NSObjectFileImageSuccess) { + NSModule mod = NSLinkModule(img, path, NSLINKMODULE_OPTION_PRIVATE | + NSLINKMODULE_OPTION_RETURN_ON_ERROR); + NSDestroyObjectFileImage(img); + if (mod == NULL) pusherror(L); + return mod; + } + lua_pushstring(L, errorfromcode(ret)); + return NULL; +} + + +static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { + NSSymbol nss = NSLookupSymbolInModule((NSModule)lib, sym); + if (nss == NULL) { + lua_pushfstring(L, "symbol " LUA_QS " not found", sym); + return NULL; + } + return (lua_CFunction)NSAddressOfSymbol(nss); +} + +/* }====================================================== */ + + + #else -#define USE_DLL 0 -#endif +/* +** {====================================================== +** Fallback for other systems +** ======================================================= +*/ + +#undef LIB_FAIL +#define LIB_FAIL "absent" + + +#define DLMSG "dynamic libraries not enabled; check your Lua installation" + + +static void ll_unloadlib (void *lib) { + (void)lib; /* to avoid warnings */ +} + + +static void *ll_load (lua_State *L, const char *path) { + (void)path; /* to avoid warnings */ + lua_pushliteral(L, DLMSG); + return NULL; +} + + +static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { + (void)lib; (void)sym; /* to avoid warnings */ + lua_pushliteral(L, DLMSG); + return NULL; +} + +/* }====================================================== */ #endif -#if USE_DLL -#define LOADLIB + +static void **ll_register (lua_State *L, const char *path) { + void **plib; + lua_pushfstring(L, "%s%s", LIBPREFIX, path); + lua_gettable(L, LUA_REGISTRYINDEX); /* check library in registry? */ + if (!lua_isnil(L, -1)) /* is there an entry? */ + plib = (void **)lua_touserdata(L, -1); + else { /* no entry yet; create one */ + lua_pop(L, 1); + plib = (void **)lua_newuserdata(L, sizeof(const void *)); + *plib = NULL; + luaL_getmetatable(L, "_LOADLIB"); + lua_setmetatable(L, -2); + lua_pushfstring(L, "%s%s", LIBPREFIX, path); + lua_pushvalue(L, -2); + lua_settable(L, LUA_REGISTRYINDEX); + } + return plib; +} + + /* -* This is an implementation of loadlib for Windows using native functions. +** __gc tag method: calls library's `ll_unloadlib' function with the lib +** handle */ +static int gctm (lua_State *L) { + void **lib = (void **)luaL_checkudata(L, 1, "_LOADLIB"); + if (*lib) ll_unloadlib(*lib); + *lib = NULL; /* mark library as closed */ + return 0; +} -#include <windows.h> -static void pusherror(lua_State *L) -{ - int error=GetLastError(); - char buffer[128]; - if (FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM, - 0, error, 0, buffer, sizeof(buffer), 0)) - lua_pushstring(L,buffer); - else - lua_pushfstring(L,"system error %d\n",error); -} - -static int loadlib(lua_State *L) -{ - const char *path=luaL_checkstring(L,1); - const char *init=luaL_checkstring(L,2); - HINSTANCE lib=LoadLibrary(path); - if (lib!=NULL) - { - lua_CFunction f=(lua_CFunction) GetProcAddress(lib,init); - if (f!=NULL) - { - lua_pushlightuserdata(L,lib); - lua_pushcclosure(L,f,1); - return 1; - } - } - lua_pushnil(L); - pusherror(L); - lua_pushstring(L,(lib!=NULL) ? "init" : "open"); - if (lib!=NULL) FreeLibrary(lib); - return 3; +static int ll_loadfunc (lua_State *L, const char *path, const char *sym) { + void **reg = ll_register(L, path); + if (*reg == NULL) *reg = ll_load(L, path); + if (*reg == NULL) + return ERRLIB; /* unable to load library */ + else { + lua_CFunction f = ll_sym(L, *reg, sym); + if (f == NULL) + return ERRFUNC; /* unable to find function */ + lua_pushcfunction(L, f); + return 0; /* return function */ + } } -#endif +static int ll_loadlib (lua_State *L) { + const char *path = luaL_checkstring(L, 1); + const char *init = luaL_checkstring(L, 2); + int stat = ll_loadfunc(L, path, init); + if (stat == 0) /* no errors? */ + return 1; /* return the loaded function */ + else { /* error; error message is on stack top */ + lua_pushnil(L); + lua_insert(L, -2); + lua_pushstring(L, (stat == ERRLIB) ? LIB_FAIL : "init"); + return 3; /* return nil, error message, and where */ + } +} -#ifndef LOADLIB -/* Fallback for other systems */ /* -** Those systems support dlopen, so they should have defined USE_DLOPEN. -** The default (no)implementation gives them a special error message. +** {====================================================== +** 'require' function +** ======================================================= */ -#ifdef linux -#define LOADLIB -#endif -#ifdef sun -#define LOADLIB -#endif -#ifdef sgi -#define LOADLIB -#endif +static int readable (const char *filename) { + FILE *f = fopen(filename, "r"); /* try to open file */ + if (f == NULL) return 0; /* open failed */ + fclose(f); + return 1; +} -#ifdef BSD -#define LOADLIB -#endif -#ifdef _WIN32 -#define LOADLIB -#endif +static const char *pushnexttemplate (lua_State *L, const char *path) { + const char *l; + while (*path == *LUA_PATHSEP) path++; /* skip separators */ + if (*path == '\0') return NULL; /* no more templates */ + l = strchr(path, *LUA_PATHSEP); /* find next separator */ + if (l == NULL) l = path + strlen(path); + lua_pushlstring(L, path, l - path); /* template */ + return l; +} -#ifdef LOADLIB -#undef LOADLIB -#define LOADLIB "`loadlib' not installed (check your Lua configuration)" -#else -#define LOADLIB "`loadlib' not supported" -#endif -static int loadlib(lua_State *L) -{ - lua_pushnil(L); - lua_pushliteral(L,LOADLIB); - lua_pushliteral(L,"absent"); - return 3; +static const char *findfile (lua_State *L, const char *name, + const char *pname) { + const char *path; + name = luaL_gsub(L, name, ".", LUA_DIRSEP); + lua_getfield(L, LUA_ENVIRONINDEX, pname); + path = lua_tostring(L, -1); + if (path == NULL) + luaL_error(L, LUA_QL("package.%s") " must be a string", pname); + lua_pushliteral(L, ""); /* error accumulator */ + while ((path = pushnexttemplate(L, path)) != NULL) { + const char *filename; + filename = luaL_gsub(L, lua_tostring(L, -1), LUA_PATH_MARK, name); + lua_remove(L, -2); /* remove path template */ + if (readable(filename)) /* does file exist and is readable? */ + return filename; /* return that file name */ + lua_pushfstring(L, "\n\tno file " LUA_QS, filename); + lua_remove(L, -2); /* remove file name */ + lua_concat(L, 2); /* add entry to possible error message */ + } + return NULL; /* not found */ } -#endif -LUALIB_API int luaopen_loadlib (lua_State *L) -{ - lua_register(L,"loadlib",loadlib); - return 0; + +static void loaderror (lua_State *L, const char *filename) { + luaL_error(L, "error loading module " LUA_QS " from file " LUA_QS ":\n\t%s", + lua_tostring(L, 1), filename, lua_tostring(L, -1)); +} + + +static int loader_Lua (lua_State *L) { + const char *filename; + const char *name = luaL_checkstring(L, 1); + filename = findfile(L, name, "path"); + if (filename == NULL) return 1; /* library not found in this path */ + if (luaL_loadfile(L, filename) != 0) + loaderror(L, filename); + return 1; /* library loaded successfully */ +} + + +static const char *mkfuncname (lua_State *L, const char *modname) { + const char *funcname; + const char *mark = strchr(modname, *LUA_IGMARK); + if (mark) modname = mark + 1; + funcname = luaL_gsub(L, modname, ".", LUA_OFSEP); + funcname = lua_pushfstring(L, POF"%s", funcname); + lua_remove(L, -2); /* remove 'gsub' result */ + return funcname; +} + + +static int loader_C (lua_State *L) { + const char *funcname; + const char *name = luaL_checkstring(L, 1); + const char *filename = findfile(L, name, "cpath"); + if (filename == NULL) return 1; /* library not found in this path */ + funcname = mkfuncname(L, name); + if (ll_loadfunc(L, filename, funcname) != 0) + loaderror(L, filename); + return 1; /* library loaded successfully */ +} + + +static int loader_Croot (lua_State *L) { + const char *funcname; + const char *filename; + const char *name = luaL_checkstring(L, 1); + const char *p = strchr(name, '.'); + int stat; + if (p == NULL) return 0; /* is root */ + lua_pushlstring(L, name, p - name); + filename = findfile(L, lua_tostring(L, -1), "cpath"); + if (filename == NULL) return 1; /* root not found */ + funcname = mkfuncname(L, name); + if ((stat = ll_loadfunc(L, filename, funcname)) != 0) { + if (stat != ERRFUNC) loaderror(L, filename); /* real error */ + lua_pushfstring(L, "\n\tno module " LUA_QS " in file " LUA_QS, + name, filename); + return 1; /* function not found */ + } + return 1; +} + + +static int loader_preload (lua_State *L) { + const char *name = luaL_checkstring(L, 1); + lua_getfield(L, LUA_ENVIRONINDEX, "preload"); + if (!lua_istable(L, -1)) + luaL_error(L, LUA_QL("package.preload") " must be a table"); + lua_getfield(L, -1, name); + if (lua_isnil(L, -1)) /* not found? */ + lua_pushfstring(L, "\n\tno field package.preload['%s']", name); + return 1; +} + + +static const int sentinel_ = 0; +#define sentinel ((void *)&sentinel_) + + +static int ll_require (lua_State *L) { + const char *name = luaL_checkstring(L, 1); + int i; + lua_settop(L, 1); /* _LOADED table will be at index 2 */ + lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"); + lua_getfield(L, 2, name); + if (lua_toboolean(L, -1)) { /* is it there? */ + if (lua_touserdata(L, -1) == sentinel) /* check loops */ + luaL_error(L, "loop or previous error loading module " LUA_QS, name); + return 1; /* package is already loaded */ + } + /* else must load it; iterate over available loaders */ + lua_getfield(L, LUA_ENVIRONINDEX, "loaders"); + if (!lua_istable(L, -1)) + luaL_error(L, LUA_QL("package.loaders") " must be a table"); + lua_pushliteral(L, ""); /* error message accumulator */ + for (i=1; ; i++) { + lua_rawgeti(L, -2, i); /* get a loader */ + if (lua_isnil(L, -1)) + luaL_error(L, "module " LUA_QS " not found:%s", + name, lua_tostring(L, -2)); + lua_pushstring(L, name); + lua_call(L, 1, 1); /* call it */ + if (lua_isfunction(L, -1)) /* did it find module? */ + break; /* module loaded successfully */ + else if (lua_isstring(L, -1)) /* loader returned error message? */ + lua_concat(L, 2); /* accumulate it */ + else + lua_pop(L, 1); + } + lua_pushlightuserdata(L, sentinel); + lua_setfield(L, 2, name); /* _LOADED[name] = sentinel */ + lua_pushstring(L, name); /* pass name as argument to module */ + lua_call(L, 1, 1); /* run loaded module */ + if (!lua_isnil(L, -1)) /* non-nil return? */ + lua_setfield(L, 2, name); /* _LOADED[name] = returned value */ + lua_getfield(L, 2, name); + if (lua_touserdata(L, -1) == sentinel) { /* module did not set a value? */ + lua_pushboolean(L, 1); /* use true as result */ + lua_pushvalue(L, -1); /* extra copy to be returned */ + lua_setfield(L, 2, name); /* _LOADED[name] = true */ + } + return 1; } +/* }====================================================== */ + + + /* -* Here are some links to available implementations of dlfcn and -* interfaces to other native dynamic loaders on top of which loadlib -* could be implemented. Please send contributions and corrections to us. -* -* AIX -* Starting with AIX 4.2, dlfcn is included in the base OS. -* There is also an emulation package available. -* http://www.faqs.org/faqs/aix-faq/part4/section-21.html -* -* HPUX -* HPUX 11 has dlfcn. For HPUX 10 use shl_*. -* http://www.geda.seul.org/mailinglist/geda-dev37/msg00094.html -* http://www.stat.umn.edu/~luke/xls/projects/dlbasics/dlbasics.html -* -* Macintosh, Windows -* http://www.stat.umn.edu/~luke/xls/projects/dlbasics/dlbasics.html -* -* Mac OS X/Darwin -* http://www.opendarwin.org/projects/dlcompat/ -* -* GLIB has wrapper code for BeOS, OS2, Unix and Windows -* http://cvs.gnome.org/lxr/source/glib/gmodule/ -* +** {====================================================== +** 'module' function +** ======================================================= */ + + +static void setfenv (lua_State *L) { + lua_Debug ar; + lua_getstack(L, 1, &ar); + lua_getinfo(L, "f", &ar); + lua_pushvalue(L, -2); + lua_setfenv(L, -2); + lua_pop(L, 1); +} + + +static void dooptions (lua_State *L, int n) { + int i; + for (i = 2; i <= n; i++) { + lua_pushvalue(L, i); /* get option (a function) */ + lua_pushvalue(L, -2); /* module */ + lua_call(L, 1, 0); + } +} + + +static void modinit (lua_State *L, const char *modname) { + const char *dot; + lua_pushvalue(L, -1); + lua_setfield(L, -2, "_M"); /* module._M = module */ + lua_pushstring(L, modname); + lua_setfield(L, -2, "_NAME"); + dot = strrchr(modname, '.'); /* look for last dot in module name */ + if (dot == NULL) dot = modname; + else dot++; + /* set _PACKAGE as package name (full module name minus last part) */ + lua_pushlstring(L, modname, dot - modname); + lua_setfield(L, -2, "_PACKAGE"); +} + + +static int ll_module (lua_State *L) { + const char *modname = luaL_checkstring(L, 1); + int loaded = lua_gettop(L) + 1; /* index of _LOADED table */ + lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"); + lua_getfield(L, loaded, modname); /* get _LOADED[modname] */ + if (!lua_istable(L, -1)) { /* not found? */ + lua_pop(L, 1); /* remove previous result */ + /* try global variable (and create one if it does not exist) */ + if (luaL_findtable(L, LUA_GLOBALSINDEX, modname, 1) != NULL) + return luaL_error(L, "name conflict for module " LUA_QS, modname); + lua_pushvalue(L, -1); + lua_setfield(L, loaded, modname); /* _LOADED[modname] = new table */ + } + /* check whether table already has a _NAME field */ + lua_getfield(L, -1, "_NAME"); + if (!lua_isnil(L, -1)) /* is table an initialized module? */ + lua_pop(L, 1); + else { /* no; initialize it */ + lua_pop(L, 1); + modinit(L, modname); + } + lua_pushvalue(L, -1); + setfenv(L); + dooptions(L, loaded - 1); + return 0; +} + + +static int ll_seeall (lua_State *L) { + luaL_checktype(L, 1, LUA_TTABLE); + if (!lua_getmetatable(L, 1)) { + lua_createtable(L, 0, 1); /* create new metatable */ + lua_pushvalue(L, -1); + lua_setmetatable(L, 1); + } + lua_pushvalue(L, LUA_GLOBALSINDEX); + lua_setfield(L, -2, "__index"); /* mt.__index = _G */ + return 0; +} + + +/* }====================================================== */ + + + +/* auxiliary mark (for internal use) */ +#define AUXMARK "\1" + +static void setpath (lua_State *L, const char *fieldname, const char *envname, + const char *def) { + const char *path = getenv(envname); + if (path == NULL) /* no environment variable? */ + lua_pushstring(L, def); /* use default */ + else { + /* replace ";;" by ";AUXMARK;" and then AUXMARK by default path */ + path = luaL_gsub(L, path, LUA_PATHSEP LUA_PATHSEP, + LUA_PATHSEP AUXMARK LUA_PATHSEP); + luaL_gsub(L, path, AUXMARK, def); + lua_remove(L, -2); + } + setprogdir(L); + lua_setfield(L, -2, fieldname); +} + + +static const luaL_Reg pk_funcs[] = { + {"loadlib", ll_loadlib}, + {"seeall", ll_seeall}, + {NULL, NULL} +}; + + +static const luaL_Reg ll_funcs[] = { + {"module", ll_module}, + {"require", ll_require}, + {NULL, NULL} +}; + + +static const lua_CFunction loaders[] = + {loader_preload, loader_Lua, loader_C, loader_Croot, NULL}; + + +LUALIB_API int luaopen_package (lua_State *L) { + int i; + /* create new type _LOADLIB */ + luaL_newmetatable(L, "_LOADLIB"); + lua_pushcfunction(L, gctm); + lua_setfield(L, -2, "__gc"); + /* create `package' table */ + luaL_register(L, LUA_LOADLIBNAME, pk_funcs); +#if defined(LUA_COMPAT_LOADLIB) + lua_getfield(L, -1, "loadlib"); + lua_setfield(L, LUA_GLOBALSINDEX, "loadlib"); +#endif + lua_pushvalue(L, -1); + lua_replace(L, LUA_ENVIRONINDEX); + /* create `loaders' table */ + lua_createtable(L, 0, sizeof(loaders)/sizeof(loaders[0]) - 1); + /* fill it with pre-defined loaders */ + for (i=0; loaders[i] != NULL; i++) { + lua_pushcfunction(L, loaders[i]); + lua_rawseti(L, -2, i+1); + } + lua_setfield(L, -2, "loaders"); /* put it in field `loaders' */ + setpath(L, "path", LUA_PATH, LUA_PATH_DEFAULT); /* set field `path' */ + setpath(L, "cpath", LUA_CPATH, LUA_CPATH_DEFAULT); /* set field `cpath' */ + /* store config information */ + lua_pushliteral(L, LUA_DIRSEP "\n" LUA_PATHSEP "\n" LUA_PATH_MARK "\n" + LUA_EXECDIR "\n" LUA_IGMARK); + lua_setfield(L, -2, "config"); + /* set field `loaded' */ + luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 2); + lua_setfield(L, -2, "loaded"); + /* set field `preload' */ + lua_newtable(L); + lua_setfield(L, -2, "preload"); + lua_pushvalue(L, LUA_GLOBALSINDEX); + luaL_register(L, NULL, ll_funcs); /* open lib into global table */ + lua_pop(L, 1); + return 1; /* return 'package' table */ +} + diff --git a/lib/lua/src/LuaLib/lstrlib.c b/lib/lua/src/LuaLib/lstrlib.c index 2e5f26e..8310752 100644 --- a/lib/lua/src/LuaLib/lstrlib.c +++ b/lib/lua/src/LuaLib/lstrlib.c @@ -1,5 +1,5 @@ /* -** $Id: lstrlib.c,v 1.4 2004-11-27 21:46:10 pixel Exp $ +** $Id: lstrlib.c,v 1.5 2007-07-27 10:05:55 pixel Exp $ ** Standard library for string operations and pattern-matching ** See Copyright Notice in lua.h */ @@ -12,6 +12,7 @@ #include <string.h> #define lstrlib_c +#define LUA_LIB #include "lua.h" @@ -20,35 +21,31 @@ /* macro to `unsign' a character */ -#ifndef uchar #define uchar(c) ((unsigned char)(c)) -#endif - -typedef long sint32; /* a signed version for size_t */ static int str_len (lua_State *L) { size_t l; luaL_checklstring(L, 1, &l); - lua_pushnumber(L, (lua_Number)l); + lua_pushinteger(L, l); return 1; } -static sint32 posrelat (sint32 pos, size_t len) { +static ptrdiff_t posrelat (ptrdiff_t pos, size_t len) { /* relative string position: negative means back from end */ - return (pos>=0) ? pos : (sint32)len+pos+1; + return (pos>=0) ? pos : (ptrdiff_t)len+pos+1; } static int str_sub (lua_State *L) { size_t l; const char *s = luaL_checklstring(L, 1, &l); - sint32 start = posrelat(luaL_checklong(L, 2), l); - sint32 end = posrelat(luaL_optlong(L, 3, -1), l); + ptrdiff_t start = posrelat(luaL_checkinteger(L, 2), l); + ptrdiff_t end = posrelat(luaL_optinteger(L, 3, -1), l); if (start < 1) start = 1; - if (end > (sint32)l) end = (sint32)l; + if (end > (ptrdiff_t)l) end = (ptrdiff_t)l; if (start <= end) lua_pushlstring(L, s+start-1, end-start+1); else lua_pushliteral(L, ""); @@ -56,6 +53,17 @@ static int str_sub (lua_State *L) { } +static int str_reverse (lua_State *L) { + size_t l; + luaL_Buffer b; + const char *s = luaL_checklstring(L, 1, &l); + luaL_buffinit(L, &b); + while (l--) luaL_addchar(&b, s[l]); + luaL_pushresult(&b); + return 1; +} + + static int str_lower (lua_State *L) { size_t l; size_t i; @@ -63,7 +71,7 @@ static int str_lower (lua_State *L) { const char *s = luaL_checklstring(L, 1, &l); luaL_buffinit(L, &b); for (i=0; i<l; i++) - luaL_putchar(&b, tolower(uchar(s[i]))); + luaL_addchar(&b, tolower(uchar(s[i]))); luaL_pushresult(&b); return 1; } @@ -76,7 +84,7 @@ static int str_upper (lua_State *L) { const char *s = luaL_checklstring(L, 1, &l); luaL_buffinit(L, &b); for (i=0; i<l; i++) - luaL_putchar(&b, toupper(uchar(s[i]))); + luaL_addchar(&b, toupper(uchar(s[i]))); luaL_pushresult(&b); return 1; } @@ -97,11 +105,19 @@ static int str_rep (lua_State *L) { static int str_byte (lua_State *L) { size_t l; const char *s = luaL_checklstring(L, 1, &l); - sint32 pos = posrelat(luaL_optlong(L, 2, 1), l); - if (pos <= 0 || (size_t)(pos) > l) /* index out of range? */ - return 0; /* no answer */ - lua_pushnumber(L, uchar(s[pos-1])); - return 1; + ptrdiff_t posi = posrelat(luaL_optinteger(L, 2, 1), l); + ptrdiff_t pose = posrelat(luaL_optinteger(L, 3, posi), l); + int n, i; + if (posi <= 0) posi = 1; + if ((size_t)pose > l) pose = l; + if (posi > pose) return 0; /* empty interval; return no values */ + n = (int)(pose - posi + 1); + if (posi + n <= pose) /* overflow? */ + luaL_error(L, "string slice too long"); + luaL_checkstack(L, n, "string slice too long"); + for (i=0; i<n; i++) + lua_pushinteger(L, uchar(s[posi+i-1])); + return n; } @@ -113,7 +129,7 @@ static int str_char (lua_State *L) { for (i=1; i<=n; i++) { int c = luaL_checkint(L, i); luaL_argcheck(L, uchar(c) == c, i, "invalid value"); - luaL_putchar(&b, uchar(c)); + luaL_addchar(&b, uchar(c)); } luaL_pushresult(&b); return 1; @@ -123,15 +139,16 @@ static int str_char (lua_State *L) { static int writer (lua_State *L, const void* b, size_t size, void* B) { (void)L; luaL_addlstring((luaL_Buffer*) B, (const char *)b, size); - return 1; + return 0; } static int str_dump (lua_State *L) { luaL_Buffer b; luaL_checktype(L, 1, LUA_TFUNCTION); + lua_settop(L, 1); luaL_buffinit(L,&b); - if (!lua_dump(L, writer, &b)) + if (lua_dump(L, writer, &b) != 0) luaL_error(L, "unable to dump given function"); luaL_pushresult(&b); return 1; @@ -145,10 +162,6 @@ static int str_dump (lua_State *L) { ** ======================================================= */ -#ifndef MAX_CAPTURES -#define MAX_CAPTURES 32 /* arbitrary limit */ -#endif - #define CAP_UNFINISHED (-1) #define CAP_POSITION (-2) @@ -160,12 +173,12 @@ typedef struct MatchState { int level; /* total number of captures (finished or unfinished) */ struct { const char *init; - sint32 len; - } capture[MAX_CAPTURES]; + ptrdiff_t len; + } capture[LUA_MAXCAPTURES]; } MatchState; -#define ESC '%' +#define L_ESC '%' #define SPECIALS "^$*+?.([%-" @@ -185,19 +198,19 @@ static int capture_to_close (MatchState *ms) { } -static const char *luaI_classend (MatchState *ms, const char *p) { +static const char *classend (MatchState *ms, const char *p) { switch (*p++) { - case ESC: { + case L_ESC: { if (*p == '\0') - luaL_error(ms->L, "malformed pattern (ends with `%')"); + luaL_error(ms->L, "malformed pattern (ends with " LUA_QL("%%") ")"); return p+1; } case '[': { if (*p == '^') p++; do { /* look for a `]' */ if (*p == '\0') - luaL_error(ms->L, "malformed pattern (missing `]')"); - if (*(p++) == ESC && *p != '\0') + luaL_error(ms->L, "malformed pattern (missing " LUA_QL("]") ")"); + if (*(p++) == L_ESC && *p != '\0') p++; /* skip escapes (e.g. `%]') */ } while (*p != ']'); return p+1; @@ -235,9 +248,9 @@ static int matchbracketclass (int c, const char *p, const char *ec) { p++; /* skip the `^' */ } while (++p < ec) { - if (*p == ESC) { + if (*p == L_ESC) { p++; - if (match_class(c, *p)) + if (match_class(c, uchar(*p))) return sig; } else if ((*(p+1) == '-') && (p+2 < ec)) { @@ -251,10 +264,10 @@ static int matchbracketclass (int c, const char *p, const char *ec) { } -static int luaI_singlematch (int c, const char *p, const char *ep) { +static int singlematch (int c, const char *p, const char *ep) { switch (*p) { case '.': return 1; /* matches any char */ - case ESC: return match_class(c, *(p+1)); + case L_ESC: return match_class(c, uchar(*(p+1))); case '[': return matchbracketclass(c, p, ep-1); default: return (uchar(*p) == c); } @@ -286,8 +299,8 @@ static const char *matchbalance (MatchState *ms, const char *s, static const char *max_expand (MatchState *ms, const char *s, const char *p, const char *ep) { - sint32 i = 0; /* counts maximum expand for item */ - while ((s+i)<ms->src_end && luaI_singlematch(uchar(*(s+i)), p, ep)) + ptrdiff_t i = 0; /* counts maximum expand for item */ + while ((s+i)<ms->src_end && singlematch(uchar(*(s+i)), p, ep)) i++; /* keeps trying to match with the maximum repetitions */ while (i>=0) { @@ -305,7 +318,7 @@ static const char *min_expand (MatchState *ms, const char *s, const char *res = match(ms, s, ep+1); if (res != NULL) return res; - else if (s<ms->src_end && luaI_singlematch(uchar(*s), p, ep)) + else if (s<ms->src_end && singlematch(uchar(*s), p, ep)) s++; /* try with one more repetition */ else return NULL; } @@ -316,7 +329,7 @@ static const char *start_capture (MatchState *ms, const char *s, const char *p, int what) { const char *res; int level = ms->level; - if (level >= MAX_CAPTURES) luaL_error(ms->L, "too many captures"); + if (level >= LUA_MAXCAPTURES) luaL_error(ms->L, "too many captures"); ms->capture[level].init = s; ms->capture[level].len = what; ms->level = level+1; @@ -360,7 +373,7 @@ static const char *match (MatchState *ms, const char *s, const char *p) { case ')': { /* end capture */ return end_capture(ms, s, p+1); } - case ESC: { + case L_ESC: { switch (*(p+1)) { case 'b': { /* balanced string? */ s = matchbalance(ms, s, p+2); @@ -371,8 +384,9 @@ static const char *match (MatchState *ms, const char *s, const char *p) { const char *ep; char previous; p += 2; if (*p != '[') - luaL_error(ms->L, "missing `[' after `%%f' in pattern"); - ep = luaI_classend(ms, p); /* points to what is next */ + luaL_error(ms->L, "missing " LUA_QL("[") " after " + LUA_QL("%%f") " in pattern"); + ep = classend(ms, p); /* points to what is next */ previous = (s == ms->src_init) ? '\0' : *(s-1); if (matchbracketclass(uchar(previous), p, ep-1) || !matchbracketclass(uchar(*s), p, ep-1)) return NULL; @@ -380,7 +394,7 @@ static const char *match (MatchState *ms, const char *s, const char *p) { } default: { if (isdigit(uchar(*(p+1)))) { /* capture results (%0-%9)? */ - s = match_capture(ms, s, *(p+1)); + s = match_capture(ms, s, uchar(*(p+1))); if (s == NULL) return NULL; p+=2; goto init; /* else return match(ms, s, p+2) */ } @@ -397,8 +411,8 @@ static const char *match (MatchState *ms, const char *s, const char *p) { else goto dflt; } default: dflt: { /* it is a pattern item */ - const char *ep = luaI_classend(ms, p); /* points to what is next */ - int m = s<ms->src_end && luaI_singlematch(uchar(*s), p, ep); + const char *ep = classend(ms, p); /* points to what is next */ + int m = s<ms->src_end && singlematch(uchar(*s), p, ep); switch (*ep) { case '?': { /* optional */ const char *res; @@ -448,45 +462,49 @@ static const char *lmemfind (const char *s1, size_t l1, } -static void push_onecapture (MatchState *ms, int i) { - int l = ms->capture[i].len; - if (l == CAP_UNFINISHED) luaL_error(ms->L, "unfinished capture"); - if (l == CAP_POSITION) - lua_pushnumber(ms->L, (lua_Number)(ms->capture[i].init - ms->src_init + 1)); - else - lua_pushlstring(ms->L, ms->capture[i].init, l); +static void push_onecapture (MatchState *ms, int i, const char *s, + const char *e) { + if (i >= ms->level) { + if (i == 0) /* ms->level == 0, too */ + lua_pushlstring(ms->L, s, e - s); /* add whole match */ + else + luaL_error(ms->L, "invalid capture index"); + } + else { + ptrdiff_t l = ms->capture[i].len; + if (l == CAP_UNFINISHED) luaL_error(ms->L, "unfinished capture"); + if (l == CAP_POSITION) + lua_pushinteger(ms->L, ms->capture[i].init - ms->src_init + 1); + else + lua_pushlstring(ms->L, ms->capture[i].init, l); + } } static int push_captures (MatchState *ms, const char *s, const char *e) { int i; - luaL_checkstack(ms->L, ms->level, "too many captures"); - if (ms->level == 0 && s) { /* no explicit captures? */ - lua_pushlstring(ms->L, s, e-s); /* return whole match */ - return 1; - } - else { /* return all captures */ - for (i=0; i<ms->level; i++) - push_onecapture(ms, i); - return ms->level; /* number of strings pushed */ - } + int nlevels = (ms->level == 0 && s) ? 1 : ms->level; + luaL_checkstack(ms->L, nlevels, "too many captures"); + for (i = 0; i < nlevels; i++) + push_onecapture(ms, i, s, e); + return nlevels; /* number of strings pushed */ } -static int str_find (lua_State *L) { +static int str_find_aux (lua_State *L, int find) { size_t l1, l2; const char *s = luaL_checklstring(L, 1, &l1); const char *p = luaL_checklstring(L, 2, &l2); - sint32 init = posrelat(luaL_optlong(L, 3, 1), l1) - 1; + ptrdiff_t init = posrelat(luaL_optinteger(L, 3, 1), l1) - 1; if (init < 0) init = 0; - else if ((size_t)(init) > l1) init = (sint32)l1; - if (lua_toboolean(L, 4) || /* explicit request? */ - strpbrk(p, SPECIALS) == NULL) { /* or no special characters? */ + else if ((size_t)(init) > l1) init = (ptrdiff_t)l1; + if (find && (lua_toboolean(L, 4) || /* explicit request? */ + strpbrk(p, SPECIALS) == NULL)) { /* or no special characters? */ /* do a plain search */ const char *s2 = lmemfind(s+init, l1-init, p, l2); if (s2) { - lua_pushnumber(L, (lua_Number)(s2-s+1)); - lua_pushnumber(L, (lua_Number)(s2-s+l2)); + lua_pushinteger(L, s2-s+1); + lua_pushinteger(L, s2-s+l2); return 2; } } @@ -501,35 +519,49 @@ static int str_find (lua_State *L) { const char *res; ms.level = 0; if ((res=match(&ms, s1, p)) != NULL) { - lua_pushnumber(L, (lua_Number)(s1-s+1)); /* start */ - lua_pushnumber(L, (lua_Number)(res-s)); /* end */ - return push_captures(&ms, NULL, 0) + 2; + if (find) { + lua_pushinteger(L, s1-s+1); /* start */ + lua_pushinteger(L, res-s); /* end */ + return push_captures(&ms, NULL, 0) + 2; + } + else + return push_captures(&ms, s1, res); } - } while (s1++<ms.src_end && !anchor); + } while (s1++ < ms.src_end && !anchor); } lua_pushnil(L); /* not found */ return 1; } -static int gfind_aux (lua_State *L) { +static int str_find (lua_State *L) { + return str_find_aux(L, 1); +} + + +static int str_match (lua_State *L) { + return str_find_aux(L, 0); +} + + +static int gmatch_aux (lua_State *L) { MatchState ms; - const char *s = lua_tostring(L, lua_upvalueindex(1)); - size_t ls = lua_strlen(L, lua_upvalueindex(1)); + size_t ls; + const char *s = lua_tolstring(L, lua_upvalueindex(1), &ls); const char *p = lua_tostring(L, lua_upvalueindex(2)); const char *src; ms.L = L; ms.src_init = s; ms.src_end = s+ls; - for (src = s + (size_t)lua_tonumber(L, lua_upvalueindex(3)); + for (src = s + (size_t)lua_tointeger(L, lua_upvalueindex(3)); src <= ms.src_end; src++) { const char *e; ms.level = 0; if ((e = match(&ms, src, p)) != NULL) { - int newstart = e-s; + lua_Integer newstart = e-s; if (e == src) newstart++; /* empty match? go at least one position */ - lua_pushnumber(L, (lua_Number)newstart); + lua_pushinteger(L, newstart); lua_replace(L, lua_upvalueindex(3)); return push_captures(&ms, src, e); } @@ -538,48 +570,77 @@ static int gfind_aux (lua_State *L) { } -static int gfind (lua_State *L) { +static int gmatch (lua_State *L) { luaL_checkstring(L, 1); luaL_checkstring(L, 2); lua_settop(L, 2); - lua_pushnumber(L, 0); - lua_pushcclosure(L, gfind_aux, 3); + lua_pushinteger(L, 0); + lua_pushcclosure(L, gmatch_aux, 3); return 1; } -static void add_s (MatchState *ms, luaL_Buffer *b, - const char *s, const char *e) { - lua_State *L = ms->L; - if (lua_isstring(L, 3)) { - const char *news = lua_tostring(L, 3); - size_t l = lua_strlen(L, 3); - size_t i; - for (i=0; i<l; i++) { - if (news[i] != ESC) - luaL_putchar(b, news[i]); +static int gfind_nodef (lua_State *L) { + return luaL_error(L, LUA_QL("string.gfind") " was renamed to " + LUA_QL("string.gmatch")); +} + + +static void add_s (MatchState *ms, luaL_Buffer *b, const char *s, + const char *e) { + size_t l, i; + const char *news = lua_tolstring(ms->L, 3, &l); + for (i = 0; i < l; i++) { + if (news[i] != L_ESC) + luaL_addchar(b, news[i]); + else { + i++; /* skip ESC */ + if (!isdigit(uchar(news[i]))) + luaL_addchar(b, news[i]); + else if (news[i] == '0') + luaL_addlstring(b, s, e - s); else { - i++; /* skip ESC */ - if (!isdigit(uchar(news[i]))) - luaL_putchar(b, news[i]); - else { - int level = check_capture(ms, news[i]); - push_onecapture(ms, level); - luaL_addvalue(b); /* add capture to accumulated result */ - } + push_onecapture(ms, news[i] - '1', s, e); + luaL_addvalue(b); /* add capture to accumulated result */ } } } - else { /* is a function */ - int n; - lua_pushvalue(L, 3); - n = push_captures(ms, s, e); - lua_call(L, n, 1); - if (lua_isstring(L, -1)) - luaL_addvalue(b); /* add return to accumulated result */ - else - lua_pop(L, 1); /* function result is not a string: pop it */ +} + + +static void add_value (MatchState *ms, luaL_Buffer *b, const char *s, + const char *e) { + lua_State *L = ms->L; + switch (lua_type(L, 3)) { + case LUA_TNUMBER: + case LUA_TSTRING: { + add_s(ms, b, s, e); + return; + } + case LUA_TFUNCTION: { + int n; + lua_pushvalue(L, 3); + n = push_captures(ms, s, e); + lua_call(L, n, 1); + break; + } + case LUA_TTABLE: { + push_onecapture(ms, 0, s, e); + lua_gettable(L, 3); + break; + } + default: { + luaL_argerror(L, 3, "string/function/table expected"); + return; + } } + if (!lua_toboolean(L, -1)) { /* nil or false? */ + lua_pop(L, 1); + lua_pushlstring(L, s, e - s); /* keep original text */ + } + else if (!lua_isstring(L, -1)) + luaL_error(L, "invalid replacement value (a %s)", luaL_typename(L, -1)); + luaL_addvalue(b); /* add result to accumulator */ } @@ -592,9 +653,6 @@ static int str_gsub (lua_State *L) { int n = 0; MatchState ms; luaL_Buffer b; - luaL_argcheck(L, - lua_gettop(L) >= 3 && (lua_isstring(L, 3) || lua_isfunction(L, 3)), - 3, "string or function expected"); luaL_buffinit(L, &b); ms.L = L; ms.src_init = src; @@ -605,18 +663,18 @@ static int str_gsub (lua_State *L) { e = match(&ms, src, p); if (e) { n++; - add_s(&ms, &b, src, e); + add_value(&ms, &b, src, e); } if (e && e>src) /* non empty match? */ src = e; /* skip it */ else if (src < ms.src_end) - luaL_putchar(&b, *src++); + luaL_addchar(&b, *src++); else break; if (anchor) break; } luaL_addlstring(&b, src, ms.src_end-src); luaL_pushresult(&b); - lua_pushnumber(L, (lua_Number)n); /* number of substitutions */ + lua_pushinteger(L, n); /* number of substitutions */ return 2; } @@ -625,19 +683,28 @@ static int str_gsub (lua_State *L) { /* maximum size of each formatted item (> len(format('%99.99f', -1e308))) */ #define MAX_ITEM 512 -/* maximum size of each format specification (such as '%-099.99d') */ -#define MAX_FORMAT 20 +/* valid flags in a format specification */ +#define FLAGS "-+ #0" +/* +** maximum size of each format specification (such as '%-099.99d') +** (+10 accounts for %99.99x plus margin of error) +*/ +#define MAX_FORMAT (sizeof(FLAGS) + sizeof(LUA_INTFRMLEN) + 10) -static void luaI_addquoted (lua_State *L, luaL_Buffer *b, int arg) { +static void addquoted (lua_State *L, luaL_Buffer *b, int arg) { size_t l; const char *s = luaL_checklstring(L, arg, &l); - luaL_putchar(b, '"'); + luaL_addchar(b, '"'); while (l--) { switch (*s) { case '"': case '\\': case '\n': { - luaL_putchar(b, '\\'); - luaL_putchar(b, *s); + luaL_addchar(b, '\\'); + luaL_addchar(b, *s); + break; + } + case '\r': { + luaL_addlstring(b, "\\r", 2); break; } case '\0': { @@ -645,39 +712,46 @@ static void luaI_addquoted (lua_State *L, luaL_Buffer *b, int arg) { break; } default: { - luaL_putchar(b, *s); + luaL_addchar(b, *s); break; } } s++; } - luaL_putchar(b, '"'); + luaL_addchar(b, '"'); } - -static const char *scanformat (lua_State *L, const char *strfrmt, - char *form, int *hasprecision) { +static const char *scanformat (lua_State *L, const char *strfrmt, char *form) { const char *p = strfrmt; - while (strchr("-+ #0", *p)) p++; /* skip flags */ + while (*p != '\0' && strchr(FLAGS, *p) != NULL) p++; /* skip flags */ + if ((size_t)(p - strfrmt) >= sizeof(FLAGS)) + luaL_error(L, "invalid format (repeated flags)"); if (isdigit(uchar(*p))) p++; /* skip width */ if (isdigit(uchar(*p))) p++; /* (2 digits at most) */ if (*p == '.') { p++; - *hasprecision = 1; if (isdigit(uchar(*p))) p++; /* skip precision */ if (isdigit(uchar(*p))) p++; /* (2 digits at most) */ } if (isdigit(uchar(*p))) luaL_error(L, "invalid format (width or precision too long)"); - if (p-strfrmt+2 > MAX_FORMAT) /* +2 to include `%' and the specifier */ - luaL_error(L, "invalid format (too long)"); - form[0] = '%'; - strncpy(form+1, strfrmt, p-strfrmt+1); - form[p-strfrmt+2] = 0; + *(form++) = '%'; + strncpy(form, strfrmt, p - strfrmt + 1); + form += p - strfrmt + 1; + *form = '\0'; return p; } +static void addintlen (char *form) { + size_t l = strlen(form); + char spec = form[l - 1]; + strcpy(form + l - 1, LUA_INTFRMLEN); + form[l + sizeof(LUA_INTFRMLEN) - 2] = spec; + form[l + sizeof(LUA_INTFRMLEN) - 1] = '\0'; +} + + static int str_format (lua_State *L) { int arg = 1; size_t sfl; @@ -686,40 +760,43 @@ static int str_format (lua_State *L) { luaL_Buffer b; luaL_buffinit(L, &b); while (strfrmt < strfrmt_end) { - if (*strfrmt != '%') - luaL_putchar(&b, *strfrmt++); - else if (*++strfrmt == '%') - luaL_putchar(&b, *strfrmt++); /* %% */ + if (*strfrmt != L_ESC) + luaL_addchar(&b, *strfrmt++); + else if (*++strfrmt == L_ESC) + luaL_addchar(&b, *strfrmt++); /* %% */ else { /* format item */ char form[MAX_FORMAT]; /* to store the format (`%...') */ char buff[MAX_ITEM]; /* to store the formatted item */ - int hasprecision = 0; - if (isdigit(uchar(*strfrmt)) && *(strfrmt+1) == '$') - return luaL_error(L, "obsolete option (d$) to `format'"); arg++; - strfrmt = scanformat(L, strfrmt, form, &hasprecision); + strfrmt = scanformat(L, strfrmt, form); switch (*strfrmt++) { - case 'c': case 'd': case 'i': { - sprintf(buff, form, luaL_checkint(L, arg)); + case 'c': { + sprintf(buff, form, (int)luaL_checknumber(L, arg)); + break; + } + case 'd': case 'i': { + addintlen(form); + sprintf(buff, form, (LUA_INTFRM_T)luaL_checknumber(L, arg)); break; } case 'o': case 'u': case 'x': case 'X': { - sprintf(buff, form, (unsigned int)(luaL_checknumber(L, arg))); + addintlen(form); + sprintf(buff, form, (unsigned LUA_INTFRM_T)luaL_checknumber(L, arg)); break; } case 'e': case 'E': case 'f': case 'g': case 'G': { - sprintf(buff, form, luaL_checknumber(L, arg)); + sprintf(buff, form, (double)luaL_checknumber(L, arg)); break; } case 'q': { - luaI_addquoted(L, &b, arg); - continue; /* skip the `addsize' at the end */ + addquoted(L, &b, arg); + continue; /* skip the 'addsize' at the end */ } case 's': { size_t l; const char *s = luaL_checklstring(L, arg, &l); - if (!hasprecision && l >= 100) { + if (!strchr(form, '.') && l >= 100) { /* no precision and string is too long to be formatted; keep original string */ lua_pushvalue(L, arg); @@ -732,7 +809,8 @@ static int str_format (lua_State *L) { } } default: { /* also treat cases `pnLlh' */ - return luaL_error(L, "invalid option to `format'"); + return luaL_error(L, "invalid option " LUA_QL("%%%c") " to " + LUA_QL("format"), *(strfrmt - 1)); } } luaL_addlstring(&b, buff, strlen(buff)); @@ -743,28 +821,48 @@ static int str_format (lua_State *L) { } -static const luaL_reg strlib[] = { - {"len", str_len}, - {"sub", str_sub}, - {"lower", str_lower}, - {"upper", str_upper}, - {"char", str_char}, - {"rep", str_rep}, +static const luaL_Reg strlib[] = { {"byte", str_byte}, - {"format", str_format}, + {"char", str_char}, {"dump", str_dump}, {"find", str_find}, - {"gfind", gfind}, + {"format", str_format}, + {"gfind", gfind_nodef}, + {"gmatch", gmatch}, {"gsub", str_gsub}, + {"len", str_len}, + {"lower", str_lower}, + {"match", str_match}, + {"rep", str_rep}, + {"reverse", str_reverse}, + {"sub", str_sub}, + {"upper", str_upper}, {NULL, NULL} }; +static void createmetatable (lua_State *L) { + lua_createtable(L, 0, 1); /* create metatable for strings */ + lua_pushliteral(L, ""); /* dummy string */ + lua_pushvalue(L, -2); + lua_setmetatable(L, -2); /* set string metatable */ + lua_pop(L, 1); /* pop dummy string */ + lua_pushvalue(L, -2); /* string library... */ + lua_setfield(L, -2, "__index"); /* ...is the __index metamethod */ + lua_pop(L, 1); /* pop metatable */ +} + + /* ** Open string library */ LUALIB_API int luaopen_string (lua_State *L) { - luaL_openlib(L, LUA_STRLIBNAME, strlib, 0); + luaL_register(L, LUA_STRLIBNAME, strlib); +#if defined(LUA_COMPAT_GFIND) + lua_getfield(L, -1, "gmatch"); + lua_setfield(L, -2, "gfind"); +#endif + createmetatable(L); return 1; } diff --git a/lib/lua/src/LuaLib/ltablib.c b/lib/lua/src/LuaLib/ltablib.c index 71f3afa..6bd11fb 100644 --- a/lib/lua/src/LuaLib/ltablib.c +++ b/lib/lua/src/LuaLib/ltablib.c @@ -1,5 +1,5 @@ /* -** $Id: ltablib.c,v 1.4 2004-11-27 21:46:10 pixel Exp $ +** $Id: ltablib.c,v 1.5 2007-07-27 10:05:55 pixel Exp $ ** Library for Table Manipulation ** See Copyright Notice in lua.h */ @@ -8,6 +8,7 @@ #include <stddef.h> #define ltablib_c +#define LUA_LIB #include "lua.h" @@ -18,13 +19,13 @@ #define aux_getn(L,n) (luaL_checktype(L, n, LUA_TTABLE), luaL_getn(L, n)) -static int luaB_foreachi (lua_State *L) { +static int foreachi (lua_State *L) { int i; int n = aux_getn(L, 1); luaL_checktype(L, 2, LUA_TFUNCTION); - for (i=1; i<=n; i++) { + for (i=1; i <= n; i++) { lua_pushvalue(L, 2); /* function */ - lua_pushnumber(L, (lua_Number)i); /* 1st argument */ + lua_pushinteger(L, i); /* 1st argument */ lua_rawgeti(L, 1, i); /* 2nd argument */ lua_call(L, 2, 1); if (!lua_isnil(L, -1)) @@ -35,13 +36,11 @@ static int luaB_foreachi (lua_State *L) { } -static int luaB_foreach (lua_State *L) { +static int foreach (lua_State *L) { luaL_checktype(L, 1, LUA_TTABLE); luaL_checktype(L, 2, LUA_TFUNCTION); lua_pushnil(L); /* first key */ - for (;;) { - if (lua_next(L, 1) == 0) - return 0; + while (lua_next(L, 1)) { lua_pushvalue(L, 2); /* function */ lua_pushvalue(L, -3); /* key */ lua_pushvalue(L, -3); /* value */ @@ -50,74 +49,102 @@ static int luaB_foreach (lua_State *L) { return 1; lua_pop(L, 2); /* remove value and result */ } + return 0; +} + + +static int maxn (lua_State *L) { + lua_Number max = 0; + luaL_checktype(L, 1, LUA_TTABLE); + lua_pushnil(L); /* first key */ + while (lua_next(L, 1)) { + lua_pop(L, 1); /* remove value */ + if (lua_type(L, -1) == LUA_TNUMBER) { + lua_Number v = lua_tonumber(L, -1); + if (v > max) max = v; + } + } + lua_pushnumber(L, max); + return 1; } -static int luaB_getn (lua_State *L) { - lua_pushnumber(L, (lua_Number)aux_getn(L, 1)); +static int getn (lua_State *L) { + lua_pushinteger(L, aux_getn(L, 1)); return 1; } -static int luaB_setn (lua_State *L) { +static int setn (lua_State *L) { luaL_checktype(L, 1, LUA_TTABLE); +#ifndef luaL_setn luaL_setn(L, 1, luaL_checkint(L, 2)); - return 0; +#else + luaL_error(L, LUA_QL("setn") " is obsolete"); +#endif + lua_pushvalue(L, 1); + return 1; } -static int luaB_tinsert (lua_State *L) { - int v = lua_gettop(L); /* number of arguments */ - int n = aux_getn(L, 1) + 1; +static int tinsert (lua_State *L) { + int e = aux_getn(L, 1) + 1; /* first empty element */ int pos; /* where to insert new element */ - if (v == 2) /* called with only 2 arguments */ - pos = n; /* insert new element at the end */ - else { - pos = luaL_checkint(L, 2); /* 2nd argument is the position */ - if (pos > n) n = pos; /* `grow' array if necessary */ - v = 3; /* function may be called with more than 3 args */ - } - luaL_setn(L, 1, n); /* new size */ - while (--n >= pos) { /* move up elements */ - lua_rawgeti(L, 1, n); - lua_rawseti(L, 1, n+1); /* t[n+1] = t[n] */ + switch (lua_gettop(L)) { + case 2: { /* called with only 2 arguments */ + pos = e; /* insert new element at the end */ + break; + } + case 3: { + int i; + pos = luaL_checkint(L, 2); /* 2nd argument is the position */ + if (pos > e) e = pos; /* `grow' array if necessary */ + for (i = e; i > pos; i--) { /* move up elements */ + lua_rawgeti(L, 1, i-1); + lua_rawseti(L, 1, i); /* t[i] = t[i-1] */ + } + break; + } + default: { + return luaL_error(L, "wrong number of arguments to " LUA_QL("insert")); + } } - lua_pushvalue(L, v); + luaL_setn(L, 1, e); /* new size */ lua_rawseti(L, 1, pos); /* t[pos] = v */ return 0; } -static int luaB_tremove (lua_State *L) { - int n = aux_getn(L, 1); - int pos = luaL_optint(L, 2, n); - if (n <= 0) return 0; /* table is `empty' */ - luaL_setn(L, 1, n-1); /* t.n = n-1 */ +static int tremove (lua_State *L) { + int e = aux_getn(L, 1); + int pos = luaL_optint(L, 2, e); + if (e == 0) return 0; /* table is `empty' */ + luaL_setn(L, 1, e - 1); /* t.n = n-1 */ lua_rawgeti(L, 1, pos); /* result = t[pos] */ - for ( ;pos<n; pos++) { + for ( ;pos<e; pos++) { lua_rawgeti(L, 1, pos+1); lua_rawseti(L, 1, pos); /* t[pos] = t[pos+1] */ } lua_pushnil(L); - lua_rawseti(L, 1, n); /* t[n] = nil */ + lua_rawseti(L, 1, e); /* t[e] = nil */ return 1; } -static int str_concat (lua_State *L) { +static int tconcat (lua_State *L) { luaL_Buffer b; size_t lsep; + int i, last; const char *sep = luaL_optlstring(L, 2, "", &lsep); - int i = luaL_optint(L, 3, 1); - int n = luaL_optint(L, 4, 0); luaL_checktype(L, 1, LUA_TTABLE); - if (n == 0) n = luaL_getn(L, 1); + i = luaL_optint(L, 3, 1); + last = luaL_opt(L, luaL_checkint, 4, luaL_getn(L, 1)); luaL_buffinit(L, &b); - for (; i <= n; i++) { + for (; i <= last; i++) { lua_rawgeti(L, 1, i); luaL_argcheck(L, lua_isstring(L, -1), 1, "table contains non-strings"); luaL_addvalue(&b); - if (i != n) + if (i != last) luaL_addlstring(&b, sep, lsep); } luaL_pushresult(&b); @@ -217,7 +244,7 @@ static void auxsort (lua_State *L, int l, int u) { } /* repeat the routine for the larger one */ } -static int luaB_sort (lua_State *L) { +static int sort (lua_State *L) { int n = aux_getn(L, 1); luaL_checkstack(L, 40, ""); /* assume array is smaller than 2^40 */ if (!lua_isnoneornil(L, 2)) /* is there a 2nd argument? */ @@ -230,21 +257,22 @@ static int luaB_sort (lua_State *L) { /* }====================================================== */ -static const luaL_reg tab_funcs[] = { - {"concat", str_concat}, - {"foreach", luaB_foreach}, - {"foreachi", luaB_foreachi}, - {"getn", luaB_getn}, - {"setn", luaB_setn}, - {"sort", luaB_sort}, - {"insert", luaB_tinsert}, - {"remove", luaB_tremove}, +static const luaL_Reg tab_funcs[] = { + {"concat", tconcat}, + {"foreach", foreach}, + {"foreachi", foreachi}, + {"getn", getn}, + {"maxn", maxn}, + {"insert", tinsert}, + {"remove", tremove}, + {"setn", setn}, + {"sort", sort}, {NULL, NULL} }; LUALIB_API int luaopen_table (lua_State *L) { - luaL_openlib(L, LUA_TABLIBNAME, tab_funcs, 0); + luaL_register(L, LUA_TABLIBNAME, tab_funcs); return 1; } diff --git a/lib/lua/src/lapi.c b/lib/lua/src/lapi.c index 7298b87..e456c8f 100644 --- a/lib/lua/src/lapi.c +++ b/lib/lua/src/lapi.c @@ -1,14 +1,17 @@ /* -** $Id: lapi.c,v 1.5 2007-07-25 16:54:32 pixel Exp $ +** $Id: lapi.c,v 1.6 2007-07-27 10:05:53 pixel Exp $ ** Lua API ** See Copyright Notice in lua.h */ #include <assert.h> +#include <math.h> +#include <stdarg.h> #include <string.h> #define lapi_c +#define LUA_CORE #include "lua.h" @@ -27,79 +30,72 @@ #include "lvm.h" + const char lua_ident[] = - "$Lua: " LUA_VERSION " " LUA_COPYRIGHT " $\n" + "$Lua: " LUA_RELEASE " " LUA_COPYRIGHT " $\n" "$Authors: " LUA_AUTHORS " $\n" "$URL: www.lua.org $\n"; -#ifndef api_check -#define api_check(L, o) /*{ assert(o); }*/ -#endif - #define api_checknelems(L, n) api_check(L, (n) <= (L->top - L->base)) -#define api_incr_top(L) {api_check(L, L->top < L->ci->top); L->top++;} +#define api_checkvalidindex(L, i) api_check(L, (i) != luaO_nilobject) +#define api_incr_top(L) {api_check(L, L->top < L->ci->top); L->top++;} -static TObject *negindex (lua_State *L, int idx) { - if (idx > LUA_REGISTRYINDEX) { +static TValue *index2adr (lua_State *L, int idx) { + if (idx > 0) { + TValue *o = L->base + (idx - 1); + api_check(L, idx <= L->ci->top - L->base); + if (o >= L->top) return cast(TValue *, luaO_nilobject); + else return o; + } + else if (idx > LUA_REGISTRYINDEX) { api_check(L, idx != 0 && -idx <= L->top - L->base); - return L->top+idx; + return L->top + idx; } else switch (idx) { /* pseudo-indices */ case LUA_REGISTRYINDEX: return registry(L); + case LUA_ENVIRONINDEX: { + Closure *func = curr_func(L); + sethvalue(L, &L->env, func->c.env); + return &L->env; + } case LUA_GLOBALSINDEX: return gt(L); default: { - TObject *func = (L->base - 1); + Closure *func = curr_func(L); idx = LUA_GLOBALSINDEX - idx; - lua_assert(iscfunction(func)); - return (idx <= clvalue(func)->c.nupvalues) - ? &clvalue(func)->c.upvalue[idx-1] - : NULL; + return (idx <= func->c.nupvalues) + ? &func->c.upvalue[idx-1] + : cast(TValue *, luaO_nilobject); } } } -static TObject *luaA_index (lua_State *L, int idx) { - if (idx > 0) { - api_check(L, idx <= L->top - L->base); - return L->base + idx - 1; - } +static Table *getcurrenv (lua_State *L) { + if (L->ci == L->base_ci) /* no enclosing function? */ + return hvalue(gt(L)); /* use global table as environment */ else { - TObject *o = negindex(L, idx); - api_check(L, o != NULL); - return o; + Closure *func = curr_func(L); + return func->c.env; } } -static TObject *luaA_indexAcceptable (lua_State *L, int idx) { - if (idx > 0) { - TObject *o = L->base+(idx-1); - api_check(L, idx <= L->stack_last - L->base); - if (o >= L->top) return NULL; - else return o; - } - else - return negindex(L, idx); -} - - -void luaA_pushobject (lua_State *L, const TObject *o) { - setobj2s(L->top, o); - incr_top(L); +void luaA_pushobject (lua_State *L, const TValue *o) { + setobj2s(L, L->top, o); + api_incr_top(L); } LUA_API int lua_checkstack (lua_State *L, int size) { int res; lua_lock(L); - if ((L->top - L->base + size) > LUA_MAXCSTACK) + if ((L->top - L->base + size) > LUAI_MAXCSTACK) res = 0; /* stack overflow */ else { luaD_checkstack(L, size); @@ -114,12 +110,14 @@ LUA_API int lua_checkstack (lua_State *L, int size) { LUA_API void lua_xmove (lua_State *from, lua_State *to, int n) { int i; + if (from == to) return; lua_lock(to); api_checknelems(from, n); + api_check(from, G(from) == G(to)); + api_check(from, to->ci->top - to->top >= n); from->top -= n; for (i = 0; i < n; i++) { - setobj2s(to->top, from->top + i); - api_incr_top(to); + setobj2s(to, to->top++, from->top + i); } lua_unlock(to); } @@ -140,10 +138,10 @@ LUA_API lua_State *lua_newthread (lua_State *L) { lua_lock(L); luaC_checkGC(L); L1 = luaE_newthread(L); - setthvalue(L->top, L1); + setthvalue(L, L->top, L1); api_incr_top(L); lua_unlock(L); - lua_userstateopen(L1); + luai_userstatethread(L, L1); return L1; } @@ -155,7 +153,7 @@ LUA_API lua_State *lua_newthread (lua_State *L) { LUA_API int lua_gettop (lua_State *L) { - return (L->top - L->base); + return cast_int(L->top - L->base); } @@ -178,8 +176,9 @@ LUA_API void lua_settop (lua_State *L, int idx) { LUA_API void lua_remove (lua_State *L, int idx) { StkId p; lua_lock(L); - p = luaA_index(L, idx); - while (++p < L->top) setobjs2s(p-1, p); + p = index2adr(L, idx); + api_checkvalidindex(L, p); + while (++p < L->top) setobjs2s(L, p-1, p); L->top--; lua_unlock(L); } @@ -189,17 +188,34 @@ LUA_API void lua_insert (lua_State *L, int idx) { StkId p; StkId q; lua_lock(L); - p = luaA_index(L, idx); - for (q = L->top; q>p; q--) setobjs2s(q, q-1); - setobjs2s(p, L->top); + p = index2adr(L, idx); + api_checkvalidindex(L, p); + for (q = L->top; q>p; q--) setobjs2s(L, q, q-1); + setobjs2s(L, p, L->top); lua_unlock(L); } LUA_API void lua_replace (lua_State *L, int idx) { + StkId o; lua_lock(L); + /* explicit test for incompatible code */ + if (idx == LUA_ENVIRONINDEX && L->ci == L->base_ci) + luaG_runerror(L, "no calling environment"); api_checknelems(L, 1); - setobj(luaA_index(L, idx), L->top - 1); /* write barrier */ + o = index2adr(L, idx); + api_checkvalidindex(L, o); + if (idx == LUA_ENVIRONINDEX) { + Closure *func = curr_func(L); + api_check(L, ttistable(L->top - 1)); + func->c.env = hvalue(L->top - 1); + luaC_barrier(L, func, L->top - 1); + } + else { + setobj(L, o, L->top - 1); + if (idx < LUA_GLOBALSINDEX) /* function upvalue? */ + luaC_barrier(L, curr_func(L), L->top - 1); + } L->top--; lua_unlock(L); } @@ -207,7 +223,7 @@ LUA_API void lua_replace (lua_State *L, int idx) { LUA_API void lua_pushvalue (lua_State *L, int idx) { lua_lock(L); - setobj2s(L->top, luaA_index(L, idx)); + setobj2s(L, L->top, index2adr(L, idx)); api_incr_top(L); lua_unlock(L); } @@ -220,8 +236,8 @@ LUA_API void lua_pushvalue (lua_State *L, int idx) { LUA_API int lua_type (lua_State *L, int idx) { - StkId o = luaA_indexAcceptable(L, idx); - return (o == NULL) ? LUA_TNONE : ttype(o); + StkId o = index2adr(L, idx); + return (o == luaO_nilobject) ? LUA_TNONE : ttype(o); } @@ -232,15 +248,15 @@ LUA_API const char *lua_typename (lua_State *L, int t) { LUA_API int lua_iscfunction (lua_State *L, int idx) { - StkId o = luaA_indexAcceptable(L, idx); - return (o == NULL) ? 0 : iscfunction(o); + StkId o = index2adr(L, idx); + return iscfunction(o); } LUA_API int lua_isnumber (lua_State *L, int idx) { - TObject n; - const TObject *o = luaA_indexAcceptable(L, idx); - return (o != NULL && tonumber(o, &n)); + TValue n; + const TValue *o = index2adr(L, idx); + return tonumber(o, &n); } @@ -251,16 +267,16 @@ LUA_API int lua_isstring (lua_State *L, int idx) { LUA_API int lua_isuserdata (lua_State *L, int idx) { - const TObject *o = luaA_indexAcceptable(L, idx); - return (o != NULL && (ttisuserdata(o) || ttislightuserdata(o))); + const TValue *o = index2adr(L, idx); + return (ttisuserdata(o) || ttislightuserdata(o)); } LUA_API int lua_rawequal (lua_State *L, int index1, int index2) { - StkId o1 = luaA_indexAcceptable(L, index1); - StkId o2 = luaA_indexAcceptable(L, index2); - return (o1 == NULL || o2 == NULL) ? 0 /* index out of range */ - : luaO_rawequalObj(o1, o2); + StkId o1 = index2adr(L, index1); + StkId o2 = index2adr(L, index2); + return (o1 == luaO_nilobject || o2 == luaO_nilobject) ? 0 + : luaO_rawequalObj(o1, o2); } @@ -268,10 +284,9 @@ LUA_API int lua_equal (lua_State *L, int index1, int index2) { StkId o1, o2; int i; lua_lock(L); /* may call tag method */ - o1 = luaA_indexAcceptable(L, index1); - o2 = luaA_indexAcceptable(L, index2); - i = (o1 == NULL || o2 == NULL) ? 0 /* index out of range */ - : equalobj(L, o1, o2); + o1 = index2adr(L, index1); + o2 = index2adr(L, index2); + i = (o1 == luaO_nilobject || o2 == luaO_nilobject) ? 0 : equalobj(L, o1, o2); lua_unlock(L); return i; } @@ -281,10 +296,10 @@ LUA_API int lua_lessthan (lua_State *L, int index1, int index2) { StkId o1, o2; int i; lua_lock(L); /* may call tag method */ - o1 = luaA_indexAcceptable(L, index1); - o2 = luaA_indexAcceptable(L, index2); - i = (o1 == NULL || o2 == NULL) ? 0 /* index out-of-range */ - : luaV_lessthan(L, o1, o2); + o1 = index2adr(L, index1); + o2 = index2adr(L, index2); + i = (o1 == luaO_nilobject || o2 == luaO_nilobject) ? 0 + : luaV_lessthan(L, o1, o2); lua_unlock(L); return i; } @@ -292,65 +307,81 @@ LUA_API int lua_lessthan (lua_State *L, int index1, int index2) { LUA_API lua_Number lua_tonumber (lua_State *L, int idx) { - TObject n; - const TObject *o = luaA_indexAcceptable(L, idx); - if (o != NULL && tonumber(o, &n)) + TValue n; + const TValue *o = index2adr(L, idx); + if (tonumber(o, &n)) return nvalue(o); else return 0; } +LUA_API lua_Integer lua_tointeger (lua_State *L, int idx) { + TValue n; + const TValue *o = index2adr(L, idx); + if (tonumber(o, &n)) { + lua_Integer res; + lua_Number num = nvalue(o); + lua_number2integer(res, num); + return res; + } + else + return 0; +} + + LUA_API int lua_toboolean (lua_State *L, int idx) { - const TObject *o = luaA_indexAcceptable(L, idx); - return (o != NULL) && !l_isfalse(o); + const TValue *o = index2adr(L, idx); + return !l_isfalse(o); } -LUA_API const char *lua_tostring (lua_State *L, int idx) { - StkId o = luaA_indexAcceptable(L, idx); - if (o == NULL) - return NULL; - else if (ttisstring(o)) - return svalue(o); - else { - const char *s; +LUA_API const char *lua_tolstring (lua_State *L, int idx, size_t *len) { + StkId o = index2adr(L, idx); + if (!ttisstring(o)) { lua_lock(L); /* `luaV_tostring' may create a new string */ - s = (luaV_tostring(L, o) ? svalue(o) : NULL); + if (!luaV_tostring(L, o)) { /* conversion failed? */ + if (len != NULL) *len = 0; + lua_unlock(L); + return NULL; + } luaC_checkGC(L); + o = index2adr(L, idx); /* previous call may reallocate the stack */ lua_unlock(L); - return s; } + if (len != NULL) *len = tsvalue(o)->len; + return svalue(o); } -LUA_API size_t lua_strlen (lua_State *L, int idx) { - StkId o = luaA_indexAcceptable(L, idx); - if (o == NULL) - return 0; - else if (ttisstring(o)) - return tsvalue(o)->tsv.len; - else { - size_t l; - lua_lock(L); /* `luaV_tostring' may create a new string */ - l = (luaV_tostring(L, o) ? tsvalue(o)->tsv.len : 0); - lua_unlock(L); - return l; +LUA_API size_t lua_objlen (lua_State *L, int idx) { + StkId o = index2adr(L, idx); + switch (ttype(o)) { + case LUA_TSTRING: return tsvalue(o)->len; + case LUA_TUSERDATA: return uvalue(o)->len; + case LUA_TTABLE: return luaH_getn(hvalue(o)); + case LUA_TNUMBER: { + size_t l; + lua_lock(L); /* `luaV_tostring' may create a new string */ + l = (luaV_tostring(L, o) ? tsvalue(o)->len : 0); + lua_unlock(L); + return l; + } + default: return 0; } } LUA_API lua_CFunction lua_tocfunction (lua_State *L, int idx) { - StkId o = luaA_indexAcceptable(L, idx); - return (o == NULL || !iscfunction(o)) ? NULL : clvalue(o)->c.f; + StkId o = index2adr(L, idx); + return (!iscfunction(o)) ? NULL : clvalue(o)->c.f; } LUA_API void *lua_touserdata (lua_State *L, int idx) { - StkId o = luaA_indexAcceptable(L, idx); - if (o == NULL) return NULL; + StkId o = index2adr(L, idx); switch (ttype(o)) { - case LUA_TUSERDATA: return (uvalue(o) + 1); + case LUA_TUSERDATA: return (rawuvalue(o) + 1); case LUA_TLIGHTUSERDATA: return pvalue(o); default: return NULL; } @@ -358,24 +389,21 @@ LUA_API void *lua_touserdata (lua_State *L, int idx) { LUA_API lua_State *lua_tothread (lua_State *L, int idx) { - StkId o = luaA_indexAcceptable(L, idx); - return (o == NULL || !ttisthread(o)) ? NULL : thvalue(o); + StkId o = index2adr(L, idx); + return (!ttisthread(o)) ? NULL : thvalue(o); } LUA_API const void *lua_topointer (lua_State *L, int idx) { - StkId o = luaA_indexAcceptable(L, idx); - if (o == NULL) return NULL; - else { - switch (ttype(o)) { - case LUA_TTABLE: return hvalue(o); - case LUA_TFUNCTION: return clvalue(o); - case LUA_TTHREAD: return thvalue(o); - case LUA_TUSERDATA: - case LUA_TLIGHTUSERDATA: - return lua_touserdata(L, idx); - default: return NULL; - } + StkId o = index2adr(L, idx); + switch (ttype(o)) { + case LUA_TTABLE: return hvalue(o); + case LUA_TFUNCTION: return clvalue(o); + case LUA_TTHREAD: return thvalue(o); + case LUA_TUSERDATA: + case LUA_TLIGHTUSERDATA: + return lua_touserdata(L, idx); + default: return NULL; } } @@ -402,10 +430,18 @@ LUA_API void lua_pushnumber (lua_State *L, lua_Number n) { } +LUA_API void lua_pushinteger (lua_State *L, lua_Integer n) { + lua_lock(L); + setnvalue(L->top, cast_num(n)); + api_incr_top(L); + lua_unlock(L); +} + + LUA_API void lua_pushlstring (lua_State *L, const char *s, size_t len) { lua_lock(L); luaC_checkGC(L); - setsvalue2s(L->top, luaS_newlstr(L, s, len)); + setsvalue2s(L, L->top, luaS_newlstr(L, s, len)); api_incr_top(L); lua_unlock(L); } @@ -448,12 +484,13 @@ LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) { lua_lock(L); luaC_checkGC(L); api_checknelems(L, n); - cl = luaF_newCclosure(L, n); + cl = luaF_newCclosure(L, n, getcurrenv(L)); cl->c.f = fn; L->top -= n; while (n--) - setobj2n(&cl->c.upvalue[n], L->top+n); - setclvalue(L->top, cl); + setobj2n(L, &cl->c.upvalue[n], L->top+n); + setclvalue(L, L->top, cl); + lua_assert(iswhite(obj2gco(cl))); api_incr_top(L); lua_unlock(L); } @@ -475,6 +512,15 @@ LUA_API void lua_pushlightuserdata (lua_State *L, void *p) { } +LUA_API int lua_pushthread (lua_State *L) { + lua_lock(L); + setthvalue(L, L->top, L); + api_incr_top(L); + lua_unlock(L); + return (G(L)->mainthread == L); +} + + /* ** get functions (Lua -> stack) @@ -484,8 +530,22 @@ LUA_API void lua_pushlightuserdata (lua_State *L, void *p) { LUA_API void lua_gettable (lua_State *L, int idx) { StkId t; lua_lock(L); - t = luaA_index(L, idx); - setobj2s(L->top - 1, luaV_gettable(L, t, L->top - 1, 0)); + t = index2adr(L, idx); + api_checkvalidindex(L, t); + luaV_gettable(L, t, L->top - 1, L->top - 1); + lua_unlock(L); +} + + +LUA_API void lua_getfield (lua_State *L, int idx, const char *k) { + StkId t; + TValue key; + lua_lock(L); + t = index2adr(L, idx); + api_checkvalidindex(L, t); + setsvalue(L, &key, luaS_new(L, k)); + luaV_gettable(L, t, &key, L->top); + api_incr_top(L); lua_unlock(L); } @@ -493,9 +553,9 @@ LUA_API void lua_gettable (lua_State *L, int idx) { LUA_API void lua_rawget (lua_State *L, int idx) { StkId t; lua_lock(L); - t = luaA_index(L, idx); + t = index2adr(L, idx); api_check(L, ttistable(t)); - setobj2s(L->top - 1, luaH_get(hvalue(t), L->top - 1)); + setobj2s(L, L->top - 1, luaH_get(hvalue(t), L->top - 1)); lua_unlock(L); } @@ -503,43 +563,44 @@ LUA_API void lua_rawget (lua_State *L, int idx) { LUA_API void lua_rawgeti (lua_State *L, int idx, int n) { StkId o; lua_lock(L); - o = luaA_index(L, idx); + o = index2adr(L, idx); api_check(L, ttistable(o)); - setobj2s(L->top, luaH_getnum(hvalue(o), n)); + setobj2s(L, L->top, luaH_getnum(hvalue(o), n)); api_incr_top(L); lua_unlock(L); } -LUA_API void lua_newtable (lua_State *L) { +LUA_API void lua_createtable (lua_State *L, int narray, int nrec) { lua_lock(L); luaC_checkGC(L); - sethvalue(L->top, luaH_new(L, 0, 0)); + sethvalue(L, L->top, luaH_new(L, narray, nrec)); api_incr_top(L); lua_unlock(L); } LUA_API int lua_getmetatable (lua_State *L, int objindex) { - const TObject *obj; + const TValue *obj; Table *mt = NULL; int res; lua_lock(L); - obj = luaA_indexAcceptable(L, objindex); - if (obj != NULL) { - switch (ttype(obj)) { - case LUA_TTABLE: - mt = hvalue(obj)->metatable; - break; - case LUA_TUSERDATA: - mt = uvalue(obj)->uv.metatable; - break; - } + obj = index2adr(L, objindex); + switch (ttype(obj)) { + case LUA_TTABLE: + mt = hvalue(obj)->metatable; + break; + case LUA_TUSERDATA: + mt = uvalue(obj)->metatable; + break; + default: + mt = G(L)->mt[ttype(obj)]; + break; } - if (mt == NULL || mt == hvalue(defaultmeta(L))) + if (mt == NULL) res = 0; else { - sethvalue(L->top, mt); + sethvalue(L, L->top, mt); api_incr_top(L); res = 1; } @@ -551,8 +612,22 @@ LUA_API int lua_getmetatable (lua_State *L, int objindex) { LUA_API void lua_getfenv (lua_State *L, int idx) { StkId o; lua_lock(L); - o = luaA_index(L, idx); - setobj2s(L->top, isLfunction(o) ? &clvalue(o)->l.g : gt(L)); + o = index2adr(L, idx); + api_checkvalidindex(L, o); + switch (ttype(o)) { + case LUA_TFUNCTION: + sethvalue(L, L->top, clvalue(o)->c.env); + break; + case LUA_TUSERDATA: + sethvalue(L, L->top, uvalue(o)->env); + break; + case LUA_TTHREAD: + setobj2s(L, L->top, gt(thvalue(o))); + break; + default: + setnilvalue(L->top); + break; + } api_incr_top(L); lua_unlock(L); } @@ -567,20 +642,36 @@ LUA_API void lua_settable (lua_State *L, int idx) { StkId t; lua_lock(L); api_checknelems(L, 2); - t = luaA_index(L, idx); + t = index2adr(L, idx); + api_checkvalidindex(L, t); luaV_settable(L, t, L->top - 2, L->top - 1); L->top -= 2; /* pop index and value */ lua_unlock(L); } +LUA_API void lua_setfield (lua_State *L, int idx, const char *k) { + StkId t; + TValue key; + lua_lock(L); + api_checknelems(L, 1); + t = index2adr(L, idx); + api_checkvalidindex(L, t); + setsvalue(L, &key, luaS_new(L, k)); + luaV_settable(L, t, &key, L->top - 1); + L->top--; /* pop value */ + lua_unlock(L); +} + + LUA_API void lua_rawset (lua_State *L, int idx) { StkId t; lua_lock(L); api_checknelems(L, 2); - t = luaA_index(L, idx); + t = index2adr(L, idx); api_check(L, ttistable(t)); - setobj2t(luaH_set(L, hvalue(t), L->top-2), L->top-1); /* write barrier */ + setobj2t(L, luaH_set(L, hvalue(t), L->top-2), L->top-1); + luaC_barriert(L, hvalue(t), L->top-1); L->top -= 2; lua_unlock(L); } @@ -590,54 +681,76 @@ LUA_API void lua_rawseti (lua_State *L, int idx, int n) { StkId o; lua_lock(L); api_checknelems(L, 1); - o = luaA_index(L, idx); + o = index2adr(L, idx); api_check(L, ttistable(o)); - setobj2t(luaH_setnum(L, hvalue(o), n), L->top-1); /* write barrier */ + setobj2t(L, luaH_setnum(L, hvalue(o), n), L->top-1); + luaC_barriert(L, hvalue(o), L->top-1); L->top--; lua_unlock(L); } LUA_API int lua_setmetatable (lua_State *L, int objindex) { - TObject *obj, *mt; - int res = 1; + TValue *obj; + Table *mt; lua_lock(L); api_checknelems(L, 1); - obj = luaA_index(L, objindex); - mt = (!ttisnil(L->top - 1)) ? L->top - 1 : defaultmeta(L); - api_check(L, ttistable(mt)); + obj = index2adr(L, objindex); + api_checkvalidindex(L, obj); + if (ttisnil(L->top - 1)) + mt = NULL; + else { + api_check(L, ttistable(L->top - 1)); + mt = hvalue(L->top - 1); + } switch (ttype(obj)) { case LUA_TTABLE: { - hvalue(obj)->metatable = hvalue(mt); /* write barrier */ + hvalue(obj)->metatable = mt; + if (mt) + luaC_objbarriert(L, hvalue(obj), mt); break; } case LUA_TUSERDATA: { - uvalue(obj)->uv.metatable = hvalue(mt); /* write barrier */ + uvalue(obj)->metatable = mt; + if (mt) + luaC_objbarrier(L, rawuvalue(obj), mt); break; } default: { - res = 0; /* cannot set */ + G(L)->mt[ttype(obj)] = mt; break; } } L->top--; lua_unlock(L); - return res; + return 1; } LUA_API int lua_setfenv (lua_State *L, int idx) { StkId o; - int res = 0; + int res = 1; lua_lock(L); api_checknelems(L, 1); - o = luaA_index(L, idx); - L->top--; - api_check(L, ttistable(L->top)); - if (isLfunction(o)) { - res = 1; - clvalue(o)->l.g = *(L->top); + o = index2adr(L, idx); + api_checkvalidindex(L, o); + api_check(L, ttistable(L->top - 1)); + switch (ttype(o)) { + case LUA_TFUNCTION: + clvalue(o)->c.env = hvalue(L->top - 1); + break; + case LUA_TUSERDATA: + uvalue(o)->env = hvalue(L->top - 1); + break; + case LUA_TTHREAD: + sethvalue(L, gt(thvalue(o)), hvalue(L->top - 1)); + break; + default: + res = 0; + break; } + luaC_objbarrier(L, gcvalue(o), hvalue(L->top - 1)); + L->top--; lua_unlock(L); return res; } @@ -647,12 +760,23 @@ LUA_API int lua_setfenv (lua_State *L, int idx) { ** `load' and `call' functions (run Lua code) */ + +#define adjustresults(L,nres) \ + { if (nres == LUA_MULTRET && L->top >= L->ci->top) L->ci->top = L->top; } + + +#define checkresults(L,na,nr) \ + api_check(L, (nr) == LUA_MULTRET || (L->ci->top - L->top >= (nr) - (na))) + + LUA_API void lua_call (lua_State *L, int nargs, int nresults) { StkId func; lua_lock(L); api_checknelems(L, nargs+1); + checkresults(L, nargs, nresults); func = L->top - (nargs+1); luaD_call(L, func, nresults); + adjustresults(L, nresults); lua_unlock(L); } @@ -679,10 +803,19 @@ LUA_API int lua_pcall (lua_State *L, int nargs, int nresults, int errfunc) { int status; ptrdiff_t func; lua_lock(L); - func = (errfunc == 0) ? 0 : savestack(L, luaA_index(L, errfunc)); + api_checknelems(L, nargs+1); + checkresults(L, nargs, nresults); + if (errfunc == 0) + func = 0; + else { + StkId o = index2adr(L, errfunc); + api_checkvalidindex(L, o); + func = savestack(L, o); + } c.func = L->top - (nargs+1); /* function to be called */ c.nresults = nresults; status = luaD_pcall(L, f_call, &c, savestack(L, c.func), func); + adjustresults(L, nresults); lua_unlock(L); return status; } @@ -700,12 +833,12 @@ struct CCallS { /* data to `f_Ccall' */ static void f_Ccall (lua_State *L, void *ud) { struct CCallS *c = cast(struct CCallS *, ud); Closure *cl; - cl = luaF_newCclosure(L, 0); + cl = luaF_newCclosure(L, 0, getcurrenv(L)); cl->c.f = c->func; - setclvalue(L->top, cl); /* push function */ - incr_top(L); + setclvalue(L, L->top, cl); /* push function */ + api_incr_top(L); setpvalue(L->top, c->ud); /* push only argument */ - incr_top(L); + api_incr_top(L); luaD_call(L, L->top - 2, 0); } @@ -722,72 +855,98 @@ LUA_API int lua_cpcall (lua_State *L, lua_CFunction func, void *ud) { } -LUA_API int lua_load (lua_State *L, lua_Chunkreader reader, void *data, +LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data, const char *chunkname) { ZIO z; int status; - int c; lua_lock(L); if (!chunkname) chunkname = "?"; - luaZ_init(&z, reader, data, chunkname); - c = luaZ_lookahead(&z); - status = luaD_protectedparser(L, &z, (c == LUA_SIGNATURE[0])); + luaZ_init(L, &z, reader, data); + status = luaD_protectedparser(L, &z, chunkname); lua_unlock(L); return status; } -LUA_API int lua_dump (lua_State *L, lua_Chunkwriter writer, void *data) { +LUA_API int lua_dump (lua_State *L, lua_Writer writer, void *data) { int status; - TObject *o; + TValue *o; lua_lock(L); api_checknelems(L, 1); o = L->top - 1; - if (isLfunction(o) && clvalue(o)->l.nupvalues == 0) { - luaU_dump(L, clvalue(o)->l.p, writer, data); - status = 1; - } + if (isLfunction(o)) + status = luaU_dump(L, clvalue(o)->l.p, writer, data, 0); else - status = 0; + status = 1; lua_unlock(L); return status; } -/* -** Garbage-collection functions -*/ +LUA_API int lua_status (lua_State *L) { + return L->status; +} -/* GC values are expressed in Kbytes: #bytes/2^10 */ -#define GCscalel(x) ((x)>>10) -#define GCscale(x) (cast(int, GCscalel(x))) -#define GCunscale(x) (cast(lu_mem, x)<<10) -LUA_API int lua_getgcthreshold (lua_State *L) { - int threshold; - lua_lock(L); - threshold = GCscale(G(L)->GCthreshold); - lua_unlock(L); - return threshold; -} +/* +** Garbage-collection function +*/ -LUA_API int lua_getgccount (lua_State *L) { - int count; +LUA_API int lua_gc (lua_State *L, int what, int data) { + int res = 0; + global_State *g; lua_lock(L); - count = GCscale(G(L)->nblocks); + g = G(L); + switch (what) { + case LUA_GCSTOP: { + g->GCthreshold = MAX_LUMEM; + break; + } + case LUA_GCRESTART: { + g->GCthreshold = g->totalbytes; + break; + } + case LUA_GCCOLLECT: { + luaC_fullgc(L); + break; + } + case LUA_GCCOUNT: { + /* GC values are expressed in Kbytes: #bytes/2^10 */ + res = cast_int(g->totalbytes >> 10); + break; + } + case LUA_GCCOUNTB: { + res = cast_int(g->totalbytes & 0x3ff); + break; + } + case LUA_GCSTEP: { + lu_mem a = (cast(lu_mem, data) << 10); + if (a <= g->totalbytes) + g->GCthreshold = g->totalbytes - a; + else + g->GCthreshold = 0; + while (g->GCthreshold <= g->totalbytes) + luaC_step(L); + if (g->gcstate == GCSpause) /* end of cycle? */ + res = 1; /* signal it */ + break; + } + case LUA_GCSETPAUSE: { + res = g->gcpause; + g->gcpause = data; + break; + } + case LUA_GCSETSTEPMUL: { + res = g->gcstepmul; + g->gcstepmul = data; + break; + } + default: res = -1; /* invalid option */ + } lua_unlock(L); - return count; + return res; } -LUA_API void lua_setgcthreshold (lua_State *L, int newthreshold) { - lua_lock(L); - if (cast(lu_mem, newthreshold) > GCscalel(MAX_LUMEM)) - G(L)->GCthreshold = MAX_LUMEM; - else - G(L)->GCthreshold = GCunscale(newthreshold); - luaC_checkGC(L); - lua_unlock(L); -} /* @@ -795,11 +954,6 @@ LUA_API void lua_setgcthreshold (lua_State *L, int newthreshold) { */ -LUA_API const char *lua_version (void) { - return LUA_VERSION; -} - - LUA_API int lua_error (lua_State *L) { lua_lock(L); api_checknelems(L, 1); @@ -813,7 +967,7 @@ LUA_API int lua_next (lua_State *L, int idx) { StkId t; int more; lua_lock(L); - t = luaA_index(L, idx); + t = index2adr(L, idx); api_check(L, ttistable(t)); more = luaH_next(L, hvalue(t), L->top - 1); if (more) { @@ -828,14 +982,14 @@ LUA_API int lua_next (lua_State *L, int idx) { LUA_API void lua_concat (lua_State *L, int n) { lua_lock(L); - luaC_checkGC(L); api_checknelems(L, n); if (n >= 2) { - luaV_concat(L, n, L->top - L->base - 1); + luaC_checkGC(L); + luaV_concat(L, n, cast_int(L->top - L->base) - 1); L->top -= (n-1); } else if (n == 0) { /* push empty string */ - setsvalue2s(L->top, luaS_newlstr(L, NULL, 0)); + setsvalue2s(L, L->top, luaS_newlstr(L, "", 0)); api_incr_top(L); } /* else n == 1; nothing to do */ @@ -843,39 +997,40 @@ LUA_API void lua_concat (lua_State *L, int n) { } +LUA_API lua_Alloc lua_getallocf (lua_State *L, void **ud) { + lua_Alloc f; + lua_lock(L); + if (ud) *ud = G(L)->ud; + f = G(L)->frealloc; + lua_unlock(L); + return f; +} + + +LUA_API void lua_setallocf (lua_State *L, lua_Alloc f, void *ud) { + lua_lock(L); + G(L)->ud = ud; + G(L)->frealloc = f; + lua_unlock(L); +} + + LUA_API void *lua_newuserdata (lua_State *L, size_t size) { Udata *u; lua_lock(L); luaC_checkGC(L); - u = luaS_newudata(L, size); - setuvalue(L->top, u); + u = luaS_newudata(L, size, getcurrenv(L)); + setuvalue(L, L->top, u); api_incr_top(L); lua_unlock(L); return u + 1; } -LUA_API int lua_pushupvalues (lua_State *L) { - Closure *func; - int n, i; - lua_lock(L); - api_check(L, iscfunction(L->base - 1)); - func = clvalue(L->base - 1); - n = func->c.nupvalues; - luaD_checkstack(L, n + LUA_MINSTACK); - for (i=0; i<n; i++) { - setobj2s(L->top, &func->c.upvalue[i]); - L->top++; - } - lua_unlock(L); - return n; -} -static const char *aux_upvalue (lua_State *L, int funcindex, int n, - TObject **val) { +static const char *aux_upvalue (StkId fi, int n, TValue **val) { Closure *f; - StkId fi = luaA_index(L, funcindex); if (!ttisfunction(fi)) return NULL; f = clvalue(fi); if (f->c.isC) { @@ -894,11 +1049,11 @@ static const char *aux_upvalue (lua_State *L, int funcindex, int n, LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n) { const char *name; - TObject *val; + TValue *val; lua_lock(L); - name = aux_upvalue(L, funcindex, n, &val); + name = aux_upvalue(index2adr(L, funcindex), n, &val); if (name) { - setobj2s(L->top, val); + setobj2s(L, L->top, val); api_incr_top(L); } lua_unlock(L); @@ -908,13 +1063,16 @@ LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n) { LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) { const char *name; - TObject *val; + TValue *val; + StkId fi; lua_lock(L); + fi = index2adr(L, funcindex); api_checknelems(L, 1); - name = aux_upvalue(L, funcindex, n, &val); + name = aux_upvalue(fi, n, &val); if (name) { L->top--; - setobj(val, L->top); /* write barrier */ + setobj(L, val, L->top); + luaC_barrier(L, clvalue(fi), L->top); } lua_unlock(L); return name; diff --git a/lib/lua/src/lcode.c b/lib/lua/src/lcode.c index f393e7c..acc7851 100644 --- a/lib/lua/src/lcode.c +++ b/lib/lua/src/lcode.c @@ -1,5 +1,5 @@ /* -** $Id: lcode.c,v 1.5 2007-07-25 16:54:32 pixel Exp $ +** $Id: lcode.c,v 1.6 2007-07-27 10:05:53 pixel Exp $ ** Code generator for Lua ** See Copyright Notice in lua.h */ @@ -8,12 +8,14 @@ #include <stdlib.h> #define lcode_c +#define LUA_CORE #include "lua.h" #include "lcode.h" #include "ldebug.h" #include "ldo.h" +#include "lgc.h" #include "llex.h" #include "lmem.h" #include "lobject.h" @@ -25,16 +27,29 @@ #define hasjumps(e) ((e)->t != (e)->f) +static int isnumeral(expdesc *e) { + return (e->k == VKNUM && e->t == NO_JUMP && e->f == NO_JUMP); +} + + void luaK_nil (FuncState *fs, int from, int n) { Instruction *previous; - if (fs->pc > fs->lasttarget && /* no jumps to current position? */ - GET_OPCODE(*(previous = &fs->f->code[fs->pc-1])) == OP_LOADNIL) { - int pfrom = GETARG_A(*previous); - int pto = GETARG_B(*previous); - if (pfrom <= from && from <= pto+1) { /* can connect both? */ - if (from+n-1 > pto) - SETARG_B(*previous, from+n-1); - return; + if (fs->pc > fs->lasttarget) { /* no jumps to current position? */ + if (fs->pc == 0) { /* function start? */ + if (from >= fs->nactvar) + return; /* positions are already clean */ + } + else { + previous = &fs->f->code[fs->pc-1]; + if (GET_OPCODE(*previous) == OP_LOADNIL) { + int pfrom = GETARG_A(*previous); + int pto = GETARG_B(*previous); + if (pfrom <= from && from <= pto+1) { /* can connect both? */ + if (from+n-1 > pto) + SETARG_B(*previous, from+n-1); + return; + } + } } } luaK_codeABC(fs, OP_LOADNIL, from, from+n-1, 0); /* else no optimization */ @@ -51,13 +66,18 @@ int luaK_jump (FuncState *fs) { } -static int luaK_condjump (FuncState *fs, OpCode op, int A, int B, int C) { +void luaK_ret (FuncState *fs, int first, int nret) { + luaK_codeABC(fs, OP_RETURN, first, nret+1, 0); +} + + +static int condjump (FuncState *fs, OpCode op, int A, int B, int C) { luaK_codeABC(fs, op, A, B, C); return luaK_jump(fs); } -static void luaK_fixjump (FuncState *fs, int pc, int dest) { +static void fixjump (FuncState *fs, int pc, int dest) { Instruction *jmp = &fs->f->code[pc]; int offset = dest-(pc+1); lua_assert(dest != NO_JUMP); @@ -77,7 +97,7 @@ int luaK_getlabel (FuncState *fs) { } -static int luaK_getjump (FuncState *fs, int pc) { +static int getjump (FuncState *fs, int pc) { int offset = GETARG_sBx(fs->f->code[pc]); if (offset == NO_JUMP) /* point to itself represents end of list */ return NO_JUMP; /* end of list */ @@ -88,7 +108,7 @@ static int luaK_getjump (FuncState *fs, int pc) { static Instruction *getjumpcontrol (FuncState *fs, int pc) { Instruction *pi = &fs->f->code[pc]; - if (pc >= 1 && testOpMode(GET_OPCODE(*(pi-1)), OpModeT)) + if (pc >= 1 && testTMode(GET_OPCODE(*(pi-1)))) return pi-1; else return pi; @@ -99,51 +119,49 @@ static Instruction *getjumpcontrol (FuncState *fs, int pc) { ** check whether list has any jump that do not produce a value ** (or produce an inverted value) */ -static int need_value (FuncState *fs, int list, int cond) { - for (; list != NO_JUMP; list = luaK_getjump(fs, list)) { +static int need_value (FuncState *fs, int list) { + for (; list != NO_JUMP; list = getjump(fs, list)) { Instruction i = *getjumpcontrol(fs, list); - if (GET_OPCODE(i) != OP_TEST || - GETARG_A(i) != NO_REG || - GETARG_C(i) != cond) - return 1; + if (GET_OPCODE(i) != OP_TESTSET) return 1; } return 0; /* not found */ } -static void patchtestreg (Instruction *i, int reg) { - if (reg == NO_REG) reg = GETARG_B(*i); - SETARG_A(*i, reg); +static int patchtestreg (FuncState *fs, int node, int reg) { + Instruction *i = getjumpcontrol(fs, node); + if (GET_OPCODE(*i) != OP_TESTSET) + return 0; /* cannot patch other instructions */ + if (reg != NO_REG && reg != GETARG_B(*i)) + SETARG_A(*i, reg); + else /* no register to put value or register already has the value */ + *i = CREATE_ABC(OP_TEST, GETARG_B(*i), 0, GETARG_C(*i)); + + return 1; } static void removevalues (FuncState *fs, int list) { - for (; list != NO_JUMP; list = luaK_getjump(fs, list)) { - Instruction *i = getjumpcontrol(fs, list); - if (GET_OPCODE(*i) == OP_TEST) - patchtestreg(i, NO_REG); - } + for (; list != NO_JUMP; list = getjump(fs, list)) + patchtestreg(fs, list, NO_REG); } -static void luaK_patchlistaux (FuncState *fs, int list, int vtarget, int reg, - int dtarget) { +static void patchlistaux (FuncState *fs, int list, int vtarget, int reg, + int dtarget) { while (list != NO_JUMP) { - int next = luaK_getjump(fs, list); - Instruction *i = getjumpcontrol(fs, list); - if (GET_OPCODE(*i) == OP_TEST && GETARG_A(*i) == NO_REG) { - patchtestreg(i, reg); - luaK_fixjump(fs, list, vtarget); - } + int next = getjump(fs, list); + if (patchtestreg(fs, list, reg)) + fixjump(fs, list, vtarget); else - luaK_fixjump(fs, list, dtarget); /* jump to default target */ + fixjump(fs, list, dtarget); /* jump to default target */ list = next; } } -static void luaK_dischargejpc (FuncState *fs) { - luaK_patchlistaux(fs, fs->jpc, fs->pc, NO_REG, fs->pc); +static void dischargejpc (FuncState *fs) { + patchlistaux(fs, fs->jpc, fs->pc, NO_REG, fs->pc); fs->jpc = NO_JUMP; } @@ -153,7 +171,7 @@ void luaK_patchlist (FuncState *fs, int list, int target) { luaK_patchtohere(fs, list); else { lua_assert(target < fs->pc); - luaK_patchlistaux(fs, list, target, NO_REG, target); + patchlistaux(fs, list, target, NO_REG, target); } } @@ -171,9 +189,9 @@ void luaK_concat (FuncState *fs, int *l1, int l2) { else { int list = *l1; int next; - while ((next = luaK_getjump(fs, list)) != NO_JUMP) /* find last element */ + while ((next = getjump(fs, list)) != NO_JUMP) /* find last element */ list = next; - luaK_fixjump(fs, list, l2); + fixjump(fs, list, l2); } } @@ -183,7 +201,7 @@ void luaK_checkstack (FuncState *fs, int n) { if (newstack > fs->f->maxstacksize) { if (newstack >= MAXSTACK) luaX_syntaxerror(fs->ls, "function or expression too complex"); - fs->f->maxstacksize = cast(lu_byte, newstack); + fs->f->maxstacksize = cast_byte(newstack); } } @@ -195,7 +213,7 @@ void luaK_reserveregs (FuncState *fs, int n) { static void freereg (FuncState *fs, int reg) { - if (reg >= fs->nactvar && reg < MAXSTACK) { + if (!ISK(reg) && reg >= fs->nactvar) { fs->freereg--; lua_assert(reg == fs->freereg); } @@ -204,56 +222,81 @@ static void freereg (FuncState *fs, int reg) { static void freeexp (FuncState *fs, expdesc *e) { if (e->k == VNONRELOC) - freereg(fs, e->info); + freereg(fs, e->u.s.info); } -static int addk (FuncState *fs, TObject *k, TObject *v) { - const TObject *idx = luaH_get(fs->h, k); +static int addk (FuncState *fs, TValue *k, TValue *v) { + lua_State *L = fs->L; + TValue *idx = luaH_set(L, fs->h, k); + Proto *f = fs->f; + int oldsize = f->sizek; if (ttisnumber(idx)) { - lua_assert(luaO_rawequalObj(&fs->f->k[cast(int, nvalue(idx))], v)); - return cast(int, nvalue(idx)); + lua_assert(luaO_rawequalObj(&fs->f->k[cast_int(nvalue(idx))], v)); + return cast_int(nvalue(idx)); } else { /* constant not found; create a new entry */ - Proto *f = fs->f; - luaM_growvector(fs->L, f->k, fs->nk, f->sizek, TObject, + setnvalue(idx, cast_num(fs->nk)); + luaM_growvector(L, f->k, fs->nk, f->sizek, TValue, MAXARG_Bx, "constant table overflow"); - setobj2n(&f->k[fs->nk], v); - setnvalue(luaH_set(fs->L, fs->h, k), cast(lua_Number, fs->nk)); + while (oldsize < f->sizek) setnilvalue(&f->k[oldsize++]); + setobj(L, &f->k[fs->nk], v); + luaC_barrier(L, f, v); return fs->nk++; } } int luaK_stringK (FuncState *fs, TString *s) { - TObject o; - setsvalue(&o, s); + TValue o; + setsvalue(fs->L, &o, s); return addk(fs, &o, &o); } int luaK_numberK (FuncState *fs, lua_Number r) { - TObject o; + TValue o; setnvalue(&o, r); return addk(fs, &o, &o); } -static int nil_constant (FuncState *fs) { - TObject k, v; +static int boolK (FuncState *fs, int b) { + TValue o; + setbvalue(&o, b); + return addk(fs, &o, &o); +} + + +static int nilK (FuncState *fs) { + TValue k, v; setnilvalue(&v); - sethvalue(&k, fs->h); /* cannot use nil as key; instead use table itself */ + /* cannot use nil as key; instead use table itself to represent nil */ + sethvalue(fs->L, &k, fs->h); return addk(fs, &k, &v); } -void luaK_setcallreturns (FuncState *fs, expdesc *e, int nresults) { +void luaK_setreturns (FuncState *fs, expdesc *e, int nresults) { if (e->k == VCALL) { /* expression is an open function call? */ SETARG_C(getcode(fs, e), nresults+1); - if (nresults == 1) { /* `regular' expression? */ - e->k = VNONRELOC; - e->info = GETARG_A(getcode(fs, e)); - } + } + else if (e->k == VVARARG) { + SETARG_B(getcode(fs, e), nresults+1); + SETARG_A(getcode(fs, e), fs->freereg); + luaK_reserveregs(fs, 1); + } +} + + +void luaK_setoneret (FuncState *fs, expdesc *e) { + if (e->k == VCALL) { /* expression is an open function call? */ + e->k = VNONRELOC; + e->u.s.info = GETARG_A(getcode(fs, e)); + } + else if (e->k == VVARARG) { + SETARG_B(getcode(fs, e), 2); + e->k = VRELOCABLE; /* can relocate its simple result */ } } @@ -265,24 +308,25 @@ void luaK_dischargevars (FuncState *fs, expdesc *e) { break; } case VUPVAL: { - e->info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->info, 0); + e->u.s.info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->u.s.info, 0); e->k = VRELOCABLE; break; } case VGLOBAL: { - e->info = luaK_codeABx(fs, OP_GETGLOBAL, 0, e->info); + e->u.s.info = luaK_codeABx(fs, OP_GETGLOBAL, 0, e->u.s.info); e->k = VRELOCABLE; break; } case VINDEXED: { - freereg(fs, e->aux); - freereg(fs, e->info); - e->info = luaK_codeABC(fs, OP_GETTABLE, 0, e->info, e->aux); + freereg(fs, e->u.s.aux); + freereg(fs, e->u.s.info); + e->u.s.info = luaK_codeABC(fs, OP_GETTABLE, 0, e->u.s.info, e->u.s.aux); e->k = VRELOCABLE; break; } + case VVARARG: case VCALL: { - luaK_setcallreturns(fs, e, 1); + luaK_setoneret(fs, e); break; } default: break; /* there is one value available (somewhere) */ @@ -308,7 +352,11 @@ static void discharge2reg (FuncState *fs, expdesc *e, int reg) { break; } case VK: { - luaK_codeABx(fs, OP_LOADK, reg, e->info); + luaK_codeABx(fs, OP_LOADK, reg, e->u.s.info); + break; + } + case VKNUM: { + luaK_codeABx(fs, OP_LOADK, reg, luaK_numberK(fs, e->u.nval)); break; } case VRELOCABLE: { @@ -317,8 +365,8 @@ static void discharge2reg (FuncState *fs, expdesc *e, int reg) { break; } case VNONRELOC: { - if (reg != e->info) - luaK_codeABC(fs, OP_MOVE, reg, e->info, 0); + if (reg != e->u.s.info) + luaK_codeABC(fs, OP_MOVE, reg, e->u.s.info, 0); break; } default: { @@ -326,7 +374,7 @@ static void discharge2reg (FuncState *fs, expdesc *e, int reg) { return; /* nothing to do... */ } } - e->info = reg; + e->u.s.info = reg; e->k = VNONRELOC; } @@ -339,28 +387,26 @@ static void discharge2anyreg (FuncState *fs, expdesc *e) { } -static void luaK_exp2reg (FuncState *fs, expdesc *e, int reg) { +static void exp2reg (FuncState *fs, expdesc *e, int reg) { discharge2reg(fs, e, reg); if (e->k == VJMP) - luaK_concat(fs, &e->t, e->info); /* put this jump in `t' list */ + luaK_concat(fs, &e->t, e->u.s.info); /* put this jump in `t' list */ if (hasjumps(e)) { int final; /* position after whole expression */ int p_f = NO_JUMP; /* position of an eventual LOAD false */ int p_t = NO_JUMP; /* position of an eventual LOAD true */ - if (need_value(fs, e->t, 1) || need_value(fs, e->f, 0)) { - int fj = NO_JUMP; /* first jump (over LOAD ops.) */ - if (e->k != VJMP) - fj = luaK_jump(fs); + if (need_value(fs, e->t) || need_value(fs, e->f)) { + int fj = (e->k == VJMP) ? NO_JUMP : luaK_jump(fs); p_f = code_label(fs, reg, 0, 1); p_t = code_label(fs, reg, 1, 0); luaK_patchtohere(fs, fj); } final = luaK_getlabel(fs); - luaK_patchlistaux(fs, e->f, final, reg, p_f); - luaK_patchlistaux(fs, e->t, final, reg, p_t); + patchlistaux(fs, e->f, final, reg, p_f); + patchlistaux(fs, e->t, final, reg, p_t); } e->f = e->t = NO_JUMP; - e->info = reg; + e->u.s.info = reg; e->k = VNONRELOC; } @@ -369,21 +415,21 @@ void luaK_exp2nextreg (FuncState *fs, expdesc *e) { luaK_dischargevars(fs, e); freeexp(fs, e); luaK_reserveregs(fs, 1); - luaK_exp2reg(fs, e, fs->freereg - 1); + exp2reg(fs, e, fs->freereg - 1); } int luaK_exp2anyreg (FuncState *fs, expdesc *e) { luaK_dischargevars(fs, e); if (e->k == VNONRELOC) { - if (!hasjumps(e)) return e->info; /* exp is already in a register */ - if (e->info >= fs->nactvar) { /* reg. is not a local? */ - luaK_exp2reg(fs, e, e->info); /* put value on it */ - return e->info; + if (!hasjumps(e)) return e->u.s.info; /* exp is already in a register */ + if (e->u.s.info >= fs->nactvar) { /* reg. is not a local? */ + exp2reg(fs, e, e->u.s.info); /* put value on it */ + return e->u.s.info; } } luaK_exp2nextreg(fs, e); /* default */ - return e->info; + return e->u.s.info; } @@ -398,17 +444,22 @@ void luaK_exp2val (FuncState *fs, expdesc *e) { int luaK_exp2RK (FuncState *fs, expdesc *e) { luaK_exp2val(fs, e); switch (e->k) { + case VKNUM: + case VTRUE: + case VFALSE: case VNIL: { - if (fs->nk + MAXSTACK <= MAXARG_C) { /* constant fit in argC? */ - e->info = nil_constant(fs); + if (fs->nk <= MAXINDEXRK) { /* constant fit in RK operand? */ + e->u.s.info = (e->k == VNIL) ? nilK(fs) : + (e->k == VKNUM) ? luaK_numberK(fs, e->u.nval) : + boolK(fs, (e->k == VTRUE)); e->k = VK; - return e->info + MAXSTACK; + return RKASK(e->u.s.info); } else break; } case VK: { - if (e->info + MAXSTACK <= MAXARG_C) /* constant fit in argC? */ - return e->info + MAXSTACK; + if (e->u.s.info <= MAXINDEXRK) /* constant fit in argC? */ + return RKASK(e->u.s.info); else break; } default: break; @@ -418,26 +469,26 @@ int luaK_exp2RK (FuncState *fs, expdesc *e) { } -void luaK_storevar (FuncState *fs, expdesc *var, expdesc *exp) { +void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) { switch (var->k) { case VLOCAL: { - freeexp(fs, exp); - luaK_exp2reg(fs, exp, var->info); + freeexp(fs, ex); + exp2reg(fs, ex, var->u.s.info); return; } case VUPVAL: { - int e = luaK_exp2anyreg(fs, exp); - luaK_codeABC(fs, OP_SETUPVAL, e, var->info, 0); + int e = luaK_exp2anyreg(fs, ex); + luaK_codeABC(fs, OP_SETUPVAL, e, var->u.s.info, 0); break; } case VGLOBAL: { - int e = luaK_exp2anyreg(fs, exp); - luaK_codeABx(fs, OP_SETGLOBAL, e, var->info); + int e = luaK_exp2anyreg(fs, ex); + luaK_codeABx(fs, OP_SETGLOBAL, e, var->u.s.info); break; } case VINDEXED: { - int e = luaK_exp2RK(fs, exp); - luaK_codeABC(fs, OP_SETTABLE, var->info, var->aux, e); + int e = luaK_exp2RK(fs, ex); + luaK_codeABC(fs, OP_SETTABLE, var->u.s.info, var->u.s.aux, e); break; } default: { @@ -445,7 +496,7 @@ void luaK_storevar (FuncState *fs, expdesc *var, expdesc *exp) { break; } } - freeexp(fs, exp); + freeexp(fs, ex); } @@ -455,17 +506,17 @@ void luaK_self (FuncState *fs, expdesc *e, expdesc *key) { freeexp(fs, e); func = fs->freereg; luaK_reserveregs(fs, 2); - luaK_codeABC(fs, OP_SELF, func, e->info, luaK_exp2RK(fs, key)); + luaK_codeABC(fs, OP_SELF, func, e->u.s.info, luaK_exp2RK(fs, key)); freeexp(fs, key); - e->info = func; + e->u.s.info = func; e->k = VNONRELOC; } static void invertjump (FuncState *fs, expdesc *e) { - Instruction *pc = getjumpcontrol(fs, e->info); - lua_assert(testOpMode(GET_OPCODE(*pc), OpModeT) && - GET_OPCODE(*pc) != OP_TEST); + Instruction *pc = getjumpcontrol(fs, e->u.s.info); + lua_assert(testTMode(GET_OPCODE(*pc)) && GET_OPCODE(*pc) != OP_TESTSET && + GET_OPCODE(*pc) != OP_TEST); SETARG_A(*pc, !(GETARG_A(*pc))); } @@ -475,13 +526,13 @@ static int jumponcond (FuncState *fs, expdesc *e, int cond) { Instruction ie = getcode(fs, e); if (GET_OPCODE(ie) == OP_NOT) { fs->pc--; /* remove previous OP_NOT */ - return luaK_condjump(fs, OP_TEST, GETARG_B(ie), GETARG_B(ie), !cond); + return condjump(fs, OP_TEST, GETARG_B(ie), 0, !cond); } /* else go through */ } discharge2anyreg(fs, e); freeexp(fs, e); - return luaK_condjump(fs, OP_TEST, NO_REG, e->info, cond); + return condjump(fs, OP_TESTSET, NO_REG, e->u.s.info, cond); } @@ -489,7 +540,7 @@ void luaK_goiftrue (FuncState *fs, expdesc *e) { int pc; /* pc of last jump */ luaK_dischargevars(fs, e); switch (e->k) { - case VK: case VTRUE: { + case VK: case VKNUM: case VTRUE: { pc = NO_JUMP; /* always true; do nothing */ break; } @@ -499,7 +550,7 @@ void luaK_goiftrue (FuncState *fs, expdesc *e) { } case VJMP: { invertjump(fs, e); - pc = e->info; + pc = e->u.s.info; break; } default: { @@ -508,10 +559,12 @@ void luaK_goiftrue (FuncState *fs, expdesc *e) { } } luaK_concat(fs, &e->f, pc); /* insert last jump in `f' list */ + luaK_patchtohere(fs, e->t); + e->t = NO_JUMP; } -void luaK_goiffalse (FuncState *fs, expdesc *e) { +static void luaK_goiffalse (FuncState *fs, expdesc *e) { int pc; /* pc of last jump */ luaK_dischargevars(fs, e); switch (e->k) { @@ -524,7 +577,7 @@ void luaK_goiffalse (FuncState *fs, expdesc *e) { break; } case VJMP: { - pc = e->info; + pc = e->u.s.info; break; } default: { @@ -533,6 +586,8 @@ void luaK_goiffalse (FuncState *fs, expdesc *e) { } } luaK_concat(fs, &e->t, pc); /* insert last jump in `t' list */ + luaK_patchtohere(fs, e->f); + e->f = NO_JUMP; } @@ -543,7 +598,7 @@ static void codenot (FuncState *fs, expdesc *e) { e->k = VTRUE; break; } - case VK: case VTRUE: { + case VK: case VKNUM: case VTRUE: { e->k = VFALSE; break; } @@ -555,7 +610,7 @@ static void codenot (FuncState *fs, expdesc *e) { case VNONRELOC: { discharge2anyreg(fs, e); freeexp(fs, e); - e->info = luaK_codeABC(fs, OP_NOT, 0, e->info, 0); + e->u.s.info = luaK_codeABC(fs, OP_NOT, 0, e->u.s.info, 0); e->k = VRELOCABLE; break; } @@ -572,25 +627,91 @@ static void codenot (FuncState *fs, expdesc *e) { void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) { - t->aux = luaK_exp2RK(fs, k); + t->u.s.aux = luaK_exp2RK(fs, k); t->k = VINDEXED; } -void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e) { - if (op == OPR_MINUS) { - luaK_exp2val(fs, e); - if (e->k == VK && ttisnumber(&fs->f->k[e->info])) - e->info = luaK_numberK(fs, -nvalue(&fs->f->k[e->info])); +static int constfolding (OpCode op, expdesc *e1, expdesc *e2) { + lua_Number v1, v2, r; + if (!isnumeral(e1) || !isnumeral(e2)) return 0; + v1 = e1->u.nval; + v2 = e2->u.nval; + switch (op) { + case OP_ADD: r = luai_numadd(v1, v2); break; + case OP_SUB: r = luai_numsub(v1, v2); break; + case OP_MUL: r = luai_nummul(v1, v2); break; + case OP_DIV: + if (v2 == 0) return 0; /* do not attempt to divide by 0 */ + r = luai_numdiv(v1, v2); break; + case OP_MOD: + if (v2 == 0) return 0; /* do not attempt to divide by 0 */ + r = luai_nummod(v1, v2); break; + case OP_POW: r = luai_numpow(v1, v2); break; + case OP_UNM: r = luai_numunm(v1); break; + case OP_LEN: return 0; /* no constant folding for 'len' */ + default: lua_assert(0); r = 0; break; + } + if (luai_numisnan(r)) return 0; /* do not attempt to produce NaN */ + e1->u.nval = r; + return 1; +} + + +static void codearith (FuncState *fs, OpCode op, expdesc *e1, expdesc *e2) { + if (constfolding(op, e1, e2)) + return; + else { + int o2 = (op != OP_UNM && op != OP_LEN) ? luaK_exp2RK(fs, e2) : 0; + int o1 = luaK_exp2RK(fs, e1); + if (o1 > o2) { + freeexp(fs, e1); + freeexp(fs, e2); + } else { - luaK_exp2anyreg(fs, e); - freeexp(fs, e); - e->info = luaK_codeABC(fs, OP_UNM, 0, e->info, 0); - e->k = VRELOCABLE; + freeexp(fs, e2); + freeexp(fs, e1); } + e1->u.s.info = luaK_codeABC(fs, op, 0, o1, o2); + e1->k = VRELOCABLE; + } +} + + +static void codecomp (FuncState *fs, OpCode op, int cond, expdesc *e1, + expdesc *e2) { + int o1 = luaK_exp2RK(fs, e1); + int o2 = luaK_exp2RK(fs, e2); + freeexp(fs, e2); + freeexp(fs, e1); + if (cond == 0 && op != OP_EQ) { + int temp; /* exchange args to replace by `<' or `<=' */ + temp = o1; o1 = o2; o2 = temp; /* o1 <==> o2 */ + cond = 1; + } + e1->u.s.info = condjump(fs, op, cond, o1, o2); + e1->k = VJMP; +} + + +void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e) { + expdesc e2; + e2.t = e2.f = NO_JUMP; e2.k = VKNUM; e2.u.nval = 0; + switch (op) { + case OPR_MINUS: { + if (e->k == VK) + luaK_exp2anyreg(fs, e); /* cannot operate on non-numeric constants */ + codearith(fs, OP_UNM, e, &e2); + break; + } + case OPR_NOT: codenot(fs, e); break; + case OPR_LEN: { + luaK_exp2anyreg(fs, e); /* cannot operate on constants */ + codearith(fs, OP_LEN, e, &e2); + break; + } + default: lua_assert(0); } - else /* op == NOT */ - codenot(fs, e); } @@ -598,20 +719,21 @@ void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) { switch (op) { case OPR_AND: { luaK_goiftrue(fs, v); - luaK_patchtohere(fs, v->t); - v->t = NO_JUMP; break; } case OPR_OR: { luaK_goiffalse(fs, v); - luaK_patchtohere(fs, v->f); - v->f = NO_JUMP; break; } case OPR_CONCAT: { luaK_exp2nextreg(fs, v); /* operand must be on the `stack' */ break; } + case OPR_ADD: case OPR_SUB: case OPR_MUL: case OPR_DIV: + case OPR_MOD: case OPR_POW: { + if (!isnumeral(v)) luaK_exp2RK(fs, v); + break; + } default: { luaK_exp2RK(fs, v); break; @@ -620,67 +742,49 @@ void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) { } -static void codebinop (FuncState *fs, expdesc *res, BinOpr op, - int o1, int o2) { - if (op <= OPR_POW) { /* arithmetic operator? */ - OpCode opc = cast(OpCode, (op - OPR_ADD) + OP_ADD); /* ORDER OP */ - res->info = luaK_codeABC(fs, opc, 0, o1, o2); - res->k = VRELOCABLE; - } - else { /* test operator */ - static const OpCode ops[] = {OP_EQ, OP_EQ, OP_LT, OP_LE, OP_LT, OP_LE}; - int cond = 1; - if (op >= OPR_GT) { /* `>' or `>='? */ - int temp; /* exchange args and replace by `<' or `<=' */ - temp = o1; o1 = o2; o2 = temp; /* o1 <==> o2 */ - } - else if (op == OPR_NE) cond = 0; - res->info = luaK_condjump(fs, ops[op - OPR_NE], cond, o1, o2); - res->k = VJMP; - } -} - - void luaK_posfix (FuncState *fs, BinOpr op, expdesc *e1, expdesc *e2) { switch (op) { case OPR_AND: { lua_assert(e1->t == NO_JUMP); /* list must be closed */ luaK_dischargevars(fs, e2); - luaK_concat(fs, &e1->f, e2->f); - e1->k = e2->k; e1->info = e2->info; e1->aux = e2->aux; e1->t = e2->t; + luaK_concat(fs, &e2->f, e1->f); + *e1 = *e2; break; } case OPR_OR: { lua_assert(e1->f == NO_JUMP); /* list must be closed */ luaK_dischargevars(fs, e2); - luaK_concat(fs, &e1->t, e2->t); - e1->k = e2->k; e1->info = e2->info; e1->aux = e2->aux; e1->f = e2->f; + luaK_concat(fs, &e2->t, e1->t); + *e1 = *e2; break; } case OPR_CONCAT: { luaK_exp2val(fs, e2); if (e2->k == VRELOCABLE && GET_OPCODE(getcode(fs, e2)) == OP_CONCAT) { - lua_assert(e1->info == GETARG_B(getcode(fs, e2))-1); + lua_assert(e1->u.s.info == GETARG_B(getcode(fs, e2))-1); freeexp(fs, e1); - SETARG_B(getcode(fs, e2), e1->info); - e1->k = e2->k; e1->info = e2->info; + SETARG_B(getcode(fs, e2), e1->u.s.info); + e1->k = VRELOCABLE; e1->u.s.info = e2->u.s.info; } else { - luaK_exp2nextreg(fs, e2); - freeexp(fs, e2); - freeexp(fs, e1); - e1->info = luaK_codeABC(fs, OP_CONCAT, 0, e1->info, e2->info); - e1->k = VRELOCABLE; + luaK_exp2nextreg(fs, e2); /* operand must be on the 'stack' */ + codearith(fs, OP_CONCAT, e1, e2); } break; } - default: { - int o1 = luaK_exp2RK(fs, e1); - int o2 = luaK_exp2RK(fs, e2); - freeexp(fs, e2); - freeexp(fs, e1); - codebinop(fs, e1, op, o1, o2); - } + case OPR_ADD: codearith(fs, OP_ADD, e1, e2); break; + case OPR_SUB: codearith(fs, OP_SUB, e1, e2); break; + case OPR_MUL: codearith(fs, OP_MUL, e1, e2); break; + case OPR_DIV: codearith(fs, OP_DIV, e1, e2); break; + case OPR_MOD: codearith(fs, OP_MOD, e1, e2); break; + case OPR_POW: codearith(fs, OP_POW, e1, e2); break; + case OPR_EQ: codecomp(fs, OP_EQ, 1, e1, e2); break; + case OPR_NE: codecomp(fs, OP_EQ, 0, e1, e2); break; + case OPR_LT: codecomp(fs, OP_LT, 1, e1, e2); break; + case OPR_LE: codecomp(fs, OP_LE, 1, e1, e2); break; + case OPR_GT: codecomp(fs, OP_LT, 0, e1, e2); break; + case OPR_GE: codecomp(fs, OP_LE, 0, e1, e2); break; + default: lua_assert(0); } } @@ -690,9 +794,9 @@ void luaK_fixline (FuncState *fs, int line) { } -int luaK_code (FuncState *fs, Instruction i, int line) { +static int luaK_code (FuncState *fs, Instruction i, int line) { Proto *f = fs->f; - luaK_dischargejpc(fs); /* `pc' will change */ + dischargejpc(fs); /* `pc' will change */ /* put new instruction in code array */ luaM_growvector(fs->L, f->code, fs->pc, f->sizecode, Instruction, MAX_INT, "code size overflow"); @@ -707,12 +811,29 @@ int luaK_code (FuncState *fs, Instruction i, int line) { int luaK_codeABC (FuncState *fs, OpCode o, int a, int b, int c) { lua_assert(getOpMode(o) == iABC); + lua_assert(getBMode(o) != OpArgN || b == 0); + lua_assert(getCMode(o) != OpArgN || c == 0); return luaK_code(fs, CREATE_ABC(o, a, b, c), fs->ls->lastline); } int luaK_codeABx (FuncState *fs, OpCode o, int a, unsigned int bc) { lua_assert(getOpMode(o) == iABx || getOpMode(o) == iAsBx); + lua_assert(getCMode(o) == OpArgN); return luaK_code(fs, CREATE_ABx(o, a, bc), fs->ls->lastline); } + +void luaK_setlist (FuncState *fs, int base, int nelems, int tostore) { + int c = (nelems - 1)/LFIELDS_PER_FLUSH + 1; + int b = (tostore == LUA_MULTRET) ? 0 : tostore; + lua_assert(tostore != 0); + if (c <= MAXARG_C) + luaK_codeABC(fs, OP_SETLIST, base, b, c); + else { + luaK_codeABC(fs, OP_SETLIST, base, b, 0); + luaK_code(fs, cast(Instruction, c), fs->ls->lastline); + } + fs->freereg = base + 1; /* free registers with list values */ +} + diff --git a/lib/lua/src/ldebug.c b/lib/lua/src/ldebug.c index 4f69bad..7d606c6 100644 --- a/lib/lua/src/ldebug.c +++ b/lib/lua/src/ldebug.c @@ -1,14 +1,17 @@ /* -** $Id: ldebug.c,v 1.6 2006-02-09 16:59:55 pixel Exp $ +** $Id: ldebug.c,v 1.7 2007-07-27 10:05:53 pixel Exp $ ** Debug Interface ** See Copyright Notice in lua.h */ -#include <stdlib.h> +#include <stdarg.h> +#include <stddef.h> #include <string.h> + #define ldebug_c +#define LUA_CORE #include "lua.h" @@ -27,23 +30,19 @@ -static const char *getfuncname (CallInfo *ci, const char **name); - +static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name); -#define isLua(ci) (!((ci)->state & CI_C)) - -static int currentpc (CallInfo *ci) { +static int currentpc (lua_State *L, CallInfo *ci) { if (!isLua(ci)) return -1; /* function is not a Lua function? */ - if (ci->state & CI_HASFRAME) /* function has a frame? */ - ci->u.l.savedpc = *ci->u.l.pc; /* use `pc' from there */ - /* function's pc is saved */ - return pcRel(ci->u.l.savedpc, ci_func(ci)->l.p); + if (ci == L->ci) + ci->savedpc = L->savedpc; + return pcRel(ci->savedpc, ci_func(ci)->l.p); } -static int currentline (CallInfo *ci) { - int pc = currentpc(ci); +static int currentline (lua_State *L, CallInfo *ci) { + int pc = currentpc(L, ci); if (pc < 0) return -1; /* only active lua functions have current-line information */ else @@ -51,14 +50,6 @@ static int currentline (CallInfo *ci) { } -void luaG_inithooks (lua_State *L) { - CallInfo *ci; - for (ci = L->ci; ci != L->base_ci; ci--) /* update all `savedpc's */ - currentpc(ci); - L->hookinit = 1; -} - - /* ** this function can be called asynchronous (e.g. during a signal) */ @@ -70,8 +61,7 @@ LUA_API int lua_sethook (lua_State *L, lua_Hook func, int mask, int count) { L->hook = func; L->basehookcount = count; resethookcount(L); - L->hookmask = cast(lu_byte, mask); - L->hookinit = 0; + L->hookmask = cast_byte(mask); return 1; } @@ -127,18 +117,18 @@ LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar) { lua_lock(L); for (ci = L->ci; level > 0 && ci > L->base_ci; ci--) { level--; - if (!(ci->state & CI_C)) /* Lua function? */ - level -= ci->u.l.tailcalls; /* skip lost tail calls */ + if (f_isLua(ci)) /* Lua function? */ + level -= ci->tailcalls; /* skip lost tail calls */ } - if (level > 0 || ci == L->base_ci) status = 0; /* there is no such level */ - else if (level < 0) { /* level is of a lost tail call */ + if (level == 0 && ci > L->base_ci) { /* level found? */ status = 1; - ar->i_ci = 0; + ar->i_ci = cast_int(ci - L->base_ci); } - else { + else if (level < 0) { /* level is of a lost tail call? */ status = 1; - ar->i_ci = ci - L->base_ci; + ar->i_ci = 0; } + else status = 0; /* no such level */ lua_unlock(L); return status; } @@ -149,87 +139,94 @@ static Proto *getluaproto (CallInfo *ci) { } -LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) { +static const char *findlocal (lua_State *L, CallInfo *ci, int n) { const char *name; - CallInfo *ci; - Proto *fp; - lua_lock(L); - name = NULL; - ci = L->base_ci + ar->i_ci; - fp = getluaproto(ci); - if (fp) { /* is a Lua function? */ - name = luaF_getlocalname(fp, n, currentpc(ci)); - if (name) - luaA_pushobject(L, ci->base+(n-1)); /* push value */ + Proto *fp = getluaproto(ci); + if (fp && (name = luaF_getlocalname(fp, n, currentpc(L, ci))) != NULL) + return name; /* is a local variable in a Lua function */ + else { + StkId limit = (ci == L->ci) ? L->top : (ci+1)->func; + if (limit - ci->base >= n && n > 0) /* is 'n' inside 'ci' stack? */ + return "(*temporary)"; + else + return NULL; } +} + + +LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) { + CallInfo *ci = L->base_ci + ar->i_ci; + const char *name = findlocal(L, ci, n); + lua_lock(L); + if (name) + luaA_pushobject(L, ci->base + (n - 1)); lua_unlock(L); return name; } LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) { - const char *name; - CallInfo *ci; - Proto *fp; + CallInfo *ci = L->base_ci + ar->i_ci; + const char *name = findlocal(L, ci, n); lua_lock(L); - name = NULL; - ci = L->base_ci + ar->i_ci; - fp = getluaproto(ci); - L->top--; /* pop new value */ - if (fp) { /* is a Lua function? */ - name = luaF_getlocalname(fp, n, currentpc(ci)); - if (!name || name[0] == '(') /* `(' starts private locals */ - name = NULL; - else - setobjs2s(ci->base+(n-1), L->top); - } + if (name) + setobjs2s(L, ci->base + (n - 1), L->top - 1); + L->top--; /* pop value */ lua_unlock(L); return name; } -static void funcinfo (lua_Debug *ar, StkId func) { - Closure *cl = clvalue(func); +static void funcinfo (lua_Debug *ar, Closure *cl) { if (cl->c.isC) { ar->source = "=[C]"; ar->linedefined = -1; + ar->lastlinedefined = -1; ar->what = "C"; } else { ar->source = getstr(cl->l.p->source); - ar->linedefined = cl->l.p->lineDefined; + ar->linedefined = cl->l.p->linedefined; + ar->lastlinedefined = cl->l.p->lastlinedefined; ar->what = (ar->linedefined == 0) ? "main" : "Lua"; } luaO_chunkid(ar->short_src, ar->source, LUA_IDSIZE); } -static const char *travglobals (lua_State *L, const TObject *o) { - Table *g = hvalue(gt(L)); - int i = sizenode(g); - while (i--) { - Node *n = gnode(g, i); - if (luaO_rawequalObj(o, gval(n)) && ttisstring(gkey(n))) - return getstr(tsvalue(gkey(n))); - } - return NULL; -} - - -static void info_tailcall (lua_State *L, lua_Debug *ar) { +static void info_tailcall (lua_Debug *ar) { ar->name = ar->namewhat = ""; ar->what = "tail"; - ar->linedefined = ar->currentline = -1; + ar->lastlinedefined = ar->linedefined = ar->currentline = -1; ar->source = "=(tail call)"; luaO_chunkid(ar->short_src, ar->source, LUA_IDSIZE); ar->nups = 0; - setnilvalue(L->top); +} + + +static void collectvalidlines (lua_State *L, Closure *f) { + if (f == NULL || f->c.isC) { + setnilvalue(L->top); + } + else { + Table *t = luaH_new(L, 0, 0); + int *lineinfo = f->l.p->lineinfo; + int i; + for (i=0; i<f->l.p->sizelineinfo; i++) + setbvalue(luaH_setnum(L, t, lineinfo[i]), 1); + sethvalue(L, L->top, t); + } + incr_top(L); } static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar, - StkId f, CallInfo *ci) { + Closure *f, CallInfo *ci) { int status = 1; + if (f == NULL) { + info_tailcall(ar); + return status; + } for (; *what; what++) { switch (*what) { case 'S': { @@ -237,27 +234,24 @@ static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar, break; } case 'l': { - ar->currentline = (ci) ? currentline(ci) : -1; + ar->currentline = (ci) ? currentline(L, ci) : -1; break; } case 'u': { - ar->nups = clvalue(f)->c.nupvalues; + ar->nups = f->c.nupvalues; break; } case 'n': { - ar->namewhat = (ci) ? getfuncname(ci, &ar->name) : NULL; + ar->namewhat = (ci) ? getfuncname(L, ci, &ar->name) : NULL; if (ar->namewhat == NULL) { - /* try to find a global name */ - if ((ar->name = travglobals(L, f)) != NULL) - ar->namewhat = "global"; - else ar->namewhat = ""; /* not found */ + ar->namewhat = ""; /* not found */ + ar->name = NULL; } break; } - case 'f': { - setobj2s(L->top, f); + case 'L': + case 'f': /* handled by lua_getinfo */ break; - } default: status = 0; /* invalid option */ } } @@ -266,23 +260,30 @@ static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar, LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) { - int status = 1; + int status; + Closure *f = NULL; + CallInfo *ci = NULL; lua_lock(L); if (*what == '>') { - StkId f = L->top - 1; - if (!ttisfunction(f)) - luaG_runerror(L, "value for `lua_getinfo' is not a function"); - status = auxgetinfo(L, what + 1, ar, f, NULL); + StkId func = L->top - 1; + luai_apicheck(L, ttisfunction(func)); + what++; /* skip the '>' */ + f = clvalue(func); L->top--; /* pop function */ } else if (ar->i_ci != 0) { /* no tail call? */ - CallInfo *ci = L->base_ci + ar->i_ci; - lua_assert(ttisfunction(ci->base - 1)); - status = auxgetinfo(L, what, ar, ci->base - 1, ci); + ci = L->base_ci + ar->i_ci; + lua_assert(ttisfunction(ci->func)); + f = clvalue(ci->func); } - else - info_tailcall(L, ar); - if (strchr(what, 'f')) incr_top(L); + status = auxgetinfo(L, what, ar, f, ci); + if (strchr(what, 'f')) { + if (f == NULL) setnilvalue(L->top); + else setclvalue(L, L->top, f); + incr_top(L); + } + if (strchr(what, 'L')) + collectvalidlines(L, f); lua_unlock(L); return status; } @@ -304,72 +305,89 @@ LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) { static int precheck (const Proto *pt) { check(pt->maxstacksize <= MAXSTACK); + lua_assert(pt->numparams+(pt->is_vararg & VARARG_HASARG) <= pt->maxstacksize); + lua_assert(!(pt->is_vararg & VARARG_NEEDSARG) || + (pt->is_vararg & VARARG_HASARG)); + check(pt->sizeupvalues <= pt->nups); check(pt->sizelineinfo == pt->sizecode || pt->sizelineinfo == 0); - lua_assert(pt->numparams+pt->is_vararg <= pt->maxstacksize); check(GET_OPCODE(pt->code[pt->sizecode-1]) == OP_RETURN); return 1; } -static int checkopenop (const Proto *pt, int pc) { - Instruction i = pt->code[pc+1]; +#define checkopenop(pt,pc) luaG_checkopenop((pt)->code[(pc)+1]) + +int luaG_checkopenop (Instruction i) { switch (GET_OPCODE(i)) { case OP_CALL: case OP_TAILCALL: - case OP_RETURN: { + case OP_RETURN: + case OP_SETLIST: { check(GETARG_B(i) == 0); return 1; } - case OP_SETLISTO: return 1; default: return 0; /* invalid instruction after an open call */ } } -static int checkRK (const Proto *pt, int r) { - return (r < pt->maxstacksize || (r >= MAXSTACK && r-MAXSTACK < pt->sizek)); +static int checkArgMode (const Proto *pt, int r, enum OpArgMask mode) { + switch (mode) { + case OpArgN: check(r == 0); break; + case OpArgU: break; + case OpArgR: checkreg(pt, r); break; + case OpArgK: + check(ISK(r) ? INDEXK(r) < pt->sizek : r < pt->maxstacksize); + break; + } + return 1; } -static Instruction luaG_symbexec (const Proto *pt, int lastpc, int reg) { +static Instruction symbexec (const Proto *pt, int lastpc, int reg) { int pc; int last; /* stores position of last instruction that changed `reg' */ last = pt->sizecode-1; /* points to final return (a `neutral' instruction) */ check(precheck(pt)); for (pc = 0; pc < lastpc; pc++) { - const Instruction i = pt->code[pc]; + Instruction i = pt->code[pc]; OpCode op = GET_OPCODE(i); int a = GETARG_A(i); int b = 0; int c = 0; + check(op < NUM_OPCODES); checkreg(pt, a); switch (getOpMode(op)) { case iABC: { b = GETARG_B(i); c = GETARG_C(i); - if (testOpMode(op, OpModeBreg)) { - checkreg(pt, b); - } - else if (testOpMode(op, OpModeBrk)) - check(checkRK(pt, b)); - if (testOpMode(op, OpModeCrk)) - check(checkRK(pt, c)); + check(checkArgMode(pt, b, getBMode(op))); + check(checkArgMode(pt, c, getCMode(op))); break; } case iABx: { b = GETARG_Bx(i); - if (testOpMode(op, OpModeK)) check(b < pt->sizek); + if (getBMode(op) == OpArgK) check(b < pt->sizek); break; } case iAsBx: { b = GETARG_sBx(i); + if (getBMode(op) == OpArgR) { + int dest = pc+1+b; + check(0 <= dest && dest < pt->sizecode); + if (dest > 0) { + /* cannot jump to a setlist count */ + Instruction d = pt->code[dest-1]; + check(!(GET_OPCODE(d) == OP_SETLIST && GETARG_C(d) == 0)); + } + } break; } } - if (testOpMode(op, OpModesetA)) { + if (testAMode(op)) { if (a == reg) last = pc; /* change register `a' */ } - if (testOpMode(op, OpModeT)) { + if (testTMode(op)) { check(pc+2 < pt->sizecode); /* check skip */ check(GET_OPCODE(pt->code[pc+1]) == OP_JMP); } @@ -399,20 +417,21 @@ static Instruction luaG_symbexec (const Proto *pt, int lastpc, int reg) { break; } case OP_CONCAT: { - /* `c' is a register, and at least two operands */ - check(c < MAXSTACK && b < c); + check(b < c); /* at least two operands */ + break; + } + case OP_TFORLOOP: { + check(c >= 1); /* at least one result (control variable) */ + checkreg(pt, a+2+c); /* space for results */ + if (reg >= a+2) last = pc; /* affect all regs above its base */ break; } - case OP_TFORLOOP: - checkreg(pt, a+c+5); - if (reg >= a) last = pc; /* affect all registers above base */ - /* go through */ case OP_FORLOOP: - checkreg(pt, a+2); + case OP_FORPREP: + checkreg(pt, a+3); /* go through */ case OP_JMP: { int dest = pc+1+b; - check(0 <= dest && dest < pt->sizecode); /* not full check and jump is forward and do not skip `lastpc'? */ if (reg != NO_REG && pc < dest && dest <= lastpc) pc += b; /* do the jump */ @@ -438,18 +457,29 @@ static Instruction luaG_symbexec (const Proto *pt, int lastpc, int reg) { break; } case OP_SETLIST: { - checkreg(pt, a + (b&(LFIELDS_PER_FLUSH-1)) + 1); + if (b > 0) checkreg(pt, a + b); + if (c == 0) pc++; break; } case OP_CLOSURE: { - int nup; + int nup, j; check(b < pt->sizep); nup = pt->p[b]->nups; check(pc + nup < pt->sizecode); - for (; nup>0; nup--) { - OpCode op1 = GET_OPCODE(pt->code[pc+nup]); + for (j = 1; j <= nup; j++) { + OpCode op1 = GET_OPCODE(pt->code[pc + j]); check(op1 == OP_GETUPVAL || op1 == OP_MOVE); } + if (reg != NO_REG) /* tracing? */ + pc += nup; /* do not 'execute' these pseudo-instructions */ + break; + } + case OP_VARARG: { + check((pt->is_vararg & VARARG_ISVARARG) && + !(pt->is_vararg & VARARG_NEEDSARG)); + b--; + if (b == LUA_MULTRET) check(checkopenop(pt, pc)); + checkreg(pt, a+b-1); break; } default: break; @@ -466,28 +496,28 @@ static Instruction luaG_symbexec (const Proto *pt, int lastpc, int reg) { int luaG_checkcode (const Proto *pt) { - return luaG_symbexec(pt, pt->sizecode, NO_REG); + return (symbexec(pt, pt->sizecode, NO_REG) != 0); } static const char *kname (Proto *p, int c) { - c = c - MAXSTACK; - if (c >= 0 && ttisstring(&p->k[c])) - return svalue(&p->k[c]); + if (ISK(c) && ttisstring(&p->k[INDEXK(c)])) + return svalue(&p->k[INDEXK(c)]); else return "?"; } -static const char *getobjname (CallInfo *ci, int stackpos, const char **name) { +static const char *getobjname (lua_State *L, CallInfo *ci, int stackpos, + const char **name) { if (isLua(ci)) { /* a Lua function? */ Proto *p = ci_func(ci)->l.p; - int pc = currentpc(ci); + int pc = currentpc(L, ci); Instruction i; *name = luaF_getlocalname(p, stackpos+1, pc); if (*name) /* is a local? */ return "local"; - i = luaG_symbexec(p, pc, stackpos); /* try symbolic execution */ + i = symbexec(p, pc, stackpos); /* try symbolic execution */ lua_assert(pc != -1); switch (GET_OPCODE(i)) { case OP_GETGLOBAL: { @@ -500,7 +530,7 @@ static const char *getobjname (CallInfo *ci, int stackpos, const char **name) { int a = GETARG_A(i); int b = GETARG_B(i); /* move from `b' to `a' */ if (b < a) - return getobjname(ci, b, name); /* get name for `b' */ + return getobjname(L, ci, b, name); /* get name for `b' */ break; } case OP_GETTABLE: { @@ -508,6 +538,11 @@ static const char *getobjname (CallInfo *ci, int stackpos, const char **name) { *name = kname(p, k); return "field"; } + case OP_GETUPVAL: { + int u = GETARG_B(i); /* upvalue index */ + *name = p->upvalues ? getstr(p->upvalues[u]) : "?"; + return "upvalue"; + } case OP_SELF: { int k = GETARG_C(i); /* key index */ *name = kname(p, k); @@ -520,21 +555,22 @@ static const char *getobjname (CallInfo *ci, int stackpos, const char **name) { } -static const char *getfuncname (CallInfo *ci, const char **name) { +static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) { Instruction i; - if ((isLua(ci) && ci->u.l.tailcalls > 0) || !isLua(ci - 1)) + if ((isLua(ci) && ci->tailcalls > 0) || !isLua(ci - 1)) return NULL; /* calling function is not Lua (or is unknown) */ ci--; /* calling function */ - i = ci_func(ci)->l.p->code[currentpc(ci)]; - if (GET_OPCODE(i) == OP_CALL || GET_OPCODE(i) == OP_TAILCALL) - return getobjname(ci, GETARG_A(i), name); + i = ci_func(ci)->l.p->code[currentpc(L, ci)]; + if (GET_OPCODE(i) == OP_CALL || GET_OPCODE(i) == OP_TAILCALL || + GET_OPCODE(i) == OP_TFORLOOP) + return getobjname(L, ci, GETARG_A(i), name); else return NULL; /* no useful name can be found */ } /* only ANSI way to check whether a pointer points to an array */ -static int isinstack (CallInfo *ci, const TObject *o) { +static int isinstack (CallInfo *ci, const TValue *o) { StkId p; for (p = ci->base; p < ci->top; p++) if (o == p) return 1; @@ -542,13 +578,14 @@ static int isinstack (CallInfo *ci, const TObject *o) { } -void luaG_typeerror (lua_State *L, const TObject *o, const char *op) { +void luaG_typeerror (lua_State *L, const TValue *o, const char *op) { const char *name = NULL; const char *t = luaT_typenames[ttype(o)]; const char *kind = (isinstack(L->ci, o)) ? - getobjname(L->ci, o - L->base, &name) : NULL; + getobjname(L, L->ci, cast_int(o - L->base), &name) : + NULL; if (kind) - luaG_runerror(L, "attempt to %s %s `%s' (a %s value)", + luaG_runerror(L, "attempt to %s %s " LUA_QS " (a %s value)", op, kind, name, t); else luaG_runerror(L, "attempt to %s a %s value", op, t); @@ -562,15 +599,15 @@ void luaG_concaterror (lua_State *L, StkId p1, StkId p2) { } -void luaG_aritherror (lua_State *L, const TObject *p1, const TObject *p2) { - TObject temp; +void luaG_aritherror (lua_State *L, const TValue *p1, const TValue *p2) { + TValue temp; if (luaV_tonumber(p1, &temp) == NULL) p2 = p1; /* first operand is wrong */ luaG_typeerror(L, p2, "perform arithmetic on"); } -int luaG_ordererror (lua_State *L, const TObject *p1, const TObject *p2) { +int luaG_ordererror (lua_State *L, const TValue *p1, const TValue *p2) { const char *t1 = luaT_typenames[ttype(p1)]; const char *t2 = luaT_typenames[ttype(p2)]; if (t1[2] == t2[2]) @@ -585,7 +622,7 @@ static void addinfo (lua_State *L, const char *msg) { CallInfo *ci = L->ci; if (isLua(ci)) { /* is Lua code? */ char buff[LUA_IDSIZE]; /* add file:line information */ - int line = currentline(ci); + int line = currentline(L, ci); luaO_chunkid(buff, getstr(getluaproto(ci)->source), LUA_IDSIZE); luaO_pushfstring(L, "%s:%d: %s", buff, line, msg); } @@ -596,8 +633,8 @@ void luaG_errormsg (lua_State *L) { if (L->errfunc != 0) { /* is there an error handling function? */ StkId errfunc = restorestack(L, L->errfunc); if (!ttisfunction(errfunc)) luaD_throw(L, LUA_ERRERR); - setobjs2s(L->top, L->top - 1); /* move argument */ - setobjs2s(L->top - 1, errfunc); /* push function */ + setobjs2s(L, L->top, L->top - 1); /* move argument */ + setobjs2s(L, L->top - 1, errfunc); /* push function */ incr_top(L); luaD_call(L, L->top - 2, 1); /* call it */ } diff --git a/lib/lua/src/ldo.c b/lib/lua/src/ldo.c index b23f8b1..6fc6d3c 100644 --- a/lib/lua/src/ldo.c +++ b/lib/lua/src/ldo.c @@ -1,5 +1,5 @@ /* -** $Id: ldo.c,v 1.8 2004-12-27 22:18:53 pixel Exp $ +** $Id: ldo.c,v 1.9 2007-07-27 10:05:53 pixel Exp $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ @@ -10,6 +10,7 @@ #include <string.h> #define ldo_c +#define LUA_CORE #include "lua.h" @@ -34,7 +35,7 @@ /* ** {====================================================== -** Error-recovery functions (based on long jumps) +** Error-recovery functions ** ======================================================= */ @@ -42,24 +43,24 @@ /* chain list of long jump buffers */ struct lua_longjmp { struct lua_longjmp *previous; - jmp_buf b; + luai_jmpbuf b; volatile int status; /* error code */ }; -static void seterrorobj (lua_State *L, int errcode, StkId oldtop) { +void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop) { switch (errcode) { case LUA_ERRMEM: { - setsvalue2s(oldtop, luaS_new(L, MEMERRMSG)); + setsvalue2s(L, oldtop, luaS_newliteral(L, MEMERRMSG)); break; } case LUA_ERRERR: { - setsvalue2s(oldtop, luaS_new(L, "error in error handling")); + setsvalue2s(L, oldtop, luaS_newliteral(L, "error in error handling")); break; } case LUA_ERRSYNTAX: case LUA_ERRRUN: { - setobjs2s(oldtop, L->top - 1); /* error message on current top */ + setobjs2s(L, oldtop, L->top - 1); /* error message on current top */ break; } } @@ -67,13 +68,41 @@ static void seterrorobj (lua_State *L, int errcode, StkId oldtop) { } +static void restore_stack_limit (lua_State *L) { + lua_assert(L->stack_last - L->stack == L->stacksize - EXTRA_STACK - 1); + if (L->size_ci > LUAI_MAXCALLS) { /* there was an overflow? */ + int inuse = cast_int(L->ci - L->base_ci); + if (inuse + 1 < LUAI_MAXCALLS) /* can `undo' overflow? */ + luaD_reallocCI(L, LUAI_MAXCALLS); + } +} + + +static void resetstack (lua_State *L, int status) { + L->ci = L->base_ci; + L->base = L->ci->base; + luaF_close(L, L->base); /* close eventual pending closures */ + luaD_seterrorobj(L, status, L->base); + L->nCcalls = 0; + L->allowhook = 1; + restore_stack_limit(L); + L->errfunc = 0; + L->errorJmp = NULL; +} + + void luaD_throw (lua_State *L, int errcode) { if (L->errorJmp) { L->errorJmp->status = errcode; - longjmp(L->errorJmp->b, 1); + LUAI_THROW(L, L->errorJmp); } else { - G(L)->panic(L); + L->status = cast_byte(errcode); + if (G(L)->panic) { + resetstack(L, errcode); + lua_unlock(L); + G(L)->panic(L); + } exit(EXIT_FAILURE); } } @@ -84,44 +113,38 @@ int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) { lj.status = 0; lj.previous = L->errorJmp; /* chain new error handler */ L->errorJmp = &lj; - if (setjmp(lj.b) == 0) + LUAI_TRY(L, &lj, (*f)(L, ud); + ); L->errorJmp = lj.previous; /* restore old error handler */ return lj.status; } - -static void restore_stack_limit (lua_State *L) { - L->stack_last = L->stack+L->stacksize-1; - if (L->size_ci > LUA_MAXCALLS) { /* there was an overflow? */ - int inuse = (L->ci - L->base_ci); - if (inuse + 1 < LUA_MAXCALLS) /* can `undo' overflow? */ - luaD_reallocCI(L, LUA_MAXCALLS); - } -} - /* }====================================================== */ -static void correctstack (lua_State *L, TObject *oldstack) { +static void correctstack (lua_State *L, TValue *oldstack) { CallInfo *ci; GCObject *up; L->top = (L->top - oldstack) + L->stack; for (up = L->openupval; up != NULL; up = up->gch.next) - gcotouv(up)->v = (gcotouv(up)->v - oldstack) + L->stack; + gco2uv(up)->v = (gco2uv(up)->v - oldstack) + L->stack; for (ci = L->base_ci; ci <= L->ci; ci++) { ci->top = (ci->top - oldstack) + L->stack; ci->base = (ci->base - oldstack) + L->stack; + ci->func = (ci->func - oldstack) + L->stack; } - L->base = L->ci->base; + L->base = (L->base - oldstack) + L->stack; } void luaD_reallocstack (lua_State *L, int newsize) { - TObject *oldstack = L->stack; - luaM_reallocvector(L, L->stack, L->stacksize, newsize, TObject); - L->stacksize = newsize; - L->stack_last = L->stack+newsize-1-EXTRA_STACK; + TValue *oldstack = L->stack; + int realsize = newsize + 1 + EXTRA_STACK; + lua_assert(L->stack_last - L->stack == L->stacksize - EXTRA_STACK - 1); + luaM_reallocvector(L, L->stack, L->stacksize, realsize, TValue); + L->stacksize = realsize; + L->stack_last = L->stack+newsize; correctstack(L, oldstack); } @@ -129,9 +152,9 @@ void luaD_reallocstack (lua_State *L, int newsize) { void luaD_reallocCI (lua_State *L, int newsize) { CallInfo *oldci = L->base_ci; luaM_reallocvector(L, L->base_ci, L->size_ci, newsize, CallInfo); - L->size_ci = cast(unsigned short, newsize); + L->size_ci = newsize; L->ci = (L->ci - oldci) + L->base_ci; - L->end_ci = L->base_ci + L->size_ci; + L->end_ci = L->base_ci + L->size_ci - 1; } @@ -139,18 +162,19 @@ void luaD_growstack (lua_State *L, int n) { if (n <= L->stacksize) /* double size is enough? */ luaD_reallocstack(L, 2*L->stacksize); else - luaD_reallocstack(L, L->stacksize + n + EXTRA_STACK); + luaD_reallocstack(L, L->stacksize + n); } -static void luaD_growCI (lua_State *L) { - if (L->size_ci > LUA_MAXCALLS) /* overflow while handling overflow? */ +static CallInfo *growCI (lua_State *L) { + if (L->size_ci > LUAI_MAXCALLS) /* overflow while handling overflow? */ luaD_throw(L, LUA_ERRERR); else { luaD_reallocCI(L, 2*L->size_ci); - if (L->size_ci > LUA_MAXCALLS) + if (L->size_ci > LUAI_MAXCALLS) luaG_runerror(L, "stack overflow"); } + return ++L->ci; } @@ -165,9 +189,10 @@ void luaD_callhook (lua_State *L, int event, int line) { if (event == LUA_HOOKTAILRET) ar.i_ci = 0; /* tail call; no debug information about it */ else - ar.i_ci = L->ci - L->base_ci; + ar.i_ci = cast_int(L->ci - L->base_ci); luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ L->ci->top = L->top + LUA_MINSTACK; + lua_assert(L->ci->top <= L->stack_last); L->allowhook = 0; /* cannot call hooks inside a hook */ lua_unlock(L); (*hook)(L, &ar); @@ -180,90 +205,129 @@ void luaD_callhook (lua_State *L, int event, int line) { } -static void adjust_varargs (lua_State *L, int nfixargs, StkId base) { +static StkId adjust_varargs (lua_State *L, Proto *p, int actual) { int i; - Table *htab; - TObject nname; - int actual = L->top - base; /* actual number of arguments */ - if (actual < nfixargs) { - luaD_checkstack(L, nfixargs - actual); - for (; actual < nfixargs; ++actual) - setnilvalue(L->top++); + int nfixargs = p->numparams; + Table *htab = NULL; + StkId base, fixed; + for (; actual < nfixargs; ++actual) + setnilvalue(L->top++); +#if defined(LUA_COMPAT_VARARG) + if (p->is_vararg & VARARG_NEEDSARG) { /* compat. with old-style vararg? */ + int nvar = actual - nfixargs; /* number of extra arguments */ + lua_assert(p->is_vararg & VARARG_HASARG); + luaC_checkGC(L); + htab = luaH_new(L, nvar, 1); /* create `arg' table */ + for (i=0; i<nvar; i++) /* put extra arguments into `arg' table */ + setobj2n(L, luaH_setnum(L, htab, i+1), L->top - nvar + i); + /* store counter in field `n' */ + setnvalue(luaH_setstr(L, htab, luaS_newliteral(L, "n")), cast_num(nvar)); } - actual -= nfixargs; /* number of extra arguments */ - htab = luaH_new(L, actual, 1); /* create `arg' table */ - for (i=0; i<actual; i++) /* put extra arguments into `arg' table */ - setobj2n(luaH_setnum(L, htab, i+1), L->top - actual + i); - /* store counter in field `n' */ - setsvalue(&nname, luaS_newliteral(L, "n")); - setnvalue(luaH_set(L, htab, &nname), cast(lua_Number, actual)); - L->top -= actual; /* remove extra elements from the stack */ - sethvalue(L->top, htab); - incr_top(L); +#endif + /* move fixed parameters to final position */ + fixed = L->top - actual; /* first fixed argument */ + base = L->top; /* final position of first argument */ + for (i=0; i<nfixargs; i++) { + setobjs2s(L, L->top++, fixed+i); + setnilvalue(fixed+i); + } + /* add `arg' parameter */ + if (htab) { + sethvalue(L, L->top++, htab); + lua_assert(iswhite(obj2gco(htab))); + } + return base; } static StkId tryfuncTM (lua_State *L, StkId func) { - const TObject *tm = luaT_gettmbyobj(L, func, TM_CALL); + const TValue *tm = luaT_gettmbyobj(L, func, TM_CALL); StkId p; ptrdiff_t funcr = savestack(L, func); if (!ttisfunction(tm)) luaG_typeerror(L, func, "call"); /* Open a hole inside the stack at `func' */ - for (p = L->top; p > func; p--) setobjs2s(p, p-1); + for (p = L->top; p > func; p--) setobjs2s(L, p, p-1); incr_top(L); func = restorestack(L, funcr); /* previous call may change stack */ - setobj2s(func, tm); /* tag method is the new function to be called */ + setobj2s(L, func, tm); /* tag method is the new function to be called */ return func; } -StkId luaD_precall (lua_State *L, StkId func) { + +#define inc_ci(L) \ + ((L->ci == L->end_ci) ? growCI(L) : \ + (condhardstacktests(luaD_reallocCI(L, L->size_ci)), ++L->ci)) + + +int luaD_precall (lua_State *L, StkId func, int nresults) { LClosure *cl; - ptrdiff_t funcr = savestack(L, func); + ptrdiff_t funcr; if (!ttisfunction(func)) /* `func' is not a function? */ func = tryfuncTM(L, func); /* check the `function' tag method */ - if (L->ci + 1 == L->end_ci) luaD_growCI(L); - else condhardstacktests(luaD_reallocCI(L, L->size_ci)); + funcr = savestack(L, func); cl = &clvalue(func)->l; + L->ci->savedpc = L->savedpc; if (!cl->isC) { /* Lua function? prepare its call */ CallInfo *ci; + StkId st, base; Proto *p = cl->p; - if (p->is_vararg) /* varargs? */ - adjust_varargs(L, p->numparams, func+1); luaD_checkstack(L, p->maxstacksize); - ci = ++L->ci; /* now `enter' new function */ - L->base = L->ci->base = restorestack(L, funcr) + 1; + func = restorestack(L, funcr); + if (!p->is_vararg) { /* no varargs? */ + base = func + 1; + if (L->top > base + p->numparams) + L->top = base + p->numparams; + } + else { /* vararg function */ + int nargs = cast_int(L->top - func) - 1; + base = adjust_varargs(L, p, nargs); + func = restorestack(L, funcr); /* previous call may change the stack */ + } + ci = inc_ci(L); /* now `enter' new function */ + ci->func = func; + L->base = ci->base = base; ci->top = L->base + p->maxstacksize; - ci->u.l.savedpc = p->code; /* starting point */ - ci->u.l.tailcalls = 0; - ci->state = CI_SAVEDPC; - while (L->top < ci->top) - setnilvalue(L->top++); + lua_assert(ci->top <= L->stack_last); + L->savedpc = p->code; /* starting point */ + ci->tailcalls = 0; + ci->nresults = nresults; + for (st = L->top; st < ci->top; st++) + setnilvalue(st); L->top = ci->top; - return NULL; + if (L->hookmask & LUA_MASKCALL) { + L->savedpc++; /* hooks assume 'pc' is already incremented */ + luaD_callhook(L, LUA_HOOKCALL, -1); + L->savedpc--; /* correct 'pc' */ + } + return PCRLUA; } else { /* if is a C function, call it */ CallInfo *ci; int n; luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ - ci = ++L->ci; /* now `enter' new function */ - L->base = L->ci->base = restorestack(L, funcr) + 1; + ci = inc_ci(L); /* now `enter' new function */ + ci->func = restorestack(L, funcr); + L->base = ci->base = ci->func + 1; ci->top = L->top + LUA_MINSTACK; - ci->state = CI_C; /* a C function */ + lua_assert(ci->top <= L->stack_last); + ci->nresults = nresults; if (L->hookmask & LUA_MASKCALL) luaD_callhook(L, LUA_HOOKCALL, -1); lua_unlock(L); -#ifdef LUA_COMPATUPVALUES - lua_pushupvalues(L); -#endif if (L->callwrap) { - n = L->callwrap(L, clvalue(L->base - 1)->c.f); /* wrap the call */ + n = L->callwrap(L, curr_func(L)->c.f); /* wrap the call */ } else { - n = (*clvalue(L->base - 1)->c.f)(L); /* do the actual call */ + n = (*curr_func(L)->c.f)(L); /* do the actual call */ } lua_lock(L); - return L->top - n; + if (n < 0) /* yielding? */ + return PCRYIELD; + else { + luaD_poscall(L, L->top - n); + return PCRC; + } } } @@ -271,29 +335,32 @@ StkId luaD_precall (lua_State *L, StkId func) { static StkId callrethooks (lua_State *L, StkId firstResult) { ptrdiff_t fr = savestack(L, firstResult); /* next call may change stack */ luaD_callhook(L, LUA_HOOKRET, -1); - if (!(L->ci->state & CI_C)) { /* Lua function? */ - while (L->ci->u.l.tailcalls--) /* call hook for eventual tail calls */ + if (f_isLua(L->ci)) { /* Lua function? */ + while (L->ci->tailcalls--) /* call hook for eventual tail calls */ luaD_callhook(L, LUA_HOOKTAILRET, -1); } return restorestack(L, fr); } -void luaD_poscall (lua_State *L, int wanted, StkId firstResult) { +int luaD_poscall (lua_State *L, StkId firstResult) { StkId res; + int wanted, i; + CallInfo *ci; if (L->hookmask & LUA_MASKRET) firstResult = callrethooks(L, firstResult); - res = L->base - 1; /* res == final position of 1st result */ - L->ci--; - L->base = L->ci->base; /* restore base */ + ci = L->ci--; + res = ci->func; /* res == final position of 1st result */ + wanted = ci->nresults; + L->base = (ci - 1)->base; /* restore base */ + L->savedpc = (ci - 1)->savedpc; /* restore savedpc */ /* move results to correct place */ - while (wanted != 0 && firstResult < L->top) { - setobjs2s(res++, firstResult++); - wanted--; - } - while (wanted-- > 0) + for (i = wanted; i != 0 && firstResult < L->top; i--) + setobjs2s(L, res++, firstResult++); + while (i-- > 0) setnilvalue(res++); L->top = res; + return (wanted - LUA_MULTRET); /* 0 iff wanted == LUA_MULTRET */ } @@ -304,56 +371,47 @@ void luaD_poscall (lua_State *L, int wanted, StkId firstResult) { ** function position. */ void luaD_call (lua_State *L, StkId func, int nResults) { - StkId firstResult; - lua_assert(!(L->ci->state & CI_CALLING)); - if (++L->nCcalls >= LUA_MAXCCALLS) { - if (L->nCcalls == LUA_MAXCCALLS) + if (++L->nCcalls >= LUAI_MAXCCALLS) { + if (L->nCcalls == LUAI_MAXCCALLS) luaG_runerror(L, "C stack overflow"); - else if (L->nCcalls >= (LUA_MAXCCALLS + (LUA_MAXCCALLS>>3))) + else if (L->nCcalls >= (LUAI_MAXCCALLS + (LUAI_MAXCCALLS>>3))) luaD_throw(L, LUA_ERRERR); /* error while handing stack error */ } - firstResult = luaD_precall(L, func); - if (firstResult == NULL) /* is a Lua function? */ - firstResult = luaV_execute(L); /* call it */ - luaD_poscall(L, nResults, firstResult); + if (luaD_precall(L, func, nResults) == PCRLUA) /* is a Lua function? */ + luaV_execute(L, 1); /* call it */ L->nCcalls--; luaC_checkGC(L); } static void resume (lua_State *L, void *ud) { - StkId firstResult; - int nargs = *cast(int *, ud); + StkId firstArg = cast(StkId, ud); CallInfo *ci = L->ci; - if (ci == L->base_ci) { /* no activation record? */ - lua_assert(nargs < L->top - L->base); - luaD_precall(L, L->top - (nargs + 1)); /* start coroutine */ + if (L->status == 0) { /* start coroutine? */ + lua_assert(ci == L->base_ci && firstArg > L->base); + if (luaD_precall(L, firstArg - 1, LUA_MULTRET) != PCRLUA) + return; } - else { /* inside a yield */ - lua_assert(ci->state & CI_YIELD); - if (ci->state & CI_C) { /* `common' yield? */ + else { /* resuming from previous yield */ + lua_assert(L->status == LUA_YIELD); + L->status = 0; + if (!f_isLua(ci)) { /* `common' yield? */ /* finish interrupted execution of `OP_CALL' */ - int nresults; - lua_assert((ci-1)->state & CI_SAVEDPC); - lua_assert(GET_OPCODE(*((ci-1)->u.l.savedpc - 1)) == OP_CALL || - GET_OPCODE(*((ci-1)->u.l.savedpc - 1)) == OP_TAILCALL); - nresults = GETARG_C(*((ci-1)->u.l.savedpc - 1)) - 1; - luaD_poscall(L, nresults, L->top - nargs); /* complete it */ - if (nresults >= 0) L->top = L->ci->top; - } - else { /* yielded inside a hook: just continue its execution */ - ci->state &= ~CI_YIELD; + lua_assert(GET_OPCODE(*((ci-1)->savedpc - 1)) == OP_CALL || + GET_OPCODE(*((ci-1)->savedpc - 1)) == OP_TAILCALL); + if (luaD_poscall(L, firstArg)) /* complete it... */ + L->top = L->ci->top; /* and correct top if not multiple results */ } + else /* yielded inside a hook: just continue its execution */ + L->base = L->ci->base; } - firstResult = luaV_execute(L); - if (firstResult != NULL) /* return? */ - luaD_poscall(L, LUA_MULTRET, firstResult); /* finalize this coroutine */ + luaV_execute(L, cast_int(L->ci - L->base_ci)); } static int resume_error (lua_State *L, const char *msg) { L->top = L->ci->base; - setsvalue2s(L->top, luaS_new(L, msg)); + setsvalue2s(L, L->top, luaS_new(L, msg)); incr_top(L); lua_unlock(L); return LUA_ERRRUN; @@ -362,60 +420,47 @@ static int resume_error (lua_State *L, const char *msg) { LUA_API int lua_resume (lua_State *L, int nargs) { int status; - lu_byte old_allowhooks; lua_lock(L); - if (L->ci == L->base_ci) { - if (nargs >= L->top - L->base) + if (L->status != LUA_YIELD) { + if (L->status != 0) return resume_error(L, "cannot resume dead coroutine"); + else if (L->ci != L->base_ci) + return resume_error(L, "cannot resume non-suspended coroutine"); } - else if (!(L->ci->state & CI_YIELD)) /* not inside a yield? */ - return resume_error(L, "cannot resume non-suspended coroutine"); - old_allowhooks = L->allowhook; + luai_userstateresume(L, nargs); lua_assert(L->errfunc == 0 && L->nCcalls == 0); - status = luaD_rawrunprotected(L, resume, &nargs); + status = luaD_rawrunprotected(L, resume, L->top - nargs); if (status != 0) { /* error? */ - L->ci = L->base_ci; /* go back to initial level */ - L->base = L->ci->base; - L->nCcalls = 0; - luaF_close(L, L->base); /* close eventual pending closures */ - seterrorobj(L, status, L->base); - L->allowhook = old_allowhooks; - restore_stack_limit(L); + L->status = cast_byte(status); /* mark thread as `dead' */ + luaD_seterrorobj(L, status, L->top); + L->ci->top = L->top; } + else + status = L->status; lua_unlock(L); return status; } LUA_API int lua_yield (lua_State *L, int nresults) { - CallInfo *ci; + luai_userstateyield(L, nresults); lua_lock(L); - ci = L->ci; if (L->nCcalls > 0) luaG_runerror(L, "attempt to yield across metamethod/C-call boundary"); - if (ci->state & CI_C) { /* usual yield */ - if ((ci-1)->state & CI_C) - luaG_runerror(L, "cannot yield a C function"); - if (L->top - nresults > L->base) { /* is there garbage in the stack? */ - int i; - for (i=0; i<nresults; i++) /* move down results */ - setobjs2s(L->base + i, L->top - nresults + i); - L->top = L->base + nresults; - } - } /* else it's an yield inside a hook: nothing to do */ - ci->state |= CI_YIELD; + L->base = L->top - nresults; /* protect stack slots below */ + L->status = LUA_YIELD; lua_unlock(L); return -1; } + LUA_API void lua_break (lua_State *L) { - CallInfo * ci; lua_lock(L); - ci = L->ci; - ci->state |= CI_BREAK; + L->do_break = 1; lua_unlock(L); } + int luaD_pcall (lua_State *L, Pfunc func, void *u, ptrdiff_t old_top, ptrdiff_t ef) { int status; @@ -428,10 +473,11 @@ int luaD_pcall (lua_State *L, Pfunc func, void *u, if (status != 0) { /* an error occurred? */ StkId oldtop = restorestack(L, old_top); luaF_close(L, oldtop); /* close eventual pending closures */ - seterrorobj(L, status, oldtop); + luaD_seterrorobj(L, status, oldtop); L->nCcalls = oldnCcalls; L->ci = restoreci(L, old_ci); L->base = L->ci->base; + L->savedpc = L->ci->savedpc; L->allowhook = old_allowhooks; restore_stack_limit(L); } @@ -447,35 +493,34 @@ int luaD_pcall (lua_State *L, Pfunc func, void *u, struct SParser { /* data to `f_parser' */ ZIO *z; Mbuffer buff; /* buffer to be used by the scanner */ - int bin; + const char *name; }; static void f_parser (lua_State *L, void *ud) { - struct SParser *p; + int i; Proto *tf; Closure *cl; + struct SParser *p = cast(struct SParser *, ud); + int c = luaZ_lookahead(p->z); luaC_checkGC(L); - p = cast(struct SParser *, ud); - tf = p->bin ? luaU_undump(L, p->z, &p->buff) : luaY_parser(L, p->z, &p->buff); - cl = luaF_newLclosure(L, 0, gt(L)); + tf = ((c == LUA_SIGNATURE[0]) ? luaU_undump : luaY_parser)(L, p->z, + &p->buff, p->name); + cl = luaF_newLclosure(L, tf->nups, hvalue(gt(L))); cl->l.p = tf; - setclvalue(L->top, cl); + for (i = 0; i < tf->nups; i++) /* initialize eventual upvalues */ + cl->l.upvals[i] = luaF_newupval(L); + setclvalue(L, L->top, cl); incr_top(L); } -int luaD_protectedparser (lua_State *L, ZIO *z, int bin) { +int luaD_protectedparser (lua_State *L, ZIO *z, const char *name) { struct SParser p; int status; - ptrdiff_t oldtopr = savestack(L, L->top); /* save current top */ - p.z = z; p.bin = bin; + p.z = z; p.name = name; luaZ_initbuffer(L, &p.buff); - status = luaD_rawrunprotected(L, f_parser, &p); + status = luaD_pcall(L, f_parser, &p, savestack(L, L->top), L->errfunc); luaZ_freebuffer(L, &p.buff); - if (status != 0) { /* error? */ - StkId oldtop = restorestack(L, oldtopr); - seterrorobj(L, status, oldtop); - } return status; } diff --git a/lib/lua/src/ldump.c b/lib/lua/src/ldump.c index 2bcfd5d..f7dd971 100644 --- a/lib/lua/src/ldump.c +++ b/lib/lua/src/ldump.c @@ -1,170 +1,164 @@ /* -** $Id: ldump.c,v 1.4 2004-11-27 21:46:07 pixel Exp $ -** save bytecodes +** $Id: ldump.c,v 1.5 2007-07-27 10:05:53 pixel Exp $ +** save precompiled Lua chunks ** See Copyright Notice in lua.h */ #include <stddef.h> #define ldump_c +#define LUA_CORE #include "lua.h" #include "lobject.h" -#include "lopcodes.h" #include "lstate.h" #include "lundump.h" -#define DumpVector(b,n,size,D) DumpBlock(b,(n)*(size),D) -#define DumpLiteral(s,D) DumpBlock("" s,(sizeof(s))-1,D) - typedef struct { lua_State* L; - lua_Chunkwriter write; + lua_Writer writer; void* data; + int strip; + int status; } DumpState; +#define DumpMem(b,n,size,D) DumpBlock(b,(n)*(size),D) +#define DumpVar(x,D) DumpMem(&x,1,sizeof(x),D) + static void DumpBlock(const void* b, size_t size, DumpState* D) { - lua_unlock(D->L); - (*D->write)(D->L,b,size,D->data); - lua_lock(D->L); + if (D->status==0) + { + lua_unlock(D->L); + D->status=(*D->writer)(D->L,b,size,D->data); + lua_lock(D->L); + } } -static void DumpByte(int y, DumpState* D) +static void DumpChar(int y, DumpState* D) { char x=(char)y; - DumpBlock(&x,sizeof(x),D); + DumpVar(x,D); } static void DumpInt(int x, DumpState* D) { - DumpBlock(&x,sizeof(x),D); + DumpVar(x,D); } -static void DumpSize(size_t x, DumpState* D) +static void DumpNumber(lua_Number x, DumpState* D) { - DumpBlock(&x,sizeof(x),D); + DumpVar(x,D); } -static void DumpNumber(lua_Number x, DumpState* D) +static void DumpVector(const void* b, int n, size_t size, DumpState* D) { - DumpBlock(&x,sizeof(x),D); + DumpInt(n,D); + DumpMem(b,n,size,D); } -static void DumpString(TString* s, DumpState* D) +static void DumpString(const TString* s, DumpState* D) { if (s==NULL || getstr(s)==NULL) - DumpSize(0,D); + { + size_t size=0; + DumpVar(size,D); + } else { size_t size=s->tsv.len+1; /* include trailing '\0' */ - DumpSize(size,D); + DumpVar(size,D); DumpBlock(getstr(s),size,D); } } -static void DumpCode(const Proto* f, DumpState* D) -{ - DumpInt(f->sizecode,D); - DumpVector(f->code,f->sizecode,sizeof(*f->code),D); -} - -static void DumpLocals(const Proto* f, DumpState* D) -{ - int i,n=f->sizelocvars; - DumpInt(n,D); - for (i=0; i<n; i++) - { - DumpString(f->locvars[i].varname,D); - DumpInt(f->locvars[i].startpc,D); - DumpInt(f->locvars[i].endpc,D); - } -} - -static void DumpLines(const Proto* f, DumpState* D) -{ - DumpInt(f->sizelineinfo,D); - DumpVector(f->lineinfo,f->sizelineinfo,sizeof(*f->lineinfo),D); -} - -static void DumpUpvalues(const Proto* f, DumpState* D) -{ - int i,n=f->sizeupvalues; - DumpInt(n,D); - for (i=0; i<n; i++) DumpString(f->upvalues[i],D); -} +#define DumpCode(f,D) DumpVector(f->code,f->sizecode,sizeof(Instruction),D) static void DumpFunction(const Proto* f, const TString* p, DumpState* D); static void DumpConstants(const Proto* f, DumpState* D) { - int i,n; - DumpInt(n=f->sizek,D); + int i,n=f->sizek; + DumpInt(n,D); for (i=0; i<n; i++) { - const TObject* o=&f->k[i]; - DumpByte(ttype(o),D); + const TValue* o=&f->k[i]; + DumpChar(ttype(o),D); switch (ttype(o)) { + case LUA_TNIL: + break; + case LUA_TBOOLEAN: + DumpChar(bvalue(o),D); + break; case LUA_TNUMBER: DumpNumber(nvalue(o),D); break; case LUA_TSTRING: - DumpString(tsvalue(o),D); - break; - case LUA_TNIL: + DumpString(rawtsvalue(o),D); break; default: lua_assert(0); /* cannot happen */ break; } } - DumpInt(n=f->sizep,D); + n=f->sizep; + DumpInt(n,D); for (i=0; i<n; i++) DumpFunction(f->p[i],f->source,D); } +static void DumpDebug(const Proto* f, DumpState* D) +{ + int i,n; + n= (D->strip) ? 0 : f->sizelineinfo; + DumpVector(f->lineinfo,n,sizeof(int),D); + n= (D->strip) ? 0 : f->sizelocvars; + DumpInt(n,D); + for (i=0; i<n; i++) + { + DumpString(f->locvars[i].varname,D); + DumpInt(f->locvars[i].startpc,D); + DumpInt(f->locvars[i].endpc,D); + } + n= (D->strip) ? 0 : f->sizeupvalues; + DumpInt(n,D); + for (i=0; i<n; i++) DumpString(f->upvalues[i],D); +} + static void DumpFunction(const Proto* f, const TString* p, DumpState* D) { - DumpString((f->source==p) ? NULL : f->source,D); - DumpInt(f->lineDefined,D); - DumpByte(f->nups,D); - DumpByte(f->numparams,D); - DumpByte(f->is_vararg,D); - DumpByte(f->maxstacksize,D); - DumpLines(f,D); - DumpLocals(f,D); - DumpUpvalues(f,D); - DumpConstants(f,D); + DumpString((f->source==p || D->strip) ? NULL : f->source,D); + DumpInt(f->linedefined,D); + DumpInt(f->lastlinedefined,D); + DumpChar(f->nups,D); + DumpChar(f->numparams,D); + DumpChar(f->is_vararg,D); + DumpChar(f->maxstacksize,D); DumpCode(f,D); + DumpConstants(f,D); + DumpDebug(f,D); } static void DumpHeader(DumpState* D) { - DumpLiteral(LUA_SIGNATURE,D); - DumpByte(VERSION,D); - DumpByte(luaU_endianness(),D); - DumpByte(sizeof(int),D); - DumpByte(sizeof(size_t),D); - DumpByte(sizeof(Instruction),D); - DumpByte(SIZE_OP,D); - DumpByte(SIZE_A,D); - DumpByte(SIZE_B,D); - DumpByte(SIZE_C,D); - DumpByte(sizeof(lua_Number),D); - DumpNumber(TEST_NUMBER,D); + char h[LUAC_HEADERSIZE]; + luaU_header(h); + DumpBlock(h,LUAC_HEADERSIZE,D); } /* -** dump function as precompiled chunk +** dump Lua function as precompiled chunk */ -void luaU_dump (lua_State* L, const Proto* Main, lua_Chunkwriter w, void* data) +int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, void* data, int strip) { DumpState D; D.L=L; - D.write=w; + D.writer=w; D.data=data; + D.strip=strip; + D.status=0; DumpHeader(&D); - DumpFunction(Main,NULL,&D); + DumpFunction(f,NULL,&D); + return D.status; } - diff --git a/lib/lua/src/lfunc.c b/lib/lua/src/lfunc.c index 45a60cb..19fdc1a 100644 --- a/lib/lua/src/lfunc.c +++ b/lib/lua/src/lfunc.c @@ -1,13 +1,14 @@ /* -** $Id: lfunc.c,v 1.5 2007-07-25 16:54:32 pixel Exp $ +** $Id: lfunc.c,v 1.6 2007-07-27 10:05:53 pixel Exp $ ** Auxiliary functions to manipulate prototypes and closures ** See Copyright Notice in lua.h */ -#include <stdlib.h> +#include <stddef.h> #define lfunc_c +#define LUA_CORE #include "lua.h" @@ -18,57 +19,102 @@ #include "lstate.h" -Closure *luaF_newCclosure (lua_State *L, int nelems) { + +Closure *luaF_newCclosure (lua_State *L, int nelems, Table *e) { Closure *c = cast(Closure *, luaM_malloc(L, sizeCclosure(nelems))); - luaC_link(L, valtogco(c), LUA_TFUNCTION); + luaC_link(L, obj2gco(c), LUA_TFUNCTION); c->c.isC = 1; - c->c.nupvalues = cast(lu_byte, nelems); + c->c.env = e; + c->c.nupvalues = cast_byte(nelems); return c; } -Closure *luaF_newLclosure (lua_State *L, int nelems, TObject *e) { +Closure *luaF_newLclosure (lua_State *L, int nelems, Table *e) { Closure *c = cast(Closure *, luaM_malloc(L, sizeLclosure(nelems))); - luaC_link(L, valtogco(c), LUA_TFUNCTION); + luaC_link(L, obj2gco(c), LUA_TFUNCTION); c->l.isC = 0; - c->l.g = *e; - c->l.nupvalues = cast(lu_byte, nelems); + c->l.env = e; + c->l.nupvalues = cast_byte(nelems); + while (nelems--) c->l.upvals[nelems] = NULL; return c; } +UpVal *luaF_newupval (lua_State *L) { + UpVal *uv = luaM_new(L, UpVal); + luaC_link(L, obj2gco(uv), LUA_TUPVAL); + uv->v = &uv->u.value; + setnilvalue(uv->v); + return uv; +} + + UpVal *luaF_findupval (lua_State *L, StkId level) { + global_State *g = G(L); GCObject **pp = &L->openupval; UpVal *p; - UpVal *v; - while ((p = ngcotouv(*pp)) != NULL && p->v >= level) { - if (p->v == level) return p; + UpVal *uv; + while (*pp != NULL && (p = ngcotouv(*pp))->v >= level) { + lua_assert(p->v != &p->u.value); + if (p->v == level) { /* found a corresponding upvalue? */ + if (isdead(g, obj2gco(p))) /* is it dead? */ + changewhite(obj2gco(p)); /* ressurect it */ + return p; + } pp = &p->next; } - v = luaM_new(L, UpVal); /* not found: create a new one */ - v->tt = LUA_TUPVAL; - v->marked = 1; /* open upvalues should not be collected */ - v->v = level; /* current value lives in the stack */ - v->next = *pp; /* chain it in the proper position */ - *pp = valtogco(v); - return v; + uv = luaM_new(L, UpVal); /* not found: create a new one */ + uv->tt = LUA_TUPVAL; + uv->marked = luaC_white(g); + uv->v = level; /* current value lives in the stack */ + uv->next = *pp; /* chain it in the proper position */ + *pp = obj2gco(uv); + uv->u.l.prev = &g->uvhead; /* double link it in `uvhead' list */ + uv->u.l.next = g->uvhead.u.l.next; + uv->u.l.next->u.l.prev = uv; + g->uvhead.u.l.next = uv; + lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv); + return uv; +} + + +static void unlinkupval (UpVal *uv) { + lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv); + uv->u.l.next->u.l.prev = uv->u.l.prev; /* remove from `uvhead' list */ + uv->u.l.prev->u.l.next = uv->u.l.next; +} + + +void luaF_freeupval (lua_State *L, UpVal *uv) { + if (uv->v != &uv->u.value) /* is it open? */ + unlinkupval(uv); /* remove from open list */ + luaM_free(L, uv); /* free upvalue */ } void luaF_close (lua_State *L, StkId level) { - UpVal *p; - while ((p = ngcotouv(L->openupval)) != NULL && p->v >= level) { - setobj(&p->value, p->v); /* save current value (write barrier) */ - p->v = &p->value; /* now current value lives here */ - L->openupval = p->next; /* remove from `open' list */ - luaC_link(L, valtogco(p), LUA_TUPVAL); + UpVal *uv; + global_State *g = G(L); + while (L->openupval != NULL && (uv = ngcotouv(L->openupval))->v >= level) { + GCObject *o = obj2gco(uv); + lua_assert(!isblack(o) && uv->v != &uv->u.value); + L->openupval = uv->next; /* remove from `open' list */ + if (isdead(g, o)) + luaF_freeupval(L, uv); /* free upvalue */ + else { + unlinkupval(uv); + setobj(L, &uv->u.value, uv->v); + uv->v = &uv->u.value; /* now current value lives here */ + luaC_linkupval(L, uv); /* link upvalue into `gcroot' list */ + } } } Proto *luaF_newproto (lua_State *L) { Proto *f = luaM_new(L, Proto); - luaC_link(L, valtogco(f), LUA_TPROTO); + luaC_link(L, obj2gco(f), LUA_TPROTO); f->k = NULL; f->sizek = 0; f->p = NULL; @@ -85,7 +131,8 @@ Proto *luaF_newproto (lua_State *L) { f->lineinfo = NULL; f->sizelocvars = 0; f->locvars = NULL; - f->lineDefined = 0; + f->linedefined = 0; + f->lastlinedefined = 0; f->source = NULL; return f; } @@ -94,18 +141,18 @@ Proto *luaF_newproto (lua_State *L) { void luaF_freeproto (lua_State *L, Proto *f) { luaM_freearray(L, f->code, f->sizecode, Instruction); luaM_freearray(L, f->p, f->sizep, Proto *); - luaM_freearray(L, f->k, f->sizek, TObject); + luaM_freearray(L, f->k, f->sizek, TValue); luaM_freearray(L, f->lineinfo, f->sizelineinfo, int); luaM_freearray(L, f->locvars, f->sizelocvars, struct LocVar); luaM_freearray(L, f->upvalues, f->sizeupvalues, TString *); - luaM_freelem(L, f); + luaM_free(L, f); } void luaF_freeclosure (lua_State *L, Closure *c) { int size = (c->c.isC) ? sizeCclosure(c->c.nupvalues) : sizeLclosure(c->l.nupvalues); - luaM_free(L, c, size); + luaM_freemem(L, c, size); } diff --git a/lib/lua/src/lgc.c b/lib/lua/src/lgc.c index dbc022d..56c2aa4 100644 --- a/lib/lua/src/lgc.c +++ b/lib/lua/src/lgc.c @@ -1,5 +1,5 @@ /* -** $Id: lgc.c,v 1.6 2007-07-25 16:54:32 pixel Exp $ +** $Id: lgc.c,v 1.7 2007-07-27 10:05:54 pixel Exp $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -7,6 +7,7 @@ #include <string.h> #define lgc_c +#define LUA_CORE #include "lua.h" @@ -22,325 +23,352 @@ #include "ltm.h" -typedef struct GCState { - GCObject *tmark; /* list of marked objects to be traversed */ - GCObject *wk; /* list of traversed key-weak tables (to be cleared) */ - GCObject *wv; /* list of traversed value-weak tables */ - GCObject *wkv; /* list of traversed key-value weak tables */ - global_State *g; -} GCState; +#define GCSTEPSIZE 1024u +#define GCSWEEPMAX 40 +#define GCSWEEPCOST 10 +#define GCFINALIZECOST 100 -/* -** some userful bit tricks -*/ -#define setbit(x,b) ((x) |= (1<<(b))) -#define resetbit(x,b) ((x) &= cast(lu_byte, ~(1<<(b)))) -#define testbit(x,b) ((x) & (1<<(b))) +#define maskmarks cast_byte(~(bitmask(BLACKBIT)|WHITEBITS)) + +#define makewhite(g,x) \ + ((x)->gch.marked = cast_byte(((x)->gch.marked & maskmarks) | luaC_white(g))) + +#define white2gray(x) reset2bits((x)->gch.marked, WHITE0BIT, WHITE1BIT) +#define black2gray(x) resetbit((x)->gch.marked, BLACKBIT) -#define unmark(x) resetbit((x)->gch.marked, 0) -#define ismarked(x) ((x)->gch.marked & ((1<<4)|1)) +#define stringmark(s) reset2bits((s)->tsv.marked, WHITE0BIT, WHITE1BIT) -#define stringmark(s) setbit((s)->tsv.marked, 0) +#define isfinalized(u) testbit((u)->marked, FINALIZEDBIT) +#define markfinalized(u) l_setbit((u)->marked, FINALIZEDBIT) -#define isfinalized(u) (!testbit((u)->uv.marked, 1)) -#define markfinalized(u) resetbit((u)->uv.marked, 1) +#define KEYWEAK bitmask(KEYWEAKBIT) +#define VALUEWEAK bitmask(VALUEWEAKBIT) -#define KEYWEAKBIT 1 -#define VALUEWEAKBIT 2 -#define KEYWEAK (1<<KEYWEAKBIT) -#define VALUEWEAK (1<<VALUEWEAKBIT) +#define markvalue(g,o) { checkconsistency(o); \ + if (iscollectable(o) && iswhite(gcvalue(o))) reallymarkobject(g,gcvalue(o)); } -#define markobject(st,o) { checkconsistency(o); \ - if (iscollectable(o) && !ismarked(gcvalue(o))) reallymarkobject(st,gcvalue(o)); } +#define markobject(g,t) { if (iswhite(obj2gco(t))) \ + reallymarkobject(g, obj2gco(t)); } -#define condmarkobject(st,o,c) { checkconsistency(o); \ - if (iscollectable(o) && !ismarked(gcvalue(o)) && (c)) \ - reallymarkobject(st,gcvalue(o)); } -#define markvalue(st,t) { if (!ismarked(valtogco(t))) \ - reallymarkobject(st, valtogco(t)); } +#define setthreshold(g) (g->GCthreshold = (g->estimate/100) * g->gcpause) +static void removeentry (Node *n) { + lua_assert(ttisnil(gval(n))); + if (iscollectable(gkey(n))) + setttype(gkey(n), LUA_TDEADKEY); /* dead key; remove it */ +} + -static void reallymarkobject (GCState *st, GCObject *o) { - lua_assert(!ismarked(o)); - setbit(o->gch.marked, 0); /* mark object */ +static void reallymarkobject (global_State *g, GCObject *o) { + lua_assert(iswhite(o) && !isdead(g, o)); + white2gray(o); switch (o->gch.tt) { + case LUA_TSTRING: { + return; + } case LUA_TUSERDATA: { - markvalue(st, gcotou(o)->uv.metatable); - break; + Table *mt = gco2u(o)->metatable; + gray2black(o); /* udata are never gray */ + if (mt) markobject(g, mt); + markobject(g, gco2u(o)->env); + return; + } + case LUA_TUPVAL: { + UpVal *uv = gco2uv(o); + markvalue(g, uv->v); + if (uv->v == &uv->u.value) /* closed? */ + gray2black(o); /* open upvalues are never black */ + return; } case LUA_TFUNCTION: { - gcotocl(o)->c.gclist = st->tmark; - st->tmark = o; + gco2cl(o)->c.gclist = g->gray; + g->gray = o; break; } case LUA_TTABLE: { - gcotoh(o)->gclist = st->tmark; - st->tmark = o; + gco2h(o)->gclist = g->gray; + g->gray = o; break; } case LUA_TTHREAD: { - gcototh(o)->gclist = st->tmark; - st->tmark = o; + gco2th(o)->gclist = g->gray; + g->gray = o; break; } case LUA_TPROTO: { - gcotop(o)->gclist = st->tmark; - st->tmark = o; + gco2p(o)->gclist = g->gray; + g->gray = o; break; } - default: lua_assert(o->gch.tt == LUA_TSTRING); + default: lua_assert(0); } } -static void marktmu (GCState *st) { - GCObject *u; - for (u = st->g->tmudata; u; u = u->gch.next) { - unmark(u); /* may be marked, if left from previous GC */ - reallymarkobject(st, u); +static void marktmu (global_State *g) { + GCObject *u = g->tmudata; + if (u) { + do { + u = u->gch.next; + makewhite(g, u); /* may be marked, if left from previous GC */ + reallymarkobject(g, u); + } while (u != g->tmudata); } } /* move `dead' udata that need finalization to list `tmudata' */ -size_t luaC_separateudata (lua_State *L) { +size_t luaC_separateudata (lua_State *L, int all) { + global_State *g = G(L); size_t deadmem = 0; - GCObject **p = &G(L)->rootudata; + GCObject **p = &g->mainthread->next; GCObject *curr; - GCObject *collected = NULL; /* to collect udata with gc event */ - GCObject **lastcollected = &collected; while ((curr = *p) != NULL) { - lua_assert(curr->gch.tt == LUA_TUSERDATA); - if (ismarked(curr) || isfinalized(gcotou(curr))) + if (!(iswhite(curr) || all) || isfinalized(gco2u(curr))) p = &curr->gch.next; /* don't bother with them */ - - else if (fasttm(L, gcotou(curr)->uv.metatable, TM_GC) == NULL) { - markfinalized(gcotou(curr)); /* don't need finalization */ + else if (fasttm(L, gco2u(curr)->metatable, TM_GC) == NULL) { + markfinalized(gco2u(curr)); /* don't need finalization */ p = &curr->gch.next; } else { /* must call its gc method */ - deadmem += sizeudata(gcotou(curr)->uv.len); + deadmem += sizeudata(gco2u(curr)); + markfinalized(gco2u(curr)); *p = curr->gch.next; - curr->gch.next = NULL; /* link `curr' at the end of `collected' list */ - *lastcollected = curr; - lastcollected = &curr->gch.next; + /* link `curr' at the end of `tmudata' list */ + if (g->tmudata == NULL) /* list is empty? */ + g->tmudata = curr->gch.next = curr; /* creates a circular list */ + else { + curr->gch.next = g->tmudata->gch.next; + g->tmudata->gch.next = curr; + g->tmudata = curr; + } } } - /* insert collected udata with gc event into `tmudata' list */ - *lastcollected = G(L)->tmudata; - G(L)->tmudata = collected; return deadmem; } -static void removekey (Node *n) { - setnilvalue(gval(n)); /* remove corresponding value ... */ - if (iscollectable(gkey(n))) - setttype(gkey(n), LUA_TNONE); /* dead key; remove it */ -} - - -static void traversetable (GCState *st, Table *h) { +static int traversetable (global_State *g, Table *h) { int i; int weakkey = 0; int weakvalue = 0; - const TObject *mode; - markvalue(st, h->metatable); - lua_assert(h->lsizenode || h->node == st->g->dummynode); - mode = gfasttm(st->g, h->metatable, TM_MODE); + const TValue *mode; + if (h->metatable) + markobject(g, h->metatable); + mode = gfasttm(g, h->metatable, TM_MODE); if (mode && ttisstring(mode)) { /* is there a weak mode? */ weakkey = (strchr(svalue(mode), 'k') != NULL); weakvalue = (strchr(svalue(mode), 'v') != NULL); if (weakkey || weakvalue) { /* is really weak? */ - GCObject **weaklist; h->marked &= ~(KEYWEAK | VALUEWEAK); /* clear bits */ - h->marked |= cast(lu_byte, (weakkey << KEYWEAKBIT) | - (weakvalue << VALUEWEAKBIT)); - weaklist = (weakkey && weakvalue) ? &st->wkv : - (weakkey) ? &st->wk : - &st->wv; - h->gclist = *weaklist; /* must be cleared after GC, ... */ - *weaklist = valtogco(h); /* ... so put in the appropriate list */ + h->marked |= cast_byte((weakkey << KEYWEAKBIT) | + (weakvalue << VALUEWEAKBIT)); + h->gclist = g->weak; /* must be cleared after GC, ... */ + g->weak = obj2gco(h); /* ... so put in the appropriate list */ } } + if (weakkey && weakvalue) return 1; if (!weakvalue) { i = h->sizearray; while (i--) - markobject(st, &h->array[i]); + markvalue(g, &h->array[i]); } i = sizenode(h); while (i--) { Node *n = gnode(h, i); - if (!ttisnil(gval(n))) { + lua_assert(ttype(gkey(n)) != LUA_TDEADKEY || ttisnil(gval(n))); + if (ttisnil(gval(n))) + removeentry(n); /* remove empty entries */ + else { lua_assert(!ttisnil(gkey(n))); - condmarkobject(st, gkey(n), !weakkey); - condmarkobject(st, gval(n), !weakvalue); + if (!weakkey) markvalue(g, gkey(n)); + if (!weakvalue) markvalue(g, gval(n)); } } + return weakkey || weakvalue; } -static void traverseproto (GCState *st, Proto *f) { +/* +** All marks are conditional because a GC may happen while the +** prototype is still being created +*/ +static void traverseproto (global_State *g, Proto *f) { int i; - stringmark(f->source); - for (i=0; i<f->sizek; i++) { /* mark literal strings */ - if (ttisstring(f->k+i)) - stringmark(tsvalue(f->k+i)); + if (f->source) stringmark(f->source); + for (i=0; i<f->sizek; i++) /* mark literals */ + markvalue(g, &f->k[i]); + for (i=0; i<f->sizeupvalues; i++) { /* mark upvalue names */ + if (f->upvalues[i]) + stringmark(f->upvalues[i]); + } + for (i=0; i<f->sizep; i++) { /* mark nested protos */ + if (f->p[i]) + markobject(g, f->p[i]); + } + for (i=0; i<f->sizelocvars; i++) { /* mark local-variable names */ + if (f->locvars[i].varname) + stringmark(f->locvars[i].varname); } - for (i=0; i<f->sizeupvalues; i++) /* mark upvalue names */ - stringmark(f->upvalues[i]); - for (i=0; i<f->sizep; i++) /* mark nested protos */ - markvalue(st, f->p[i]); - for (i=0; i<f->sizelocvars; i++) /* mark local-variable names */ - stringmark(f->locvars[i].varname); - lua_assert(luaG_checkcode(f)); } -static void traverseclosure (GCState *st, Closure *cl) { +static void traverseclosure (global_State *g, Closure *cl) { + markobject(g, cl->c.env); if (cl->c.isC) { int i; for (i=0; i<cl->c.nupvalues; i++) /* mark its upvalues */ - markobject(st, &cl->c.upvalue[i]); + markvalue(g, &cl->c.upvalue[i]); } else { int i; lua_assert(cl->l.nupvalues == cl->l.p->nups); - markvalue(st, hvalue(&cl->l.g)); - markvalue(st, cl->l.p); - for (i=0; i<cl->l.nupvalues; i++) { /* mark its upvalues */ - UpVal *u = cl->l.upvals[i]; - markobject(st, u->v); - u->marked = 1; - } + markobject(g, cl->l.p); + for (i=0; i<cl->l.nupvalues; i++) /* mark its upvalues */ + markobject(g, cl->l.upvals[i]); } } static void checkstacksizes (lua_State *L, StkId max) { - int used = L->ci - L->base_ci; /* number of `ci' in use */ - if (4*used < L->size_ci && 2*BASIC_CI_SIZE < L->size_ci) + int ci_used = cast_int(L->ci - L->base_ci); /* number of `ci' in use */ + int s_used = cast_int(max - L->stack); /* part of stack in use */ + if (L->size_ci > LUAI_MAXCALLS) /* handling overflow? */ + return; /* do not touch the stacks */ + if (4*ci_used < L->size_ci && 2*BASIC_CI_SIZE < L->size_ci) luaD_reallocCI(L, L->size_ci/2); /* still big enough... */ - else condhardstacktests(luaD_reallocCI(L, L->size_ci)); - used = max - L->stack; /* part of stack in use */ - if (4*used < L->stacksize && 2*(BASIC_STACK_SIZE+EXTRA_STACK) < L->stacksize) + condhardstacktests(luaD_reallocCI(L, ci_used + 1)); + if (4*s_used < L->stacksize && + 2*(BASIC_STACK_SIZE+EXTRA_STACK) < L->stacksize) luaD_reallocstack(L, L->stacksize/2); /* still big enough... */ - else condhardstacktests(luaD_reallocstack(L, L->stacksize)); + condhardstacktests(luaD_reallocstack(L, s_used)); } -static void traversestack (GCState *st, lua_State *L1) { +static void traversestack (global_State *g, lua_State *l) { StkId o, lim; CallInfo *ci; - markobject(st, gt(L1)); - lim = L1->top; - for (ci = L1->base_ci; ci <= L1->ci; ci++) { - lua_assert(ci->top <= L1->stack_last); - lua_assert(ci->state & (CI_C | CI_HASFRAME | CI_SAVEDPC)); - if (lim < ci->top) - lim = ci->top; + markvalue(g, gt(l)); + lim = l->top; + for (ci = l->base_ci; ci <= l->ci; ci++) { + lua_assert(ci->top <= l->stack_last); + if (lim < ci->top) lim = ci->top; } - for (o = L1->stack; o < L1->top; o++) - markobject(st, o); + for (o = l->stack; o < l->top; o++) + markvalue(g, o); for (; o <= lim; o++) setnilvalue(o); - checkstacksizes(L1, lim); + checkstacksizes(l, lim); } -static lu_mem propagatemarks (GCState *st) { - lu_mem mf = 0; - while (st->tmark) { /* traverse marked objects */ - switch (st->tmark->gch.tt) { - case LUA_TTABLE: { - Table *h = gcotoh(st->tmark); - st->tmark = h->gclist; - traversetable(st, h); - mf += sizeof(Table) + sizeof(TObject) * h->sizearray + - sizeof(Node) * sizenode(h); - break; - } - case LUA_TFUNCTION: { - Closure *cl = gcotocl(st->tmark); - st->tmark = cl->c.gclist; - traverseclosure(st, cl); - mf += (cl->c.isC) ? sizeCclosure(cl->c.nupvalues) : - sizeLclosure(cl->l.nupvalues); - break; - } - case LUA_TTHREAD: { - lua_State *th = gcototh(st->tmark); - st->tmark = th->gclist; - traversestack(st, th); - mf += sizeof(lua_State) + sizeof(TObject) * th->stacksize + - sizeof(CallInfo) * th->size_ci; - break; - } - case LUA_TPROTO: { - Proto *p = gcotop(st->tmark); - st->tmark = p->gclist; - traverseproto(st, p); - /* do not need 'mf' for this case (cannot happen inside a udata) */ - break; - } - default: lua_assert(0); +/* +** traverse one gray object, turning it to black. +** Returns `quantity' traversed. +*/ +static l_mem propagatemark (global_State *g) { + GCObject *o = g->gray; + lua_assert(isgray(o)); + gray2black(o); + switch (o->gch.tt) { + case LUA_TTABLE: { + Table *h = gco2h(o); + g->gray = h->gclist; + if (traversetable(g, h)) /* table is weak? */ + black2gray(o); /* keep it gray */ + return sizeof(Table) + sizeof(TValue) * h->sizearray + + sizeof(Node) * sizenode(h); + } + case LUA_TFUNCTION: { + Closure *cl = gco2cl(o); + g->gray = cl->c.gclist; + traverseclosure(g, cl); + return (cl->c.isC) ? sizeCclosure(cl->c.nupvalues) : + sizeLclosure(cl->l.nupvalues); } + case LUA_TTHREAD: { + lua_State *th = gco2th(o); + g->gray = th->gclist; + th->gclist = g->grayagain; + g->grayagain = o; + black2gray(o); + traversestack(g, th); + return sizeof(lua_State) + sizeof(TValue) * th->stacksize + + sizeof(CallInfo) * th->size_ci; + } + case LUA_TPROTO: { + Proto *p = gco2p(o); + g->gray = p->gclist; + traverseproto(g, p); + return sizeof(Proto) + sizeof(Instruction) * p->sizecode + + sizeof(Proto *) * p->sizep + + sizeof(TValue) * p->sizek + + sizeof(int) * p->sizelineinfo + + sizeof(LocVar) * p->sizelocvars + + sizeof(TString *) * p->sizeupvalues; + } + default: lua_assert(0); return 0; } - return mf; } -static int valismarked (const TObject *o) { - if (ttisstring(o)) - stringmark(tsvalue(o)); /* strings are `values', so are never weak */ - return !iscollectable(o) || testbit(o->value.gc->gch.marked, 0); +static size_t propagateall (global_State *g) { + size_t m = 0; + while (g->gray) m += propagatemark(g); + return m; } /* -** clear collected keys from weaktables +** The next function tells whether a key or value can be cleared from +** a weak table. Non-collectable objects are never removed from weak +** tables. Strings behave as `values', so are never removed too. for +** other objects: if really collected, cannot keep them; for userdata +** being finalized, keep them in keys, but not in values */ -static void cleartablekeys (GCObject *l) { - while (l) { - Table *h = gcotoh(l); - int i = sizenode(h); - lua_assert(h->marked & KEYWEAK); - while (i--) { - Node *n = gnode(h, i); - if (!valismarked(gkey(n))) /* key was collected? */ - removekey(n); /* remove entry from table */ - } - l = h->gclist; +static int iscleared (const TValue *o, int iskey) { + if (!iscollectable(o)) return 0; + if (ttisstring(o)) { + stringmark(rawtsvalue(o)); /* strings are `values', so are never weak */ + return 0; } + return iswhite(gcvalue(o)) || + (ttisuserdata(o) && (!iskey && isfinalized(uvalue(o)))); } /* -** clear collected values from weaktables +** clear collected entries from weaktables */ -static void cleartablevalues (GCObject *l) { +static void cleartable (GCObject *l) { while (l) { - Table *h = gcotoh(l); + Table *h = gco2h(l); int i = h->sizearray; - lua_assert(h->marked & VALUEWEAK); - while (i--) { - TObject *o = &h->array[i]; - if (!valismarked(o)) /* value was collected? */ - setnilvalue(o); /* remove value */ + lua_assert(testbit(h->marked, VALUEWEAKBIT) || + testbit(h->marked, KEYWEAKBIT)); + if (testbit(h->marked, VALUEWEAKBIT)) { + while (i--) { + TValue *o = &h->array[i]; + if (iscleared(o, 0)) /* value was collected? */ + setnilvalue(o); /* remove value */ + } } i = sizenode(h); while (i--) { Node *n = gnode(h, i); - if (!valismarked(gval(n))) /* value was collected? */ - removekey(n); /* remove entry from table */ + if (!ttisnil(gval(n)) && /* non-empty entry? */ + (iscleared(key2tval(n), 1) || iscleared(gval(n), 0))) { + setnilvalue(gval(n)); /* remove value ... */ + removeentry(n); /* remove entry from table */ + } } l = h->gclist; } @@ -349,21 +377,22 @@ static void cleartablevalues (GCObject *l) { static void freeobj (lua_State *L, GCObject *o) { switch (o->gch.tt) { - case LUA_TPROTO: luaF_freeproto(L, gcotop(o)); break; - case LUA_TFUNCTION: luaF_freeclosure(L, gcotocl(o)); break; - case LUA_TUPVAL: luaM_freelem(L, gcotouv(o)); break; - case LUA_TTABLE: luaH_free(L, gcotoh(o)); break; + case LUA_TPROTO: luaF_freeproto(L, gco2p(o)); break; + case LUA_TFUNCTION: luaF_freeclosure(L, gco2cl(o)); break; + case LUA_TUPVAL: luaF_freeupval(L, gco2uv(o)); break; + case LUA_TTABLE: luaH_free(L, gco2h(o)); break; case LUA_TTHREAD: { - lua_assert(gcototh(o) != L && gcototh(o) != G(L)->mainthread); - luaE_freethread(L, gcototh(o)); + lua_assert(gco2th(o) != L && gco2th(o) != G(L)->mainthread); + luaE_freethread(L, gco2th(o)); break; } case LUA_TSTRING: { - luaM_free(L, o, sizestring(gcotots(o)->tsv.len)); + G(L)->strt.nuse--; + luaM_freemem(L, o, sizestring(gco2ts(o))); break; } case LUA_TUSERDATA: { - luaM_free(L, o, sizeudata(gcotou(o)->uv.len)); + luaM_freemem(L, o, sizeudata(gco2u(o))); break; } default: lua_assert(0); @@ -371,135 +400,312 @@ static void freeobj (lua_State *L, GCObject *o) { } -static int sweeplist (lua_State *L, GCObject **p, int limit) { + +#define sweepwholelist(L,p) sweeplist(L,p,MAX_LUMEM) + + +static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) { GCObject *curr; - int count = 0; /* number of collected items */ - while ((curr = *p) != NULL) { - if ((curr->gch.marked & ~(KEYWEAK | VALUEWEAK)) > limit) { - unmark(curr); + global_State *g = G(L); + int deadmask = otherwhite(g); + while ((curr = *p) != NULL && count-- > 0) { + if (curr->gch.tt == LUA_TTHREAD) /* sweep open upvalues of each thread */ + sweepwholelist(L, &gco2th(curr)->openupval); + if ((curr->gch.marked ^ WHITEBITS) & deadmask) { /* not dead? */ + lua_assert(!isdead(g, curr) || testbit(curr->gch.marked, FIXEDBIT)); + makewhite(g, curr); /* make it white (for next cycle) */ p = &curr->gch.next; } - else { - count++; + else { /* must erase `curr' */ + lua_assert(isdead(g, curr) || deadmask == bitmask(SFIXEDBIT)); *p = curr->gch.next; + if (curr == g->rootgc) /* is the first element of the list? */ + g->rootgc = curr->gch.next; /* adjust first */ freeobj(L, curr); } } - return count; -} - - -static void sweepstrings (lua_State *L, int all) { - int i; - for (i=0; i<G(L)->strt.size; i++) { /* for each list */ - G(L)->strt.nuse -= sweeplist(L, &G(L)->strt.hash[i], all); - } + return p; } -static void checkSizes (lua_State *L, size_t deadmem) { +static void checkSizes (lua_State *L) { + global_State *g = G(L); /* check size of string hash */ - if (G(L)->strt.nuse < cast(ls_nstr, G(L)->strt.size/4) && - G(L)->strt.size > MINSTRTABSIZE*2) - luaS_resize(L, G(L)->strt.size/2); /* table is too big */ + if (g->strt.nuse < cast(lu_int32, g->strt.size/4) && + g->strt.size > MINSTRTABSIZE*2) + luaS_resize(L, g->strt.size/2); /* table is too big */ /* check size of buffer */ - if (luaZ_sizebuffer(&G(L)->buff) > LUA_MINBUFFER*2) { /* buffer too big? */ - size_t newsize = luaZ_sizebuffer(&G(L)->buff) / 2; - luaZ_resizebuffer(L, &G(L)->buff, newsize); + if (luaZ_sizebuffer(&g->buff) > LUA_MINBUFFER*2) { /* buffer too big? */ + size_t newsize = luaZ_sizebuffer(&g->buff) / 2; + luaZ_resizebuffer(L, &g->buff, newsize); } - G(L)->GCthreshold = 2*G(L)->nblocks - deadmem; /* new threshold */ } -static void do1gcTM (lua_State *L, Udata *udata) { - const TObject *tm = fasttm(L, udata->uv.metatable, TM_GC); +static void GCTM (lua_State *L) { + global_State *g = G(L); + GCObject *o = g->tmudata->gch.next; /* get first element */ + Udata *udata = rawgco2u(o); + const TValue *tm; + /* remove udata from `tmudata' */ + if (o == g->tmudata) /* last element? */ + g->tmudata = NULL; + else + g->tmudata->gch.next = udata->uv.next; + udata->uv.next = g->mainthread->next; /* return it to `root' list */ + g->mainthread->next = o; + makewhite(g, o); + tm = fasttm(L, udata->uv.metatable, TM_GC); if (tm != NULL) { - setobj2s(L->top, tm); - setuvalue(L->top+1, udata); + lu_byte oldah = L->allowhook; + lu_mem oldt = g->GCthreshold; + L->allowhook = 0; /* stop debug hooks during GC tag method */ + g->GCthreshold = 2*g->totalbytes; /* avoid GC steps */ + setobj2s(L, L->top, tm); + setuvalue(L, L->top+1, udata); L->top += 2; luaD_call(L, L->top - 2, 0); + L->allowhook = oldah; /* restore hooks */ + g->GCthreshold = oldt; /* restore threshold */ } } +/* +** Call all GC tag methods +*/ void luaC_callGCTM (lua_State *L) { - lu_byte oldah = L->allowhook; - L->allowhook = 0; /* stop debug hooks during GC tag methods */ - L->top++; /* reserve space to keep udata while runs its gc method */ - while (G(L)->tmudata != NULL) { - GCObject *o = G(L)->tmudata; - Udata *udata = gcotou(o); - G(L)->tmudata = udata->uv.next; /* remove udata from `tmudata' */ - udata->uv.next = G(L)->rootudata; /* return it to `root' list */ - G(L)->rootudata = o; - setuvalue(L->top - 1, udata); /* keep a reference to it */ - unmark(o); - markfinalized(udata); - do1gcTM(L, udata); - } - L->top--; - L->allowhook = oldah; /* restore hooks */ + while (G(L)->tmudata) + GCTM(L); +} + + +void luaC_freeall (lua_State *L) { + global_State *g = G(L); + int i; + g->currentwhite = WHITEBITS | bitmask(SFIXEDBIT); /* mask to collect all elements */ + sweepwholelist(L, &g->rootgc); + for (i = 0; i < g->strt.size; i++) /* free all string lists */ + sweepwholelist(L, &g->strt.hash[i]); } -void luaC_sweep (lua_State *L, int all) { - if (all) all = 256; /* larger than any mark */ - sweeplist(L, &G(L)->rootudata, all); - sweepstrings(L, all); - sweeplist(L, &G(L)->rootgc, all); +static void markmt (global_State *g) { + int i; + for (i=0; i<NUM_TAGS; i++) + if (g->mt[i]) markobject(g, g->mt[i]); } /* mark root set */ -static void markroot (GCState *st, lua_State *L) { - global_State *g = st->g; - markobject(st, defaultmeta(L)); - markobject(st, registry(L)); - traversestack(st, g->mainthread); - if (L != g->mainthread) /* another thread is running? */ - markvalue(st, L); /* cannot collect it */ +static void markroot (lua_State *L) { + global_State *g = G(L); + g->gray = NULL; + g->grayagain = NULL; + g->weak = NULL; + markobject(g, g->mainthread); + /* make global table be traversed before main stack */ + markvalue(g, gt(g->mainthread)); + markvalue(g, registry(L)); + markmt(g); + g->gcstate = GCSpropagate; } -static size_t mark (lua_State *L) { - size_t deadmem; - GCState st; - GCObject *wkv; - st.g = G(L); - st.tmark = NULL; - st.wkv = st.wk = st.wv = NULL; - markroot(&st, L); - propagatemarks(&st); /* mark all reachable objects */ - cleartablevalues(st.wkv); - cleartablevalues(st.wv); - wkv = st.wkv; /* keys must be cleared after preserving udata */ - st.wkv = NULL; - st.wv = NULL; - deadmem = luaC_separateudata(L); /* separate userdata to be preserved */ - marktmu(&st); /* mark `preserved' userdata */ - deadmem += propagatemarks(&st); /* remark, to propagate `preserveness' */ - cleartablekeys(wkv); - /* `propagatemarks' may resuscitate some weak tables; clear them too */ - cleartablekeys(st.wk); - cleartablevalues(st.wv); - cleartablekeys(st.wkv); - cleartablevalues(st.wkv); - return deadmem; +static void remarkupvals (global_State *g) { + UpVal *uv; + for (uv = g->uvhead.u.l.next; uv != &g->uvhead; uv = uv->u.l.next) { + lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv); + if (isgray(obj2gco(uv))) + markvalue(g, uv->v); + } } -void luaC_collectgarbage (lua_State *L) { - size_t deadmem = mark(L); - luaC_sweep(L, 0); - checkSizes(L, deadmem); - luaC_callGCTM(L); +static void atomic (lua_State *L) { + global_State *g = G(L); + size_t udsize; /* total size of userdata to be finalized */ + /* remark occasional upvalues of (maybe) dead threads */ + remarkupvals(g); + /* traverse objects cautch by write barrier and by 'remarkupvals' */ + propagateall(g); + /* remark weak tables */ + g->gray = g->weak; + g->weak = NULL; + lua_assert(!iswhite(obj2gco(g->mainthread))); + markobject(g, L); /* mark running thread */ + markmt(g); /* mark basic metatables (again) */ + propagateall(g); + /* remark gray again */ + g->gray = g->grayagain; + g->grayagain = NULL; + propagateall(g); + udsize = luaC_separateudata(L, 0); /* separate userdata to be finalized */ + marktmu(g); /* mark `preserved' userdata */ + udsize += propagateall(g); /* remark, to propagate `preserveness' */ + cleartable(g->weak); /* remove collected objects from weak tables */ + /* flip current white */ + g->currentwhite = cast_byte(otherwhite(g)); + g->sweepstrgc = 0; + g->sweepgc = &g->rootgc; + g->gcstate = GCSsweepstring; + g->estimate = g->totalbytes - udsize; /* first estimate */ +} + + +static l_mem singlestep (lua_State *L) { + global_State *g = G(L); + /*lua_checkmemory(L);*/ + switch (g->gcstate) { + case GCSpause: { + markroot(L); /* start a new collection */ + return 0; + } + case GCSpropagate: { + if (g->gray) + return propagatemark(g); + else { /* no more `gray' objects */ + atomic(L); /* finish mark phase */ + return 0; + } + } + case GCSsweepstring: { + lu_mem old = g->totalbytes; + sweepwholelist(L, &g->strt.hash[g->sweepstrgc++]); + if (g->sweepstrgc >= g->strt.size) /* nothing more to sweep? */ + g->gcstate = GCSsweep; /* end sweep-string phase */ + lua_assert(old >= g->totalbytes); + g->estimate -= old - g->totalbytes; + return GCSWEEPCOST; + } + case GCSsweep: { + lu_mem old = g->totalbytes; + g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX); + if (*g->sweepgc == NULL) { /* nothing more to sweep? */ + checkSizes(L); + g->gcstate = GCSfinalize; /* end sweep phase */ + } + lua_assert(old >= g->totalbytes); + g->estimate -= old - g->totalbytes; + return GCSWEEPMAX*GCSWEEPCOST; + } + case GCSfinalize: { + if (g->tmudata) { + GCTM(L); + if (g->estimate > GCFINALIZECOST) + g->estimate -= GCFINALIZECOST; + return GCFINALIZECOST; + } + else { + g->gcstate = GCSpause; /* end collection */ + g->gcdept = 0; + return 0; + } + } + default: lua_assert(0); return 0; + } +} + + +void luaC_step (lua_State *L) { + global_State *g = G(L); + l_mem lim = (GCSTEPSIZE/100) * g->gcstepmul; + if (lim == 0) + lim = (MAX_LUMEM-1)/2; /* no limit */ + g->gcdept += g->totalbytes - g->GCthreshold; + do { + lim -= singlestep(L); + if (g->gcstate == GCSpause) + break; + } while (lim > 0); + if (g->gcstate != GCSpause) { + if (g->gcdept < GCSTEPSIZE) + g->GCthreshold = g->totalbytes + GCSTEPSIZE; /* - lim/g->gcstepmul;*/ + else { + g->gcdept -= GCSTEPSIZE; + g->GCthreshold = g->totalbytes; + } + } + else { + lua_assert(g->totalbytes >= g->estimate); + setthreshold(g); + } +} + + +void luaC_fullgc (lua_State *L) { + global_State *g = G(L); + if (g->gcstate <= GCSpropagate) { + /* reset sweep marks to sweep all elements (returning them to white) */ + g->sweepstrgc = 0; + g->sweepgc = &g->rootgc; + /* reset other collector lists */ + g->gray = NULL; + g->grayagain = NULL; + g->weak = NULL; + g->gcstate = GCSsweepstring; + } + lua_assert(g->gcstate != GCSpause && g->gcstate != GCSpropagate); + /* finish any pending sweep phase */ + while (g->gcstate != GCSfinalize) { + lua_assert(g->gcstate == GCSsweepstring || g->gcstate == GCSsweep); + singlestep(L); + } + markroot(L); + while (g->gcstate != GCSpause) { + singlestep(L); + } + setthreshold(g); +} + + +void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v) { + global_State *g = G(L); + lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o)); + lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause); + lua_assert(ttype(&o->gch) != LUA_TTABLE); + /* must keep invariant? */ + if (g->gcstate == GCSpropagate) + reallymarkobject(g, v); /* restore invariant */ + else /* don't mind */ + makewhite(g, o); /* mark as white just to avoid other barriers */ +} + + +void luaC_barrierback (lua_State *L, Table *t) { + global_State *g = G(L); + GCObject *o = obj2gco(t); + lua_assert(isblack(o) && !isdead(g, o)); + lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause); + black2gray(o); /* make table gray (again) */ + t->gclist = g->grayagain; + g->grayagain = o; } void luaC_link (lua_State *L, GCObject *o, lu_byte tt) { - o->gch.next = G(L)->rootgc; - G(L)->rootgc = o; - o->gch.marked = 0; + global_State *g = G(L); + o->gch.next = g->rootgc; + g->rootgc = o; + o->gch.marked = luaC_white(g); o->gch.tt = tt; } + +void luaC_linkupval (lua_State *L, UpVal *uv) { + global_State *g = G(L); + GCObject *o = obj2gco(uv); + o->gch.next = g->rootgc; /* link upvalue into `rootgc' list */ + g->rootgc = o; + if (isgray(o)) { + if (g->gcstate == GCSpropagate) { + gray2black(o); /* closed upvalues need barrier */ + luaC_barrier(L, uv, uv->v); + } + else { /* sweep phase: sweep it (turning it into white) */ + makewhite(g, o); + lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause); + } + } +} + diff --git a/lib/lua/src/llex.c b/lib/lua/src/llex.c index c06ea9f..f48a277 100644 --- a/lib/lua/src/llex.c +++ b/lib/lua/src/llex.c @@ -1,14 +1,16 @@ /* -** $Id: llex.c,v 1.6 2004-12-19 16:14:04 pixel Exp $ +** $Id: llex.c,v 1.7 2007-07-27 10:05:54 pixel Exp $ ** Lexical Analyzer ** See Copyright Notice in lua.h */ #include <ctype.h> +#include <locale.h> #include <string.h> #define llex_c +#define LUA_CORE #include "lua.h" @@ -18,32 +20,54 @@ #include "lparser.h" #include "lstate.h" #include "lstring.h" +#include "ltable.h" #include "lzio.h" -#define next(LS) (LS->current = zgetc(LS->z)) +#define next(ls) (ls->current = zgetc(ls->z)) + +#define currIsNewline(ls) (ls->current == '\n' || ls->current == '\r') + + /* ORDER RESERVED */ -static const char *const token2string [] = { +const char *const luaX_tokens [] = { "and", "break", "do", "else", "elseif", "end", "false", "for", "function", "if", "in", "local", "nil", "not", "or", "repeat", - "return", "then", "true", "until", "while", "*name", + "return", "then", "true", "until", "while", "..", "...", "==", ">=", "<=", "~=", - "*number", "*string", "<eof>" + "<number>", "<name>", "<string>", "<eof>", + NULL }; +#define save_and_next(ls) (save(ls, ls->current), next(ls)) + + +static void save (LexState *ls, int c) { + Mbuffer *b = ls->buff; + if (b->n + 1 > b->buffsize) { + size_t newsize; + if (b->buffsize >= MAX_SIZET/2) + luaX_lexerror(ls, "lexical element too long", 0); + newsize = b->buffsize * 2; + luaZ_resizebuffer(ls->L, b, newsize); + } + b->buffer[b->n++] = cast(char, c); +} + + void luaX_init (lua_State *L) { int i; for (i=0; i<NUM_RESERVED; i++) { - TString *ts = luaS_new(L, token2string[i]); + TString *ts = luaS_new(L, luaX_tokens[i]); luaS_fix(ts); /* reserved words are never collected */ - lua_assert(strlen(token2string[i])+1 <= TOKEN_LEN); - ts->tsv.reserved = cast(lu_byte, i+1); /* reserved word */ + lua_assert(strlen(luaX_tokens[i])+1 <= TOKEN_LEN); + ts->tsv.reserved = cast_byte(i+1); /* reserved word */ } } @@ -51,85 +75,77 @@ void luaX_init (lua_State *L) { #define MAXSRC 80 -void luaX_checklimit (LexState *ls, int val, int limit, const char *msg) { - if (val > limit) { - msg = luaO_pushfstring(ls->L, "too many %s (limit=%d)", msg, limit); - luaX_syntaxerror(ls, msg); +const char *luaX_token2str (LexState *ls, int token) { + if (token < FIRST_RESERVED) { + lua_assert(token == cast(unsigned char, token)); + return (iscntrl(token)) ? luaO_pushfstring(ls->L, "char(%d)", token) : + luaO_pushfstring(ls->L, "%c", token); } + else + return luaX_tokens[token-FIRST_RESERVED]; } -void luaX_errorline (LexState *ls, const char *s, const char *token, int line) { - lua_State *L = ls->L; - char buff[MAXSRC]; - luaO_chunkid(buff, getstr(ls->source), MAXSRC); - luaO_pushfstring(L, "%s:%d: %s near `%s'", buff, line, s, token); - luaD_throw(L, LUA_ERRSYNTAX); -} - - -static void luaX_error (LexState *ls, const char *s, const char *token) { - luaX_errorline(ls, s, token, ls->linenumber); -} - - -void luaX_syntaxerror (LexState *ls, const char *msg) { - const char *lasttoken; - switch (ls->t.token) { +static const char *txtToken (LexState *ls, int token) { + switch (token) { case TK_NAME: - lasttoken = getstr(ls->t.seminfo.ts); - break; case TK_STRING: case TK_NUMBER: - lasttoken = luaZ_buffer(ls->buff); - break; + save(ls, '\0'); + return luaZ_buffer(ls->buff); default: - lasttoken = luaX_token2str(ls, ls->t.token); - break; + return luaX_token2str(ls, token); } - luaX_error(ls, msg, lasttoken); } -const char *luaX_token2str (LexState *ls, int token) { - if (token < FIRST_RESERVED) { - lua_assert(token == (unsigned char)token); - return luaO_pushfstring(ls->L, "%c", token); - } - else - return token2string[token-FIRST_RESERVED]; +void luaX_lexerror (LexState *ls, const char *msg, int token) { + char buff[MAXSRC]; + luaO_chunkid(buff, getstr(ls->source), MAXSRC); + msg = luaO_pushfstring(ls->L, "%s:%d: %s", buff, ls->linenumber, msg); + if (token) + luaO_pushfstring(ls->L, "%s near " LUA_QS, msg, txtToken(ls, token)); + luaD_throw(ls->L, LUA_ERRSYNTAX); } -static void luaX_lexerror (LexState *ls, const char *s, int token) { - if (token == TK_EOS) - luaX_error(ls, s, luaX_token2str(ls, token)); - else - luaX_error(ls, s, luaZ_buffer(ls->buff)); +void luaX_syntaxerror (LexState *ls, const char *msg) { + luaX_lexerror(ls, msg, ls->t.token); } -static void inclinenumber (LexState *LS) { - next(LS); /* skip `\n' */ - ++LS->linenumber; - luaX_checklimit(LS, LS->linenumber, MAX_INT, "lines in a chunk"); +TString *luaX_newstring (LexState *ls, const char *str, size_t l) { + lua_State *L = ls->L; + TString *ts = luaS_newlstr(L, str, l); + TValue *o = luaH_setstr(L, ls->fs->h, ts); /* entry for `str' */ + if (ttisnil(o)) + setbvalue(o, 1); /* make sure `str' will not be collected */ + return ts; } -void luaX_setinput (lua_State *L, LexState *LS, ZIO *z, TString *source) { - LS->L = L; - LS->lookahead.token = TK_EOS; /* no look-ahead token */ - LS->z = z; - LS->fs = NULL; - LS->linenumber = 1; - LS->lastline = 1; - LS->source = source; - next(LS); /* read first char */ - if (LS->current == '#') { - do { /* skip first line */ - next(LS); - } while (LS->current != '\n' && LS->current != EOZ); - } +static void inclinenumber (LexState *ls) { + int old = ls->current; + lua_assert(currIsNewline(ls)); + next(ls); /* skip `\n' or `\r' */ + if (currIsNewline(ls) && ls->current != old) + next(ls); /* skip `\n\r' or `\r\n' */ + if (++ls->linenumber >= MAX_INT) + luaX_syntaxerror(ls, "chunk has too many lines"); +} + + +void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source) { + ls->decpoint = '.'; + ls->L = L; + ls->lookahead.token = TK_EOS; /* no look-ahead token */ + ls->z = z; + ls->fs = NULL; + ls->linenumber = 1; + ls->lastline = 1; + ls->source = source; + luaZ_resizebuffer(ls->L, ls->buff, LUA_MINBUFFER); /* initialize buffer */ + next(ls); /* read first char */ } @@ -141,269 +157,250 @@ void luaX_setinput (lua_State *L, LexState *LS, ZIO *z, TString *source) { */ -/* use buffer to store names, literal strings and numbers */ -/* extra space to allocate when growing buffer */ -#define EXTRABUFF 32 +static int check_next (LexState *ls, const char *set) { + if (!strchr(set, ls->current)) + return 0; + save_and_next(ls); + return 1; +} + -/* maximum number of chars that can be read without checking buffer size */ -#define MAXNOCHECK 5 +static void buffreplace (LexState *ls, char from, char to) { + size_t n = luaZ_bufflen(ls->buff); + char *p = luaZ_buffer(ls->buff); + while (n--) + if (p[n] == from) p[n] = to; +} -#define checkbuffer(LS, len) \ - if (((len)+MAXNOCHECK)*sizeof(char) > luaZ_sizebuffer((LS)->buff)) \ - luaZ_openspace((LS)->L, (LS)->buff, (len)+EXTRABUFF) -#define save(LS, c, l) \ - (luaZ_buffer((LS)->buff)[l++] = cast(char, c)) -#define save_and_next(LS, l) (save(LS, LS->current, l), next(LS)) +static void trydecpoint (LexState *ls, SemInfo *seminfo) { + /* format error: try to update decimal point separator */ + struct lconv *cv = localeconv(); + char old = ls->decpoint; + ls->decpoint = (cv ? cv->decimal_point[0] : '.'); + buffreplace(ls, old, ls->decpoint); /* try updated decimal separator */ + if (!luaO_str2d(luaZ_buffer(ls->buff), &seminfo->r)) { + /* format error with correct decimal point: no more options */ + buffreplace(ls, ls->decpoint, '.'); /* undo change (for error message) */ + luaX_lexerror(ls, "malformed number", TK_NUMBER); + } +} -static size_t readname (LexState *LS) { - size_t l = 0; - checkbuffer(LS, l); +/* LUA_NUMBER */ +static void read_numeral (LexState *ls, SemInfo *seminfo) { + lua_assert(isdigit(ls->current)); do { - checkbuffer(LS, l); - save_and_next(LS, l); - } while (isalnum(LS->current) || LS->current == '_'); - save(LS, '\0', l); - return l-1; + save_and_next(ls); + } while (isdigit(ls->current) || ls->current == '.'); + if (check_next(ls, "Ee")) /* `E'? */ + check_next(ls, "+-"); /* optional exponent sign */ + while (isalnum(ls->current) || ls->current == '_') + save_and_next(ls); + save(ls, '\0'); + buffreplace(ls, '.', ls->decpoint); /* follow locale for decimal point */ + if (!luaO_str2d(luaZ_buffer(ls->buff), &seminfo->r)) /* format error? */ + trydecpoint(ls, seminfo); /* try to update decimal point separator */ } -/* LUA_NUMBER */ -static void read_numeral (LexState *LS, int comma, SemInfo *seminfo) { - int oct = 0, hex = 0; - size_t l = 0; - checkbuffer(LS, l); - if (comma) save(LS, '.', l); - else if (LS->current == '0') { - oct = 1; - checkbuffer(LS, 1); - save_and_next(LS, l); - if (LS->current == 'x') { - oct = 0; - hex = 1; - checkbuffer(LS, 1); - save_and_next(LS, l); - } else if (LS->current == '.') { - oct = hex = 0; - } - } - while (isdigit(LS->current) || (hex && isxdigit(LS->current))) { - checkbuffer(LS, l); - save_and_next(LS, l); - } - checkbuffer(LS, 1); - if (LS->current == '.') { - save_and_next(LS, l); - if (hex || oct) { - save(LS, '\0', l); - luaX_lexerror(LS, - "error in number, mixing decimal point with octal or hexadecimal", - TK_NUMBER); - } - if (LS->current == '.') { - save_and_next(LS, l); - save(LS, '\0', l); - luaX_lexerror(LS, - "ambiguous syntax (decimal point x string concatenation)", - TK_NUMBER); - } - } - while (isdigit(LS->current)) { - checkbuffer(LS, l); - save_and_next(LS, l); +static int skip_sep (LexState *ls) { + int count = 0; + int s = ls->current; + lua_assert(s == '[' || s == ']'); + save_and_next(ls); + while (ls->current == '=') { + save_and_next(ls); + count++; } - if (LS->current == 'e' || LS->current == 'E') { - save_and_next(LS, l); /* read `E' */ - if (hex || oct) { - save(LS, '\0', l); - luaX_lexerror(LS, - "error in number, mixing exponential with octal or hexadecimal", - TK_NUMBER); - } - if (LS->current == '+' || LS->current == '-') - save_and_next(LS, l); /* optional exponent sign */ - while (isdigit(LS->current)) { - checkbuffer(LS, l); - save_and_next(LS, l); - } - } - save(LS, '\0', l); - if (!luaO_str2d(luaZ_buffer(LS->buff), &seminfo->r)) - luaX_lexerror(LS, "malformed number", TK_NUMBER); + return (ls->current == s) ? count : (-count) - 1; } -static void read_long_string (LexState *LS, SemInfo *seminfo) { +static void read_long_string (LexState *ls, SemInfo *seminfo, int sep) { int cont = 0; - size_t l = 0; - checkbuffer(LS, l); - save(LS, '[', l); /* save first `[' */ - save_and_next(LS, l); /* pass the second `[' */ - if (LS->current == '\n') /* string starts with a newline? */ - inclinenumber(LS); /* skip it */ + (void)(cont); /* avoid warnings when `cont' is not used */ + save_and_next(ls); /* skip 2nd `[' */ + if (currIsNewline(ls)) /* string starts with a newline? */ + inclinenumber(ls); /* skip it */ for (;;) { - checkbuffer(LS, l); - switch (LS->current) { + switch (ls->current) { case EOZ: - save(LS, '\0', l); - luaX_lexerror(LS, (seminfo) ? "unfinished long string" : + luaX_lexerror(ls, (seminfo) ? "unfinished long string" : "unfinished long comment", TK_EOS); break; /* to avoid warnings */ - case '[': - save_and_next(LS, l); - if (LS->current == '[') { +#if defined(LUA_COMPAT_LSTR) + case '[': { + if (skip_sep(ls) == sep) { + save_and_next(ls); /* skip 2nd `[' */ cont++; - save_and_next(LS, l); +#if LUA_COMPAT_LSTR == 1 + if (sep == 0) + luaX_lexerror(ls, "nesting of [[...]] is deprecated", '['); +#endif } - continue; - case ']': - save_and_next(LS, l); - if (LS->current == ']') { - if (cont == 0) goto endloop; + break; + } +#endif + case ']': { + if (skip_sep(ls) == sep) { + save_and_next(ls); /* skip 2nd `]' */ +#if defined(LUA_COMPAT_LSTR) && LUA_COMPAT_LSTR == 2 cont--; - save_and_next(LS, l); + if (sep == 0 && cont >= 0) break; +#endif + goto endloop; } - continue; + break; + } case '\n': - save(LS, '\n', l); - inclinenumber(LS); - if (!seminfo) l = 0; /* reset buffer to avoid wasting space */ - continue; - default: - save_and_next(LS, l); + case '\r': { + save(ls, '\n'); + inclinenumber(ls); + if (!seminfo) luaZ_resetbuffer(ls->buff); /* avoid wasting space */ + break; + } + default: { + if (seminfo) save_and_next(ls); + else next(ls); + } } } endloop: - save_and_next(LS, l); /* skip the second `]' */ - save(LS, '\0', l); if (seminfo) - seminfo->ts = luaS_newlstr(LS->L, luaZ_buffer(LS->buff) + 2, l - 5); + seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff) + (2 + sep), + luaZ_bufflen(ls->buff) - 2*(2 + sep)); } -static void read_string (LexState *LS, int del, SemInfo *seminfo) { - size_t l = 0; - checkbuffer(LS, l); - save_and_next(LS, l); - while (LS->current != del) { - checkbuffer(LS, l); - switch (LS->current) { +static void read_string (LexState *ls, int del, SemInfo *seminfo) { + save_and_next(ls); + while (ls->current != del) { + switch (ls->current) { case EOZ: - save(LS, '\0', l); - luaX_lexerror(LS, "unfinished string", TK_EOS); - break; /* to avoid warnings */ + luaX_lexerror(ls, "unfinished string", TK_EOS); + continue; /* to avoid warnings */ case '\n': - save(LS, '\0', l); - luaX_lexerror(LS, "unfinished string", TK_STRING); - break; /* to avoid warnings */ - case '\\': - next(LS); /* do not save the `\' */ - switch (LS->current) { - case 'a': save(LS, '\a', l); next(LS); break; - case 'b': save(LS, '\b', l); next(LS); break; - case 'f': save(LS, '\f', l); next(LS); break; - case 'n': save(LS, '\n', l); next(LS); break; - case 'r': save(LS, '\r', l); next(LS); break; - case 't': save(LS, '\t', l); next(LS); break; - case 'v': save(LS, '\v', l); next(LS); break; - case '\n': save(LS, '\n', l); inclinenumber(LS); break; - case EOZ: break; /* will raise an error next loop */ + case '\r': + luaX_lexerror(ls, "unfinished string", TK_STRING); + continue; /* to avoid warnings */ + case '\\': { + int c; + next(ls); /* do not save the `\' */ + switch (ls->current) { + case 'a': c = '\a'; break; + case 'b': c = '\b'; break; + case 'f': c = '\f'; break; + case 'n': c = '\n'; break; + case 'r': c = '\r'; break; + case 't': c = '\t'; break; + case 'v': c = '\v'; break; + case '\n': /* go through */ + case '\r': save(ls, '\n'); inclinenumber(ls); continue; + case EOZ: continue; /* will raise an error next loop */ default: { - if (!isdigit(LS->current)) - save_and_next(LS, l); /* handles \\, \", \', and \? */ + if (!isdigit(ls->current)) + save_and_next(ls); /* handles \\, \", \', and \? */ else { /* \xxx */ - int c = 0; int i = 0; + c = 0; do { - c = 10*c + (LS->current-'0'); - next(LS); - } while (++i<3 && isdigit(LS->current)); - if (c > UCHAR_MAX) { - save(LS, '\0', l); - luaX_lexerror(LS, "escape sequence too large", TK_STRING); - } - save(LS, c, l); + c = 10*c + (ls->current-'0'); + next(ls); + } while (++i<3 && isdigit(ls->current)); + if (c > UCHAR_MAX) + luaX_lexerror(ls, "escape sequence too large", TK_STRING); + save(ls, c); } + continue; } } - break; + save(ls, c); + next(ls); + continue; + } default: - save_and_next(LS, l); + save_and_next(ls); } } - save_and_next(LS, l); /* skip delimiter */ - save(LS, '\0', l); - seminfo->ts = luaS_newlstr(LS->L, luaZ_buffer(LS->buff) + 1, l - 3); + save_and_next(ls); /* skip delimiter */ + seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff) + 1, + luaZ_bufflen(ls->buff) - 2); } -int luaX_lex (LexState *LS, SemInfo *seminfo) { +static int llex (LexState *ls, SemInfo *seminfo) { + luaZ_resetbuffer(ls->buff); for (;;) { - switch (LS->current) { - - case '\n': { - inclinenumber(LS); + switch (ls->current) { + case '\n': + case '\r': { + inclinenumber(ls); continue; } case '-': { - next(LS); - if (LS->current != '-') return '-'; + next(ls); + if (ls->current != '-') return '-'; /* else is a comment */ - next(LS); - if (LS->current == '[' && (next(LS), LS->current == '[')) - read_long_string(LS, NULL); /* long comment */ - else /* short comment */ - while (LS->current != '\n' && LS->current != EOZ) - next(LS); + next(ls); + if (ls->current == '[') { + int sep = skip_sep(ls); + luaZ_resetbuffer(ls->buff); /* `skip_sep' may dirty the buffer */ + if (sep >= 0) { + read_long_string(ls, NULL, sep); /* long comment */ + luaZ_resetbuffer(ls->buff); + continue; + } + } + /* else short comment */ + while (!currIsNewline(ls) && ls->current != EOZ) + next(ls); continue; } case '[': { - next(LS); - if (LS->current != '[') return '['; - else { - read_long_string(LS, seminfo); + int sep = skip_sep(ls); + if (sep >= 0) { + read_long_string(ls, seminfo, sep); return TK_STRING; } + else if (sep == -1) return '['; + else luaX_lexerror(ls, "invalid long string delimiter", TK_STRING); } case '=': { - next(LS); - if (LS->current != '=') return '='; - else { next(LS); return TK_EQ; } + next(ls); + if (ls->current != '=') return '='; + else { next(ls); return TK_EQ; } } case '<': { - next(LS); - if (LS->current != '=') return '<'; - else { next(LS); return TK_LE; } + next(ls); + if (ls->current != '=') return '<'; + else { next(ls); return TK_LE; } } case '>': { - next(LS); - if (LS->current != '=') return '>'; - else { next(LS); return TK_GE; } + next(ls); + if (ls->current != '=') return '>'; + else { next(ls); return TK_GE; } } case '~': { - next(LS); - if (LS->current != '=') return '~'; - else { next(LS); return TK_NE; } + next(ls); + if (ls->current != '=') return '~'; + else { next(ls); return TK_NE; } } case '"': case '\'': { - read_string(LS, LS->current, seminfo); + read_string(ls, ls->current, seminfo); return TK_STRING; } case '.': { - next(LS); - if (LS->current == '.') { - next(LS); - if (LS->current == '.') { - next(LS); + save_and_next(ls); + if (check_next(ls, ".")) { + if (check_next(ls, ".")) return TK_DOTS; /* ... */ - } else return TK_CONCAT; /* .. */ } - else if (!isdigit(LS->current)) return '.'; + else if (!isdigit(ls->current)) return '.'; else { - read_numeral(LS, 1, seminfo); + read_numeral(ls, seminfo); return TK_NUMBER; } } @@ -411,29 +408,33 @@ int luaX_lex (LexState *LS, SemInfo *seminfo) { return TK_EOS; } default: { - if (isspace(LS->current)) { - next(LS); + if (isspace(ls->current)) { + lua_assert(!currIsNewline(ls)); + next(ls); continue; } - else if (isdigit(LS->current)) { - read_numeral(LS, 0, seminfo); + else if (isdigit(ls->current)) { + read_numeral(ls, seminfo); return TK_NUMBER; } - else if (isalpha(LS->current) || LS->current == '_') { + else if (isalpha(ls->current) || ls->current == '_') { /* identifier or reserved word */ - size_t l = readname(LS); - TString *ts = luaS_newlstr(LS->L, luaZ_buffer(LS->buff), l); + TString *ts; + do { + save_and_next(ls); + } while (isalnum(ls->current) || ls->current == '_'); + ts = luaX_newstring(ls, luaZ_buffer(ls->buff), + luaZ_bufflen(ls->buff)); if (ts->tsv.reserved > 0) /* reserved word? */ return ts->tsv.reserved - 1 + FIRST_RESERVED; - seminfo->ts = ts; - return TK_NAME; + else { + seminfo->ts = ts; + return TK_NAME; + } } else { - int c = LS->current; - if (iscntrl(c)) - luaX_error(LS, "invalid control char", - luaO_pushfstring(LS->L, "char(%d)", c)); - next(LS); + int c = ls->current; + next(ls); return c; /* single-char tokens (+ - / ...) */ } } @@ -441,4 +442,20 @@ int luaX_lex (LexState *LS, SemInfo *seminfo) { } } -#undef next + +void luaX_next (LexState *ls) { + ls->lastline = ls->linenumber; + if (ls->lookahead.token != TK_EOS) { /* is there a look-ahead token? */ + ls->t = ls->lookahead; /* use this one */ + ls->lookahead.token = TK_EOS; /* and discharge it */ + } + else + ls->t.token = llex(ls, &ls->t.seminfo); /* read next token */ +} + + +void luaX_lookahead (LexState *ls) { + lua_assert(ls->lookahead.token == TK_EOS); + ls->lookahead.token = llex(ls, &ls->lookahead.seminfo); +} + diff --git a/lib/lua/src/lmem.c b/lib/lua/src/lmem.c index b10ec3f..c95d1c3 100644 --- a/lib/lua/src/lmem.c +++ b/lib/lua/src/lmem.c @@ -1,13 +1,14 @@ /* -** $Id: lmem.c,v 1.4 2004-11-27 21:46:07 pixel Exp $ +** $Id: lmem.c,v 1.5 2007-07-27 10:05:54 pixel Exp $ ** Interface to Memory Manager ** See Copyright Notice in lua.h */ -#include <stdlib.h> +#include <stddef.h> #define lmem_c +#define LUA_CORE #include "lua.h" @@ -20,72 +21,66 @@ /* -** definition for realloc function. It must assure that l_realloc(NULL, -** 0, x) allocates a new block (ANSI C assures that). (`os' is the old -** block size; some allocators may use that.) +** About the realloc function: +** void * frealloc (void *ud, void *ptr, size_t osize, size_t nsize); +** (`osize' is the old size, `nsize' is the new size) +** +** Lua ensures that (ptr == NULL) iff (osize == 0). +** +** * frealloc(ud, NULL, 0, x) creates a new block of size `x' +** +** * frealloc(ud, p, x, 0) frees the block `p' +** (in this specific case, frealloc must return NULL). +** particularly, frealloc(ud, NULL, 0, 0) does nothing +** (which is equivalent to free(NULL) in ANSI C) +** +** frealloc returns NULL if it cannot create or reallocate the area +** (any reallocation to an equal or smaller size cannot fail!) */ -#ifndef l_realloc -#define l_realloc(b,os,s) realloc(b,s) -#endif -/* -** definition for free function. (`os' is the old block size; some -** allocators may use that.) -*/ -#ifndef l_free -#define l_free(b,os) free(b) -#endif #define MINSIZEARRAY 4 -void *luaM_growaux (lua_State *L, void *block, int *size, int size_elems, - int limit, const char *errormsg) { +void *luaM_growaux_ (lua_State *L, void *block, int *size, size_t size_elems, + int limit, const char *errormsg) { void *newblock; - int newsize = (*size)*2; - if (newsize < MINSIZEARRAY) - newsize = MINSIZEARRAY; /* minimum size */ - else if (*size >= limit/2) { /* cannot double it? */ - if (*size < limit - MINSIZEARRAY) /* try something smaller... */ - newsize = limit; /* still have at least MINSIZEARRAY free places */ - else luaG_runerror(L, errormsg); + int newsize; + if (*size >= limit/2) { /* cannot double it? */ + if (*size >= limit) /* cannot grow even a little? */ + luaG_runerror(L, errormsg); + newsize = limit; /* still have at least one free place */ + } + else { + newsize = (*size)*2; + if (newsize < MINSIZEARRAY) + newsize = MINSIZEARRAY; /* minimum size */ } - newblock = luaM_realloc(L, block, - cast(lu_mem, *size)*cast(lu_mem, size_elems), - cast(lu_mem, newsize)*cast(lu_mem, size_elems)); + newblock = luaM_reallocv(L, block, *size, newsize, size_elems); *size = newsize; /* update only when everything else is OK */ return newblock; } +void *luaM_toobig (lua_State *L) { + luaG_runerror(L, "memory allocation error: block too big"); + return NULL; /* to avoid warnings */ +} + + + /* ** generic allocation routine. */ -void *luaM_realloc (lua_State *L, void *block, lu_mem oldsize, lu_mem size) { - lua_assert((oldsize == 0) == (block == NULL)); - if (size == 0) { - if (block != NULL) { - l_free(block, oldsize); - block = NULL; - } - else return NULL; /* avoid `nblocks' computations when oldsize==size==0 */ - } - else if (size >= MAX_SIZET) - luaG_runerror(L, "memory allocation error: block too big"); - else { - block = l_realloc(block, oldsize, size); - if (block == NULL) { - if (L) - luaD_throw(L, LUA_ERRMEM); - else return NULL; /* error before creating state! */ - } - } - if (L) { - lua_assert(G(L) != NULL && G(L)->nblocks > 0); - G(L)->nblocks -= oldsize; - G(L)->nblocks += size; - } +void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) { + global_State *g = G(L); + lua_assert((osize == 0) == (block == NULL)); + block = (*g->frealloc)(g->ud, block, osize, nsize); + if (block == NULL && nsize > 0) + luaD_throw(L, LUA_ERRMEM); + lua_assert((nsize == 0) == (block == NULL)); + g->totalbytes = (g->totalbytes - osize) + nsize; return block; } diff --git a/lib/lua/src/lobject.c b/lib/lua/src/lobject.c index 62c70b6..0bfc9be 100644 --- a/lib/lua/src/lobject.c +++ b/lib/lua/src/lobject.c @@ -1,15 +1,17 @@ /* -** $Id: lobject.c,v 1.6 2004-12-19 16:14:04 pixel Exp $ +** $Id: lobject.c,v 1.7 2007-07-27 10:05:54 pixel Exp $ ** Some generic functions over Lua objects ** See Copyright Notice in lua.h */ #include <ctype.h> #include <stdarg.h> +#include <stdio.h> #include <stdlib.h> #include <string.h> #define lobject_c +#define LUA_CORE #include "lua.h" @@ -20,57 +22,60 @@ #include "lstring.h" #include "lvm.h" -const TObject luaO_nilobject = {LUA_TNIL, {NULL}}; + + +const TValue luaO_nilobject_ = {{NULL}, LUA_TNIL}; /* ** converts an integer to a "floating point byte", represented as -** (mmmmmxxx), where the real value is (xxx) * 2^(mmmmm) +** (eeeeexxx), where the real value is (1xxx) * 2^(eeeee - 1) if +** eeeee != 0 and (xxx) otherwise. */ int luaO_int2fb (unsigned int x) { - int m = 0; /* mantissa */ - while (x >= (1<<3)) { + int e = 0; /* expoent */ + while (x >= 16) { x = (x+1) >> 1; - m++; + e++; } - return (m << 3) | cast(int, x); + if (x < 8) return x; + else return ((e+1) << 3) | (cast_int(x) - 8); +} + + +/* converts back */ +int luaO_fb2int (int x) { + int e = (x >> 3) & 31; + if (e == 0) return x; + else return ((x & 7)+8) << (e - 1); } int luaO_log2 (unsigned int x) { - static const lu_byte log_8[255] = { - 0, - 1,1, - 2,2,2,2, - 3,3,3,3,3,3,3,3, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + static const lu_byte log_2[256] = { + 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7 + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8 }; - if (x >= 0x00010000) { - if (x >= 0x01000000) return log_8[((x>>24) & 0xff) - 1]+24; - else return log_8[((x>>16) & 0xff) - 1]+16; - } - else { - if (x >= 0x00000100) return log_8[((x>>8) & 0xff) - 1]+8; - else if (x) return log_8[(x & 0xff) - 1]; - return -1; /* special `log' for 0 */ - } + int l = -1; + while (x >= 256) { l += 8; x >>= 8; } + return l + log_2[x]; + } -int luaO_rawequalObj (const TObject *t1, const TObject *t2) { +int luaO_rawequalObj (const TValue *t1, const TValue *t2) { if (ttype(t1) != ttype(t2)) return 0; else switch (ttype(t1)) { case LUA_TNIL: return 1; case LUA_TNUMBER: - return nvalue(t1) == nvalue(t2); + return luai_numeq(nvalue(t1), nvalue(t2)); case LUA_TBOOLEAN: return bvalue(t1) == bvalue(t2); /* boolean true must be 1 !! */ case LUA_TLIGHTUSERDATA: @@ -84,45 +89,40 @@ int luaO_rawequalObj (const TObject *t1, const TObject *t2) { int luaO_str2d (const char *s, lua_Number *result) { char *endptr; - size_t l = strlen(s); - lua_Number res; - if ((l > 0) && (s[0] == '0') && (s[1] != '.')) { - if ((l > 2) && (s[1] == 'x')) { - res = strtol(s + 2, &endptr, 16); - } else { - res = strtol(s + 1, &endptr, 8); - } - } else { - res = strtod(s, &endptr); - } - if (endptr == s) return 0; /* no conversion */ - while (isspace((unsigned char)(*endptr))) endptr++; + *result = lua_str2number(s, &endptr); + if (endptr == s) return 0; /* conversion failed */ + if (*endptr == 'x' || *endptr == 'X') /* maybe an hexadecimal constant? */ + *result = cast_num(strtoul(s, &endptr, 16)); + if (*endptr == '\0') return 1; /* most common case */ + while (isspace(cast(unsigned char, *endptr))) endptr++; if (*endptr != '\0') return 0; /* invalid trailing characters? */ - *result = res; return 1; } static void pushstr (lua_State *L, const char *str) { - setsvalue2s(L->top, luaS_new(L, str)); + setsvalue2s(L, L->top, luaS_new(L, str)); incr_top(L); } -/* this function handles only `%d', `%c', %f, and `%s' formats */ +/* this function handles only `%d', `%c', %f, %p, and `%s' formats */ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) { int n = 1; pushstr(L, ""); for (;;) { const char *e = strchr(fmt, '%'); if (e == NULL) break; - setsvalue2s(L->top, luaS_newlstr(L, fmt, e-fmt)); + setsvalue2s(L, L->top, luaS_newlstr(L, fmt, e-fmt)); incr_top(L); switch (*(e+1)) { - case 's': - pushstr(L, va_arg(argp, char *)); + case 's': { + const char *s = va_arg(argp, char *); + if (s == NULL) s = "(null)"; + pushstr(L, s); break; + } case 'c': { char buff[2]; buff[0] = cast(char, va_arg(argp, int)); @@ -130,24 +130,40 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) { pushstr(L, buff); break; } - case 'd': - setnvalue(L->top, cast(lua_Number, va_arg(argp, int))); + case 'd': { + setnvalue(L->top, cast_num(va_arg(argp, int))); incr_top(L); break; - case 'f': - setnvalue(L->top, cast(lua_Number, va_arg(argp, l_uacNumber))); + } + case 'f': { + setnvalue(L->top, cast_num(va_arg(argp, l_uacNumber))); incr_top(L); break; - case '%': + } + case 'p': { + char buff[4*sizeof(void *) + 8]; /* should be enough space for a `%p' */ + sprintf(buff, "%p", va_arg(argp, void *)); + pushstr(L, buff); + break; + } + case '%': { pushstr(L, "%"); break; - default: lua_assert(0); + } + default: { + char buff[3]; + buff[0] = '%'; + buff[1] = *(e+1); + buff[2] = '\0'; + pushstr(L, buff); + break; + } } n += 2; fmt = e+2; } pushstr(L, fmt); - luaV_concat(L, n+1, L->top - L->base - 1); + luaV_concat(L, n+1, cast_int(L->top - L->base) - 1); L->top -= n; return svalue(L->top - 1); } @@ -163,26 +179,26 @@ const char *luaO_pushfstring (lua_State *L, const char *fmt, ...) { } -void luaO_chunkid (char *out, const char *source, int bufflen) { +void luaO_chunkid (char *out, const char *source, size_t bufflen) { if (*source == '=') { strncpy(out, source+1, bufflen); /* remove first char */ out[bufflen-1] = '\0'; /* ensures null termination */ } else { /* out = "source", or "...source" */ if (*source == '@') { - int l; + size_t l; source++; /* skip the `@' */ - bufflen -= sizeof(" `...' "); + bufflen -= sizeof(" '...' "); l = strlen(source); strcpy(out, ""); - if (l>bufflen) { + if (l > bufflen) { source += (l-bufflen); /* get last part of file name */ strcat(out, "..."); } strcat(out, source); } else { /* out = [string "string"] */ - int len = strcspn(source, "\n"); /* stop at first newline */ + size_t len = strcspn(source, "\n\r"); /* stop at first newline */ bufflen -= sizeof(" [string \"...\"] "); if (len > bufflen) len = bufflen; strcpy(out, "[string \""); diff --git a/lib/lua/src/lopcodes.c b/lib/lua/src/lopcodes.c index c018ea8..a38e405 100644 --- a/lib/lua/src/lopcodes.c +++ b/lib/lua/src/lopcodes.c @@ -1,22 +1,19 @@ /* -** $Id: lopcodes.c,v 1.4 2004-11-27 21:46:07 pixel Exp $ -** extracted automatically from lopcodes.h by mkprint.lua -** DO NOT EDIT +** $Id: lopcodes.c,v 1.5 2007-07-27 10:05:54 pixel Exp $ ** See Copyright Notice in lua.h */ #define lopcodes_c +#define LUA_CORE -#include "lua.h" -#include "lobject.h" #include "lopcodes.h" -#ifdef LUA_OPNAMES +/* ORDER OP */ -const char *const luaP_opnames[] = { +const char *const luaP_opnames[NUM_OPCODES+1] = { "MOVE", "LOADK", "LOADBOOL", @@ -33,70 +30,73 @@ const char *const luaP_opnames[] = { "SUB", "MUL", "DIV", + "MOD", "POW", "UNM", "NOT", + "LEN", "CONCAT", "JMP", "EQ", "LT", "LE", "TEST", + "TESTSET", "CALL", "TAILCALL", "RETURN", "FORLOOP", + "FORPREP", "TFORLOOP", - "TFORPREP", "SETLIST", - "SETLISTO", "CLOSE", - "CLOSURE" + "CLOSURE", + "VARARG", + NULL }; -#endif - -#define opmode(t,b,bk,ck,sa,k,m) (((t)<<OpModeT) | \ - ((b)<<OpModeBreg) | ((bk)<<OpModeBrk) | ((ck)<<OpModeCrk) | \ - ((sa)<<OpModesetA) | ((k)<<OpModeK) | (m)) +#define opmode(t,a,b,c,m) (((t)<<7) | ((a)<<6) | ((b)<<4) | ((c)<<2) | (m)) const lu_byte luaP_opmodes[NUM_OPCODES] = { -/* T B Bk Ck sA K mode opcode */ - opmode(0, 1, 0, 0, 1, 0, iABC) /* OP_MOVE */ - ,opmode(0, 0, 0, 0, 1, 1, iABx) /* OP_LOADK */ - ,opmode(0, 0, 0, 0, 1, 0, iABC) /* OP_LOADBOOL */ - ,opmode(0, 1, 0, 0, 1, 0, iABC) /* OP_LOADNIL */ - ,opmode(0, 0, 0, 0, 1, 0, iABC) /* OP_GETUPVAL */ - ,opmode(0, 0, 0, 0, 1, 1, iABx) /* OP_GETGLOBAL */ - ,opmode(0, 1, 0, 1, 1, 0, iABC) /* OP_GETTABLE */ - ,opmode(0, 0, 0, 0, 0, 1, iABx) /* OP_SETGLOBAL */ - ,opmode(0, 0, 0, 0, 0, 0, iABC) /* OP_SETUPVAL */ - ,opmode(0, 0, 1, 1, 0, 0, iABC) /* OP_SETTABLE */ - ,opmode(0, 0, 0, 0, 1, 0, iABC) /* OP_NEWTABLE */ - ,opmode(0, 1, 0, 1, 1, 0, iABC) /* OP_SELF */ - ,opmode(0, 0, 1, 1, 1, 0, iABC) /* OP_ADD */ - ,opmode(0, 0, 1, 1, 1, 0, iABC) /* OP_SUB */ - ,opmode(0, 0, 1, 1, 1, 0, iABC) /* OP_MUL */ - ,opmode(0, 0, 1, 1, 1, 0, iABC) /* OP_DIV */ - ,opmode(0, 0, 1, 1, 1, 0, iABC) /* OP_POW */ - ,opmode(0, 1, 0, 0, 1, 0, iABC) /* OP_UNM */ - ,opmode(0, 1, 0, 0, 1, 0, iABC) /* OP_NOT */ - ,opmode(0, 1, 0, 1, 1, 0, iABC) /* OP_CONCAT */ - ,opmode(0, 0, 0, 0, 0, 0, iAsBx) /* OP_JMP */ - ,opmode(1, 0, 1, 1, 0, 0, iABC) /* OP_EQ */ - ,opmode(1, 0, 1, 1, 0, 0, iABC) /* OP_LT */ - ,opmode(1, 0, 1, 1, 0, 0, iABC) /* OP_LE */ - ,opmode(1, 1, 0, 0, 1, 0, iABC) /* OP_TEST */ - ,opmode(0, 0, 0, 0, 0, 0, iABC) /* OP_CALL */ - ,opmode(0, 0, 0, 0, 0, 0, iABC) /* OP_TAILCALL */ - ,opmode(0, 0, 0, 0, 0, 0, iABC) /* OP_RETURN */ - ,opmode(0, 0, 0, 0, 0, 0, iAsBx) /* OP_FORLOOP */ - ,opmode(1, 0, 0, 0, 0, 0, iABC) /* OP_TFORLOOP */ - ,opmode(0, 0, 0, 0, 0, 0, iAsBx) /* OP_TFORPREP */ - ,opmode(0, 0, 0, 0, 0, 0, iABx) /* OP_SETLIST */ - ,opmode(0, 0, 0, 0, 0, 0, iABx) /* OP_SETLISTO */ - ,opmode(0, 0, 0, 0, 0, 0, iABC) /* OP_CLOSE */ - ,opmode(0, 0, 0, 0, 1, 0, iABx) /* OP_CLOSURE */ +/* T A B C mode opcode */ + opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_MOVE */ + ,opmode(0, 1, OpArgK, OpArgN, iABx) /* OP_LOADK */ + ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_LOADBOOL */ + ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_LOADNIL */ + ,opmode(0, 1, OpArgU, OpArgN, iABC) /* OP_GETUPVAL */ + ,opmode(0, 1, OpArgK, OpArgN, iABx) /* OP_GETGLOBAL */ + ,opmode(0, 1, OpArgR, OpArgK, iABC) /* OP_GETTABLE */ + ,opmode(0, 0, OpArgK, OpArgN, iABx) /* OP_SETGLOBAL */ + ,opmode(0, 0, OpArgU, OpArgN, iABC) /* OP_SETUPVAL */ + ,opmode(0, 0, OpArgK, OpArgK, iABC) /* OP_SETTABLE */ + ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_NEWTABLE */ + ,opmode(0, 1, OpArgR, OpArgK, iABC) /* OP_SELF */ + ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_ADD */ + ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_SUB */ + ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_MUL */ + ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_DIV */ + ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_MOD */ + ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_POW */ + ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_UNM */ + ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_NOT */ + ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_LEN */ + ,opmode(0, 1, OpArgR, OpArgR, iABC) /* OP_CONCAT */ + ,opmode(0, 0, OpArgR, OpArgN, iAsBx) /* OP_JMP */ + ,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_EQ */ + ,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_LT */ + ,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_LE */ + ,opmode(1, 1, OpArgR, OpArgU, iABC) /* OP_TEST */ + ,opmode(1, 1, OpArgR, OpArgU, iABC) /* OP_TESTSET */ + ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_CALL */ + ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_TAILCALL */ + ,opmode(0, 0, OpArgU, OpArgN, iABC) /* OP_RETURN */ + ,opmode(0, 1, OpArgR, OpArgN, iAsBx) /* OP_FORLOOP */ + ,opmode(0, 1, OpArgR, OpArgN, iAsBx) /* OP_FORPREP */ + ,opmode(1, 0, OpArgN, OpArgU, iABC) /* OP_TFORLOOP */ + ,opmode(0, 0, OpArgU, OpArgU, iABC) /* OP_SETLIST */ + ,opmode(0, 0, OpArgN, OpArgN, iABC) /* OP_CLOSE */ + ,opmode(0, 1, OpArgU, OpArgN, iABx) /* OP_CLOSURE */ + ,opmode(0, 1, OpArgU, OpArgN, iABC) /* OP_VARARG */ }; diff --git a/lib/lua/src/lparser.c b/lib/lua/src/lparser.c index 227e27a..206364a 100644 --- a/lib/lua/src/lparser.c +++ b/lib/lua/src/lparser.c @@ -1,5 +1,5 @@ /* -** $Id: lparser.c,v 1.6 2005-01-02 05:01:17 pixel Exp $ +** $Id: lparser.c,v 1.7 2007-07-27 10:05:54 pixel Exp $ ** Lua Parser ** See Copyright Notice in lua.h */ @@ -8,11 +8,13 @@ #include <string.h> #define lparser_c +#define LUA_CORE #include "lua.h" #include "lcode.h" #include "ldebug.h" +#include "ldo.h" #include "lfunc.h" #include "llex.h" #include "lmem.h" @@ -21,16 +23,15 @@ #include "lparser.h" #include "lstate.h" #include "lstring.h" +#include "ltable.h" +#define hasmultret(k) ((k) == VCALL || (k) == VVARARG) #define getlocvar(fs, i) ((fs)->f->locvars[(fs)->actvar[i]]) - -#define enterlevel(ls) if (++(ls)->nestlevel > LUA_MAXPARSERLEVEL) \ - luaX_syntaxerror(ls, "too many syntax levels"); -#define leavelevel(ls) ((ls)->nestlevel--) +#define luaY_checklimit(fs,v,l,m) if ((v)>(l)) errorlimit(fs,l,m) /* @@ -39,9 +40,9 @@ typedef struct BlockCnt { struct BlockCnt *previous; /* chain */ int breaklist; /* list of jumps out of this loop */ - int nactvar; /* # active local variables outside the breakable structure */ - int upval; /* true if some variable in the block is an upvalue */ - int isbreakable; /* true if `block' is a loop */ + lu_byte nactvar; /* # active locals outside the breakable structure */ + lu_byte upval; /* true if some variable in the block is an upvalue */ + lu_byte isbreakable; /* true if `block' is a loop */ } BlockCnt; @@ -53,33 +54,32 @@ static void chunk (LexState *ls); static void expr (LexState *ls, expdesc *v); - -static void next (LexState *ls) { - ls->lastline = ls->linenumber; - if (ls->lookahead.token != TK_EOS) { /* is there a look-ahead token? */ - ls->t = ls->lookahead; /* use this one */ - ls->lookahead.token = TK_EOS; /* and discharge it */ +static void anchor_token (LexState *ls) { + if (ls->t.token == TK_NAME || ls->t.token == TK_STRING) { + TString *ts = ls->t.seminfo.ts; + luaX_newstring(ls, getstr(ts), ts->tsv.len); } - else - ls->t.token = luaX_lex(ls, &ls->t.seminfo); /* read next token */ } -static void lookahead (LexState *ls) { - lua_assert(ls->lookahead.token == TK_EOS); - ls->lookahead.token = luaX_lex(ls, &ls->lookahead.seminfo); +static void error_expected (LexState *ls, int token) { + luaX_syntaxerror(ls, + luaO_pushfstring(ls->L, LUA_QS " expected", luaX_token2str(ls, token))); } -static void error_expected (LexState *ls, int token) { - luaX_syntaxerror(ls, - luaO_pushfstring(ls->L, "`%s' expected", luaX_token2str(ls, token))); +static void errorlimit (FuncState *fs, int limit, const char *what) { + const char *msg = (fs->f->linedefined == 0) ? + luaO_pushfstring(fs->L, "main function has more than %d %s", limit, what) : + luaO_pushfstring(fs->L, "function at line %d has more than %d %s", + fs->f->linedefined, limit, what); + luaX_lexerror(fs->ls, msg, 0); } static int testnext (LexState *ls, int c) { if (ls->t.token == c) { - next(ls); + luaX_next(ls); return 1; } else return 0; @@ -87,10 +87,15 @@ static int testnext (LexState *ls, int c) { static void check (LexState *ls, int c) { - if (!testnext(ls, c)) + if (ls->t.token != c) error_expected(ls, c); } +static void checknext (LexState *ls, int c) { + check(ls, c); + luaX_next(ls); +} + #define check_condition(ls,c,msg) { if (!(c)) luaX_syntaxerror(ls, msg); } @@ -102,7 +107,7 @@ static void check_match (LexState *ls, int what, int who, int where) { error_expected(ls, what); else { luaX_syntaxerror(ls, luaO_pushfstring(ls->L, - "`%s' expected (to close `%s' at line %d)", + LUA_QS " expected (to close " LUA_QS " at line %d)", luaX_token2str(ls, what), luaX_token2str(ls, who), where)); } } @@ -111,9 +116,9 @@ static void check_match (LexState *ls, int what, int who, int where) { static TString *str_checkname (LexState *ls) { TString *ts; - check_condition(ls, (ls->t.token == TK_NAME), "<name> expected"); + check(ls, TK_NAME); ts = ls->t.seminfo.ts; - next(ls); + luaX_next(ls); return ts; } @@ -121,7 +126,7 @@ static TString *str_checkname (LexState *ls) { static void init_exp (expdesc *e, expkind k, int i) { e->f = e->t = NO_JUMP; e->k = k; - e->info = i; + e->u.s.info = i; } @@ -135,26 +140,33 @@ static void checkname(LexState *ls, expdesc *e) { } -static int luaI_registerlocalvar (LexState *ls, TString *varname) { +static int registerlocalvar (LexState *ls, TString *varname) { FuncState *fs = ls->fs; Proto *f = fs->f; + int oldsize = f->sizelocvars; luaM_growvector(ls->L, f->locvars, fs->nlocvars, f->sizelocvars, - LocVar, MAX_INT, ""); + LocVar, SHRT_MAX, "too many local variables"); + while (oldsize < f->sizelocvars) f->locvars[oldsize++].varname = NULL; f->locvars[fs->nlocvars].varname = varname; + luaC_objbarrier(ls->L, f, varname); return fs->nlocvars++; } +#define new_localvarliteral(ls,v,n) \ + new_localvar(ls, luaX_newstring(ls, "" v, (sizeof(v)/sizeof(char))-1), n) + + static void new_localvar (LexState *ls, TString *name, int n) { FuncState *fs = ls->fs; - luaX_checklimit(ls, fs->nactvar+n+1, MAXVARS, "local variables"); - fs->actvar[fs->nactvar+n] = luaI_registerlocalvar(ls, name); + luaY_checklimit(fs, fs->nactvar+n+1, LUAI_MAXVARS, "local variables"); + fs->actvar[fs->nactvar+n] = cast(unsigned short, registerlocalvar(ls, name)); } static void adjustlocalvars (LexState *ls, int nvars) { FuncState *fs = ls->fs; - fs->nactvar += nvars; + fs->nactvar = cast_byte(fs->nactvar + nvars); for (; nvars; nvars--) { getlocvar(fs, fs->nactvar - nvars).startpc = fs->pc; } @@ -168,32 +180,26 @@ static void removevars (LexState *ls, int tolevel) { } -static void new_localvarstr (LexState *ls, const char *name, int n) { - new_localvar(ls, luaS_new(ls->L, name), n); -} - - -static void create_local (LexState *ls, const char *name) { - new_localvarstr(ls, name, 0); - adjustlocalvars(ls, 1); -} - - static int indexupvalue (FuncState *fs, TString *name, expdesc *v) { int i; Proto *f = fs->f; + int oldsize = f->sizeupvalues; for (i=0; i<f->nups; i++) { - if (fs->upvalues[i].k == v->k && fs->upvalues[i].info == v->info) { - lua_assert(fs->f->upvalues[i] == name); + if (fs->upvalues[i].k == v->k && fs->upvalues[i].info == v->u.s.info) { + lua_assert(f->upvalues[i] == name); return i; } } /* new one */ - luaX_checklimit(fs->ls, f->nups + 1, MAXUPVALUES, "upvalues"); - luaM_growvector(fs->L, fs->f->upvalues, f->nups, fs->f->sizeupvalues, + luaY_checklimit(fs, f->nups + 1, LUAI_MAXUPVALUES, "upvalues"); + luaM_growvector(fs->L, f->upvalues, f->nups, f->sizeupvalues, TString *, MAX_INT, ""); - fs->f->upvalues[f->nups] = name; - fs->upvalues[f->nups] = *v; + while (oldsize < f->sizeupvalues) f->upvalues[oldsize++] = NULL; + f->upvalues[f->nups] = name; + luaC_objbarrier(fs->L, f, name); + lua_assert(v->k == VLOCAL || v->k == VUPVAL); + fs->upvalues[f->nups].k = cast_byte(v->k); + fs->upvalues[f->nups].info = cast_byte(v->u.s.info); return f->nups++; } @@ -215,46 +221,46 @@ static void markupval (FuncState *fs, int level) { } -static void singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) { - if (fs == NULL) /* no more levels? */ +static int singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) { + if (fs == NULL) { /* no more levels? */ init_exp(var, VGLOBAL, NO_REG); /* default is global variable */ + return VGLOBAL; + } else { int v = searchvar(fs, n); /* look up at current level */ if (v >= 0) { init_exp(var, VLOCAL, v); if (!base) markupval(fs, v); /* local will be used as an upval */ + return VLOCAL; } else { /* not found at current level; try upper one */ - singlevaraux(fs->prev, n, var, 0); - if (var->k == VGLOBAL) { - if (base) - var->info = luaK_stringK(fs, n); /* info points to global name */ - } - else { /* LOCAL or UPVAL */ - var->info = indexupvalue(fs, n, var); - var->k = VUPVAL; /* upvalue in this level */ - } + if (singlevaraux(fs->prev, n, var, 0) == VGLOBAL) + return VGLOBAL; + var->u.s.info = indexupvalue(fs, n, var); /* else was LOCAL or UPVAL */ + var->k = VUPVAL; /* upvalue in this level */ + return VUPVAL; } } } -static TString *singlevar (LexState *ls, expdesc *var, int base) { +static void singlevar (LexState *ls, expdesc *var) { TString *varname = str_checkname(ls); - singlevaraux(ls->fs, varname, var, base); - return varname; + FuncState *fs = ls->fs; + if (singlevaraux(fs, varname, var, 1) == VGLOBAL) + var->u.s.info = luaK_stringK(fs, varname); /* info points to global name */ } static void adjust_assign (LexState *ls, int nvars, int nexps, expdesc *e) { FuncState *fs = ls->fs; int extra = nvars - nexps; - if (e->k == VCALL) { + if (hasmultret(e->k)) { extra++; /* includes call itself */ - if (extra <= 0) extra = 0; - else luaK_reserveregs(fs, extra-1); - luaK_setcallreturns(fs, e, extra); /* call provides the difference */ + if (extra < 0) extra = 0; + luaK_setreturns(fs, e, extra); /* last exp. provides the difference */ + if (extra > 1) luaK_reserveregs(fs, extra-1); } else { if (e->k != VVOID) luaK_exp2nextreg(fs, e); /* close last expression */ @@ -267,19 +273,16 @@ static void adjust_assign (LexState *ls, int nvars, int nexps, expdesc *e) { } -static void code_params (LexState *ls, int nparams, int dots) { - FuncState *fs = ls->fs; - adjustlocalvars(ls, nparams); - luaX_checklimit(ls, fs->nactvar, MAXPARAMS, "parameters"); - fs->f->numparams = cast(lu_byte, fs->nactvar); - fs->f->is_vararg = cast(lu_byte, dots); - if (dots) - create_local(ls, "arg"); - luaK_reserveregs(fs, fs->nactvar); /* reserve register for parameters */ +static void enterlevel (LexState *ls) { + if (++ls->L->nCcalls > LUAI_MAXCCALLS) + luaX_lexerror(ls, "chunk has too many syntax levels", 0); } -static void enterblock (FuncState *fs, BlockCnt *bl, int isbreakable) { +#define leavelevel(ls) ((ls)->L->nCcalls--) + + +static void enterblock (FuncState *fs, BlockCnt *bl, lu_byte isbreakable) { bl->breaklist = NO_JUMP; bl->isbreakable = isbreakable; bl->nactvar = fs->nactvar; @@ -296,6 +299,8 @@ static void leaveblock (FuncState *fs) { removevars(fs->ls, bl->nactvar); if (bl->upval) luaK_codeABC(fs, OP_CLOSE, bl->nactvar, 0, 0); + /* a block either controls scope or breaks (never both) */ + lua_assert(!bl->isbreakable || !bl->upval); lua_assert(bl->nactvar == fs->nactvar); fs->freereg = fs->nactvar; /* free registers */ luaK_patchtohere(fs, bl->breaklist); @@ -305,10 +310,13 @@ static void leaveblock (FuncState *fs) { static void pushclosure (LexState *ls, FuncState *func, expdesc *v) { FuncState *fs = ls->fs; Proto *f = fs->f; + int oldsize = f->sizep; int i; luaM_growvector(ls->L, f->p, fs->np, f->sizep, Proto *, MAXARG_Bx, "constant table overflow"); + while (oldsize < f->sizep) f->p[oldsize++] = NULL; f->p[fs->np++] = func->f; + luaC_objbarrier(ls->L, f, func->f); init_exp(v, VRELOCABLE, luaK_codeABx(fs, OP_CLOSURE, 0, fs->np-1)); for (i=0; i<func->f->nups; i++) { OpCode o = (func->upvalues[i].k == VLOCAL) ? OP_MOVE : OP_GETUPVAL; @@ -318,24 +326,30 @@ static void pushclosure (LexState *ls, FuncState *func, expdesc *v) { static void open_func (LexState *ls, FuncState *fs) { - Proto *f = luaF_newproto(ls->L); + lua_State *L = ls->L; + Proto *f = luaF_newproto(L); fs->f = f; fs->prev = ls->fs; /* linked list of funcstates */ fs->ls = ls; - fs->L = ls->L; + fs->L = L; ls->fs = fs; fs->pc = 0; - fs->lasttarget = 0; + fs->lasttarget = -1; fs->jpc = NO_JUMP; fs->freereg = 0; fs->nk = 0; - fs->h = luaH_new(ls->L, 0, 0); fs->np = 0; fs->nlocvars = 0; fs->nactvar = 0; fs->bl = NULL; f->source = ls->source; f->maxstacksize = 2; /* registers 0/1 are always valid */ + fs->h = luaH_new(L, 0, 0); + /* anchor table of constants and prototype (to avoid being collected) */ + sethvalue2s(L, L->top, fs->h); + incr_top(L); + setptvalue2s(L, L->top, f); + incr_top(L); } @@ -344,12 +358,12 @@ static void close_func (LexState *ls) { FuncState *fs = ls->fs; Proto *f = fs->f; removevars(ls, 0); - luaK_codeABC(fs, OP_RETURN, 0, 1, 0); /* final return */ + luaK_ret(fs, 0, 0); /* final return */ luaM_reallocvector(L, f->code, f->sizecode, fs->pc, Instruction); f->sizecode = fs->pc; luaM_reallocvector(L, f->lineinfo, f->sizelineinfo, fs->pc, int); f->sizelineinfo = fs->pc; - luaM_reallocvector(L, f->k, f->sizek, fs->nk, TObject); + luaM_reallocvector(L, f->k, f->sizek, fs->nk, TValue); f->sizek = fs->nk; luaM_reallocvector(L, f->p, f->sizep, fs->np, Proto *); f->sizep = fs->np; @@ -360,23 +374,26 @@ static void close_func (LexState *ls) { lua_assert(luaG_checkcode(f)); lua_assert(fs->bl == NULL); ls->fs = fs->prev; + L->top -= 2; /* remove table and prototype from the stack */ + /* last token read was anchored in defunct function; must reanchor it */ + if (fs) anchor_token(ls); } -Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff) { +Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, const char *name) { struct LexState lexstate; struct FuncState funcstate; lexstate.buff = buff; - lexstate.nestlevel = 0; - luaX_setinput(L, &lexstate, z, luaS_new(L, zname(z))); + luaX_setinput(L, &lexstate, z, luaS_new(L, name)); open_func(&lexstate, &funcstate); - next(&lexstate); /* read first token */ + funcstate.f->is_vararg = VARARG_ISVARARG; /* main func. is always vararg */ + luaX_next(&lexstate); /* read first token */ chunk(&lexstate); - check_condition(&lexstate, (lexstate.t.token == TK_EOS), "<eof> expected"); + check(&lexstate, TK_EOS); close_func(&lexstate); lua_assert(funcstate.prev == NULL); lua_assert(funcstate.f->nups == 0); - lua_assert(lexstate.nestlevel == 0); + lua_assert(lexstate.fs == NULL); return funcstate.f; } @@ -387,23 +404,23 @@ Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff) { /*============================================================*/ -static void luaY_field (LexState *ls, expdesc *v) { +static void field (LexState *ls, expdesc *v) { /* field -> ['.' | ':'] NAME */ FuncState *fs = ls->fs; expdesc key; luaK_exp2anyreg(fs, v); - next(ls); /* skip the dot or colon */ + luaX_next(ls); /* skip the dot or colon */ checkname(ls, &key); luaK_indexed(fs, v, &key); } -static void luaY_index (LexState *ls, expdesc *v) { +static void yindex (LexState *ls, expdesc *v) { /* index -> '[' expr ']' */ - next(ls); /* skip the '[' */ + luaX_next(ls); /* skip the '[' */ expr(ls, v); luaK_exp2val(ls->fs, v); - check(ls, ']'); + checknext(ls, ']'); } @@ -428,18 +445,18 @@ static void recfield (LexState *ls, struct ConsControl *cc) { FuncState *fs = ls->fs; int reg = ls->fs->freereg; expdesc key, val; + int rkkey; if (ls->t.token == TK_NAME) { - luaX_checklimit(ls, cc->nh, MAX_INT, "items in a constructor"); - cc->nh++; + luaY_checklimit(fs, cc->nh, MAX_INT, "items in a constructor"); checkname(ls, &key); } else /* ls->t.token == '[' */ - luaY_index(ls, &key); - check(ls, '='); - luaK_exp2RK(fs, &key); + yindex(ls, &key); + cc->nh++; + checknext(ls, '='); + rkkey = luaK_exp2RK(fs, &key); expr(ls, &val); - luaK_codeABC(fs, OP_SETTABLE, cc->t->info, luaK_exp2RK(fs, &key), - luaK_exp2RK(fs, &val)); + luaK_codeABC(fs, OP_SETTABLE, cc->t->u.s.info, rkkey, luaK_exp2RK(fs, &val)); fs->freereg = reg; /* free registers */ } @@ -449,31 +466,30 @@ static void closelistfield (FuncState *fs, struct ConsControl *cc) { luaK_exp2nextreg(fs, &cc->v); cc->v.k = VVOID; if (cc->tostore == LFIELDS_PER_FLUSH) { - luaK_codeABx(fs, OP_SETLIST, cc->t->info, cc->na-1); /* flush */ + luaK_setlist(fs, cc->t->u.s.info, cc->na, cc->tostore); /* flush */ cc->tostore = 0; /* no more items pending */ - fs->freereg = cc->t->info + 1; /* free registers */ } } static void lastlistfield (FuncState *fs, struct ConsControl *cc) { if (cc->tostore == 0) return; - if (cc->v.k == VCALL) { - luaK_setcallreturns(fs, &cc->v, LUA_MULTRET); - luaK_codeABx(fs, OP_SETLISTO, cc->t->info, cc->na-1); + if (hasmultret(cc->v.k)) { + luaK_setmultret(fs, &cc->v); + luaK_setlist(fs, cc->t->u.s.info, cc->na, LUA_MULTRET); + cc->na--; /* do not count last expression (unknown number of elements) */ } else { if (cc->v.k != VVOID) luaK_exp2nextreg(fs, &cc->v); - luaK_codeABx(fs, OP_SETLIST, cc->t->info, cc->na-1); + luaK_setlist(fs, cc->t->u.s.info, cc->na, cc->tostore); } - fs->freereg = cc->t->info + 1; /* free registers */ } static void listfield (LexState *ls, struct ConsControl *cc) { expr(ls, &cc->v); - luaX_checklimit(ls, cc->na, MAXARG_Bx, "items in a constructor"); + luaY_checklimit(ls->fs, cc->na, MAX_INT, "items in a constructor"); cc->na++; cc->tostore++; } @@ -490,15 +506,14 @@ static void constructor (LexState *ls, expdesc *t) { init_exp(t, VRELOCABLE, pc); init_exp(&cc.v, VVOID, 0); /* no value (yet) */ luaK_exp2nextreg(ls->fs, t); /* fix it at stack top (for gc) */ - check(ls, '{'); + checknext(ls, '{'); do { lua_assert(cc.v.k == VVOID || cc.tostore > 0); - testnext(ls, ';'); /* compatibility only */ if (ls->t.token == '}') break; closelistfield(fs, &cc); switch(ls->t.token) { case TK_NAME: { /* may be listfields or recfields */ - lookahead(ls); + luaX_lookahead(ls); if (ls->lookahead.token != '=') /* expression? */ listfield(ls, &cc); else @@ -518,7 +533,7 @@ static void constructor (LexState *ls, expdesc *t) { check_match(ls, '}', '{', line); lastlistfield(fs, &cc); SETARG_B(fs->f->code[pc], luaO_int2fb(cc.na)); /* set initial array size */ - SETARG_C(fs->f->code[pc], luaO_log2(cc.nh)+1); /* set initial table size */ + SETARG_C(fs->f->code[pc], luaO_int2fb(cc.nh)); /* set initial table size */ } /* }====================================================================== */ @@ -527,18 +542,34 @@ static void constructor (LexState *ls, expdesc *t) { static void parlist (LexState *ls) { /* parlist -> [ param { `,' param } ] */ + FuncState *fs = ls->fs; + Proto *f = fs->f; int nparams = 0; - int dots = 0; + f->is_vararg = 0; if (ls->t.token != ')') { /* is `parlist' not empty? */ do { switch (ls->t.token) { - case TK_DOTS: dots = 1; next(ls); break; - case TK_NAME: new_localvar(ls, str_checkname(ls), nparams++); break; - default: luaX_syntaxerror(ls, "<name> or `...' expected"); + case TK_NAME: { /* param -> NAME */ + new_localvar(ls, str_checkname(ls), nparams++); + break; + } + case TK_DOTS: { /* param -> `...' */ + luaX_next(ls); +#if defined(LUA_COMPAT_VARARG) + /* use `arg' as default name */ + new_localvarliteral(ls, "arg", nparams++); + f->is_vararg = VARARG_HASARG | VARARG_NEEDSARG; +#endif + f->is_vararg |= VARARG_ISVARARG; + break; + } + default: luaX_syntaxerror(ls, "<name> or " LUA_QL("...") " expected"); } - } while (!dots && testnext(ls, ',')); + } while (!f->is_vararg && testnext(ls, ',')); } - code_params(ls, nparams, dots); + adjustlocalvars(ls, nparams); + f->numparams = cast_byte(fs->nactvar - (f->is_vararg & VARARG_HASARG)); + luaK_reserveregs(fs, fs->nactvar); /* reserve register for parameters */ } @@ -546,13 +577,16 @@ static void body (LexState *ls, expdesc *e, int needself, int line) { /* body -> `(' parlist `)' chunk END */ FuncState new_fs; open_func(ls, &new_fs); - new_fs.f->lineDefined = line; - check(ls, '('); - if (needself) - create_local(ls, "self"); + new_fs.f->linedefined = line; + checknext(ls, '('); + if (needself) { + new_localvarliteral(ls, "self", 0); + adjustlocalvars(ls, 1); + } parlist(ls); - check(ls, ')'); + checknext(ls, ')'); chunk(ls); + new_fs.f->lastlinedefined = ls->linenumber; check_match(ls, TK_END, TK_FUNCTION, line); close_func(ls); pushclosure(ls, &new_fs, e); @@ -581,12 +615,12 @@ static void funcargs (LexState *ls, expdesc *f) { case '(': { /* funcargs -> `(' [ explist1 ] `)' */ if (line != ls->lastline) luaX_syntaxerror(ls,"ambiguous syntax (function call x new statement)"); - next(ls); + luaX_next(ls); if (ls->t.token == ')') /* arg list is empty? */ args.k = VVOID; else { explist1(ls, &args); - luaK_setcallreturns(fs, &args, LUA_MULTRET); + luaK_setmultret(fs, &args); } check_match(ls, ')', '(', line); break; @@ -597,7 +631,7 @@ static void funcargs (LexState *ls, expdesc *f) { } case TK_STRING: { /* funcargs -> STRING */ codestring(ls, &args, ls->t.seminfo.ts); - next(ls); /* must use `seminfo' before `next' */ + luaX_next(ls); /* must use `seminfo' before `next' */ break; } default: { @@ -606,8 +640,8 @@ static void funcargs (LexState *ls, expdesc *f) { } } lua_assert(f->k == VNONRELOC); - base = f->info; /* base register for call */ - if (args.k == VCALL) + base = f->u.s.info; /* base register for call */ + if (hasmultret(args.k)) nparams = LUA_MULTRET; /* open call */ else { if (args.k != VVOID) @@ -635,28 +669,16 @@ static void prefixexp (LexState *ls, expdesc *v) { switch (ls->t.token) { case '(': { int line = ls->linenumber; - next(ls); + luaX_next(ls); expr(ls, v); check_match(ls, ')', '(', line); luaK_dischargevars(ls->fs, v); return; } case TK_NAME: { - singlevar(ls, v, 1); - return; - } -#ifdef LUA_COMPATUPSYNTAX - case '%': { /* for compatibility only */ - TString *varname; - int line = ls->linenumber; - next(ls); /* skip `%' */ - varname = singlevar(ls, v, 1); - if (v->k != VUPVAL) - luaX_errorline(ls, "global upvalues are obsolete", - getstr(varname), line); + singlevar(ls, v); return; } -#endif default: { luaX_syntaxerror(ls, "unexpected symbol"); return; @@ -673,19 +695,19 @@ static void primaryexp (LexState *ls, expdesc *v) { for (;;) { switch (ls->t.token) { case '.': { /* field */ - luaY_field(ls, v); + field(ls, v); break; } case '[': { /* `[' exp1 `]' */ expdesc key; luaK_exp2anyreg(fs, v); - luaY_index(ls, &key); + yindex(ls, &key); luaK_indexed(fs, v, &key); break; } case ':': { /* `:' NAME funcargs */ expdesc key; - next(ls); + luaX_next(ls); checkname(ls, &key); luaK_self(fs, v, &key); funcargs(ls, v); @@ -703,48 +725,53 @@ static void primaryexp (LexState *ls, expdesc *v) { static void simpleexp (LexState *ls, expdesc *v) { - /* simpleexp -> NUMBER | STRING | NIL | constructor | FUNCTION body - | primaryexp */ + /* simpleexp -> NUMBER | STRING | NIL | true | false | ... | + constructor | FUNCTION body | primaryexp */ switch (ls->t.token) { case TK_NUMBER: { - init_exp(v, VK, luaK_numberK(ls->fs, ls->t.seminfo.r)); - next(ls); /* must use `seminfo' before `next' */ + init_exp(v, VKNUM, 0); + v->u.nval = ls->t.seminfo.r; break; } case TK_STRING: { codestring(ls, v, ls->t.seminfo.ts); - next(ls); /* must use `seminfo' before `next' */ break; } case TK_NIL: { init_exp(v, VNIL, 0); - next(ls); break; } case TK_TRUE: { init_exp(v, VTRUE, 0); - next(ls); break; } case TK_FALSE: { init_exp(v, VFALSE, 0); - next(ls); + break; + } + case TK_DOTS: { /* vararg */ + FuncState *fs = ls->fs; + check_condition(ls, fs->f->is_vararg, + "cannot use " LUA_QL("...") " outside a vararg function"); + fs->f->is_vararg &= ~VARARG_NEEDSARG; /* don't need 'arg' */ + init_exp(v, VVARARG, luaK_codeABC(fs, OP_VARARG, 0, 1, 0)); break; } case '{': { /* constructor */ constructor(ls, v); - break; + return; } case TK_FUNCTION: { - next(ls); + luaX_next(ls); body(ls, v, 0, ls->linenumber); - break; + return; } default: { primaryexp(ls, v); - break; + return; } } + luaX_next(ls); } @@ -752,6 +779,7 @@ static UnOpr getunopr (int op) { switch (op) { case TK_NOT: return OPR_NOT; case '-': return OPR_MINUS; + case '#': return OPR_LEN; default: return OPR_NOUNOPR; } } @@ -761,8 +789,9 @@ static BinOpr getbinopr (int op) { switch (op) { case '+': return OPR_ADD; case '-': return OPR_SUB; - case '*': return OPR_MULT; + case '*': return OPR_MUL; case '/': return OPR_DIV; + case '%': return OPR_MOD; case '^': return OPR_POW; case TK_CONCAT: return OPR_CONCAT; case TK_NE: return OPR_NE; @@ -782,9 +811,9 @@ static const struct { lu_byte left; /* left priority for each binary operator */ lu_byte right; /* right priority */ } priority[] = { /* ORDER OPR */ - {6, 6}, {6, 6}, {7, 7}, {7, 7}, /* arithmetic */ + {6, 6}, {6, 6}, {7, 7}, {7, 7}, {7, 7}, /* `+' `-' `/' `%' */ {10, 9}, {5, 4}, /* power and concat (right associative) */ - {3, 3}, {3, 3}, /* equality */ + {3, 3}, {3, 3}, /* equality and inequality */ {3, 3}, {3, 3}, {3, 3}, {3, 3}, /* order */ {2, 2}, {1, 1} /* logical (and/or) */ }; @@ -793,29 +822,29 @@ static const struct { /* -** subexpr -> (simplexep | unop subexpr) { binop subexpr } +** subexpr -> (simpleexp | unop subexpr) { binop subexpr } ** where `binop' is any binary operator with a priority higher than `limit' */ -static BinOpr subexpr (LexState *ls, expdesc *v, int limit) { +static BinOpr subexpr (LexState *ls, expdesc *v, unsigned int limit) { BinOpr op; UnOpr uop; enterlevel(ls); uop = getunopr(ls->t.token); if (uop != OPR_NOUNOPR) { - next(ls); + luaX_next(ls); subexpr(ls, v, UNARY_PRIORITY); luaK_prefix(ls->fs, uop, v); } else simpleexp(ls, v); /* expand while operators have priorities higher than `limit' */ op = getbinopr(ls->t.token); - while (op != OPR_NOBINOPR && cast(int, priority[op].left) > limit) { + while (op != OPR_NOBINOPR && priority[op].left > limit) { expdesc v2; BinOpr nextop; - next(ls); + luaX_next(ls); luaK_infix(ls->fs, op, v); /* read sub-expression with higher priority */ - nextop = subexpr(ls, &v2, cast(int, priority[op].right)); + nextop = subexpr(ls, &v2, priority[op].right); luaK_posfix(ls->fs, op, v, &v2); op = nextop; } @@ -825,7 +854,7 @@ static BinOpr subexpr (LexState *ls, expdesc *v, int limit) { static void expr (LexState *ls, expdesc *v) { - subexpr(ls, v, -1); + subexpr(ls, v, 0); } /* }==================================================================== */ @@ -882,18 +911,18 @@ static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v) { int conflict = 0; for (; lh; lh = lh->prev) { if (lh->v.k == VINDEXED) { - if (lh->v.info == v->info) { /* conflict? */ + if (lh->v.u.s.info == v->u.s.info) { /* conflict? */ conflict = 1; - lh->v.info = extra; /* previous assignment will use safe copy */ + lh->v.u.s.info = extra; /* previous assignment will use safe copy */ } - if (lh->v.aux == v->info) { /* conflict? */ + if (lh->v.u.s.aux == v->u.s.info) { /* conflict? */ conflict = 1; - lh->v.aux = extra; /* previous assignment will use safe copy */ + lh->v.u.s.aux = extra; /* previous assignment will use safe copy */ } } } if (conflict) { - luaK_codeABC(fs, OP_MOVE, fs->freereg, v->info, 0); /* make copy */ + luaK_codeABC(fs, OP_MOVE, fs->freereg, v->u.s.info, 0); /* make copy */ luaK_reserveregs(fs, 1); } } @@ -913,7 +942,7 @@ static void assignment (LexState *ls, struct LHS_assign *lh, int nvars) { } else { /* assignment -> `=' explist1 */ int nexps; - check(ls, '='); + checknext(ls, '='); nexps = explist1(ls, &e); if (nexps != nvars) { adjust_assign(ls, nvars, nexps, &e); @@ -921,7 +950,7 @@ static void assignment (LexState *ls, struct LHS_assign *lh, int nvars) { ls->fs->freereg -= nexps - nvars; /* remove extra values */ } else { - luaK_setcallreturns(ls->fs, &e, 1); /* close last expression */ + luaK_setoneret(ls->fs, &e); /* close last expression */ luaK_storevar(ls->fs, &lh->v, &e); return; /* avoid default */ } @@ -931,88 +960,74 @@ static void assignment (LexState *ls, struct LHS_assign *lh, int nvars) { } -static void cond (LexState *ls, expdesc *v) { +static int cond (LexState *ls) { /* cond -> exp */ - expr(ls, v); /* read condition */ - if (v->k == VNIL) v->k = VFALSE; /* `falses' are all equal here */ - luaK_goiftrue(ls->fs, v); - luaK_patchtohere(ls->fs, v->t); + expdesc v; + expr(ls, &v); /* read condition */ + if (v.k == VNIL) v.k = VFALSE; /* `falses' are all equal here */ + luaK_goiftrue(ls->fs, &v); + return v.f; } -/* -** The while statement optimizes its code by coding the condition -** after its body (and thus avoiding one jump in the loop). -*/ - -/* -** maximum size of expressions for optimizing `while' code -*/ -#ifndef MAXEXPWHILE -#define MAXEXPWHILE 100 -#endif +static void breakstat (LexState *ls) { + FuncState *fs = ls->fs; + BlockCnt *bl = fs->bl; + int upval = 0; + while (bl && !bl->isbreakable) { + upval |= bl->upval; + bl = bl->previous; + } + if (!bl) + luaX_syntaxerror(ls, "no loop to break"); + if (upval) + luaK_codeABC(fs, OP_CLOSE, bl->nactvar, 0, 0); + luaK_concat(fs, &bl->breaklist, luaK_jump(fs)); +} -/* -** the call `luaK_goiffalse' may grow the size of an expression by -** at most this: -*/ -#define EXTRAEXP 5 static void whilestat (LexState *ls, int line) { /* whilestat -> WHILE cond DO block END */ - Instruction codeexp[MAXEXPWHILE + EXTRAEXP]; - int lineexp; - int i; - int sizeexp; FuncState *fs = ls->fs; - int whileinit, blockinit, expinit; - expdesc v; + int whileinit; + int condexit; BlockCnt bl; - next(ls); /* skip WHILE */ - whileinit = luaK_jump(fs); /* jump to condition (which will be moved) */ - expinit = luaK_getlabel(fs); - expr(ls, &v); /* parse condition */ - if (v.k == VK) v.k = VTRUE; /* `trues' are all equal here */ - lineexp = ls->linenumber; - luaK_goiffalse(fs, &v); - luaK_concat(fs, &v.f, fs->jpc); - fs->jpc = NO_JUMP; - sizeexp = fs->pc - expinit; /* size of expression code */ - if (sizeexp > MAXEXPWHILE) - luaX_syntaxerror(ls, "`while' condition too complex"); - for (i = 0; i < sizeexp; i++) /* save `exp' code */ - codeexp[i] = fs->f->code[expinit + i]; - fs->pc = expinit; /* remove `exp' code */ + luaX_next(ls); /* skip WHILE */ + whileinit = luaK_getlabel(fs); + condexit = cond(ls); enterblock(fs, &bl, 1); - check(ls, TK_DO); - blockinit = luaK_getlabel(fs); + checknext(ls, TK_DO); block(ls); - luaK_patchtohere(fs, whileinit); /* initial jump jumps to here */ - /* move `exp' back to code */ - if (v.t != NO_JUMP) v.t += fs->pc - expinit; - if (v.f != NO_JUMP) v.f += fs->pc - expinit; - for (i=0; i<sizeexp; i++) - luaK_code(fs, codeexp[i], lineexp); + luaK_patchlist(fs, luaK_jump(fs), whileinit); check_match(ls, TK_END, TK_WHILE, line); leaveblock(fs); - luaK_patchlist(fs, v.t, blockinit); /* true conditions go back to loop */ - luaK_patchtohere(fs, v.f); /* false conditions finish the loop */ + luaK_patchtohere(fs, condexit); /* false conditions finish the loop */ } static void repeatstat (LexState *ls, int line) { /* repeatstat -> REPEAT block UNTIL cond */ + int condexit; FuncState *fs = ls->fs; int repeat_init = luaK_getlabel(fs); - expdesc v; - BlockCnt bl; - enterblock(fs, &bl, 1); - next(ls); - block(ls); + BlockCnt bl1, bl2; + enterblock(fs, &bl1, 1); /* loop block */ + enterblock(fs, &bl2, 0); /* scope block */ + luaX_next(ls); /* skip REPEAT */ + chunk(ls); check_match(ls, TK_UNTIL, TK_REPEAT, line); - cond(ls, &v); - luaK_patchlist(fs, v.f, repeat_init); - leaveblock(fs); + condexit = cond(ls); /* read condition (inside scope block) */ + if (!bl2.upval) { /* no upvalues? */ + leaveblock(fs); /* finish scope */ + luaK_patchlist(ls->fs, condexit, repeat_init); /* close the loop */ + } + else { /* complete semantics when there are upvalues */ + breakstat(ls); /* if condition then break */ + luaK_patchtohere(ls->fs, condexit); /* else... */ + leaveblock(fs); /* finish scope... */ + luaK_patchlist(ls->fs, luaK_jump(fs), repeat_init); /* and repeat */ + } + leaveblock(fs); /* finish loop */ } @@ -1027,33 +1042,37 @@ static int exp1 (LexState *ls) { static void forbody (LexState *ls, int base, int line, int nvars, int isnum) { + /* forbody -> DO block */ BlockCnt bl; FuncState *fs = ls->fs; int prep, endfor; - adjustlocalvars(ls, nvars); /* scope for all variables */ - check(ls, TK_DO); - enterblock(fs, &bl, 1); /* loop block */ - prep = luaK_getlabel(fs); + adjustlocalvars(ls, 3); /* control variables */ + checknext(ls, TK_DO); + prep = isnum ? luaK_codeAsBx(fs, OP_FORPREP, base, NO_JUMP) : luaK_jump(fs); + enterblock(fs, &bl, 0); /* scope for declared variables */ + adjustlocalvars(ls, nvars); + luaK_reserveregs(fs, nvars); block(ls); - luaK_patchtohere(fs, prep-1); + leaveblock(fs); /* end of scope for declared variables */ + luaK_patchtohere(fs, prep); endfor = (isnum) ? luaK_codeAsBx(fs, OP_FORLOOP, base, NO_JUMP) : - luaK_codeABC(fs, OP_TFORLOOP, base, 0, nvars - 3); + luaK_codeABC(fs, OP_TFORLOOP, base, 0, nvars); luaK_fixline(fs, line); /* pretend that `OP_FOR' starts the loop */ - luaK_patchlist(fs, (isnum) ? endfor : luaK_jump(fs), prep); - leaveblock(fs); + luaK_patchlist(fs, (isnum ? endfor : luaK_jump(fs)), prep + 1); } static void fornum (LexState *ls, TString *varname, int line) { - /* fornum -> NAME = exp1,exp1[,exp1] DO body */ + /* fornum -> NAME = exp1,exp1[,exp1] forbody */ FuncState *fs = ls->fs; int base = fs->freereg; - new_localvar(ls, varname, 0); - new_localvarstr(ls, "(for limit)", 1); - new_localvarstr(ls, "(for step)", 2); - check(ls, '='); + new_localvarliteral(ls, "(for index)", 0); + new_localvarliteral(ls, "(for limit)", 1); + new_localvarliteral(ls, "(for step)", 2); + new_localvar(ls, varname, 3); + checknext(ls, '='); exp1(ls); /* initial value */ - check(ls, ','); + checknext(ls, ','); exp1(ls); /* limit */ if (testnext(ls, ',')) exp1(ls); /* optional step */ @@ -1061,79 +1080,81 @@ static void fornum (LexState *ls, TString *varname, int line) { luaK_codeABx(fs, OP_LOADK, fs->freereg, luaK_numberK(fs, 1)); luaK_reserveregs(fs, 1); } - luaK_codeABC(fs, OP_SUB, fs->freereg - 3, fs->freereg - 3, fs->freereg - 1); - luaK_jump(fs); - forbody(ls, base, line, 3, 1); + forbody(ls, base, line, 1, 1); } static void forlist (LexState *ls, TString *indexname) { - /* forlist -> NAME {,NAME} IN explist1 DO body */ + /* forlist -> NAME {,NAME} IN explist1 forbody */ FuncState *fs = ls->fs; expdesc e; int nvars = 0; int line; int base = fs->freereg; - new_localvarstr(ls, "(for generator)", nvars++); - new_localvarstr(ls, "(for state)", nvars++); + /* create control variables */ + new_localvarliteral(ls, "(for generator)", nvars++); + new_localvarliteral(ls, "(for state)", nvars++); + new_localvarliteral(ls, "(for control)", nvars++); + /* create declared variables */ new_localvar(ls, indexname, nvars++); while (testnext(ls, ',')) new_localvar(ls, str_checkname(ls), nvars++); - check(ls, TK_IN); + checknext(ls, TK_IN); line = ls->linenumber; - adjust_assign(ls, nvars, explist1(ls, &e), &e); + adjust_assign(ls, 3, explist1(ls, &e), &e); luaK_checkstack(fs, 3); /* extra space to call generator */ - luaK_codeAsBx(fs, OP_TFORPREP, base, NO_JUMP); - forbody(ls, base, line, nvars, 0); + forbody(ls, base, line, nvars - 3, 0); } static void forstat (LexState *ls, int line) { - /* forstat -> fornum | forlist */ + /* forstat -> FOR (fornum | forlist) END */ FuncState *fs = ls->fs; TString *varname; BlockCnt bl; - enterblock(fs, &bl, 0); /* block to control variable scope */ - next(ls); /* skip `for' */ + enterblock(fs, &bl, 1); /* scope for loop and control variables */ + luaX_next(ls); /* skip `for' */ varname = str_checkname(ls); /* first variable name */ switch (ls->t.token) { case '=': fornum(ls, varname, line); break; case ',': case TK_IN: forlist(ls, varname); break; - default: luaX_syntaxerror(ls, "`=' or `in' expected"); + default: luaX_syntaxerror(ls, LUA_QL("=") " or " LUA_QL("in") " expected"); } check_match(ls, TK_END, TK_FOR, line); - leaveblock(fs); + leaveblock(fs); /* loop scope (`break' jumps to this point) */ } -static void test_then_block (LexState *ls, expdesc *v) { +static int test_then_block (LexState *ls) { /* test_then_block -> [IF | ELSEIF] cond THEN block */ - next(ls); /* skip IF or ELSEIF */ - cond(ls, v); - check(ls, TK_THEN); + int condexit; + luaX_next(ls); /* skip IF or ELSEIF */ + condexit = cond(ls); + checknext(ls, TK_THEN); block(ls); /* `then' part */ + return condexit; } static void ifstat (LexState *ls, int line) { /* ifstat -> IF cond THEN block {ELSEIF cond THEN block} [ELSE block] END */ FuncState *fs = ls->fs; - expdesc v; + int flist; int escapelist = NO_JUMP; - test_then_block(ls, &v); /* IF cond THEN block */ + flist = test_then_block(ls); /* IF cond THEN block */ while (ls->t.token == TK_ELSEIF) { luaK_concat(fs, &escapelist, luaK_jump(fs)); - luaK_patchtohere(fs, v.f); - test_then_block(ls, &v); /* ELSEIF cond THEN block */ + luaK_patchtohere(fs, flist); + flist = test_then_block(ls); /* ELSEIF cond THEN block */ } if (ls->t.token == TK_ELSE) { luaK_concat(fs, &escapelist, luaK_jump(fs)); - luaK_patchtohere(fs, v.f); - next(ls); /* skip ELSE (after patch, for correct line info) */ + luaK_patchtohere(fs, flist); + luaX_next(ls); /* skip ELSE (after patch, for correct line info) */ block(ls); /* `else' part */ } else - luaK_concat(fs, &escapelist, v.f); + luaK_concat(fs, &escapelist, flist); luaK_patchtohere(fs, escapelist); check_match(ls, TK_END, TK_IF, line); } @@ -1175,12 +1196,12 @@ static void localstat (LexState *ls) { static int funcname (LexState *ls, expdesc *v) { /* funcname -> NAME {field} [`:' NAME] */ int needself = 0; - singlevar(ls, v, 1); + singlevar(ls, v); while (ls->t.token == '.') - luaY_field(ls, v); + field(ls, v); if (ls->t.token == ':') { needself = 1; - luaY_field(ls, v); + field(ls, v); } return needself; } @@ -1190,7 +1211,7 @@ static void funcstat (LexState *ls, int line) { /* funcstat -> FUNCTION funcname body */ int needself; expdesc v, b; - next(ls); /* skip FUNCTION */ + luaX_next(ls); /* skip FUNCTION */ needself = funcname(ls, &v); body(ls, &b, needself, line); luaK_storevar(ls->fs, &v, &b); @@ -1203,9 +1224,8 @@ static void exprstat (LexState *ls) { FuncState *fs = ls->fs; struct LHS_assign v; primaryexp(ls, &v.v); - if (v.v.k == VCALL) { /* stat -> func */ - luaK_setcallreturns(fs, &v.v, 0); /* call statement uses no results */ - } + if (v.v.k == VCALL) /* stat -> func */ + SETARG_C(getcode(fs, &v.v), 1); /* call statement uses no results */ else { /* stat -> assignment */ v.prev = NULL; assignment(ls, &v, 1); @@ -1218,14 +1238,14 @@ static void retstat (LexState *ls) { FuncState *fs = ls->fs; expdesc e; int first, nret; /* registers with returned values */ - next(ls); /* skip RETURN */ + luaX_next(ls); /* skip RETURN */ if (block_follow(ls->t.token) || ls->t.token == ';') first = nret = 0; /* return no values */ else { nret = explist1(ls, &e); /* optional return values */ - if (e.k == VCALL) { - luaK_setcallreturns(fs, &e, LUA_MULTRET); - if (nret == 1) { /* tail call? */ + if (hasmultret(e.k)) { + luaK_setmultret(fs, &e); + if (e.k == VCALL && nret == 1) { /* tail call? */ SET_OPCODE(getcode(fs,&e), OP_TAILCALL); lua_assert(GETARG_A(getcode(fs,&e)) == fs->nactvar); } @@ -1242,25 +1262,7 @@ static void retstat (LexState *ls) { } } } - luaK_codeABC(fs, OP_RETURN, first, nret+1, 0); -} - - -static void breakstat (LexState *ls) { - /* stat -> BREAK [NAME] */ - FuncState *fs = ls->fs; - BlockCnt *bl = fs->bl; - int upval = 0; - next(ls); /* skip BREAK */ - while (bl && !bl->isbreakable) { - upval |= bl->upval; - bl = bl->previous; - } - if (!bl) - luaX_syntaxerror(ls, "no loop to break"); - if (upval) - luaK_codeABC(fs, OP_CLOSE, bl->nactvar, 0, 0); - luaK_concat(fs, &bl->breaklist, luaK_jump(fs)); + luaK_ret(fs, first, nret); } @@ -1276,7 +1278,7 @@ static int statement (LexState *ls) { return 0; } case TK_DO: { /* stat -> DO block END */ - next(ls); /* skip DO */ + luaX_next(ls); /* skip DO */ block(ls); check_match(ls, TK_END, TK_DO, line); return 0; @@ -1294,7 +1296,7 @@ static int statement (LexState *ls) { return 0; } case TK_LOCAL: { /* stat -> localstat */ - next(ls); /* skip LOCAL */ + luaX_next(ls); /* skip LOCAL */ if (testnext(ls, TK_FUNCTION)) /* local function? */ localfunc(ls); else @@ -1306,6 +1308,7 @@ static int statement (LexState *ls) { return 1; /* must be last statement */ } case TK_BREAK: { /* stat -> breakstat */ + luaX_next(ls); /* skip BREAK */ breakstat(ls); return 1; /* must be last statement */ } @@ -1324,7 +1327,8 @@ static void chunk (LexState *ls) { while (!islast && !block_follow(ls->t.token)) { islast = statement(ls); testnext(ls, ';'); - lua_assert(ls->fs->freereg >= ls->fs->nactvar); + lua_assert(ls->fs->f->maxstacksize >= ls->fs->freereg && + ls->fs->freereg >= ls->fs->nactvar); ls->fs->freereg = ls->fs->nactvar; /* free registers */ } leavelevel(ls); diff --git a/lib/lua/src/lstate.c b/lib/lua/src/lstate.c index a2618a5..8d5f3a6 100644 --- a/lib/lua/src/lstate.c +++ b/lib/lua/src/lstate.c @@ -1,13 +1,14 @@ /* -** $Id: lstate.c,v 1.6 2006-02-09 16:59:55 pixel Exp $ +** $Id: lstate.c,v 1.7 2007-07-27 10:05:54 pixel Exp $ ** Global State ** See Copyright Notice in lua.h */ -#include <stdlib.h> +#include <stddef.h> #define lstate_c +#define LUA_CORE #include "lua.h" @@ -23,63 +24,43 @@ #include "ltm.h" -/* -** macro to allow the inclusion of user information in Lua state -*/ -#ifndef LUA_USERSTATE -#define EXTRASPACE 0 -#else -union UEXTRASPACE {L_Umaxalign a; LUA_USERSTATE b;}; -#define EXTRASPACE (sizeof(union UEXTRASPACE)) -#endif - +#define state_size(x) (sizeof(x) + LUAI_EXTRASPACE) +#define fromstate(l) (cast(lu_byte *, (l)) - LUAI_EXTRASPACE) +#define tostate(l) (cast(lua_State *, cast(lu_byte *, l) + LUAI_EXTRASPACE)) /* -** you can change this function through the official API: -** call `lua_setpanicf' +** Main thread combines a thread state and the global state */ -static int default_panic (lua_State *L) { - UNUSED(L); - return 0; -} - - -static lua_State *mallocstate (lua_State *L) { - lu_byte *block = (lu_byte *)luaM_malloc(L, sizeof(lua_State) + EXTRASPACE); - if (block == NULL) return NULL; - else { - block += EXTRASPACE; - return cast(lua_State *, block); - } -} - - -static void freestate (lua_State *L, lua_State *L1) { - luaM_free(L, cast(lu_byte *, L1) - EXTRASPACE, - sizeof(lua_State) + EXTRASPACE); -} +typedef struct LG { + lua_State l; + global_State g; +} LG; + static void stack_init (lua_State *L1, lua_State *L) { - L1->stack = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK, TObject); + /* initialize CallInfo array */ + L1->base_ci = luaM_newvector(L, BASIC_CI_SIZE, CallInfo); + L1->ci = L1->base_ci; + L1->size_ci = BASIC_CI_SIZE; + L1->end_ci = L1->base_ci + L1->size_ci - 1; + /* initialize stack array */ + L1->stack = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK, TValue); L1->stacksize = BASIC_STACK_SIZE + EXTRA_STACK; L1->top = L1->stack; L1->stack_last = L1->stack+(L1->stacksize - EXTRA_STACK)-1; - L1->base_ci = luaM_newvector(L, BASIC_CI_SIZE, CallInfo); - L1->ci = L1->base_ci; - L1->ci->state = CI_C; /* not a Lua function */ + /* initialize first ci */ + L1->ci->func = L1->top; setnilvalue(L1->top++); /* `function' entry for this `ci' */ L1->base = L1->ci->base = L1->top; L1->ci->top = L1->top + LUA_MINSTACK; - L1->size_ci = BASIC_CI_SIZE; - L1->end_ci = L1->base_ci + L1->size_ci; } static void freestack (lua_State *L, lua_State *L1) { luaM_freearray(L, L1->base_ci, L1->size_ci, CallInfo); - luaM_freearray(L, L1->stack, L1->stacksize, TObject); + luaM_freearray(L, L1->stack, L1->stacksize, TValue); } @@ -87,119 +68,132 @@ static void freestack (lua_State *L, lua_State *L1) { ** open parts that may cause memory-allocation errors */ static void f_luaopen (lua_State *L, void *ud) { - /* create a new global state */ - global_State *g = luaM_new(NULL, global_State); + global_State *g = G(L); UNUSED(ud); - if (g == NULL) luaD_throw(L, LUA_ERRMEM); - L->l_G = g; - g->mainthread = L; - g->GCthreshold = 0; /* mark it as unfinished state */ - g->strt.size = 0; - g->strt.nuse = 0; - g->strt.hash = NULL; - setnilvalue(defaultmeta(L)); - setnilvalue(registry(L)); - luaZ_initbuffer(L, &g->buff); - g->panic = default_panic; - g->rootgc = NULL; - g->rootudata = NULL; - g->tmudata = NULL; - setnilvalue(gkey(g->dummynode)); - setnilvalue(gval(g->dummynode)); - g->dummynode->next = NULL; - g->nblocks = sizeof(lua_State) + sizeof(global_State); stack_init(L, L); /* init stack */ - /* create default meta table with a dummy table, and then close the loop */ - defaultmeta(L)->tt = LUA_TTABLE; - sethvalue(defaultmeta(L), luaH_new(L, 0, 0)); - hvalue(defaultmeta(L))->metatable = hvalue(defaultmeta(L)); - sethvalue(gt(L), luaH_new(L, 0, 4)); /* table of globals */ - sethvalue(registry(L), luaH_new(L, 4, 4)); /* registry */ + sethvalue(L, gt(L), luaH_new(L, 0, 2)); /* table of globals */ + sethvalue(L, registry(L), luaH_new(L, 0, 2)); /* registry */ luaS_resize(L, MINSTRTABSIZE); /* initial size of string table */ luaT_init(L); luaX_init(L); luaS_fix(luaS_newliteral(L, MEMERRMSG)); - g->GCthreshold = 4*G(L)->nblocks; + g->GCthreshold = 4*g->totalbytes; } -static void preinit_state (lua_State *L) { +static void preinit_state (lua_State *L, global_State *g) { + G(L) = g; L->stack = NULL; L->stacksize = 0; L->errorJmp = NULL; L->hook = NULL; - L->hookmask = L->hookinit = 0; + L->hookmask = 0; L->basehookcount = 0; L->allowhook = 1; resethookcount(L); L->openupval = NULL; L->size_ci = 0; L->nCcalls = 0; + L->status = 0; L->base_ci = L->ci = NULL; + L->savedpc = NULL; L->errfunc = 0; L->callwrap = 0; L->createhook = 0; L->destroyhook = 0; + L->do_break = 0; setnilvalue(gt(L)); } static void close_state (lua_State *L) { + global_State *g = G(L); luaF_close(L, L->stack); /* close all upvalues for this thread */ - if (G(L)) { /* close global state */ - luaC_sweep(L, 1); /* collect all elements */ - lua_assert(G(L)->rootgc == NULL); - lua_assert(G(L)->rootudata == NULL); - luaS_freeall(L); - luaZ_freebuffer(L, &G(L)->buff); - } + luaC_freeall(L); /* collect all objects */ + lua_assert(g->rootgc == obj2gco(L)); + lua_assert(g->strt.nuse == 0); + luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size, TString *); + luaZ_freebuffer(L, &g->buff); freestack(L, L); - if (G(L)) { - lua_assert(G(L)->nblocks == sizeof(lua_State) + sizeof(global_State)); - luaM_freelem(NULL, G(L)); - } - freestate(NULL, L); + lua_assert(g->totalbytes == sizeof(LG)); + (*g->frealloc)(g->ud, fromstate(L), state_size(LG), 0); } lua_State *luaE_newthread (lua_State *L) { - lua_State *L1 = mallocstate(L); - luaC_link(L, valtogco(L1), LUA_TTHREAD); - preinit_state(L1); - L1->l_G = L->l_G; + lua_State *L1 = tostate(luaM_malloc(L, state_size(lua_State))); + luaC_link(L, obj2gco(L1), LUA_TTHREAD); + preinit_state(L1, G(L)); stack_init(L1, L); /* init stack */ - setobj2n(gt(L1), gt(L)); /* share table of globals */ + setobj2n(L, gt(L1), gt(L)); /* share table of globals */ + L1->hookmask = L->hookmask; + L1->basehookcount = L->basehookcount; + L1->hook = L->hook; + resethookcount(L1); + lua_assert(iswhite(obj2gco(L1))); if (L->createhook) - L->createhook(L, L1); + L->createhook(L, L1); return L1; } void luaE_freethread (lua_State *L, lua_State *L1) { if (L->destroyhook) - L->destroyhook(L, L1); + L->destroyhook(L, L1); luaF_close(L1, L1->stack); /* close all upvalues for this thread */ lua_assert(L1->openupval == NULL); + luai_userstatefree(L1); freestack(L, L1); - freestate(L, L1); + luaM_freemem(L, fromstate(L1), state_size(lua_State)); } -LUA_API lua_State *lua_open (void) { - lua_State *L = mallocstate(NULL); - if (L) { /* allocation OK? */ - L->tt = LUA_TTHREAD; - L->marked = 0; - L->next = L->gclist = NULL; - preinit_state(L); - L->l_G = NULL; - if (luaD_rawrunprotected(L, f_luaopen, NULL) != 0) { - /* memory allocation error: free partial state */ - close_state(L); - L = NULL; - } +LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { + int i; + lua_State *L; + global_State *g; + void *l = (*f)(ud, NULL, 0, state_size(LG)); + if (l == NULL) return NULL; + L = tostate(l); + g = &((LG *)L)->g; + L->next = NULL; + L->tt = LUA_TTHREAD; + g->currentwhite = bit2mask(WHITE0BIT, FIXEDBIT); + L->marked = luaC_white(g); + set2bits(L->marked, FIXEDBIT, SFIXEDBIT); + preinit_state(L, g); + g->frealloc = f; + g->ud = ud; + g->mainthread = L; + g->uvhead.u.l.prev = &g->uvhead; + g->uvhead.u.l.next = &g->uvhead; + g->GCthreshold = 0; /* mark it as unfinished state */ + g->strt.size = 0; + g->strt.nuse = 0; + g->strt.hash = NULL; + setnilvalue(registry(L)); + luaZ_initbuffer(L, &g->buff); + g->panic = NULL; + g->gcstate = GCSpause; + g->rootgc = obj2gco(L); + g->sweepstrgc = 0; + g->sweepgc = &g->rootgc; + g->gray = NULL; + g->grayagain = NULL; + g->weak = NULL; + g->tmudata = NULL; + g->totalbytes = sizeof(LG); + g->gcpause = LUAI_GCPAUSE; + g->gcstepmul = LUAI_GCMUL; + g->gcdept = 0; + for (i=0; i<NUM_TAGS; i++) g->mt[i] = NULL; + if (luaD_rawrunprotected(L, f_luaopen, NULL) != 0) { + /* memory allocation error: free partial state */ + close_state(L); + L = NULL; } - lua_userstateopen(L); + else + luai_userstateopen(L); return L; } @@ -211,10 +205,10 @@ static void callallgcTM (lua_State *L, void *ud) { LUA_API void lua_close (lua_State *L) { - lua_lock(L); L = G(L)->mainthread; /* only the main thread can be closed */ + lua_lock(L); luaF_close(L, L->stack); /* close all upvalues for this thread */ - luaC_separateudata(L); /* separate udata that have GC metamethods */ + luaC_separateudata(L, 1); /* separate udata that have GC metamethods */ L->errfunc = 0; /* no error function during GC metamethods */ do { /* repeat until no more errors */ L->ci = L->base_ci; @@ -222,6 +216,7 @@ LUA_API void lua_close (lua_State *L) { L->nCcalls = 0; } while (luaD_rawrunprotected(L, callallgcTM, NULL) != 0); lua_assert(G(L)->tmudata == NULL); + luai_userstateclose(L); close_state(L); } diff --git a/lib/lua/src/lstring.c b/lib/lua/src/lstring.c index 56df94e..f7b009f 100644 --- a/lib/lua/src/lstring.c +++ b/lib/lua/src/lstring.c @@ -1,5 +1,5 @@ /* -** $Id: lstring.c,v 1.4 2004-11-27 21:46:07 pixel Exp $ +** $Id: lstring.c,v 1.5 2007-07-27 10:05:54 pixel Exp $ ** String table (keeps all strings handled by Lua) ** See Copyright Notice in lua.h */ @@ -8,6 +8,7 @@ #include <string.h> #define lstring_c +#define LUA_CORE #include "lua.h" @@ -18,25 +19,23 @@ -void luaS_freeall (lua_State *L) { - lua_assert(G(L)->strt.nuse==0); - luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size, TString *); -} - - void luaS_resize (lua_State *L, int newsize) { - GCObject **newhash = luaM_newvector(L, newsize, GCObject *); - stringtable *tb = &G(L)->strt; + GCObject **newhash; + stringtable *tb; int i; + if (G(L)->gcstate == GCSsweepstring) + return; /* cannot resize during GC traverse */ + newhash = luaM_newvector(L, newsize, GCObject *); + tb = &G(L)->strt; for (i=0; i<newsize; i++) newhash[i] = NULL; /* rehash */ for (i=0; i<tb->size; i++) { GCObject *p = tb->hash[i]; while (p) { /* for each node in the list */ GCObject *next = p->gch.next; /* save next */ - lu_hash h = gcotots(p)->tsv.hash; + unsigned int h = gco2ts(p)->hash; int h1 = lmod(h, newsize); /* new position */ - lua_assert(cast(int, h%newsize) == lmod(h, newsize)); + lua_assert(cast_int(h%newsize) == lmod(h, newsize)); p->gch.next = newhash[h1]; /* chain it */ newhash[h1] = p; p = next; @@ -48,12 +47,16 @@ void luaS_resize (lua_State *L, int newsize) { } -static TString *newlstr (lua_State *L, const char *str, size_t l, lu_hash h) { - TString *ts = cast(TString *, luaM_malloc(L, sizestring(l))); +static TString *newlstr (lua_State *L, const char *str, size_t l, + unsigned int h) { + TString *ts; stringtable *tb; + if (l+1 > (MAX_SIZET - sizeof(TString))/sizeof(char)) + luaM_toobig(L); + ts = cast(TString *, luaM_malloc(L, (l+1)*sizeof(char)+sizeof(TString))); ts->tsv.len = l; ts->tsv.hash = h; - ts->tsv.marked = 0; + ts->tsv.marked = luaC_white(G(L)); ts->tsv.tt = LUA_TSTRING; ts->tsv.reserved = 0; memcpy(ts+1, str, l*sizeof(char)); @@ -61,9 +64,9 @@ static TString *newlstr (lua_State *L, const char *str, size_t l, lu_hash h) { tb = &G(L)->strt; h = lmod(h, tb->size); ts->tsv.next = tb->hash[h]; /* chain new entry */ - tb->hash[h] = valtogco(ts); + tb->hash[h] = obj2gco(ts); tb->nuse++; - if (tb->nuse > cast(ls_nstr, tb->size) && tb->size <= MAX_INT/2) + if (tb->nuse > cast(lu_int32, tb->size) && tb->size <= MAX_INT/2) luaS_resize(L, tb->size*2); /* too crowded */ return ts; } @@ -71,32 +74,38 @@ static TString *newlstr (lua_State *L, const char *str, size_t l, lu_hash h) { TString *luaS_newlstr (lua_State *L, const char *str, size_t l) { GCObject *o; - lu_hash h = (lu_hash)l; /* seed */ + unsigned int h = cast(unsigned int, l); /* seed */ size_t step = (l>>5)+1; /* if string is too long, don't hash all its chars */ size_t l1; for (l1=l; l1>=step; l1-=step) /* compute hash */ - h = h ^ ((h<<5)+(h>>2)+(unsigned char)(str[l1-1])); + h = h ^ ((h<<5)+(h>>2)+cast(unsigned char, str[l1-1])); for (o = G(L)->strt.hash[lmod(h, G(L)->strt.size)]; o != NULL; o = o->gch.next) { - TString *ts = gcotots(o); - if (ts->tsv.len == l && (memcmp(str, getstr(ts), l) == 0)) + TString *ts = rawgco2ts(o); + if (ts->tsv.len == l && (memcmp(str, getstr(ts), l) == 0)) { + /* string may be dead */ + if (isdead(G(L), o)) changewhite(o); return ts; + } } return newlstr(L, str, l, h); /* not found */ } -Udata *luaS_newudata (lua_State *L, size_t s) { +Udata *luaS_newudata (lua_State *L, size_t s, Table *e) { Udata *u; - u = cast(Udata *, luaM_malloc(L, sizeudata(s))); - u->uv.marked = (1<<1); /* is not finalized */ + if (s > MAX_SIZET - sizeof(Udata)) + luaM_toobig(L); + u = cast(Udata *, luaM_malloc(L, s + sizeof(Udata))); + u->uv.marked = luaC_white(G(L)); /* is not finalized */ u->uv.tt = LUA_TUSERDATA; u->uv.len = s; - u->uv.metatable = hvalue(defaultmeta(L)); - /* chain it on udata list */ - u->uv.next = G(L)->rootudata; - G(L)->rootudata = valtogco(u); + u->uv.metatable = NULL; + u->uv.env = e; + /* chain it on udata list (after main thread) */ + u->uv.next = G(L)->mainthread->next; + G(L)->mainthread->next = obj2gco(u); return u; } diff --git a/lib/lua/src/ltable.c b/lib/lua/src/ltable.c index 4969d84..62d757a 100644 --- a/lib/lua/src/ltable.c +++ b/lib/lua/src/ltable.c @@ -1,5 +1,5 @@ /* -** $Id: ltable.c,v 1.4 2004-11-27 21:46:07 pixel Exp $ +** $Id: ltable.c,v 1.5 2007-07-27 10:05:54 pixel Exp $ ** Lua tables (hash) ** See Copyright Notice in lua.h */ @@ -15,15 +15,14 @@ ** A main invariant of these tables is that, if an element is not ** in its main position (i.e. the `original' position that its hash gives ** to it), then the colliding element is in its own main position. -** In other words, there are collisions only when two elements have the -** same main position (i.e. the same hash values for that table size). -** Because of that, the load factor of these tables can be 100% without -** performance penalties. +** Hence even when the load factor reaches 100%, performance remains good. */ +#include <math.h> #include <string.h> #define ltable_c +#define LUA_CORE #include "lua.h" @@ -39,20 +38,13 @@ /* ** max size of array part is 2^MAXBITS */ -#if BITS_INT > 26 -#define MAXBITS 24 +#if LUAI_BITSINT > 26 +#define MAXBITS 26 #else -#define MAXBITS (BITS_INT-2) +#define MAXBITS (LUAI_BITSINT-2) #endif -/* check whether `x' < 2^MAXBITS */ -#define toobig(x) ((((x)-1) >> MAXBITS) != 0) - - -/* function to convert a lua_Number to int (with any rounding method) */ -#ifndef lua_number2int -#define lua_number2int(i,n) ((i)=(int)(n)) -#endif +#define MAXASIZE (1 << MAXBITS) #define hashpow2(t,n) (gnode(t, lmod((n), sizenode(t)))) @@ -74,7 +66,16 @@ /* ** number of ints inside a lua_Number */ -#define numints cast(int, sizeof(lua_Number)/sizeof(int)) +#define numints cast_int(sizeof(lua_Number)/sizeof(int)) + + + +#define dummynode (&dummynode_) + +static const Node dummynode_ = { + {{NULL}, LUA_TNIL}, /* value */ + {{{NULL}, LUA_TNIL, NULL}} /* key */ +}; /* @@ -87,7 +88,7 @@ static Node *hashnum (const Table *t, lua_Number n) { lua_assert(sizeof(a) <= sizeof(n)); memcpy(a, &n, sizeof(a)); for (i = 1; i < numints; i++) a[0] += a[i]; - return hashmod(t, cast(lu_hash, a[0])); + return hashmod(t, a[0]); } @@ -96,12 +97,12 @@ static Node *hashnum (const Table *t, lua_Number n) { ** returns the `main' position of an element in a table (that is, the index ** of its hash value) */ -Node *luaH_mainposition (const Table *t, const TObject *key) { +static Node *mainposition (const Table *t, const TValue *key) { switch (ttype(key)) { case LUA_TNUMBER: return hashnum(t, nvalue(key)); case LUA_TSTRING: - return hashstr(t, tsvalue(key)); + return hashstr(t, rawtsvalue(key)); case LUA_TBOOLEAN: return hashboolean(t, bvalue(key)); case LUA_TLIGHTUSERDATA: @@ -116,11 +117,12 @@ Node *luaH_mainposition (const Table *t, const TObject *key) { ** returns the index for `key' if `key' is an appropriate key to live in ** the array part of the table, -1 otherwise. */ -static int arrayindex (const TObject *key) { +static int arrayindex (const TValue *key) { if (ttisnumber(key)) { + lua_Number n = nvalue(key); int k; - lua_number2int(k, (nvalue(key))); - if (cast(lua_Number, k) == nvalue(key) && k >= 1 && !toobig(k)) + lua_number2int(k, n); + if (luai_numeq(cast_num(k), n)) return k; } return -1; /* `key' did not match some condition */ @@ -130,39 +132,46 @@ static int arrayindex (const TObject *key) { /* ** returns the index of a `key' for table traversals. First goes all ** elements in the array part, then elements in the hash part. The -** beginning and end of a traversal are signalled by -1. +** beginning of a traversal is signalled by -1. */ -static int luaH_index (lua_State *L, Table *t, StkId key) { +static int findindex (lua_State *L, Table *t, StkId key) { int i; if (ttisnil(key)) return -1; /* first iteration */ i = arrayindex(key); - if (0 <= i && i <= t->sizearray) { /* is `key' inside array part? */ + if (0 < i && i <= t->sizearray) /* is `key' inside array part? */ return i-1; /* yes; that's the index (corrected to C) */ - } else { - const TObject *v = luaH_get(t, key); - if (v == &luaO_nilobject) - luaG_runerror(L, "invalid key for `next'"); - i = cast(int, (cast(const lu_byte *, v) - - cast(const lu_byte *, gval(gnode(t, 0)))) / sizeof(Node)); - return i + t->sizearray; /* hash elements are numbered after array ones */ + Node *n = mainposition(t, key); + do { /* check whether `key' is somewhere in the chain */ + /* key may be dead already, but it is ok to use it in `next' */ + if (luaO_rawequalObj(key2tval(n), key) || + (ttype(gkey(n)) == LUA_TDEADKEY && iscollectable(key) && + gcvalue(gkey(n)) == gcvalue(key))) { + i = cast_int(n - gnode(t, 0)); /* key index in hash table */ + /* hash elements are numbered after array ones */ + return i + t->sizearray; + } + else n = gnext(n); + } while (n); + luaG_runerror(L, "invalid key to " LUA_QL("next")); /* key not found */ + return 0; /* to avoid warnings */ } } int luaH_next (lua_State *L, Table *t, StkId key) { - int i = luaH_index(L, t, key); /* find original element */ + int i = findindex(L, t, key); /* find original element */ for (i++; i < t->sizearray; i++) { /* try first array part */ if (!ttisnil(&t->array[i])) { /* a non-nil value? */ - setnvalue(key, cast(lua_Number, i+1)); - setobj2s(key+1, &t->array[i]); + setnvalue(key, cast_num(i+1)); + setobj2s(L, key+1, &t->array[i]); return 1; } } for (i -= t->sizearray; i < sizenode(t); i++) { /* then hash part */ if (!ttisnil(gval(gnode(t, i)))) { /* a non-nil value? */ - setobj2s(key, gkey(gnode(t, i))); - setobj2s(key+1, gval(gnode(t, i))); + setobj2s(L, key, key2tval(gnode(t, i))); + setobj2s(L, key+1, gval(gnode(t, i))); return 1; } } @@ -177,95 +186,111 @@ int luaH_next (lua_State *L, Table *t, StkId key) { */ -static void computesizes (int nums[], int ntotal, int *narray, int *nhash) { +static int computesizes (int nums[], int *narray) { int i; - int a = nums[0]; /* number of elements smaller than 2^i */ - int na = a; /* number of elements to go to array part */ - int n = (na == 0) ? -1 : 0; /* (log of) optimal size for array part */ - for (i = 1; a < *narray && *narray >= twoto(i-1); i++) { + int twotoi; /* 2^i */ + int a = 0; /* number of elements smaller than 2^i */ + int na = 0; /* number of elements to go to array part */ + int n = 0; /* optimal size for array part */ + for (i = 0, twotoi = 1; twotoi/2 < *narray; i++, twotoi *= 2) { if (nums[i] > 0) { a += nums[i]; - if (a >= twoto(i-1)) { /* more than half elements in use? */ - n = i; - na = a; + if (a > twotoi/2) { /* more than half elements present? */ + n = twotoi; /* optimal size (till now) */ + na = a; /* all elements smaller than n will go to array part */ } } + if (a == *narray) break; /* all elements already counted */ } - lua_assert(na <= *narray && *narray <= ntotal); - *nhash = ntotal - na; - *narray = (n == -1) ? 0 : twoto(n); - lua_assert(na <= *narray && na >= *narray/2); + *narray = n; + lua_assert(*narray/2 <= na && na <= *narray); + return na; } -static void numuse (const Table *t, int *narray, int *nhash) { - int nums[MAXBITS+1]; - int i, lg; - int totaluse = 0; - /* count elements in array part */ - for (i=0, lg=0; lg<=MAXBITS; lg++) { /* for each slice [2^(lg-1) to 2^lg) */ - int ttlg = twoto(lg); /* 2^lg */ - if (ttlg > t->sizearray) { - ttlg = t->sizearray; - if (i >= ttlg) break; +static int countint (const TValue *key, int *nums) { + int k = arrayindex(key); + if (0 < k && k <= MAXASIZE) { /* is `key' an appropriate array index? */ + nums[ceillog2(k)]++; /* count as such */ + return 1; + } + else + return 0; +} + + +static int numusearray (const Table *t, int *nums) { + int lg; + int ttlg; /* 2^lg */ + int ause = 0; /* summation of `nums' */ + int i = 1; /* count to traverse all array keys */ + for (lg=0, ttlg=1; lg<=MAXBITS; lg++, ttlg*=2) { /* for each slice */ + int lc = 0; /* counter */ + int lim = ttlg; + if (lim > t->sizearray) { + lim = t->sizearray; /* adjust upper limit */ + if (i > lim) + break; /* no more elements to count */ } - nums[lg] = 0; - for (; i<ttlg; i++) { - if (!ttisnil(&t->array[i])) { - nums[lg]++; - totaluse++; - } + /* count elements in range (2^(lg-1), 2^lg] */ + for (; i <= lim; i++) { + if (!ttisnil(&t->array[i-1])) + lc++; } + nums[lg] += lc; + ause += lc; } - for (; lg<=MAXBITS; lg++) nums[lg] = 0; /* reset other counts */ - *narray = totaluse; /* all previous uses were in array part */ - /* count elements in hash part */ - i = sizenode(t); + return ause; +} + + +static int numusehash (const Table *t, int *nums, int *pnasize) { + int totaluse = 0; /* total number of elements */ + int ause = 0; /* summation of `nums' */ + int i = sizenode(t); while (i--) { Node *n = &t->node[i]; if (!ttisnil(gval(n))) { - int k = arrayindex(gkey(n)); - if (k >= 0) { /* is `key' an appropriate array index? */ - nums[luaO_log2(k-1)+1]++; /* count as such */ - (*narray)++; - } + ause += countint(key2tval(n), nums); totaluse++; } } - computesizes(nums, totaluse, narray, nhash); + *pnasize += ause; + return totaluse; } static void setarrayvector (lua_State *L, Table *t, int size) { int i; - luaM_reallocvector(L, t->array, t->sizearray, size, TObject); + luaM_reallocvector(L, t->array, t->sizearray, size, TValue); for (i=t->sizearray; i<size; i++) setnilvalue(&t->array[i]); t->sizearray = size; } -static void setnodevector (lua_State *L, Table *t, int lsize) { - int i; - int size = twoto(lsize); - if (lsize > MAXBITS) - luaG_runerror(L, "table overflow"); - if (lsize == 0) { /* no elements to hash part? */ - t->node = G(L)->dummynode; /* use common `dummynode' */ - lua_assert(ttisnil(gkey(t->node))); /* assert invariants: */ - lua_assert(ttisnil(gval(t->node))); - lua_assert(t->node->next == NULL); /* (`dummynode' must be empty) */ +static void setnodevector (lua_State *L, Table *t, int size) { + int lsize; + if (size == 0) { /* no elements to hash part? */ + t->node = cast(Node *, dummynode); /* use common `dummynode' */ + lsize = 0; } else { + int i; + lsize = ceillog2(size); + if (lsize > MAXBITS) + luaG_runerror(L, "table overflow"); + size = twoto(lsize); t->node = luaM_newvector(L, size, Node); for (i=0; i<size; i++) { - t->node[i].next = NULL; - setnilvalue(gkey(gnode(t, i))); - setnilvalue(gval(gnode(t, i))); + Node *n = gnode(t, i); + gnext(n) = NULL; + setnilvalue(gkey(n)); + setnilvalue(gval(n)); } } - t->lsizenode = cast(lu_byte, lsize); - t->firstfree = gnode(t, size-1); /* first free position to be used */ + t->lsizenode = cast_byte(lsize); + t->lastfree = gnode(t, size); /* all positions are free */ } @@ -273,48 +298,54 @@ static void resize (lua_State *L, Table *t, int nasize, int nhsize) { int i; int oldasize = t->sizearray; int oldhsize = t->lsizenode; - Node *nold; - Node temp[1]; - if (oldhsize) - nold = t->node; /* save old hash ... */ - else { /* old hash is `dummynode' */ - lua_assert(t->node == G(L)->dummynode); - temp[0] = t->node[0]; /* copy it to `temp' */ - nold = temp; - setnilvalue(gkey(G(L)->dummynode)); /* restate invariant */ - setnilvalue(gval(G(L)->dummynode)); - lua_assert(G(L)->dummynode->next == NULL); - } + Node *nold = t->node; /* save old hash ... */ if (nasize > oldasize) /* array part must grow? */ setarrayvector(L, t, nasize); /* create new hash part with appropriate size */ setnodevector(L, t, nhsize); - /* re-insert elements */ if (nasize < oldasize) { /* array part must shrink? */ t->sizearray = nasize; /* re-insert elements from vanishing slice */ for (i=nasize; i<oldasize; i++) { if (!ttisnil(&t->array[i])) - setobjt2t(luaH_setnum(L, t, i+1), &t->array[i]); + setobjt2t(L, luaH_setnum(L, t, i+1), &t->array[i]); } /* shrink array */ - luaM_reallocvector(L, t->array, oldasize, nasize, TObject); + luaM_reallocvector(L, t->array, oldasize, nasize, TValue); } - /* re-insert elements in hash part */ + /* re-insert elements from hash part */ for (i = twoto(oldhsize) - 1; i >= 0; i--) { Node *old = nold+i; if (!ttisnil(gval(old))) - setobjt2t(luaH_set(L, t, gkey(old)), gval(old)); + setobjt2t(L, luaH_set(L, t, key2tval(old)), gval(old)); } - if (oldhsize) + if (nold != dummynode) luaM_freearray(L, nold, twoto(oldhsize), Node); /* free old array */ } -static void rehash (lua_State *L, Table *t) { - int nasize, nhsize; - numuse(t, &nasize, &nhsize); /* compute new sizes for array and hash parts */ - resize(L, t, nasize, luaO_log2(nhsize)+1); +void luaH_resizearray (lua_State *L, Table *t, int nasize) { + int nsize = (t->node == dummynode) ? 0 : sizenode(t); + resize(L, t, nasize, nsize); +} + + +static void rehash (lua_State *L, Table *t, const TValue *ek) { + int nasize, na; + int nums[MAXBITS+1]; /* nums[i] = number of keys between 2^(i-1) and 2^i */ + int i; + int totaluse; + for (i=0; i<=MAXBITS; i++) nums[i] = 0; /* reset counts */ + nasize = numusearray(t, nums); /* count keys in array part */ + totaluse = nasize; /* all those keys are integer keys */ + totaluse += numusehash(t, nums, &nasize); /* count keys in hash part */ + /* count extra key */ + nasize += countint(ek, nums); + totaluse++; + /* compute new size for array part */ + na = computesizes(nums, &nasize); + /* resize the table to new computed sizes */ + resize(L, t, nasize, totaluse - na); } @@ -324,49 +355,38 @@ static void rehash (lua_State *L, Table *t) { */ -Table *luaH_new (lua_State *L, int narray, int lnhash) { +Table *luaH_new (lua_State *L, int narray, int nhash) { Table *t = luaM_new(L, Table); - luaC_link(L, valtogco(t), LUA_TTABLE); - t->metatable = hvalue(defaultmeta(L)); - t->flags = cast(lu_byte, ~0); + luaC_link(L, obj2gco(t), LUA_TTABLE); + t->metatable = NULL; + t->flags = cast_byte(~0); /* temporary values (kept only if some malloc fails) */ t->array = NULL; t->sizearray = 0; t->lsizenode = 0; - t->node = NULL; + t->node = cast(Node *, dummynode); setarrayvector(L, t, narray); - setnodevector(L, t, lnhash); + setnodevector(L, t, nhash); return t; } void luaH_free (lua_State *L, Table *t) { - if (t->lsizenode) + if (t->node != dummynode) luaM_freearray(L, t->node, sizenode(t), Node); - luaM_freearray(L, t->array, t->sizearray, TObject); - luaM_freelem(L, t); + luaM_freearray(L, t->array, t->sizearray, TValue); + luaM_free(L, t); } -#if 0 -/* -** try to remove an element from a hash table; cannot move any element -** (because gc can call `remove' during a table traversal) -*/ -void luaH_remove (Table *t, Node *e) { - Node *mp = luaH_mainposition(t, gkey(e)); - if (e != mp) { /* element not in its main position? */ - while (mp->next != e) mp = mp->next; /* find previous */ - mp->next = e->next; /* remove `e' from its list */ - } - else { - if (e->next != NULL) ?? +static Node *getfreepos (Table *t) { + while (t->lastfree-- > t->node) { + if (ttisnil(gkey(t->lastfree))) + return t->lastfree; } - lua_assert(ttisnil(gval(node))); - setnilvalue(gkey(e)); /* clear node `e' */ - e->next = NULL; + return NULL; /* could not find a free place */ } -#endif + /* @@ -376,76 +396,55 @@ void luaH_remove (Table *t, Node *e) { ** put new key in its main position; otherwise (colliding node is in its main ** position), new key goes to an empty position. */ -static TObject *newkey (lua_State *L, Table *t, const TObject *key) { - TObject *val; - Node *mp = luaH_mainposition(t, key); - if (!ttisnil(gval(mp))) { /* main position is not free? */ - Node *othern = luaH_mainposition(t, gkey(mp)); /* `mp' of colliding node */ - Node *n = t->firstfree; /* get a free place */ +static TValue *newkey (lua_State *L, Table *t, const TValue *key) { + Node *mp = mainposition(t, key); + if (!ttisnil(gval(mp)) || mp == dummynode) { + Node *othern; + Node *n = getfreepos(t); /* get a free place */ + if (n == NULL) { /* cannot find a free place? */ + rehash(L, t, key); /* grow table */ + return luaH_set(L, t, key); /* re-insert key into grown table */ + } + lua_assert(n != dummynode); + othern = mainposition(t, key2tval(mp)); if (othern != mp) { /* is colliding node out of its main position? */ /* yes; move colliding node into free position */ - while (othern->next != mp) othern = othern->next; /* find previous */ - othern->next = n; /* redo the chain with `n' in place of `mp' */ + while (gnext(othern) != mp) othern = gnext(othern); /* find previous */ + gnext(othern) = n; /* redo the chain with `n' in place of `mp' */ *n = *mp; /* copy colliding node into free pos. (mp->next also goes) */ - mp->next = NULL; /* now `mp' is free */ + gnext(mp) = NULL; /* now `mp' is free */ setnilvalue(gval(mp)); } else { /* colliding node is in its own main position */ /* new node will go into free position */ - n->next = mp->next; /* chain new position */ - mp->next = n; + gnext(n) = gnext(mp); /* chain new position */ + gnext(mp) = n; mp = n; } } - setobj2t(gkey(mp), key); /* write barrier */ + gkey(mp)->value = key->value; gkey(mp)->tt = key->tt; + luaC_barriert(L, t, key); lua_assert(ttisnil(gval(mp))); - for (;;) { /* correct `firstfree' */ - if (ttisnil(gkey(t->firstfree))) - return gval(mp); /* OK; table still has a free place */ - else if (t->firstfree == t->node) break; /* cannot decrement from here */ - else (t->firstfree)--; - } - /* no more free places; must create one */ - setbvalue(gval(mp), 0); /* avoid new key being removed */ - rehash(L, t); /* grow table */ - val = cast(TObject *, luaH_get(t, key)); /* get new position */ - lua_assert(ttisboolean(val)); - setnilvalue(val); - return val; -} - - -/* -** generic search function -*/ -static const TObject *luaH_getany (Table *t, const TObject *key) { - if (ttisnil(key)) return &luaO_nilobject; - else { - Node *n = luaH_mainposition(t, key); - do { /* check whether `key' is somewhere in the chain */ - if (luaO_rawequalObj(gkey(n), key)) return gval(n); /* that's it */ - else n = n->next; - } while (n); - return &luaO_nilobject; - } + return gval(mp); } /* ** search function for integers */ -const TObject *luaH_getnum (Table *t, int key) { - if (1 <= key && key <= t->sizearray) +const TValue *luaH_getnum (Table *t, int key) { + /* (1 <= key && key <= t->sizearray) */ + if (cast(unsigned int, key-1) < cast(unsigned int, t->sizearray)) return &t->array[key-1]; else { - lua_Number nk = cast(lua_Number, key); + lua_Number nk = cast_num(key); Node *n = hashnum(t, nk); do { /* check whether `key' is somewhere in the chain */ - if (ttisnumber(gkey(n)) && nvalue(gkey(n)) == nk) + if (ttisnumber(gkey(n)) && luai_numeq(nvalue(gkey(n)), nk)) return gval(n); /* that's it */ - else n = n->next; + else n = gnext(n); } while (n); - return &luaO_nilobject; + return luaO_nilobject; } } @@ -453,57 +452,137 @@ const TObject *luaH_getnum (Table *t, int key) { /* ** search function for strings */ -const TObject *luaH_getstr (Table *t, TString *key) { +const TValue *luaH_getstr (Table *t, TString *key) { Node *n = hashstr(t, key); do { /* check whether `key' is somewhere in the chain */ - if (ttisstring(gkey(n)) && tsvalue(gkey(n)) == key) + if (ttisstring(gkey(n)) && rawtsvalue(gkey(n)) == key) return gval(n); /* that's it */ - else n = n->next; + else n = gnext(n); } while (n); - return &luaO_nilobject; + return luaO_nilobject; } /* ** main search function */ -const TObject *luaH_get (Table *t, const TObject *key) { +const TValue *luaH_get (Table *t, const TValue *key) { switch (ttype(key)) { - case LUA_TSTRING: return luaH_getstr(t, tsvalue(key)); + case LUA_TNIL: return luaO_nilobject; + case LUA_TSTRING: return luaH_getstr(t, rawtsvalue(key)); case LUA_TNUMBER: { int k; - lua_number2int(k, (nvalue(key))); - if (cast(lua_Number, k) == nvalue(key)) /* is an integer index? */ + lua_Number n = nvalue(key); + lua_number2int(k, n); + if (luai_numeq(cast_num(k), nvalue(key))) /* index is int? */ return luaH_getnum(t, k); /* use specialized version */ /* else go through */ } - default: return luaH_getany(t, key); + default: { + Node *n = mainposition(t, key); + do { /* check whether `key' is somewhere in the chain */ + if (luaO_rawequalObj(key2tval(n), key)) + return gval(n); /* that's it */ + else n = gnext(n); + } while (n); + return luaO_nilobject; + } } } -TObject *luaH_set (lua_State *L, Table *t, const TObject *key) { - const TObject *p = luaH_get(t, key); +TValue *luaH_set (lua_State *L, Table *t, const TValue *key) { + const TValue *p = luaH_get(t, key); t->flags = 0; - if (p != &luaO_nilobject) - return cast(TObject *, p); + if (p != luaO_nilobject) + return cast(TValue *, p); else { if (ttisnil(key)) luaG_runerror(L, "table index is nil"); - else if (ttisnumber(key) && nvalue(key) != nvalue(key)) + else if (ttisnumber(key) && luai_numisnan(nvalue(key))) luaG_runerror(L, "table index is NaN"); return newkey(L, t, key); } } -TObject *luaH_setnum (lua_State *L, Table *t, int key) { - const TObject *p = luaH_getnum(t, key); - if (p != &luaO_nilobject) - return cast(TObject *, p); +TValue *luaH_setnum (lua_State *L, Table *t, int key) { + const TValue *p = luaH_getnum(t, key); + if (p != luaO_nilobject) + return cast(TValue *, p); else { - TObject k; - setnvalue(&k, cast(lua_Number, key)); + TValue k; + setnvalue(&k, cast_num(key)); return newkey(L, t, &k); } } + +TValue *luaH_setstr (lua_State *L, Table *t, TString *key) { + const TValue *p = luaH_getstr(t, key); + if (p != luaO_nilobject) + return cast(TValue *, p); + else { + TValue k; + setsvalue(L, &k, key); + return newkey(L, t, &k); + } +} + + +static int unbound_search (Table *t, unsigned int j) { + unsigned int i = j; /* i is zero or a present index */ + j++; + /* find `i' and `j' such that i is present and j is not */ + while (!ttisnil(luaH_getnum(t, j))) { + i = j; + j *= 2; + if (j > cast(unsigned int, MAX_INT)) { /* overflow? */ + /* table was built with bad purposes: resort to linear search */ + i = 1; + while (!ttisnil(luaH_getnum(t, i))) i++; + return i - 1; + } + } + /* now do a binary search between them */ + while (j - i > 1) { + unsigned int m = (i+j)/2; + if (ttisnil(luaH_getnum(t, m))) j = m; + else i = m; + } + return i; +} + + +/* +** Try to find a boundary in table `t'. A `boundary' is an integer index +** such that t[i] is non-nil and t[i+1] is nil (and 0 if t[1] is nil). +*/ +int luaH_getn (Table *t) { + unsigned int j = t->sizearray; + if (j > 0 && ttisnil(&t->array[j - 1])) { + /* there is a boundary in the array part: (binary) search for it */ + unsigned int i = 0; + while (j - i > 1) { + unsigned int m = (i+j)/2; + if (ttisnil(&t->array[m - 1])) j = m; + else i = m; + } + return i; + } + /* else must find a boundary in hash part */ + else if (t->node == dummynode) /* hash part is empty? */ + return j; /* that is easy... */ + else return unbound_search(t, j); +} + + + +#if defined(LUA_DEBUG) + +Node *luaH_mainposition (const Table *t, const TValue *key) { + return mainposition(t, key); +} + +int luaH_isdummy (Node *n) { return n == dummynode; } + +#endif diff --git a/lib/lua/src/ltm.c b/lib/lua/src/ltm.c index 5ad7858..2fcb68c 100644 --- a/lib/lua/src/ltm.c +++ b/lib/lua/src/ltm.c @@ -1,5 +1,5 @@ /* -** $Id: ltm.c,v 1.4 2004-11-27 21:46:07 pixel Exp $ +** $Id: ltm.c,v 1.5 2007-07-27 10:05:54 pixel Exp $ ** Tag methods ** See Copyright Notice in lua.h */ @@ -8,6 +8,7 @@ #include <string.h> #define ltm_c +#define LUA_CORE #include "lua.h" @@ -21,7 +22,8 @@ const char *const luaT_typenames[] = { "nil", "boolean", "userdata", "number", - "string", "table", "function", "userdata", "thread" + "string", "table", "function", "userdata", "thread", + "proto", "upval" }; @@ -29,8 +31,8 @@ void luaT_init (lua_State *L) { static const char *const luaT_eventname[] = { /* ORDER TM */ "__index", "__newindex", "__gc", "__mode", "__eq", - "__add", "__sub", "__mul", "__div", - "__pow", "__unm", "__lt", "__le", + "__add", "__sub", "__mul", "__div", "__mod", + "__pow", "__unm", "__len", "__lt", "__le", "__concat", "__call" }; int i; @@ -45,26 +47,29 @@ void luaT_init (lua_State *L) { ** function to be used with macro "fasttm": optimized for absence of ** tag methods */ -const TObject *luaT_gettm (Table *events, TMS event, TString *ename) { - const TObject *tm = luaH_getstr(events, ename); +const TValue *luaT_gettm (Table *events, TMS event, TString *ename) { + const TValue *tm = luaH_getstr(events, ename); lua_assert(event <= TM_EQ); if (ttisnil(tm)) { /* no tag method? */ - events->flags |= cast(lu_byte, 1u<<event); /* cache this fact */ + events->flags |= cast_byte(1u<<event); /* cache this fact */ return NULL; } else return tm; } -const TObject *luaT_gettmbyobj (lua_State *L, const TObject *o, TMS event) { - TString *ename = G(L)->tmname[event]; +const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o, TMS event) { + Table *mt; switch (ttype(o)) { case LUA_TTABLE: - return luaH_getstr(hvalue(o)->metatable, ename); + mt = hvalue(o)->metatable; + break; case LUA_TUSERDATA: - return luaH_getstr(uvalue(o)->uv.metatable, ename); + mt = uvalue(o)->metatable; + break; default: - return &luaO_nilobject; + mt = G(L)->mt[ttype(o)]; } + return (mt ? luaH_getstr(mt, G(L)->tmname[event]) : luaO_nilobject); } diff --git a/lib/lua/src/luacomp.c b/lib/lua/src/luacomp.c index 0009b24..1246869 100644 --- a/lib/lua/src/luacomp.c +++ b/lib/lua/src/luacomp.c @@ -1,5 +1,5 @@ /* - ** $Id: luacomp.c,v 1.7 2004-12-27 19:52:24 pixel Exp $ + ** $Id: luacomp.c,v 1.8 2007-07-27 10:05:54 pixel Exp $ ** Lua compiler (saves bytecodes to files; also list bytecodes) ** Highly hacked by Nicolas "Pixel" Noble to be transformed into a ** small form-factor LUA compiler. @@ -19,6 +19,7 @@ #include "lopcodes.h" #include "lstring.h" #include "lundump.h" +#include "ldo.h" #ifndef PROGNAME #define PROGNAME "luacomp" /* program name */ @@ -26,27 +27,26 @@ const char * progname = PROGNAME; /* actual program name */ -static Proto * toproto(lua_State * L, int i) { - const Closure * c = (const Closure *) lua_topointer(L, i); +#define toproto(L, i) (clvalue(L->top + (i))->l.p) - return c->l.p; -} - -static Proto * combine(lua_State * L, int n) { +static const Proto * combine(lua_State * L, int n) { if (n == 1) return toproto(L, -1); else { int i, pc = 0; Proto * f = luaF_newproto(L); + setptvalue2s(L, L->top, f); incr_top(L); f->source = luaS_newliteral(L, "=(" PROGNAME ")"); f->maxstacksize = 1; + pc = 2 * n + 1; + f->code = luaM_newvector(L, pc, Instruction); + f->sizecode = pc; f->p = luaM_newvector(L, n, Proto *); f->sizep = n; - f->sizecode = 2 * n + 1; - f->code = luaM_newvector(L, f->sizecode, Instruction); + pc = 0; for (i = 0; i < n; i++) { - f->p[i] = toproto(L, i - n); + f->p[i] = toproto(L, i - n - 1); f->code[pc++] = CREATE_ABx(OP_CLOSURE, 0, i); f->code[pc++] = CREATE_ABC(OP_CALL, 0, 1, 1); } @@ -55,30 +55,13 @@ static Proto * combine(lua_State * L, int n) { } } -static void strip(lua_State * L, Proto * f) { - int i, n = f->sizep; - luaM_freearray(L, f->lineinfo, f->sizelineinfo, int); - luaM_freearray(L, f->locvars, f->sizelocvars, struct LocVar); - - luaM_freearray(L, f->upvalues, f->sizeupvalues, TString *); - f->lineinfo = NULL; - f->sizelineinfo = 0; - f->locvars = NULL; - f->sizelocvars = 0; - f->upvalues = NULL; - f->sizeupvalues = 0; - f->source = luaS_newliteral(L, "=(none)"); - for (i = 0; i < n; i++) - strip(L, f->p[i]); -} - -void luacmain(lua_State * L, int stripping, lua_Chunkwriter w, void *uD) { +void luacmain(lua_State * L, int stripping, lua_Chunkwriter w, void *uD, int listing) { Proto * f; f = combine(L, lua_gettop(L)); - if (stripping) - strip(L, f); + if (listing) + luaU_print(f, listing > 1); lua_lock(L); - luaU_dump(L, f, w, uD); + luaU_dump(L, f, w, uD, stripping); lua_unlock(L); } diff --git a/lib/lua/src/lundump.c b/lib/lua/src/lundump.c index 7d9f031..a8692a8 100644 --- a/lib/lua/src/lundump.c +++ b/lib/lua/src/lundump.c @@ -1,286 +1,223 @@ /* -** $Id: lundump.c,v 1.4 2004-11-27 21:46:07 pixel Exp $ -** load pre-compiled Lua chunks +** $Id: lundump.c,v 1.5 2007-07-27 10:05:54 pixel Exp $ +** load precompiled Lua chunks ** See Copyright Notice in lua.h */ +#include <string.h> + #define lundump_c +#define LUA_CORE #include "lua.h" #include "ldebug.h" +#include "ldo.h" #include "lfunc.h" #include "lmem.h" -#include "lopcodes.h" +#include "lobject.h" #include "lstring.h" #include "lundump.h" #include "lzio.h" -#define LoadByte (lu_byte) ezgetc - typedef struct { lua_State* L; ZIO* Z; Mbuffer* b; - int swap; const char* name; } LoadState; -static void unexpectedEOZ (LoadState* S) -{ - luaG_runerror(S->L,"unexpected end of file in %s",S->name); -} +#ifdef LUAC_TRUST_BINARIES +#define IF(c,s) +#else +#define IF(c,s) if (c) error(S,s) -static int ezgetc (LoadState* S) +static void error(LoadState* S, const char* why) { - int c=zgetc(S->Z); - if (c==EOZ) unexpectedEOZ(S); - return c; + luaO_pushfstring(S->L,"%s: %s in precompiled chunk",S->name,why); + luaD_throw(S->L,LUA_ERRSYNTAX); } +#endif -static void ezread (LoadState* S, void* b, int n) -{ - int r=luaZ_read(S->Z,b,n); - if (r!=0) unexpectedEOZ(S); -} +#define LoadMem(S,b,n,size) LoadBlock(S,b,(n)*(size)) +#define LoadByte(S) (lu_byte)LoadChar(S) +#define LoadVar(S,x) LoadMem(S,&x,1,sizeof(x)) +#define LoadVector(S,b,n,size) LoadMem(S,b,n,size) -static void LoadBlock (LoadState* S, void* b, size_t size) +static void LoadBlock(LoadState* S, void* b, size_t size) { - if (S->swap) - { - char* p=(char*) b+size-1; - int n=size; - while (n--) *p--=(char)ezgetc(S); - } - else - ezread(S,b,size); + size_t r=luaZ_read(S->Z,b,size); + IF (r!=0, "unexpected end"); } -static void LoadVector (LoadState* S, void* b, int m, size_t size) +static int LoadChar(LoadState* S) { - if (S->swap) - { - char* q=(char*) b; - while (m--) - { - char* p=q+size-1; - int n=size; - while (n--) *p--=(char)ezgetc(S); - q+=size; - } - } - else - ezread(S,b,m*size); -} - -static int LoadInt (LoadState* S) -{ - int x; - LoadBlock(S,&x,sizeof(x)); - if (x<0) luaG_runerror(S->L,"bad integer in %s",S->name); + char x; + LoadVar(S,x); return x; } -static size_t LoadSize (LoadState* S) +static int LoadInt(LoadState* S) { - size_t x; - LoadBlock(S,&x,sizeof(x)); + int x; + LoadVar(S,x); + IF (x<0, "bad integer"); return x; } -static lua_Number LoadNumber (LoadState* S) +static lua_Number LoadNumber(LoadState* S) { lua_Number x; - LoadBlock(S,&x,sizeof(x)); + LoadVar(S,x); return x; } -static TString* LoadString (LoadState* S) +static TString* LoadString(LoadState* S) { - size_t size=LoadSize(S); + size_t size; + LoadVar(S,size); if (size==0) return NULL; else { char* s=luaZ_openspace(S->L,S->b,size); - ezread(S,s,size); + LoadBlock(S,s,size); return luaS_newlstr(S->L,s,size-1); /* remove trailing '\0' */ } } -static void LoadCode (LoadState* S, Proto* f) +static void LoadCode(LoadState* S, Proto* f) { - int size=LoadInt(S); - f->code=luaM_newvector(S->L,size,Instruction); - f->sizecode=size; - LoadVector(S,f->code,size,sizeof(*f->code)); -} - -static void LoadLocals (LoadState* S, Proto* f) -{ - int i,n; - n=LoadInt(S); - f->locvars=luaM_newvector(S->L,n,LocVar); - f->sizelocvars=n; - for (i=0; i<n; i++) - { - f->locvars[i].varname=LoadString(S); - f->locvars[i].startpc=LoadInt(S); - f->locvars[i].endpc=LoadInt(S); - } -} - -static void LoadLines (LoadState* S, Proto* f) -{ - int size=LoadInt(S); - f->lineinfo=luaM_newvector(S->L,size,int); - f->sizelineinfo=size; - LoadVector(S,f->lineinfo,size,sizeof(*f->lineinfo)); -} - -static void LoadUpvalues (LoadState* S, Proto* f) -{ - int i,n; - n=LoadInt(S); - if (n!=0 && n!=f->nups) - luaG_runerror(S->L,"bad nupvalues in %s: read %d; expected %d", - S->name,n,f->nups); - f->upvalues=luaM_newvector(S->L,n,TString*); - f->sizeupvalues=n; - for (i=0; i<n; i++) f->upvalues[i]=LoadString(S); + int n=LoadInt(S); + f->code=luaM_newvector(S->L,n,Instruction); + f->sizecode=n; + LoadVector(S,f->code,n,sizeof(Instruction)); } -static Proto* LoadFunction (LoadState* S, TString* p); +static Proto* LoadFunction(LoadState* S, TString* p); -static void LoadConstants (LoadState* S, Proto* f) +static void LoadConstants(LoadState* S, Proto* f) { int i,n; n=LoadInt(S); - f->k=luaM_newvector(S->L,n,TObject); + f->k=luaM_newvector(S->L,n,TValue); f->sizek=n; + for (i=0; i<n; i++) setnilvalue(&f->k[i]); for (i=0; i<n; i++) { - TObject* o=&f->k[i]; - int t=LoadByte(S); + TValue* o=&f->k[i]; + int t=LoadChar(S); switch (t) { + case LUA_TNIL: + setnilvalue(o); + break; + case LUA_TBOOLEAN: + setbvalue(o,LoadChar(S)); + break; case LUA_TNUMBER: setnvalue(o,LoadNumber(S)); break; case LUA_TSTRING: - setsvalue2n(o,LoadString(S)); - break; - case LUA_TNIL: - setnilvalue(o); + setsvalue2n(S->L,o,LoadString(S)); break; default: - luaG_runerror(S->L,"bad constant type (%d) in %s",t,S->name); + IF (1, "bad constant"); break; } } n=LoadInt(S); f->p=luaM_newvector(S->L,n,Proto*); f->sizep=n; + for (i=0; i<n; i++) f->p[i]=NULL; for (i=0; i<n; i++) f->p[i]=LoadFunction(S,f->source); } -static Proto* LoadFunction (LoadState* S, TString* p) +static void LoadDebug(LoadState* S, Proto* f) +{ + int i,n; + n=LoadInt(S); + f->lineinfo=luaM_newvector(S->L,n,int); + f->sizelineinfo=n; + LoadVector(S,f->lineinfo,n,sizeof(int)); + n=LoadInt(S); + f->locvars=luaM_newvector(S->L,n,LocVar); + f->sizelocvars=n; + for (i=0; i<n; i++) f->locvars[i].varname=NULL; + for (i=0; i<n; i++) + { + f->locvars[i].varname=LoadString(S); + f->locvars[i].startpc=LoadInt(S); + f->locvars[i].endpc=LoadInt(S); + } + n=LoadInt(S); + f->upvalues=luaM_newvector(S->L,n,TString*); + f->sizeupvalues=n; + for (i=0; i<n; i++) f->upvalues[i]=NULL; + for (i=0; i<n; i++) f->upvalues[i]=LoadString(S); +} + +static Proto* LoadFunction(LoadState* S, TString* p) { Proto* f=luaF_newproto(S->L); + setptvalue2s(S->L,S->L->top,f); incr_top(S->L); f->source=LoadString(S); if (f->source==NULL) f->source=p; - f->lineDefined=LoadInt(S); + f->linedefined=LoadInt(S); + f->lastlinedefined=LoadInt(S); f->nups=LoadByte(S); f->numparams=LoadByte(S); f->is_vararg=LoadByte(S); f->maxstacksize=LoadByte(S); - LoadLines(S,f); - LoadLocals(S,f); - LoadUpvalues(S,f); - LoadConstants(S,f); LoadCode(S,f); -#ifndef TRUST_BINARIES - if (!luaG_checkcode(f)) luaG_runerror(S->L,"bad code in %s",S->name); -#endif + LoadConstants(S,f); + LoadDebug(S,f); + IF (!luaG_checkcode(f), "bad code"); + S->L->top--; return f; } -static void LoadSignature (LoadState* S) -{ - const char* s=LUA_SIGNATURE; - while (*s!=0 && ezgetc(S)==*s) - ++s; - if (*s!=0) luaG_runerror(S->L,"bad signature in %s",S->name); -} - -static void TestSize (LoadState* S, int s, const char* what) -{ - int r=LoadByte(S); - if (r!=s) - luaG_runerror(S->L,"virtual machine mismatch in %s: " - "size of %s is %d but read %d",S->name,what,s,r); -} - -#define TESTSIZE(s,w) TestSize(S,s,w) -#define V(v) v/16,v%16 - -static void LoadHeader (LoadState* S) -{ - int version; - lua_Number x,tx=TEST_NUMBER; - LoadSignature(S); - version=LoadByte(S); - if (version>VERSION) - luaG_runerror(S->L,"%s too new: " - "read version %d.%d; expected at most %d.%d", - S->name,V(version),V(VERSION)); - if (version<VERSION0) /* check last major change */ - luaG_runerror(S->L,"%s too old: " - "read version %d.%d; expected at least %d.%d", - S->name,V(version),V(VERSION0)); - S->swap=(luaU_endianness()!=LoadByte(S)); /* need to swap bytes? */ - TESTSIZE(sizeof(int),"int"); - TESTSIZE(sizeof(size_t), "size_t"); - TESTSIZE(sizeof(Instruction), "Instruction"); - TESTSIZE(SIZE_OP, "OP"); - TESTSIZE(SIZE_A, "A"); - TESTSIZE(SIZE_B, "B"); - TESTSIZE(SIZE_C, "C"); - TESTSIZE(sizeof(lua_Number), "number"); - x=LoadNumber(S); - if ((long)x!=(long)tx) /* disregard errors in last bits of fraction */ - luaG_runerror(S->L,"unknown number format in %s",S->name); -} - -static Proto* LoadChunk (LoadState* S) +static void LoadHeader(LoadState* S) { - LoadHeader(S); - return LoadFunction(S,NULL); + char h[LUAC_HEADERSIZE]; + char s[LUAC_HEADERSIZE]; + luaU_header(h); + LoadBlock(S,s,LUAC_HEADERSIZE); + IF (memcmp(h,s,LUAC_HEADERSIZE)!=0, "bad header"); } /* ** load precompiled chunk */ -Proto* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff) +Proto* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char* name) { LoadState S; - const char* s=zname(Z); - if (*s=='@' || *s=='=') - S.name=s+1; - else if (*s==LUA_SIGNATURE[0]) + if (*name=='@' || *name=='=') + S.name=name+1; + else if (*name==LUA_SIGNATURE[0]) S.name="binary string"; else - S.name=s; + S.name=name; S.L=L; S.Z=Z; S.b=buff; - return LoadChunk(&S); + LoadHeader(&S); + return LoadFunction(&S,luaS_newliteral(L,"=?")); } /* -** find byte order +* make header */ -int luaU_endianness (void) +void luaU_header (char* h) { int x=1; - return *(char*)&x; + memcpy(h,LUA_SIGNATURE,sizeof(LUA_SIGNATURE)-1); + h+=sizeof(LUA_SIGNATURE)-1; + *h++=(char)LUAC_VERSION; + *h++=(char)LUAC_FORMAT; + *h++=(char)*(char*)&x; /* endianness */ + *h++=(char)sizeof(int); + *h++=(char)sizeof(size_t); + *h++=(char)sizeof(Instruction); + *h++=(char)sizeof(lua_Number); + *h++=(char)(((lua_Number)0.5)==0); /* is lua_Number integral? */ } diff --git a/lib/lua/src/lvm.c b/lib/lua/src/lvm.c index 5103140..52f65e6 100644 --- a/lib/lua/src/lvm.c +++ b/lib/lua/src/lvm.c @@ -1,18 +1,16 @@ /* -** $Id: lvm.c,v 1.10 2007-07-25 16:54:32 pixel Exp $ +** $Id: lvm.c,v 1.11 2007-07-27 10:05:54 pixel Exp $ ** Lua virtual machine ** See Copyright Notice in lua.h */ -#include <stdarg.h> +#include <stdio.h> #include <stdlib.h> #include <string.h> -/* needed only when `lua_number2str' uses `sprintf' */ -#include <stdio.h> - #define lvm_c +#define LUA_CORE #include "lua.h" @@ -30,17 +28,11 @@ -/* function to convert a lua_Number to a string */ -#ifndef lua_number2str -#define lua_number2str(s,n) sprintf((s), LUA_NUMBER_FMT, (n)) -#endif - - /* limit for table tag-method chains (to avoid loops) */ #define MAXTAGLOOP 100 -const TObject *luaV_tonumber (const TObject *obj, TObject *n) { +const TValue *luaV_tonumber (const TValue *obj, TValue *n) { lua_Number num; if (ttisnumber(obj)) return obj; if (ttisstring(obj) && luaO_str2d(svalue(obj), &num)) { @@ -53,149 +45,105 @@ const TObject *luaV_tonumber (const TObject *obj, TObject *n) { int luaV_tostring (lua_State *L, StkId obj) { -#if 0 if (!ttisnumber(obj)) return 0; else { - char s[32]; /* 16 digits, sign, point and \0 (+ some extra...) */ - lua_number2str(s, nvalue(obj)); - setsvalue2s(obj, luaS_new(L, s)); + char s[LUAI_MAXNUMBER2STR]; + lua_Number n = nvalue(obj); + lua_number2str(s, n); + setsvalue2s(L, obj, luaS_new(L, s)); return 1; } -#else - if (ttisnumber(obj)) { - char s[32]; /* 16 digits, sign, point and \0 (+ some extra...) */ - lua_number2str(s, nvalue(obj)); - setsvalue2s(obj, luaS_new(L, s)); - return 1; - } else if (ttisboolean(obj)) { - if (bvalue(obj)) - setsvalue2s(obj, luaS_new(L, "(true)")) - else - setsvalue2s(obj, luaS_new(L, "(false)")); - return 1; - } else if (ttisnil(obj)) { - setsvalue(obj, luaS_new(L, "(nil)")); - return 1; - } else { - return 0; - } -#endif } -static void traceexec (lua_State *L) { +static void traceexec (lua_State *L, const Instruction *pc) { lu_byte mask = L->hookmask; - if (mask & LUA_MASKCOUNT) { /* instruction-hook set? */ + const Instruction *oldpc = L->savedpc; + L->savedpc = pc; + if (mask > LUA_MASKLINE) { /* instruction-hook set? */ if (L->hookcount == 0) { resethookcount(L); luaD_callhook(L, LUA_HOOKCOUNT, -1); - return; } } if (mask & LUA_MASKLINE) { - CallInfo *ci = L->ci; - Proto *p = ci_func(ci)->l.p; - int newline = getline(p, pcRel(*ci->u.l.pc, p)); - if (!L->hookinit) { - luaG_inithooks(L); - return; - } - lua_assert(ci->state & CI_HASFRAME); - if (pcRel(*ci->u.l.pc, p) == 0) /* tracing may be starting now? */ - ci->u.l.savedpc = *ci->u.l.pc; /* initialize `savedpc' */ - /* calls linehook when enters a new line or jumps back (loop) */ - if (*ci->u.l.pc <= ci->u.l.savedpc || - newline != getline(p, pcRel(ci->u.l.savedpc, p))) { + Proto *p = ci_func(L->ci)->l.p; + int npc = pcRel(pc, p); + int newline = getline(p, npc); + /* call linehook when enter a new function, when jump back (loop), + or when enter a new line */ + if (npc == 0 || pc <= oldpc || newline != getline(p, pcRel(oldpc, p))) luaD_callhook(L, LUA_HOOKLINE, newline); - ci = L->ci; /* previous call may reallocate `ci' */ - } - ci->u.l.savedpc = *ci->u.l.pc; } } -static void callTMres (lua_State *L, const TObject *f, - const TObject *p1, const TObject *p2) { - setobj2s(L->top, f); /* push function */ - setobj2s(L->top+1, p1); /* 1st argument */ - setobj2s(L->top+2, p2); /* 2nd argument */ - luaD_checkstack(L, 3); /* cannot check before (could invalidate p1, p2) */ +static void callTMres (lua_State *L, StkId res, const TValue *f, + const TValue *p1, const TValue *p2) { + ptrdiff_t result = savestack(L, res); + setobj2s(L, L->top, f); /* push function */ + setobj2s(L, L->top+1, p1); /* 1st argument */ + setobj2s(L, L->top+2, p2); /* 2nd argument */ + luaD_checkstack(L, 3); L->top += 3; luaD_call(L, L->top - 3, 1); - L->top--; /* result will be in L->top */ + res = restorestack(L, result); + L->top--; + setobjs2s(L, res, L->top); } -static void callTM (lua_State *L, const TObject *f, - const TObject *p1, const TObject *p2, const TObject *p3) { - setobj2s(L->top, f); /* push function */ - setobj2s(L->top+1, p1); /* 1st argument */ - setobj2s(L->top+2, p2); /* 2nd argument */ - setobj2s(L->top+3, p3); /* 3th argument */ - luaD_checkstack(L, 4); /* cannot check before (could invalidate p1...p3) */ +static void callTM (lua_State *L, const TValue *f, const TValue *p1, + const TValue *p2, const TValue *p3) { + setobj2s(L, L->top, f); /* push function */ + setobj2s(L, L->top+1, p1); /* 1st argument */ + setobj2s(L, L->top+2, p2); /* 2nd argument */ + setobj2s(L, L->top+3, p3); /* 3th argument */ + luaD_checkstack(L, 4); L->top += 4; luaD_call(L, L->top - 4, 0); } -static const TObject *luaV_index (lua_State *L, const TObject *t, - TObject *key, int loop) { - const TObject *tm = fasttm(L, hvalue(t)->metatable, TM_INDEX); - if (tm == NULL) return &luaO_nilobject; /* no TM */ - if (ttisfunction(tm)) { - callTMres(L, tm, t, key); - return L->top; - } - else return luaV_gettable(L, tm, key, loop); -} - -static const TObject *luaV_getnotable (lua_State *L, const TObject *t, - TObject *key, int loop) { - const TObject *tm = luaT_gettmbyobj(L, t, TM_INDEX); - if (ttisnil(tm)) - luaG_typeerror(L, t, "index"); - if (ttisfunction(tm)) { - callTMres(L, tm, t, key); - return L->top; - } - else return luaV_gettable(L, tm, key, loop); -} - - -/* -** Function to index a table. -** Receives the table at `t' and the key at `key'. -** leaves the result at `res'. -*/ -const TObject *luaV_gettable (lua_State *L, const TObject *t, TObject *key, - int loop) { - if (loop > MAXTAGLOOP) - luaG_runerror(L, "loop in gettable"); - if (ttistable(t)) { /* `t' is a table? */ - Table *h = hvalue(t); - const TObject *v = luaH_get(h, key); /* do a primitive get */ - if (!ttisnil(v)) return v; - else return luaV_index(L, t, key, loop+1); +void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val) { + int loop; + for (loop = 0; loop < MAXTAGLOOP; loop++) { + const TValue *tm; + if (ttistable(t)) { /* `t' is a table? */ + Table *h = hvalue(t); + const TValue *res = luaH_get(h, key); /* do a primitive get */ + if (!ttisnil(res) || /* result is no nil? */ + (tm = fasttm(L, h->metatable, TM_INDEX)) == NULL) { /* or no TM? */ + setobj2s(L, val, res); + return; + } + /* else will try the tag method */ + } + else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_INDEX))) + luaG_typeerror(L, t, "index"); + if (ttisfunction(tm)) { + callTMres(L, val, tm, t, key); + return; + } + t = tm; /* else repeat with `tm' */ } - else return luaV_getnotable(L, t, key, loop+1); + luaG_runerror(L, "loop in gettable"); } -/* -** Receives table at `t', key at `key' and value at `val'. -*/ -void luaV_settable (lua_State *L, const TObject *t, TObject *key, StkId val) { - const TObject *tm; - int loop = 0; - do { +void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) { + int loop; + for (loop = 0; loop < MAXTAGLOOP; loop++) { + const TValue *tm; if (ttistable(t)) { /* `t' is a table? */ Table *h = hvalue(t); - TObject *oldval = luaH_set(L, h, key); /* do a primitive set */ + TValue *oldval = luaH_set(L, h, key); /* do a primitive set */ if (!ttisnil(oldval) || /* result is no nil? */ (tm = fasttm(L, h->metatable, TM_NEWINDEX)) == NULL) { /* or no TM? */ - setobj2t(oldval, val); /* write barrier */ + setobj2t(L, oldval, val); + luaC_barriert(L, h, val); return; } /* else will try the tag method */ @@ -207,29 +155,26 @@ void luaV_settable (lua_State *L, const TObject *t, TObject *key, StkId val) { return; } t = tm; /* else repeat with `tm' */ - } while (++loop <= MAXTAGLOOP); + } luaG_runerror(L, "loop in settable"); } -static int call_binTM (lua_State *L, const TObject *p1, const TObject *p2, +static int call_binTM (lua_State *L, const TValue *p1, const TValue *p2, StkId res, TMS event) { - ptrdiff_t result = savestack(L, res); - const TObject *tm = luaT_gettmbyobj(L, p1, event); /* try first operand */ + const TValue *tm = luaT_gettmbyobj(L, p1, event); /* try first operand */ if (ttisnil(tm)) tm = luaT_gettmbyobj(L, p2, event); /* try second operand */ - if (!ttisfunction(tm)) return 0; - callTMres(L, tm, p1, p2); - res = restorestack(L, result); /* previous call may change stack */ - setobjs2s(res, L->top); + if (ttisnil(tm)) return 0; + callTMres(L, res, tm, p1, p2); return 1; } -static const TObject *get_compTM (lua_State *L, Table *mt1, Table *mt2, +static const TValue *get_compTM (lua_State *L, Table *mt1, Table *mt2, TMS event) { - const TObject *tm1 = fasttm(L, mt1, event); - const TObject *tm2; + const TValue *tm1 = fasttm(L, mt1, event); + const TValue *tm2; if (tm1 == NULL) return NULL; /* no metamethod */ if (mt1 == mt2) return tm1; /* same metatables => same metamethods */ tm2 = fasttm(L, mt2, event); @@ -240,20 +185,20 @@ static const TObject *get_compTM (lua_State *L, Table *mt1, Table *mt2, } -static int call_orderTM (lua_State *L, const TObject *p1, const TObject *p2, +static int call_orderTM (lua_State *L, const TValue *p1, const TValue *p2, TMS event) { - const TObject *tm1 = luaT_gettmbyobj(L, p1, event); - const TObject *tm2; + const TValue *tm1 = luaT_gettmbyobj(L, p1, event); + const TValue *tm2; if (ttisnil(tm1)) return -1; /* no metamethod? */ tm2 = luaT_gettmbyobj(L, p2, event); if (!luaO_rawequalObj(tm1, tm2)) /* different metamethods? */ return -1; - callTMres(L, tm1, p1, p2); + callTMres(L, L->top, tm1, p1, p2); return !l_isfalse(L->top); } -static int luaV_strcmp (const TString *ls, const TString *rs) { +static int l_strcmp (const TString *ls, const TString *rs) { const char *l = getstr(ls); size_t ll = ls->tsv.len; const char *r = getstr(rs); @@ -275,28 +220,28 @@ static int luaV_strcmp (const TString *ls, const TString *rs) { } -int luaV_lessthan (lua_State *L, const TObject *l, const TObject *r) { +int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r) { int res; if (ttype(l) != ttype(r)) return luaG_ordererror(L, l, r); else if (ttisnumber(l)) - return nvalue(l) < nvalue(r); + return luai_numlt(nvalue(l), nvalue(r)); else if (ttisstring(l)) - return luaV_strcmp(tsvalue(l), tsvalue(r)) < 0; + return l_strcmp(rawtsvalue(l), rawtsvalue(r)) < 0; else if ((res = call_orderTM(L, l, r, TM_LT)) != -1) return res; return luaG_ordererror(L, l, r); } -static int luaV_lessequal (lua_State *L, const TObject *l, const TObject *r) { +static int lessequal (lua_State *L, const TValue *l, const TValue *r) { int res; if (ttype(l) != ttype(r)) return luaG_ordererror(L, l, r); else if (ttisnumber(l)) - return nvalue(l) <= nvalue(r); + return luai_numle(nvalue(l), nvalue(r)); else if (ttisstring(l)) - return luaV_strcmp(tsvalue(l), tsvalue(r)) <= 0; + return l_strcmp(rawtsvalue(l), rawtsvalue(r)) <= 0; else if ((res = call_orderTM(L, l, r, TM_LE)) != -1) /* first try `le' */ return res; else if ((res = call_orderTM(L, r, l, TM_LT)) != -1) /* else try `lt' */ @@ -305,17 +250,17 @@ static int luaV_lessequal (lua_State *L, const TObject *l, const TObject *r) { } -int luaV_equalval (lua_State *L, const TObject *t1, const TObject *t2) { - const TObject *tm; +int luaV_equalval (lua_State *L, const TValue *t1, const TValue *t2) { + const TValue *tm; lua_assert(ttype(t1) == ttype(t2)); switch (ttype(t1)) { case LUA_TNIL: return 1; - case LUA_TNUMBER: return nvalue(t1) == nvalue(t2); + case LUA_TNUMBER: return luai_numeq(nvalue(t1), nvalue(t2)); case LUA_TBOOLEAN: return bvalue(t1) == bvalue(t2); /* true must be 1 !! */ case LUA_TLIGHTUSERDATA: return pvalue(t1) == pvalue(t2); case LUA_TUSERDATA: { if (uvalue(t1) == uvalue(t2)) return 1; - tm = get_compTM(L, uvalue(t1)->uv.metatable, uvalue(t2)->uv.metatable, + tm = get_compTM(L, uvalue(t1)->metatable, uvalue(t2)->metatable, TM_EQ); break; /* will try TM */ } @@ -327,7 +272,7 @@ int luaV_equalval (lua_State *L, const TObject *t1, const TObject *t2) { default: return gcvalue(t1) == gcvalue(t2); } if (tm == NULL) return 0; /* no TM? */ - callTMres(L, tm, t1, t2); /* call TM */ + callTMres(L, L->top, tm, t1, t2); /* call TM */ return !l_isfalse(L->top); } @@ -336,28 +281,30 @@ void luaV_concat (lua_State *L, int total, int last) { do { StkId top = L->base + last + 1; int n = 2; /* number of elements handled in this pass (at least 2) */ - if (!tostring(L, top-2) || !tostring(L, top-1)) { + if (!(ttisstring(top-2) || ttisnumber(top-2)) || !tostring(L, top-1)) { if (!call_binTM(L, top-2, top-1, top-2, TM_CONCAT)) luaG_concaterror(L, top-2, top-1); - } else if (tsvalue(top-1)->tsv.len > 0) { /* if len=0, do nothing */ + } else if (tsvalue(top-1)->len == 0) /* second op is empty? */ + (void)tostring(L, top - 2); /* result is first op (as string) */ + else { /* at least two string values; get as many as possible */ - size_t tl = tsvalue(top-1)->tsv.len; + size_t tl = tsvalue(top-1)->len; char *buffer; int i; /* collect total length */ for (n = 1; n < total && tostring(L, top-n-1); n++) { - size_t l = tsvalue(top-n-1)->tsv.len; + size_t l = tsvalue(top-n-1)->len; if (l >= MAX_SIZET - tl) luaG_runerror(L, "string length overflow"); tl += l; } buffer = luaZ_openspace(L, &G(L)->buff, tl); tl = 0; for (i=n; i>0; i--) { /* concat all strings */ - size_t l = tsvalue(top-i)->tsv.len; + size_t l = tsvalue(top-i)->len; memcpy(buffer+tl, svalue(top-i), l); tl += l; } - setsvalue2s(top-n, luaS_newlstr(L, buffer, tl)); + setsvalue2s(L, top-n, luaS_newlstr(L, buffer, tl)); } total -= n-1; /* got `n' strings to create 1 new */ last -= n-1; @@ -365,27 +312,21 @@ void luaV_concat (lua_State *L, int total, int last) { } -static void Arith (lua_State *L, StkId ra, - const TObject *rb, const TObject *rc, TMS op) { - TObject tempb, tempc; - const TObject *b, *c; +static void Arith (lua_State *L, StkId ra, const TValue *rb, + const TValue *rc, TMS op) { + TValue tempb, tempc; + const TValue *b, *c; if ((b = luaV_tonumber(rb, &tempb)) != NULL && (c = luaV_tonumber(rc, &tempc)) != NULL) { + lua_Number nb = nvalue(b), nc = nvalue(c); switch (op) { - case TM_ADD: setnvalue(ra, nvalue(b) + nvalue(c)); break; - case TM_SUB: setnvalue(ra, nvalue(b) - nvalue(c)); break; - case TM_MUL: setnvalue(ra, nvalue(b) * nvalue(c)); break; - case TM_DIV: setnvalue(ra, nvalue(b) / nvalue(c)); break; - case TM_POW: { - const TObject *f = luaH_getstr(hvalue(gt(L)), G(L)->tmname[TM_POW]); - ptrdiff_t res = savestack(L, ra); - if (!ttisfunction(f)) - luaG_runerror(L, "`__pow' (`^' operator) is not a function"); - callTMres(L, f, b, c); - ra = restorestack(L, res); /* previous call may change stack */ - setobjs2s(ra, L->top); - break; - } + case TM_ADD: setnvalue(ra, luai_numadd(nb, nc)); break; + case TM_SUB: setnvalue(ra, luai_numsub(nb, nc)); break; + case TM_MUL: setnvalue(ra, luai_nummul(nb, nc)); break; + case TM_DIV: setnvalue(ra, luai_numdiv(nb, nc)); break; + case TM_MOD: setnvalue(ra, luai_nummod(nb, nc)); break; + case TM_POW: setnvalue(ra, luai_numpow(nb, nc)); break; + case TM_UNM: setnvalue(ra, luai_numunm(nb)); break; default: lua_assert(0); break; } } @@ -399,384 +340,387 @@ static void Arith (lua_State *L, StkId ra, ** some macros for common tasks in `luaV_execute' */ -#define runtime_check(L, c) { if (!(c)) return 0; } +#define runtime_check(L, c) { if (!(c)) break; } #define RA(i) (base+GETARG_A(i)) /* to be used after possible stack reallocation */ -#define XRA(i) (L->base+GETARG_A(i)) -#define RB(i) (base+GETARG_B(i)) -#define RKB(i) ((GETARG_B(i) < MAXSTACK) ? RB(i) : k+GETARG_B(i)-MAXSTACK) -#define RC(i) (base+GETARG_C(i)) -#define RKC(i) ((GETARG_C(i) < MAXSTACK) ? RC(i) : k+GETARG_C(i)-MAXSTACK) -#define KBx(i) (k+GETARG_Bx(i)) +#define RB(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgR, base+GETARG_B(i)) +#define RC(i) check_exp(getCMode(GET_OPCODE(i)) == OpArgR, base+GETARG_C(i)) +#define RKB(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgK, \ + ISK(GETARG_B(i)) ? k+INDEXK(GETARG_B(i)) : base+GETARG_B(i)) +#define RKC(i) check_exp(getCMode(GET_OPCODE(i)) == OpArgK, \ + ISK(GETARG_C(i)) ? k+INDEXK(GETARG_C(i)) : base+GETARG_C(i)) +#define KBx(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgK, k+GETARG_Bx(i)) + + +#define dojump(L,pc,i) {(pc) += (i); luai_threadyield(L);} -#define dojump(pc, i) ((pc) += (i)) +#define Protect(x) { L->savedpc = pc; {x;}; base = L->base; } -StkId luaV_execute (lua_State *L) { +#define arith_op(op,tm) { \ + TValue *rb = RKB(i); \ + TValue *rc = RKC(i); \ + if (ttisnumber(rb) && ttisnumber(rc)) { \ + lua_Number nb = nvalue(rb), nc = nvalue(rc); \ + setnvalue(ra, op(nb, nc)); \ + } \ + else \ + Protect(Arith(L, ra, rb, rc, tm)); \ + } + + + +void luaV_execute (lua_State *L, int nexeccalls) { LClosure *cl; - TObject *k; + StkId base; + TValue *k; const Instruction *pc; - callentry: /* entry point when calling new functions */ - if (L->hookmask & LUA_MASKCALL) { - L->ci->u.l.pc = &pc; - luaD_callhook(L, LUA_HOOKCALL, -1); - } - retentry: /* entry point when returning to old functions */ - L->ci->u.l.pc = &pc; - lua_assert(L->ci->state == CI_SAVEDPC || - L->ci->state == (CI_SAVEDPC | CI_CALLING)); - L->ci->state = CI_HASFRAME; /* activate frame */ - pc = L->ci->u.l.savedpc; - cl = &clvalue(L->base - 1)->l; + reentry: /* entry point */ + lua_assert(isLua(L->ci)); + pc = L->savedpc; + cl = &clvalue(L->ci->func)->l; + base = L->base; k = cl->p->k; /* main loop of interpreter */ for (;;) { const Instruction i = *pc++; - StkId base, ra; + StkId ra; if ((L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) && (--L->hookcount == 0 || L->hookmask & LUA_MASKLINE)) { - traceexec(L); - if (L->ci->state & CI_YIELD) { /* did hook yield? */ - L->ci->u.l.savedpc = pc - 1; - L->ci->state = CI_YIELD | CI_SAVEDPC; - return NULL; - } - if (L->ci->state & CI_BREAK) { /* did hook break? */ - L->ci->state &= ~CI_BREAK; - luaG_runerror(L, "breaking"); + traceexec(L, pc); + if (L->status == LUA_YIELD) { /* did hook yield? */ + L->savedpc = pc - 1; + return; } + base = L->base; + } + if (L->do_break) { + L->do_break = 0; + luaG_runerror(L, "breaking"); } /* warning!! several calls may realloc the stack and invalidate `ra' */ - base = L->base; ra = RA(i); - lua_assert(L->ci->state & CI_HASFRAME); - lua_assert(base == L->ci->base); - lua_assert(L->top <= L->stack + L->stacksize && L->top >= base); - lua_assert(L->top == L->ci->top || - GET_OPCODE(i) == OP_CALL || GET_OPCODE(i) == OP_TAILCALL || - GET_OPCODE(i) == OP_RETURN || GET_OPCODE(i) == OP_SETLISTO); + lua_assert(base == L->base && L->base == L->ci->base); + lua_assert(base <= L->top && L->top <= L->stack + L->stacksize); + lua_assert(L->top == L->ci->top || luaG_checkopenop(i)); switch (GET_OPCODE(i)) { case OP_MOVE: { - setobjs2s(ra, RB(i)); - break; + setobjs2s(L, ra, RB(i)); + continue; } case OP_LOADK: { - setobj2s(ra, KBx(i)); - break; + setobj2s(L, ra, KBx(i)); + continue; } case OP_LOADBOOL: { setbvalue(ra, GETARG_B(i)); if (GETARG_C(i)) pc++; /* skip next instruction (if C) */ - break; + continue; } case OP_LOADNIL: { - TObject *rb = RB(i); + TValue *rb = RB(i); do { setnilvalue(rb--); } while (rb >= ra); - break; + continue; } case OP_GETUPVAL: { int b = GETARG_B(i); - setobj2s(ra, cl->upvals[b]->v); - break; + setobj2s(L, ra, cl->upvals[b]->v); + continue; } case OP_GETGLOBAL: { - TObject *rb = KBx(i); - const TObject *v; - lua_assert(ttisstring(rb) && ttistable(&cl->g)); - v = luaH_getstr(hvalue(&cl->g), tsvalue(rb)); - if (!ttisnil(v)) { setobj2s(ra, v); } - else - setobj2s(XRA(i), luaV_index(L, &cl->g, rb, 0)); - break; + TValue g; + TValue *rb = KBx(i); + sethvalue(L, &g, cl->env); + lua_assert(ttisstring(rb)); + Protect(luaV_gettable(L, &g, rb, ra)); + continue; } case OP_GETTABLE: { - StkId rb = RB(i); - TObject *rc = RKC(i); - if (ttistable(rb)) { - const TObject *v = luaH_get(hvalue(rb), rc); - if (!ttisnil(v)) { setobj2s(ra, v); } - else - setobj2s(XRA(i), luaV_index(L, rb, rc, 0)); - } - else - setobj2s(XRA(i), luaV_getnotable(L, rb, rc, 0)); - break; + Protect(luaV_gettable(L, RB(i), RKC(i), ra)); + continue; } case OP_SETGLOBAL: { - lua_assert(ttisstring(KBx(i)) && ttistable(&cl->g)); - luaV_settable(L, &cl->g, KBx(i), ra); - break; + TValue g; + sethvalue(L, &g, cl->env); + lua_assert(ttisstring(KBx(i))); + Protect(luaV_settable(L, &g, KBx(i), ra)); + continue; } case OP_SETUPVAL: { - int b = GETARG_B(i); - setobj(cl->upvals[b]->v, ra); /* write barrier */ - break; + UpVal *uv = cl->upvals[GETARG_B(i)]; + setobj(L, uv->v, ra); + luaC_barrier(L, uv, ra); + continue; } case OP_SETTABLE: { - luaV_settable(L, ra, RKB(i), RKC(i)); - break; + Protect(luaV_settable(L, ra, RKB(i), RKC(i))); + continue; } case OP_NEWTABLE: { int b = GETARG_B(i); - b = fb2int(b); - sethvalue(ra, luaH_new(L, b, GETARG_C(i))); - luaC_checkGC(L); - break; + int c = GETARG_C(i); + sethvalue(L, ra, luaH_new(L, luaO_fb2int(b), luaO_fb2int(c))); + Protect(luaC_checkGC(L)); + continue; } case OP_SELF: { StkId rb = RB(i); - TObject *rc = RKC(i); - runtime_check(L, ttisstring(rc)); - setobjs2s(ra+1, rb); - if (ttistable(rb)) { - const TObject *v = luaH_getstr(hvalue(rb), tsvalue(rc)); - if (!ttisnil(v)) { setobj2s(ra, v); } - else - setobj2s(XRA(i), luaV_index(L, rb, rc, 0)); - } - else - setobj2s(XRA(i), luaV_getnotable(L, rb, rc, 0)); - break; + setobjs2s(L, ra+1, rb); + Protect(luaV_gettable(L, rb, RKC(i), ra)); + continue; } case OP_ADD: { - TObject *rb = RKB(i); - TObject *rc = RKC(i); - if (ttisnumber(rb) && ttisnumber(rc)) { - setnvalue(ra, nvalue(rb) + nvalue(rc)); - } - else - Arith(L, ra, rb, rc, TM_ADD); - break; + arith_op(luai_numadd, TM_ADD); + continue; } case OP_SUB: { - TObject *rb = RKB(i); - TObject *rc = RKC(i); - if (ttisnumber(rb) && ttisnumber(rc)) { - setnvalue(ra, nvalue(rb) - nvalue(rc)); - } - else - Arith(L, ra, rb, rc, TM_SUB); - break; + arith_op(luai_numsub, TM_SUB); + continue; } case OP_MUL: { - TObject *rb = RKB(i); - TObject *rc = RKC(i); - if (ttisnumber(rb) && ttisnumber(rc)) { - setnvalue(ra, nvalue(rb) * nvalue(rc)); - } - else - Arith(L, ra, rb, rc, TM_MUL); - break; + arith_op(luai_nummul, TM_MUL); + continue; } case OP_DIV: { - TObject *rb = RKB(i); - TObject *rc = RKC(i); - if (ttisnumber(rb) && ttisnumber(rc)) { - setnvalue(ra, nvalue(rb) / nvalue(rc)); - } - else - Arith(L, ra, rb, rc, TM_DIV); - break; + arith_op(luai_numdiv, TM_DIV); + continue; + } + case OP_MOD: { + arith_op(luai_nummod, TM_MOD); + continue; } case OP_POW: { - Arith(L, ra, RKB(i), RKC(i), TM_POW); - break; + arith_op(luai_numpow, TM_POW); + continue; } case OP_UNM: { - const TObject *rb = RB(i); - TObject temp; - if (tonumber(rb, &temp)) { - setnvalue(ra, -nvalue(rb)); + TValue *rb = RB(i); + if (ttisnumber(rb)) { + lua_Number nb = nvalue(rb); + setnvalue(ra, luai_numunm(nb)); } else { - setnilvalue(&temp); - if (!call_binTM(L, RB(i), &temp, ra, TM_UNM)) - luaG_aritherror(L, RB(i), &temp); + Protect(Arith(L, ra, rb, rb, TM_UNM)); } - break; + continue; } case OP_NOT: { int res = l_isfalse(RB(i)); /* next assignment may change this value */ setbvalue(ra, res); - break; + continue; + } + case OP_LEN: { + const TValue *rb = RB(i); + switch (ttype(rb)) { + case LUA_TTABLE: { + setnvalue(ra, cast_num(luaH_getn(hvalue(rb)))); + break; + } + case LUA_TSTRING: { + setnvalue(ra, cast_num(tsvalue(rb)->len)); + break; + } + default: { /* try metamethod */ + Protect( + if (!call_binTM(L, rb, luaO_nilobject, ra, TM_LEN)) + luaG_typeerror(L, rb, "get length of"); + ) + } + } + continue; } case OP_CONCAT: { int b = GETARG_B(i); int c = GETARG_C(i); - luaV_concat(L, c-b+1, c); /* may change `base' (and `ra') */ - base = L->base; - setobjs2s(RA(i), base+b); - luaC_checkGC(L); - break; + Protect(luaV_concat(L, c-b+1, c); luaC_checkGC(L)); + setobjs2s(L, RA(i), base+b); + continue; } case OP_JMP: { - dojump(pc, GETARG_sBx(i)); - break; + dojump(L, pc, GETARG_sBx(i)); + continue; } case OP_EQ: { - if (equalobj(L, RKB(i), RKC(i)) != GETARG_A(i)) pc++; - else dojump(pc, GETARG_sBx(*pc) + 1); - break; + TValue *rb = RKB(i); + TValue *rc = RKC(i); + Protect( + if (equalobj(L, rb, rc) == GETARG_A(i)) + dojump(L, pc, GETARG_sBx(*pc)); + ) + pc++; + continue; } case OP_LT: { - if (luaV_lessthan(L, RKB(i), RKC(i)) != GETARG_A(i)) pc++; - else dojump(pc, GETARG_sBx(*pc) + 1); - break; + Protect( + if (luaV_lessthan(L, RKB(i), RKC(i)) == GETARG_A(i)) + dojump(L, pc, GETARG_sBx(*pc)); + ) + pc++; + continue; } case OP_LE: { - if (luaV_lessequal(L, RKB(i), RKC(i)) != GETARG_A(i)) pc++; - else dojump(pc, GETARG_sBx(*pc) + 1); - break; + Protect( + if (lessequal(L, RKB(i), RKC(i)) == GETARG_A(i)) + dojump(L, pc, GETARG_sBx(*pc)); + ) + pc++; + continue; } case OP_TEST: { - TObject *rb = RB(i); - if (l_isfalse(rb) == GETARG_C(i)) pc++; - else { - setobjs2s(ra, rb); - dojump(pc, GETARG_sBx(*pc) + 1); + if (l_isfalse(ra) != GETARG_C(i)) + dojump(L, pc, GETARG_sBx(*pc)); + pc++; + continue; + } + case OP_TESTSET: { + TValue *rb = RB(i); + if (l_isfalse(rb) != GETARG_C(i)) { + setobjs2s(L, ra, rb); + dojump(L, pc, GETARG_sBx(*pc)); } - break; + pc++; + continue; } - case OP_CALL: - case OP_TAILCALL: { - StkId firstResult; + case OP_CALL: { int b = GETARG_B(i); - int nresults; + int nresults = GETARG_C(i) - 1; if (b != 0) L->top = ra+b; /* else previous instruction set top */ - nresults = GETARG_C(i) - 1; - firstResult = luaD_precall(L, ra); - if (firstResult) { - if (firstResult > L->top) { /* yield? */ - lua_assert(L->ci->state == (CI_C | CI_YIELD)); - (L->ci - 1)->u.l.savedpc = pc; - (L->ci - 1)->state = CI_SAVEDPC; - return NULL; + L->savedpc = pc; + switch (luaD_precall(L, ra, nresults)) { + case PCRLUA: { + nexeccalls++; + goto reentry; /* restart luaV_execute over new Lua function */ } - /* it was a C function (`precall' called it); adjust results */ - luaD_poscall(L, nresults, firstResult); - if (nresults >= 0) L->top = L->ci->top; - } - else { /* it is a Lua function */ - if (GET_OPCODE(i) == OP_CALL) { /* regular call? */ - (L->ci-1)->u.l.savedpc = pc; /* save `pc' to return later */ - (L->ci-1)->state = (CI_SAVEDPC | CI_CALLING); + case PCRC: { + /* it was a C function (`precall' called it); adjust results */ + if (nresults >= 0) L->top = L->ci->top; + base = L->base; + continue; } - else { /* tail call: put new frame in place of previous one */ + default: { + return; /* yield */ + } + } + } + case OP_TAILCALL: { + int b = GETARG_B(i); + if (b != 0) L->top = ra+b; /* else previous instruction set top */ + L->savedpc = pc; + lua_assert(GETARG_C(i) - 1 == LUA_MULTRET); + switch (luaD_precall(L, ra, LUA_MULTRET)) { + case PCRLUA: { + /* tail call: put new frame in place of previous one */ + CallInfo *ci = L->ci - 1; /* previous frame */ int aux; - base = (L->ci - 1)->base; /* `luaD_precall' may change the stack */ - ra = RA(i); - if (L->openupval) luaF_close(L, base); - for (aux = 0; ra+aux < L->top; aux++) /* move frame down */ - setobjs2s(base+aux-1, ra+aux); - (L->ci - 1)->top = L->top = base+aux; /* correct top */ - lua_assert(L->ci->state & CI_SAVEDPC); - (L->ci - 1)->u.l.savedpc = L->ci->u.l.savedpc; - (L->ci - 1)->u.l.tailcalls++; /* one more call lost */ - (L->ci - 1)->state = CI_SAVEDPC; + StkId func = ci->func; + StkId pfunc = (ci+1)->func; /* previous function index */ + if (L->openupval) luaF_close(L, ci->base); + L->base = ci->base = ci->func + ((ci+1)->base - pfunc); + for (aux = 0; pfunc+aux < L->top; aux++) /* move frame down */ + setobjs2s(L, func+aux, pfunc+aux); + ci->top = L->top = func+aux; /* correct top */ + lua_assert(L->top == L->base + clvalue(func)->l.p->maxstacksize); + ci->savedpc = L->savedpc; + ci->tailcalls++; /* one more call lost */ L->ci--; /* remove new frame */ - L->base = L->ci->base; + goto reentry; + } + case PCRC: { /* it was a C function (`precall' called it) */ + base = L->base; + continue; + } + default: { + return; /* yield */ } - goto callentry; } - break; } case OP_RETURN: { - CallInfo *ci = L->ci - 1; /* previous function frame */ int b = GETARG_B(i); if (b != 0) L->top = ra+b-1; - lua_assert(L->ci->state & CI_HASFRAME); if (L->openupval) luaF_close(L, base); - L->ci->state = CI_SAVEDPC; /* deactivate current function */ - L->ci->u.l.savedpc = pc; - /* previous function was running `here'? */ - if (!(ci->state & CI_CALLING)) { - lua_assert((ci->state & CI_C) || ci->u.l.pc != &pc); - return ra; /* no: return */ - } + L->savedpc = pc; + b = luaD_poscall(L, ra); + if (--nexeccalls == 0) /* was previous function running `here'? */ + return; /* no: return */ else { /* yes: continue its execution */ - int nresults; - lua_assert(ttisfunction(ci->base - 1) && (ci->state & CI_SAVEDPC)); - lua_assert(GET_OPCODE(*(ci->u.l.savedpc - 1)) == OP_CALL); - nresults = GETARG_C(*(ci->u.l.savedpc - 1)) - 1; - luaD_poscall(L, nresults, ra); - if (nresults >= 0) L->top = L->ci->top; - goto retentry; + if (b) L->top = L->ci->top; + lua_assert(isLua(L->ci)); + lua_assert(GET_OPCODE(*((L->ci)->savedpc - 1)) == OP_CALL); + goto reentry; } } case OP_FORLOOP: { - lua_Number step, idx, limit; - const TObject *plimit = ra+1; - const TObject *pstep = ra+2; - if (!ttisnumber(ra)) - luaG_runerror(L, "`for' initial value must be a number"); - if (!tonumber(plimit, ra+1)) - luaG_runerror(L, "`for' limit must be a number"); - if (!tonumber(pstep, ra+2)) - luaG_runerror(L, "`for' step must be a number"); - step = nvalue(pstep); - idx = nvalue(ra) + step; /* increment index */ - limit = nvalue(plimit); - if (step > 0 ? idx <= limit : idx >= limit) { - dojump(pc, GETARG_sBx(i)); /* jump back */ - chgnvalue(ra, idx); /* update index */ + lua_Number step = nvalue(ra+2); + lua_Number idx = luai_numadd(nvalue(ra), step); /* increment index */ + lua_Number limit = nvalue(ra+1); + if (luai_numlt(0, step) ? luai_numle(idx, limit) + : luai_numle(limit, idx)) { + dojump(L, pc, GETARG_sBx(i)); /* jump back */ + setnvalue(ra, idx); /* update internal index... */ + setnvalue(ra+3, idx); /* ...and external index */ } - break; + continue; + } + case OP_FORPREP: { + const TValue *init = ra; + const TValue *plimit = ra+1; + const TValue *pstep = ra+2; + L->savedpc = pc; /* next steps may throw errors */ + if (!tonumber(init, ra)) + luaG_runerror(L, LUA_QL("for") " initial value must be a number"); + else if (!tonumber(plimit, ra+1)) + luaG_runerror(L, LUA_QL("for") " limit must be a number"); + else if (!tonumber(pstep, ra+2)) + luaG_runerror(L, LUA_QL("for") " step must be a number"); + setnvalue(ra, luai_numsub(nvalue(ra), nvalue(pstep))); + dojump(L, pc, GETARG_sBx(i)); + continue; } case OP_TFORLOOP: { - int nvar = GETARG_C(i) + 1; - StkId cb = ra + nvar + 2; /* call base */ - setobjs2s(cb, ra); - setobjs2s(cb+1, ra+1); - setobjs2s(cb+2, ra+2); + StkId cb = ra + 3; /* call base */ + setobjs2s(L, cb+2, ra+2); + setobjs2s(L, cb+1, ra+1); + setobjs2s(L, cb, ra); L->top = cb+3; /* func. + 2 args (state and index) */ - luaD_call(L, cb, nvar); + Protect(luaD_call(L, cb, GETARG_C(i))); L->top = L->ci->top; - ra = XRA(i) + 2; /* final position of first result */ - cb = ra + nvar; - do { /* move results to proper positions */ - nvar--; - setobjs2s(ra+nvar, cb+nvar); - } while (nvar > 0); - if (ttisnil(ra)) /* break loop? */ - pc++; /* skip jump (break loop) */ - else - dojump(pc, GETARG_sBx(*pc) + 1); /* jump back */ - break; - } - case OP_TFORPREP: { /* for compatibility only */ - if (ttistable(ra)) { - setobjs2s(ra+1, ra); - setobj2s(ra, luaH_getstr(hvalue(gt(L)), luaS_new(L, "next"))); + cb = RA(i) + 3; /* previous call may change the stack */ + if (!ttisnil(cb)) { /* continue loop? */ + setobjs2s(L, cb-1, cb); /* save control variable */ + dojump(L, pc, GETARG_sBx(*pc)); /* jump back */ } - dojump(pc, GETARG_sBx(i)); - break; + pc++; + continue; } - case OP_SETLIST: - case OP_SETLISTO: { - int bc; - int n; + case OP_SETLIST: { + int n = GETARG_B(i); + int c = GETARG_C(i); + int last; Table *h; + if (n == 0) { + n = cast_int(L->top - ra) - 1; + L->top = L->ci->top; + } + if (c == 0) c = cast_int(*pc++); runtime_check(L, ttistable(ra)); h = hvalue(ra); - bc = GETARG_Bx(i); - if (GET_OPCODE(i) == OP_SETLIST) - n = (bc&(LFIELDS_PER_FLUSH-1)) + 1; - else { - n = L->top - ra - 1; - L->top = L->ci->top; + last = ((c-1)*LFIELDS_PER_FLUSH) + n; + if (last > h->sizearray) /* needs more space? */ + luaH_resizearray(L, h, last); /* pre-alloc it at once */ + for (; n > 0; n--) { + TValue *val = ra+n; + setobj2t(L, luaH_setnum(L, h, last--), val); + luaC_barriert(L, h, val); } - bc &= ~(LFIELDS_PER_FLUSH-1); /* bc = bc - bc%FPF */ - for (; n > 0; n--) - setobj2t(luaH_setnum(L, h, bc+n), ra+n); /* write barrier */ - break; + continue; } case OP_CLOSE: { luaF_close(L, ra); - break; + continue; } case OP_CLOSURE: { Proto *p; @@ -784,7 +728,7 @@ StkId luaV_execute (lua_State *L) { int nup, j; p = cl->p->p[GETARG_Bx(i)]; nup = p->nups; - ncl = luaF_newLclosure(L, nup, &cl->g); + ncl = luaF_newLclosure(L, nup, cl->env); ncl->l.p = p; for (j=0; j<nup; j++, pc++) { if (GET_OPCODE(*pc) == OP_GETUPVAL) @@ -794,9 +738,30 @@ StkId luaV_execute (lua_State *L) { ncl->l.upvals[j] = luaF_findupval(L, base + GETARG_B(*pc)); } } - setclvalue(ra, ncl); - luaC_checkGC(L); - break; + setclvalue(L, ra, ncl); + Protect(luaC_checkGC(L)); + continue; + } + case OP_VARARG: { + int b = GETARG_B(i) - 1; + int j; + CallInfo *ci = L->ci; + int n = cast_int(ci->base - ci->func) - cl->p->numparams - 1; + if (b == LUA_MULTRET) { + Protect(luaD_checkstack(L, n)); + ra = RA(i); /* previous call may change the stack */ + b = n; + L->top = ra + n; + } + for (j = 0; j < b; j++) { + if (j < n) { + setobjs2s(L, ra + j, ci->base - n + j); + } + else { + setnilvalue(ra + j); + } + } + continue; } } } diff --git a/lib/lua/src/lzio.c b/lib/lua/src/lzio.c index 277a656..8665a43 100644 --- a/lib/lua/src/lzio.c +++ b/lib/lua/src/lzio.c @@ -1,5 +1,5 @@ /* -** $Id: lzio.c,v 1.4 2004-11-27 21:46:07 pixel Exp $ +** $Id: lzio.c,v 1.5 2007-07-27 10:05:54 pixel Exp $ ** a generic input stream interface ** See Copyright Notice in lua.h */ @@ -8,17 +8,23 @@ #include <string.h> #define lzio_c +#define LUA_CORE #include "lua.h" #include "llimits.h" #include "lmem.h" +#include "lstate.h" #include "lzio.h" int luaZ_fill (ZIO *z) { size_t size; - const char *buff = z->reader(NULL, z->data, &size); + lua_State *L = z->L; + const char *buff; + lua_unlock(L); + buff = z->reader(L, z->data, &size); + lua_lock(L); if (buff == NULL || size == 0) return EOZ; z->n = size - 1; z->p = buff; @@ -28,19 +34,21 @@ int luaZ_fill (ZIO *z) { int luaZ_lookahead (ZIO *z) { if (z->n == 0) { - int c = luaZ_fill(z); - if (c == EOZ) return c; - z->n++; - z->p--; + if (luaZ_fill(z) == EOZ) + return EOZ; + else { + z->n++; /* luaZ_fill removed first byte; put back it */ + z->p--; + } } return char2int(*z->p); } -void luaZ_init (ZIO *z, lua_Chunkreader reader, void *data, const char *name) { +void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader, void *data) { + z->L = L; z->reader = reader; z->data = data; - z->name = name; z->n = 0; z->p = NULL; } @@ -50,14 +58,8 @@ void luaZ_init (ZIO *z, lua_Chunkreader reader, void *data, const char *name) { size_t luaZ_read (ZIO *z, void *b, size_t n) { while (n) { size_t m; - if (z->n == 0) { - if (luaZ_fill(z) == EOZ) - return n; /* return number of missing bytes */ - else { - ++z->n; /* filbuf removed first byte; put back it */ - --z->p; - } - } + if (luaZ_lookahead(z) == EOZ) + return n; /* return number of missing bytes */ m = (n <= z->n) ? n : z->n; /* min. between n and z->n */ memcpy(b, z->p, m); z->n -= m; @@ -72,8 +74,7 @@ size_t luaZ_read (ZIO *z, void *b, size_t n) { char *luaZ_openspace (lua_State *L, Mbuffer *buff, size_t n) { if (n > buff->buffsize) { if (n < LUA_MINBUFFER) n = LUA_MINBUFFER; - luaM_reallocvector(L, buff->buffer, buff->buffsize, n, char); - buff->buffsize = n; + luaZ_resizebuffer(L, buff, n); } return buff->buffer; } |