C functions and userdata also have environments

This commit is contained in:
Roberto Ierusalimschy
2005-02-18 10:40:02 -02:00
parent 73d7640244
commit 7d45a5f48f
17 changed files with 206 additions and 111 deletions

66
lapi.c
View File

@@ -1,5 +1,5 @@
/* /*
** $Id: lapi.c,v 2.25 2005/01/07 19:53:32 roberto Exp roberto $ ** $Id: lapi.c,v 2.26 2005/01/14 14:19:42 roberto Exp roberto $
** Lua API ** Lua API
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@@ -58,6 +58,11 @@ static TValue *index2adr (lua_State *L, int idx) {
} }
else switch (idx) { /* pseudo-indices */ else switch (idx) { /* pseudo-indices */
case LUA_REGISTRYINDEX: return registry(L); 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); case LUA_GLOBALSINDEX: return gt(L);
default: { default: {
Closure *func = curr_func(L); Closure *func = curr_func(L);
@@ -70,6 +75,16 @@ static TValue *index2adr (lua_State *L, int idx) {
} }
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 {
Closure *func = curr_func(L);
return func->c.env;
}
}
void luaA_pushobject (lua_State *L, const TValue *o) { void luaA_pushobject (lua_State *L, const TValue *o) {
setobj2s(L, L->top, o); setobj2s(L, L->top, o);
incr_top(L); incr_top(L);
@@ -186,9 +201,17 @@ LUA_API void lua_replace (lua_State *L, int idx) {
api_checknelems(L, 1); api_checknelems(L, 1);
o = index2adr(L, idx); o = index2adr(L, idx);
api_checkvalidindex(L, o); api_checkvalidindex(L, o);
setobj(L, o, L->top - 1); if (idx == LUA_ENVIRONINDEX) {
if (idx < LUA_GLOBALSINDEX) /* function upvalue? */ Closure *func = curr_func(L);
luaC_barrier(L, curr_func(L), L->top - 1); 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--; L->top--;
lua_unlock(L); lua_unlock(L);
} }
@@ -452,7 +475,7 @@ LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
lua_lock(L); lua_lock(L);
luaC_checkGC(L); luaC_checkGC(L);
api_checknelems(L, n); api_checknelems(L, n);
cl = luaF_newCclosure(L, n); cl = luaF_newCclosure(L, n, getcurrenv(L));
cl->c.f = fn; cl->c.f = fn;
L->top -= n; L->top -= n;
while (n--) while (n--)
@@ -579,7 +602,17 @@ LUA_API void lua_getfenv (lua_State *L, int idx) {
lua_lock(L); lua_lock(L);
o = index2adr(L, idx); o = index2adr(L, idx);
api_checkvalidindex(L, o); api_checkvalidindex(L, o);
setobj2s(L, L->top, isLfunction(o) ? &clvalue(o)->l.g : gt(L)); 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;
default:
setnilvalue(L->top);
break;
}
api_incr_top(L); api_incr_top(L);
lua_unlock(L); lua_unlock(L);
} }
@@ -682,17 +715,24 @@ LUA_API int lua_setmetatable (lua_State *L, int objindex) {
LUA_API int lua_setfenv (lua_State *L, int idx) { LUA_API int lua_setfenv (lua_State *L, int idx) {
StkId o; StkId o;
int res = 0; int res = 1;
lua_lock(L); lua_lock(L);
api_checknelems(L, 1); api_checknelems(L, 1);
o = index2adr(L, idx); o = index2adr(L, idx);
api_checkvalidindex(L, o); api_checkvalidindex(L, o);
api_check(L, ttistable(L->top - 1)); api_check(L, ttistable(L->top - 1));
if (isLfunction(o)) { switch (ttype(o)) {
res = 1; case LUA_TFUNCTION:
clvalue(o)->l.g = *(L->top - 1); clvalue(o)->c.env = hvalue(L->top - 1);
luaC_objbarrier(L, clvalue(o), hvalue(L->top - 1)); break;
case LUA_TUSERDATA:
uvalue(o)->env = hvalue(L->top - 1);
break;
default:
res = 0;
break;
} }
luaC_objbarrier(L, gcvalue(o), hvalue(L->top - 1));
L->top--; L->top--;
lua_unlock(L); lua_unlock(L);
return res; return res;
@@ -776,7 +816,7 @@ struct CCallS { /* data to `f_Ccall' */
static void f_Ccall (lua_State *L, void *ud) { static void f_Ccall (lua_State *L, void *ud) {
struct CCallS *c = cast(struct CCallS *, ud); struct CCallS *c = cast(struct CCallS *, ud);
Closure *cl; Closure *cl;
cl = luaF_newCclosure(L, 0); cl = luaF_newCclosure(L, 0, getcurrenv(L));
cl->c.f = c->func; cl->c.f = c->func;
setclvalue(L, L->top, cl); /* push function */ setclvalue(L, L->top, cl); /* push function */
incr_top(L); incr_top(L);
@@ -943,7 +983,7 @@ LUA_API void *lua_newuserdata (lua_State *L, size_t size) {
Udata *u; Udata *u;
lua_lock(L); lua_lock(L);
luaC_checkGC(L); luaC_checkGC(L);
u = luaS_newudata(L, size); u = luaS_newudata(L, size, getcurrenv(L));
setuvalue(L, L->top, u); setuvalue(L, L->top, u);
api_incr_top(L); api_incr_top(L);
lua_unlock(L); lua_unlock(L);

View File

@@ -1,5 +1,5 @@
/* /*
** $Id: lbaselib.c,v 1.165 2005/01/14 14:19:42 roberto Exp roberto $ ** $Id: lbaselib.c,v 1.166 2005/02/14 13:19:44 roberto Exp roberto $
** Basic library ** Basic library
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@@ -131,7 +131,10 @@ static void getfunc (lua_State *L) {
static int luaB_getfenv (lua_State *L) { static int luaB_getfenv (lua_State *L) {
getfunc(L); getfunc(L);
lua_getfenv(L, -1); if (lua_iscfunction(L, -1)) /* is a C function? */
lua_pushvalue(L, LUA_GLOBALSINDEX); /* return the global env. */
else
lua_getfenv(L, -1);
return 1; return 1;
} }
@@ -144,8 +147,8 @@ static int luaB_setfenv (lua_State *L) {
lua_replace(L, LUA_GLOBALSINDEX); lua_replace(L, LUA_GLOBALSINDEX);
return 0; return 0;
} }
else if (lua_setfenv(L, -2) == 0) else if (lua_iscfunction(L, -2) || lua_setfenv(L, -2) == 0)
luaL_error(L, "`setfenv' cannot change environment of given function"); luaL_error(L, "`setfenv' cannot change environment of given object");
return 1; return 1;
} }

View File

@@ -1,5 +1,5 @@
/* /*
** $Id: ldblib.c,v 1.91 2005/01/10 17:21:10 roberto Exp roberto $ ** $Id: ldblib.c,v 1.92 2005/01/18 17:23:25 roberto Exp roberto $
** Interface from Lua to its debug API ** Interface from Lua to its debug API
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@@ -19,6 +19,40 @@
static int getmetatable (lua_State *L) {
luaL_checkany(L, 1);
if (!lua_getmetatable(L, 1)) {
lua_pushnil(L); /* no metatable */
}
return 1;
}
static int 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 getfenv (lua_State *L) {
lua_getfenv(L, 1);
return 1;
}
static int setfenv (lua_State *L) {
luaL_checktype(L, 2, LUA_TTABLE);
lua_settop(L, 2);
if (lua_setfenv(L, 1) == 0)
luaL_error(L, "`setfenv' cannot change environment of given object");
return 1;
}
static void settabss (lua_State *L, const char *i, const char *v) { static void settabss (lua_State *L, const char *i, const char *v) {
lua_pushstring(L, v); lua_pushstring(L, v);
lua_setfield(L, -2, i); lua_setfield(L, -2, i);
@@ -328,6 +362,10 @@ static int errorfb (lua_State *L) {
static const luaL_reg dblib[] = { static const luaL_reg dblib[] = {
{"getmetatable", getmetatable},
{"setmetatable", setmetatable},
{"getfenv", getfenv},
{"setfenv", setfenv},
{"getlocal", getlocal}, {"getlocal", getlocal},
{"getinfo", getinfo}, {"getinfo", getinfo},
{"gethook", gethook}, {"gethook", gethook},

4
ldo.c
View File

@@ -1,5 +1,5 @@
/* /*
** $Id: ldo.c,v 2.12 2004/12/01 15:52:54 roberto Exp roberto $ ** $Id: ldo.c,v 2.13 2004/12/03 20:35:33 roberto Exp roberto $
** Stack and Call structure of Lua ** Stack and Call structure of Lua
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@@ -474,7 +474,7 @@ static void f_parser (lua_State *L, void *ud) {
luaC_checkGC(L); luaC_checkGC(L);
tf = ((c == LUA_SIGNATURE[0]) ? luaU_undump : luaY_parser)(L, p->z, tf = ((c == LUA_SIGNATURE[0]) ? luaU_undump : luaY_parser)(L, p->z,
&p->buff, p->name); &p->buff, p->name);
cl = luaF_newLclosure(L, tf->nups, gt(L)); cl = luaF_newLclosure(L, tf->nups, hvalue(gt(L)));
cl->l.p = tf; cl->l.p = tf;
for (i = 0; i < tf->nups; i++) /* initialize eventual upvalues */ for (i = 0; i < tf->nups; i++) /* initialize eventual upvalues */
cl->l.upvals[i] = luaF_newupval(L); cl->l.upvals[i] = luaF_newupval(L);

View File

@@ -1,5 +1,5 @@
/* /*
** $Id: lfunc.c,v 2.7 2005/01/19 15:54:26 roberto Exp roberto $ ** $Id: lfunc.c,v 2.8 2005/02/10 13:25:02 roberto Exp roberto $
** Auxiliary functions to manipulate prototypes and closures ** Auxiliary functions to manipulate prototypes and closures
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@@ -20,20 +20,21 @@
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))); Closure *c = cast(Closure *, luaM_malloc(L, sizeCclosure(nelems)));
luaC_link(L, obj2gco(c), LUA_TFUNCTION); luaC_link(L, obj2gco(c), LUA_TFUNCTION);
c->c.isC = 1; c->c.isC = 1;
c->c.env = e;
c->c.nupvalues = cast(lu_byte, nelems); c->c.nupvalues = cast(lu_byte, nelems);
return c; return c;
} }
Closure *luaF_newLclosure (lua_State *L, int nelems, TValue *e) { Closure *luaF_newLclosure (lua_State *L, int nelems, Table *e) {
Closure *c = cast(Closure *, luaM_malloc(L, sizeLclosure(nelems))); Closure *c = cast(Closure *, luaM_malloc(L, sizeLclosure(nelems)));
luaC_link(L, obj2gco(c), LUA_TFUNCTION); luaC_link(L, obj2gco(c), LUA_TFUNCTION);
c->l.isC = 0; c->l.isC = 0;
c->l.g = *e; c->l.env = e;
c->l.nupvalues = cast(lu_byte, nelems); c->l.nupvalues = cast(lu_byte, nelems);
while (nelems--) c->l.upvals[nelems] = NULL; while (nelems--) c->l.upvals[nelems] = NULL;
return c; return c;

View File

@@ -1,5 +1,5 @@
/* /*
** $Id: lfunc.h,v 2.1 2003/12/10 12:13:36 roberto Exp $ ** $Id: lfunc.h,v 2.2 2005/01/18 17:18:09 roberto Exp roberto $
** Auxiliary functions to manipulate prototypes and closures ** Auxiliary functions to manipulate prototypes and closures
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@@ -19,8 +19,8 @@
Proto *luaF_newproto (lua_State *L); Proto *luaF_newproto (lua_State *L);
Closure *luaF_newCclosure (lua_State *L, int nelems); Closure *luaF_newCclosure (lua_State *L, int nelems, Table *e);
Closure *luaF_newLclosure (lua_State *L, int nelems, TValue *e); Closure *luaF_newLclosure (lua_State *L, int nelems, Table *e);
UpVal *luaF_newupval (lua_State *L); UpVal *luaF_newupval (lua_State *L);
UpVal *luaF_findupval (lua_State *L, StkId level); UpVal *luaF_findupval (lua_State *L, StkId level);
void luaF_close (lua_State *L, StkId level); void luaF_close (lua_State *L, StkId level);

5
lgc.c
View File

@@ -1,5 +1,5 @@
/* /*
** $Id: lgc.c,v 2.24 2005/02/11 20:03:35 roberto Exp roberto $ ** $Id: lgc.c,v 2.25 2005/02/14 13:19:50 roberto Exp roberto $
** Garbage Collector ** Garbage Collector
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@@ -79,6 +79,7 @@ static void reallymarkobject (global_State *g, GCObject *o) {
Table *mt = gco2u(o)->metatable; Table *mt = gco2u(o)->metatable;
gray2black(o); /* udata are never gray */ gray2black(o); /* udata are never gray */
if (mt) markobject(g, mt); if (mt) markobject(g, mt);
markobject(g, gco2u(o)->env);
return; return;
} }
case LUA_TUPVAL: { case LUA_TUPVAL: {
@@ -223,6 +224,7 @@ static void traverseproto (global_State *g, Proto *f) {
static void traverseclosure (global_State *g, Closure *cl) { static void traverseclosure (global_State *g, Closure *cl) {
markobject(g, cl->c.env);
if (cl->c.isC) { if (cl->c.isC) {
int i; int i;
for (i=0; i<cl->c.nupvalues; i++) /* mark its upvalues */ for (i=0; i<cl->c.nupvalues; i++) /* mark its upvalues */
@@ -231,7 +233,6 @@ static void traverseclosure (global_State *g, Closure *cl) {
else { else {
int i; int i;
lua_assert(cl->l.nupvalues == cl->l.p->nups); lua_assert(cl->l.nupvalues == cl->l.p->nups);
markobject(g, hvalue(&cl->l.g));
markobject(g, cl->l.p); markobject(g, cl->l.p);
for (i=0; i<cl->l.nupvalues; i++) /* mark its upvalues */ for (i=0; i<cl->l.nupvalues; i++) /* mark its upvalues */
markobject(g, cl->l.upvals[i]); markobject(g, cl->l.upvals[i]);

View File

@@ -1,5 +1,5 @@
/* /*
** $Id: linit.c,v 1.7 2004/07/09 14:29:29 roberto Exp roberto $ ** $Id: linit.c,v 1.8 2004/07/09 15:47:48 roberto Exp roberto $
** Initialization of libraries for lua.c ** Initialization of libraries for lua.c
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@@ -32,6 +32,8 @@ LUALIB_API int luaopen_stdlibs (lua_State *L) {
for (; lib->func; lib++) { for (; lib->func; lib++) {
lib->func(L); /* open library */ lib->func(L); /* open library */
lua_settop(L, 0); /* discard any results */ lua_settop(L, 0); /* discard any results */
lua_pushvalue(L, LUA_GLOBALSINDEX);
lua_replace(L, LUA_ENVIRONINDEX); /* restore environment */
} }
return 0; return 0;
} }

View File

@@ -1,5 +1,5 @@
/* /*
** $Id: liolib.c,v 2.56 2004/08/09 14:35:59 roberto Exp roberto $ ** $Id: liolib.c,v 2.57 2004/08/13 19:52:13 roberto Exp roberto $
** Standard I/O (and system) library ** Standard I/O (and system) library
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@@ -105,8 +105,8 @@ static int aux_close (lua_State *L) {
static int io_close (lua_State *L) { static int io_close (lua_State *L) {
if (lua_isnone(L, 1) && lua_type(L, lua_upvalueindex(1)) == LUA_TTABLE) if (lua_isnone(L, 1))
lua_rawgeti(L, lua_upvalueindex(1), IO_OUTPUT); lua_rawgeti(L, LUA_ENVIRONINDEX, IO_OUTPUT);
return pushresult(L, aux_close(L), NULL); return pushresult(L, aux_close(L), NULL);
} }
@@ -147,7 +147,7 @@ static int io_tmpfile (lua_State *L) {
static FILE *getiofile (lua_State *L, int findex) { static FILE *getiofile (lua_State *L, int findex) {
FILE *f; FILE *f;
lua_rawgeti(L, lua_upvalueindex(1), findex); lua_rawgeti(L, LUA_ENVIRONINDEX, findex);
lua_assert(luaL_checkudata(L, -1, LUA_FILEHANDLE)); lua_assert(luaL_checkudata(L, -1, LUA_FILEHANDLE));
f = *(FILE **)lua_touserdata(L, -1); f = *(FILE **)lua_touserdata(L, -1);
if (f == NULL) if (f == NULL)
@@ -170,10 +170,10 @@ static int g_iofile (lua_State *L, int f, const char *mode) {
lua_pushvalue(L, 1); lua_pushvalue(L, 1);
} }
lua_assert(luaL_checkudata(L, -1, LUA_FILEHANDLE)); lua_assert(luaL_checkudata(L, -1, LUA_FILEHANDLE));
lua_rawseti(L, lua_upvalueindex(1), f); lua_rawseti(L, LUA_ENVIRONINDEX, f);
} }
/* return current value */ /* return current value */
lua_rawgeti(L, lua_upvalueindex(1), f); lua_rawgeti(L, LUA_ENVIRONINDEX, f);
return 1; return 1;
} }
@@ -192,10 +192,9 @@ static int io_readline (lua_State *L);
static void aux_lines (lua_State *L, int idx, int close) { static void aux_lines (lua_State *L, int idx, int close) {
lua_getfield(L, LUA_REGISTRYINDEX, LUA_FILEHANDLE);
lua_pushvalue(L, idx); lua_pushvalue(L, idx);
lua_pushboolean(L, close); /* close/not close file when finished */ lua_pushboolean(L, close); /* close/not close file when finished */
lua_pushcclosure(L, io_readline, 3); lua_pushcclosure(L, io_readline, 2);
} }
@@ -209,7 +208,7 @@ static int f_lines (lua_State *L) {
static int io_lines (lua_State *L) { static int io_lines (lua_State *L) {
if (lua_isnoneornil(L, 1)) { /* no arguments? */ if (lua_isnoneornil(L, 1)) { /* no arguments? */
/* will iterate over default input */ /* will iterate over default input */
lua_rawgeti(L, lua_upvalueindex(1), IO_INPUT); lua_rawgeti(L, LUA_ENVIRONINDEX, IO_INPUT);
return f_lines(L); return f_lines(L);
} }
else { else {
@@ -349,7 +348,7 @@ static int f_read (lua_State *L) {
static int io_readline (lua_State *L) { 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; int sucess;
if (f == NULL) /* file is already closed? */ if (f == NULL) /* file is already closed? */
luaL_error(L, "file is already closed"); luaL_error(L, "file is already closed");
@@ -358,9 +357,9 @@ static int io_readline (lua_State *L) {
luaL_error(L, "%s", strerror(errno)); luaL_error(L, "%s", strerror(errno));
if (sucess) return 1; if (sucess) return 1;
else { /* EOF */ 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_settop(L, 0);
lua_pushvalue(L, lua_upvalueindex(2)); lua_pushvalue(L, lua_upvalueindex(1));
aux_close(L); /* close it */ aux_close(L); /* close it */
} }
return 0; return 0;
@@ -489,12 +488,13 @@ LUALIB_API int luaopen_io (lua_State *L) {
createmeta(L); createmeta(L);
createupval(L); createupval(L);
lua_pushvalue(L, -1); lua_pushvalue(L, -1);
luaL_openlib(L, LUA_IOLIBNAME, iolib, 1); lua_replace(L, LUA_ENVIRONINDEX);
luaL_openlib(L, LUA_IOLIBNAME, iolib, 0);
/* put predefined file handles into `io' table */ /* put predefined file handles into `io' table */
lua_rawgeti(L, -2, IO_INPUT); /* get current input from metatable */ lua_rawgeti(L, -2, IO_INPUT); /* get current input from upval */
lua_setfield(L, -2, "stdin"); /* io.stdin = metatable[IO_INPUT] */ lua_setfield(L, -2, "stdin"); /* io.stdin = upval[IO_INPUT] */
lua_rawgeti(L, -2, IO_OUTPUT); /* get current output from metatable */ lua_rawgeti(L, -2, IO_OUTPUT); /* get current output from upval */
lua_setfield(L, -2, "stdout"); /* io.stdout = metatable[IO_OUTPUT] */ lua_setfield(L, -2, "stdout"); /* io.stdout = upval[IO_OUTPUT] */
*newfile(L) = stderr; *newfile(L) = stderr;
lua_setfield(L, -2, "stderr"); /* io.stderr = newfile(stderr) */ lua_setfield(L, -2, "stderr"); /* io.stderr = newfile(stderr) */
return 1; return 1;

View File

@@ -1,5 +1,5 @@
/* /*
** $Id: loadlib.c,v 1.15 2004/12/29 18:56:34 roberto Exp roberto $ ** $Id: loadlib.c,v 1.16 2005/01/14 14:17:18 roberto Exp roberto $
** Dynamic library loader for Lua ** Dynamic library loader for Lua
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
* *
@@ -302,7 +302,7 @@ static int loader_Lua (lua_State *L) {
path = lua_tostring(L, -1); path = lua_tostring(L, -1);
if (!path) { if (!path) {
lua_pop(L, 1); lua_pop(L, 1);
luaL_getfield(L, LUA_REGISTRYINDEX, "_PACKAGE.path"); lua_getfield(L, LUA_ENVIRONINDEX, "path");
path = lua_tostring(L, -1); path = lua_tostring(L, -1);
} }
if (path == NULL) if (path == NULL)
@@ -320,7 +320,7 @@ static int loader_C (lua_State *L) {
const char *fname = luaL_gsub(L, name, ".", LUA_DIRSEP); const char *fname = luaL_gsub(L, name, ".", LUA_DIRSEP);
const char *path; const char *path;
const char *funcname; const char *funcname;
luaL_getfield(L, LUA_REGISTRYINDEX, "_PACKAGE.cpath"); lua_getfield(L, LUA_ENVIRONINDEX, "cpath");
path = lua_tostring(L, -1); path = lua_tostring(L, -1);
if (path == NULL) if (path == NULL)
luaL_error(L, "`package.cpath' must be a string"); luaL_error(L, "`package.cpath' must be a string");
@@ -335,7 +335,7 @@ static int loader_C (lua_State *L) {
static int loader_preload (lua_State *L) { static int loader_preload (lua_State *L) {
luaL_getfield(L, LUA_REGISTRYINDEX, "_PACKAGE.preload"); lua_getfield(L, LUA_ENVIRONINDEX, "preload");
if (!lua_istable(L, -1)) if (!lua_istable(L, -1))
luaL_error(L, "`package.preload' must be a table"); luaL_error(L, "`package.preload' must be a table");
lua_getfield(L, -1, luaL_checkstring(L, 1)); lua_getfield(L, -1, luaL_checkstring(L, 1));
@@ -355,7 +355,7 @@ static int ll_require (lua_State *L) {
lua_pushboolean(L, 1); lua_pushboolean(L, 1);
lua_setfield(L, 2, name); /* _LOADED[name] = true */ lua_setfield(L, 2, name); /* _LOADED[name] = true */
/* iterate over available loaders */ /* iterate over available loaders */
luaL_getfield(L, LUA_REGISTRYINDEX, "_PACKAGE.loaders"); lua_getfield(L, LUA_ENVIRONINDEX, "loaders");
if (!lua_istable(L, -1)) if (!lua_istable(L, -1))
luaL_error(L, "`package.loaders' must be a table"); luaL_error(L, "`package.loaders' must be a table");
for (i=1;; i++) { for (i=1;; i++) {
@@ -457,6 +457,8 @@ LUALIB_API int luaopen_loadlib (lua_State *L) {
lua_setglobal(L, "package"); lua_setglobal(L, "package");
lua_pushvalue(L, -1); lua_pushvalue(L, -1);
lua_setfield(L, LUA_REGISTRYINDEX, "_PACKAGE"); lua_setfield(L, LUA_REGISTRYINDEX, "_PACKAGE");
lua_pushvalue(L, -1);
lua_replace(L, LUA_ENVIRONINDEX);
/* create `loaders' table */ /* create `loaders' table */
lua_newtable(L); lua_newtable(L);
/* fill it with pre-defined loaders */ /* fill it with pre-defined loaders */

View File

@@ -1,5 +1,5 @@
/* /*
** $Id: lobject.h,v 2.9 2005/01/05 18:20:51 roberto Exp $ ** $Id: lobject.h,v 2.10 2005/01/18 17:18:09 roberto Exp roberto $
** Type definitions for Lua objects ** Type definitions for Lua objects
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@@ -218,6 +218,7 @@ typedef union Udata {
struct { struct {
CommonHeader; CommonHeader;
struct Table *metatable; struct Table *metatable;
struct Table *env;
size_t len; size_t len;
} uv; } uv;
} Udata; } Udata;
@@ -286,7 +287,8 @@ typedef struct UpVal {
*/ */
#define ClosureHeader \ #define ClosureHeader \
CommonHeader; lu_byte isC; lu_byte nupvalues; GCObject *gclist CommonHeader; lu_byte isC; lu_byte nupvalues; GCObject *gclist; \
struct Table *env
typedef struct CClosure { typedef struct CClosure {
ClosureHeader; ClosureHeader;
@@ -298,7 +300,6 @@ typedef struct CClosure {
typedef struct LClosure { typedef struct LClosure {
ClosureHeader; ClosureHeader;
struct Proto *p; struct Proto *p;
TValue g; /* global table for this closure */
UpVal *upvals[1]; UpVal *upvals[1];
} LClosure; } LClosure;

View File

@@ -1,5 +1,5 @@
/* /*
** $Id: lstate.h,v 2.13 2005/01/18 17:18:09 roberto Exp roberto $ ** $Id: lstate.h,v 2.14 2005/02/11 20:03:35 roberto Exp roberto $
** Global State ** Global State
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@@ -116,6 +116,7 @@ struct lua_State {
int hookcount; int hookcount;
lua_Hook hook; lua_Hook hook;
TValue _gt; /* table of globals */ TValue _gt; /* table of globals */
TValue env; /* temporary place for environments */
GCObject *openupval; /* list of open upvalues in this stack */ GCObject *openupval; /* list of open upvalues in this stack */
GCObject *gclist; GCObject *gclist;
struct lua_longjmp *errorJmp; /* current error recover point */ struct lua_longjmp *errorJmp; /* current error recover point */

View File

@@ -1,5 +1,5 @@
/* /*
** $Id: lstring.c,v 2.5 2004/11/24 19:16:03 roberto Exp $ ** $Id: lstring.c,v 2.6 2005/01/18 17:18:09 roberto Exp roberto $
** String table (keeps all strings handled by Lua) ** String table (keeps all strings handled by Lua)
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@@ -93,7 +93,7 @@ TString *luaS_newlstr (lua_State *L, const char *str, size_t l) {
} }
Udata *luaS_newudata (lua_State *L, size_t s) { Udata *luaS_newudata (lua_State *L, size_t s, Table *e) {
Udata *u; Udata *u;
if (s > MAX_SIZET - sizeof(Udata)) if (s > MAX_SIZET - sizeof(Udata))
luaM_toobig(L); luaM_toobig(L);
@@ -102,6 +102,7 @@ Udata *luaS_newudata (lua_State *L, size_t s) {
u->uv.tt = LUA_TUSERDATA; u->uv.tt = LUA_TUSERDATA;
u->uv.len = s; u->uv.len = s;
u->uv.metatable = NULL; u->uv.metatable = NULL;
u->uv.env = e;
/* chain it on udata list (after main thread) */ /* chain it on udata list (after main thread) */
u->uv.next = G(L)->mainthread->next; u->uv.next = G(L)->mainthread->next;
G(L)->mainthread->next = obj2gco(u); G(L)->mainthread->next = obj2gco(u);

View File

@@ -1,5 +1,5 @@
/* /*
** $Id: lstring.h,v 1.39 2004/08/24 20:12:06 roberto Exp roberto $ ** $Id: lstring.h,v 1.40 2004/11/19 15:52:40 roberto Exp roberto $
** String table (keep all strings handled by Lua) ** String table (keep all strings handled by Lua)
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@@ -24,7 +24,7 @@
#define luaS_fix(s) setbit((s)->tsv.marked, FIXEDBIT) #define luaS_fix(s) setbit((s)->tsv.marked, FIXEDBIT)
void luaS_resize (lua_State *L, int newsize); void luaS_resize (lua_State *L, int newsize);
Udata *luaS_newudata (lua_State *L, size_t s); Udata *luaS_newudata (lua_State *L, size_t s, Table *e);
TString *luaS_newlstr (lua_State *L, const char *str, size_t l); TString *luaS_newlstr (lua_State *L, const char *str, size_t l);

View File

@@ -1,5 +1,5 @@
/* /*
** $Id: ltests.c,v 2.17 2005/01/14 14:19:42 roberto Exp $ ** $Id: ltests.c,v 2.19 2005/01/19 15:54:26 roberto Exp roberto $
** Internal Module for Debugging of the Lua Implementation ** Internal Module for Debugging of the Lua Implementation
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@@ -249,6 +249,7 @@ static void checkproto (global_State *g, Proto *f) {
static void checkclosure (global_State *g, Closure *cl) { static void checkclosure (global_State *g, Closure *cl) {
GCObject *clgc = obj2gco(cl); GCObject *clgc = obj2gco(cl);
checkobjref(g, clgc, cl->l.env);
if (cl->c.isC) { if (cl->c.isC) {
int i; int i;
for (i=0; i<cl->c.nupvalues; i++) for (i=0; i<cl->c.nupvalues; i++)
@@ -257,7 +258,6 @@ static void checkclosure (global_State *g, Closure *cl) {
else { else {
int i; int i;
lua_assert(cl->l.nupvalues == cl->l.p->nups); lua_assert(cl->l.nupvalues == cl->l.p->nups);
checkobjref(g, clgc, hvalue(&cl->l.g));
checkobjref(g, clgc, cl->l.p); checkobjref(g, clgc, cl->l.p);
for (i=0; i<cl->l.nupvalues; i++) { for (i=0; i<cl->l.nupvalues; i++) {
if (cl->l.upvals[i]) { if (cl->l.upvals[i]) {
@@ -622,20 +622,6 @@ static int unref (lua_State *L) {
return 0; return 0;
} }
static int metatable (lua_State *L) {
luaL_checkany(L, 1);
if (lua_isnone(L, 2)) {
if (lua_getmetatable(L, 1) == 0)
lua_pushnil(L);
}
else {
lua_settop(L, 2);
luaL_checktype(L, 2, LUA_TTABLE);
lua_setmetatable(L, 1);
}
return 1;
}
static int upvalue (lua_State *L) { static int upvalue (lua_State *L) {
int n = luaL_checkint(L, 2); int n = luaL_checkint(L, 2);
@@ -814,10 +800,22 @@ static const char *getname_aux (char *buff, const char **pc) {
} }
static int getindex_aux (lua_State *L, const char **pc) {
skip(pc);
switch (*(*pc)++) {
case 'R': return LUA_REGISTRYINDEX;
case 'G': return LUA_GLOBALSINDEX;
case 'E': return LUA_ENVIRONINDEX;
case 'U': return lua_upvalueindex(getnum_aux(L, pc));
default: (*pc)--; return getnum_aux(L, pc);
}
}
#define EQ(s1) (strcmp(s1, inst) == 0) #define EQ(s1) (strcmp(s1, inst) == 0)
#define getnum (getnum_aux(L, &pc)) #define getnum (getnum_aux(L, &pc))
#define getname (getname_aux(buff, &pc)) #define getname (getname_aux(buff, &pc))
#define getindex (getindex_aux(L, &pc))
static int testC (lua_State *L) { static int testC (lua_State *L) {
@@ -836,44 +834,44 @@ static int testC (lua_State *L) {
const char *inst = getname; const char *inst = getname;
if EQ("") return 0; if EQ("") return 0;
else if EQ("isnumber") { else if EQ("isnumber") {
lua_pushinteger(L1, lua_isnumber(L1, getnum)); lua_pushinteger(L1, lua_isnumber(L1, getindex));
} }
else if EQ("isstring") { else if EQ("isstring") {
lua_pushinteger(L1, lua_isstring(L1, getnum)); lua_pushinteger(L1, lua_isstring(L1, getindex));
} }
else if EQ("istable") { else if EQ("istable") {
lua_pushinteger(L1, lua_istable(L1, getnum)); lua_pushinteger(L1, lua_istable(L1, getindex));
} }
else if EQ("iscfunction") { else if EQ("iscfunction") {
lua_pushinteger(L1, lua_iscfunction(L1, getnum)); lua_pushinteger(L1, lua_iscfunction(L1, getindex));
} }
else if EQ("isfunction") { else if EQ("isfunction") {
lua_pushinteger(L1, lua_isfunction(L1, getnum)); lua_pushinteger(L1, lua_isfunction(L1, getindex));
} }
else if EQ("isuserdata") { else if EQ("isuserdata") {
lua_pushinteger(L1, lua_isuserdata(L1, getnum)); lua_pushinteger(L1, lua_isuserdata(L1, getindex));
} }
else if EQ("isudataval") { else if EQ("isudataval") {
lua_pushinteger(L1, lua_islightuserdata(L1, getnum)); lua_pushinteger(L1, lua_islightuserdata(L1, getindex));
} }
else if EQ("isnil") { else if EQ("isnil") {
lua_pushinteger(L1, lua_isnil(L1, getnum)); lua_pushinteger(L1, lua_isnil(L1, getindex));
} }
else if EQ("isnull") { else if EQ("isnull") {
lua_pushinteger(L1, lua_isnone(L1, getnum)); lua_pushinteger(L1, lua_isnone(L1, getindex));
} }
else if EQ("tonumber") { else if EQ("tonumber") {
lua_pushnumber(L1, lua_tonumber(L1, getnum)); lua_pushnumber(L1, lua_tonumber(L1, getindex));
} }
else if EQ("tostring") { else if EQ("tostring") {
const char *s = lua_tostring(L1, getnum); const char *s = lua_tostring(L1, getindex);
lua_pushstring(L1, s); lua_pushstring(L1, s);
} }
else if EQ("objsize") { else if EQ("objsize") {
lua_pushinteger(L1, lua_objsize(L1, getnum)); lua_pushinteger(L1, lua_objsize(L1, getindex));
} }
else if EQ("tocfunction") { else if EQ("tocfunction") {
lua_pushcfunction(L1, lua_tocfunction(L1, getnum)); lua_pushcfunction(L1, lua_tocfunction(L1, getindex));
} }
else if EQ("return") { else if EQ("return") {
return getnum; return getnum;
@@ -899,11 +897,14 @@ static int testC (lua_State *L) {
else if EQ("pushbool") { else if EQ("pushbool") {
lua_pushboolean(L1, getnum); lua_pushboolean(L1, getnum);
} }
else if EQ("newuserdata") {
lua_newuserdata(L1, getnum);
}
else if EQ("tobool") { else if EQ("tobool") {
lua_pushinteger(L1, lua_toboolean(L1, getnum)); lua_pushinteger(L1, lua_toboolean(L1, getindex));
} }
else if EQ("pushvalue") { else if EQ("pushvalue") {
lua_pushvalue(L1, getnum); lua_pushvalue(L1, getindex);
} }
else if EQ("pushcclosure") { else if EQ("pushcclosure") {
lua_pushcclosure(L1, testC, getnum); lua_pushcclosure(L1, testC, getnum);
@@ -915,13 +916,13 @@ static int testC (lua_State *L) {
lua_insert(L1, getnum); lua_insert(L1, getnum);
} }
else if EQ("replace") { else if EQ("replace") {
lua_replace(L1, getnum); lua_replace(L1, getindex);
} }
else if EQ("gettable") { else if EQ("gettable") {
lua_gettable(L1, getnum); lua_gettable(L1, getindex);
} }
else if EQ("settable") { else if EQ("settable") {
lua_settable(L1, getnum); lua_settable(L1, getindex);
} }
else if EQ("next") { else if EQ("next") {
lua_next(L1, -2); lua_next(L1, -2);
@@ -930,12 +931,12 @@ static int testC (lua_State *L) {
lua_concat(L1, getnum); lua_concat(L1, getnum);
} }
else if EQ("lessthan") { else if EQ("lessthan") {
int a = getnum; int a = getindex;
lua_pushboolean(L1, lua_lessthan(L1, a, getnum)); lua_pushboolean(L1, lua_lessthan(L1, a, getindex));
} }
else if EQ("equal") { else if EQ("equal") {
int a = getnum; int a = getindex;
lua_pushboolean(L1, lua_equal(L1, a, getnum)); lua_pushboolean(L1, lua_equal(L1, a, getindex));
} }
else if EQ("rawcall") { else if EQ("rawcall") {
int narg = getnum; int narg = getnum;
@@ -956,21 +957,21 @@ static int testC (lua_State *L) {
luaL_loadfile(L1, luaL_checkstring(L1, getnum)); luaL_loadfile(L1, luaL_checkstring(L1, getnum));
} }
else if EQ("setmetatable") { else if EQ("setmetatable") {
lua_setmetatable(L1, getnum); lua_setmetatable(L1, getindex);
} }
else if EQ("getmetatable") { else if EQ("getmetatable") {
if (lua_getmetatable(L1, getnum) == 0) if (lua_getmetatable(L1, getindex) == 0)
lua_pushnil(L1); lua_pushnil(L1);
} }
else if EQ("type") { else if EQ("type") {
lua_pushstring(L1, luaL_typename(L1, getnum)); lua_pushstring(L1, luaL_typename(L1, getnum));
} }
else if EQ("getn") { else if EQ("getn") {
int i = getnum; int i = getindex;
lua_pushinteger(L1, luaL_getn(L1, i)); lua_pushinteger(L1, luaL_getn(L1, i));
} }
else if EQ("setn") { else if EQ("setn") {
int i = getnum; int i = getindex;
int n = cast(int, lua_tonumber(L1, -1)); int n = cast(int, lua_tonumber(L1, -1));
luaL_setn(L1, i, n); luaL_setn(L1, i, n);
lua_pop(L1, 1); lua_pop(L1, 1);
@@ -1095,7 +1096,6 @@ static const struct luaL_reg tests_funcs[] = {
{"unref", unref}, {"unref", unref},
{"d2s", d2s}, {"d2s", d2s},
{"s2d", s2d}, {"s2d", s2d},
{"metatable", metatable},
{"upvalue", upvalue}, {"upvalue", upvalue},
{"newuserdata", newuserdata}, {"newuserdata", newuserdata},
{"pushuserdata", pushuserdata}, {"pushuserdata", pushuserdata},

5
lua.h
View File

@@ -1,5 +1,5 @@
/* /*
** $Id: lua.h,v 1.200 2005/01/14 14:19:42 roberto Exp roberto $ ** $Id: lua.h,v 1.201 2005/01/17 23:50:55 roberto Exp roberto $
** Lua - An Extensible Extension Language ** Lua - An Extensible Extension Language
** Tecgraf: Computer Graphics Technology Group, PUC-Rio, Brazil ** Tecgraf: Computer Graphics Technology Group, PUC-Rio, Brazil
** http://www.lua.org mailto:info@lua.org ** http://www.lua.org mailto:info@lua.org
@@ -34,7 +34,8 @@
** pseudo-indices ** pseudo-indices
*/ */
#define LUA_REGISTRYINDEX (-10000) #define LUA_REGISTRYINDEX (-10000)
#define LUA_GLOBALSINDEX (-10001) #define LUA_ENVIRONINDEX (-10001)
#define LUA_GLOBALSINDEX (-10002)
#define lua_upvalueindex(i) (LUA_GLOBALSINDEX-(i)) #define lua_upvalueindex(i) (LUA_GLOBALSINDEX-(i))

16
lvm.c
View File

@@ -1,5 +1,5 @@
/* /*
** $Id: lvm.c,v 2.22 2005/01/10 18:17:39 roberto Exp roberto $ ** $Id: lvm.c,v 2.23 2005/01/10 18:33:37 roberto Exp roberto $
** Lua virtual machine ** Lua virtual machine
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@@ -428,9 +428,11 @@ StkId luaV_execute (lua_State *L, int nexeccalls) {
continue; continue;
} }
case OP_GETGLOBAL: { case OP_GETGLOBAL: {
TValue g;
TValue *rb = KBx(i); TValue *rb = KBx(i);
lua_assert(ttisstring(rb) && ttistable(&cl->g)); sethvalue(L, &g, cl->env);
base = luaV_gettable(L, &cl->g, rb, ra, pc); /***/ lua_assert(ttisstring(rb));
base = luaV_gettable(L, &g, rb, ra, pc); /***/
continue; continue;
} }
case OP_GETTABLE: { case OP_GETTABLE: {
@@ -438,8 +440,10 @@ StkId luaV_execute (lua_State *L, int nexeccalls) {
continue; continue;
} }
case OP_SETGLOBAL: { case OP_SETGLOBAL: {
lua_assert(ttisstring(KBx(i)) && ttistable(&cl->g)); TValue g;
base = luaV_settable(L, &cl->g, KBx(i), ra, pc); /***/ sethvalue(L, &g, cl->env);
lua_assert(ttisstring(KBx(i)));
base = luaV_settable(L, &g, KBx(i), ra, pc); /***/
continue; continue;
} }
case OP_SETUPVAL: { case OP_SETUPVAL: {
@@ -740,7 +744,7 @@ StkId luaV_execute (lua_State *L, int nexeccalls) {
int nup, j; int nup, j;
p = cl->p->p[GETARG_Bx(i)]; p = cl->p->p[GETARG_Bx(i)];
nup = p->nups; nup = p->nups;
ncl = luaF_newLclosure(L, nup, &cl->g); ncl = luaF_newLclosure(L, nup, cl->env);
ncl->l.p = p; ncl->l.p = p;
for (j=0; j<nup; j++, pc++) { for (j=0; j<nup; j++, pc++) {
if (GET_OPCODE(*pc) == OP_GETUPVAL) if (GET_OPCODE(*pc) == OP_GETUPVAL)