Browse Source

C functions and userdata also have environments

Roberto Ierusalimschy 20 năm trước cách đây
mục cha
commit
7d45a5f48f
17 tập tin đã thay đổi với 206 bổ sung111 xóa
  1. 53 13
      lapi.c
  2. 7 4
      lbaselib.c
  3. 39 1
      ldblib.c
  4. 2 2
      ldo.c
  5. 5 4
      lfunc.c
  6. 3 3
      lfunc.h
  7. 3 2
      lgc.c
  8. 3 1
      linit.c
  9. 17 17
      liolib.c
  10. 7 5
      loadlib.c
  11. 4 3
      lobject.h
  12. 2 1
      lstate.h
  13. 3 2
      lstring.c
  14. 2 2
      lstring.h
  15. 43 43
      ltests.c
  16. 3 2
      lua.h
  17. 10 6
      lvm.c

+ 53 - 13
lapi.c

@@ -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
 ** See Copyright Notice in lua.h
 */
@@ -58,6 +58,11 @@ static TValue *index2adr (lua_State *L, int 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: {
       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) {
   setobj2s(L, L->top, o);
   incr_top(L);
@@ -186,9 +201,17 @@ LUA_API void lua_replace (lua_State *L, int idx) {
   api_checknelems(L, 1);
   o = index2adr(L, idx);
   api_checkvalidindex(L, o);
-  setobj(L, o, L->top - 1);
-  if (idx < LUA_GLOBALSINDEX)  /* function upvalue? */
-    luaC_barrier(L, curr_func(L), L->top - 1);
+  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);
 }
@@ -452,7 +475,7 @@ 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--)
@@ -579,7 +602,17 @@ LUA_API void lua_getfenv (lua_State *L, int idx) {
   lua_lock(L);
   o = index2adr(L, idx);
   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);
   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) {
   StkId o;
-  int res = 0;
+  int res = 1;
   lua_lock(L);
   api_checknelems(L, 1);
   o = index2adr(L, idx);
   api_checkvalidindex(L, o);
   api_check(L, ttistable(L->top - 1));
-  if (isLfunction(o)) {
-    res = 1;
-    clvalue(o)->l.g = *(L->top - 1);
-    luaC_objbarrier(L, clvalue(o), hvalue(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;
+    default:
+      res = 0;
+      break;
   }
+  luaC_objbarrier(L, gcvalue(o), hvalue(L->top - 1));
   L->top--;
   lua_unlock(L);
   return res;
@@ -776,7 +816,7 @@ 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, L->top, cl);  /* push function */
   incr_top(L);
@@ -943,7 +983,7 @@ LUA_API void *lua_newuserdata (lua_State *L, size_t size) {
   Udata *u;
   lua_lock(L);
   luaC_checkGC(L);
-  u = luaS_newudata(L, size);
+  u = luaS_newudata(L, size, getcurrenv(L));
   setuvalue(L, L->top, u);
   api_incr_top(L);
   lua_unlock(L);

+ 7 - 4
lbaselib.c

@@ -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
 ** See Copyright Notice in lua.h
 */
@@ -131,7 +131,10 @@ static void getfunc (lua_State *L) {
 
 static int luaB_getfenv (lua_State *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;
 }
 
@@ -144,8 +147,8 @@ static int luaB_setfenv (lua_State *L) {
     lua_replace(L, LUA_GLOBALSINDEX);
     return 0;
   }
-  else if (lua_setfenv(L, -2) == 0)
-    luaL_error(L, "`setfenv' cannot change environment of given function");
+  else if (lua_iscfunction(L, -2) || lua_setfenv(L, -2) == 0)
+    luaL_error(L, "`setfenv' cannot change environment of given object");
   return 1;
 }
 

+ 39 - 1
ldblib.c

@@ -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
 ** 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) {
   lua_pushstring(L, v);
   lua_setfield(L, -2, i);
@@ -328,6 +362,10 @@ static int errorfb (lua_State *L) {
 
 
 static const luaL_reg dblib[] = {
+  {"getmetatable", getmetatable},
+  {"setmetatable", setmetatable},
+  {"getfenv", getfenv},
+  {"setfenv", setfenv},
   {"getlocal", getlocal},
   {"getinfo", getinfo},
   {"gethook", gethook},

+ 2 - 2
ldo.c

@@ -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
 ** See Copyright Notice in lua.h
 */
@@ -474,7 +474,7 @@ static void f_parser (lua_State *L, void *ud) {
   luaC_checkGC(L);
   tf = ((c == LUA_SIGNATURE[0]) ? luaU_undump : luaY_parser)(L, p->z,
                                                              &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;
   for (i = 0; i < tf->nups; i++)  /* initialize eventual upvalues */
     cl->l.upvals[i] = luaF_newupval(L);

+ 5 - 4
lfunc.c

@@ -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
 ** 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)));
   luaC_link(L, obj2gco(c), LUA_TFUNCTION);
   c->c.isC = 1;
+  c->c.env = e;
   c->c.nupvalues = cast(lu_byte, nelems);
   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)));
   luaC_link(L, obj2gco(c), LUA_TFUNCTION);
   c->l.isC = 0;
-  c->l.g = *e;
+  c->l.env = e;
   c->l.nupvalues = cast(lu_byte, nelems);
   while (nelems--) c->l.upvals[nelems] = NULL;
   return c;

+ 3 - 3
lfunc.h

@@ -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
 ** See Copyright Notice in lua.h
 */
@@ -19,8 +19,8 @@
 
 
 Proto *luaF_newproto (lua_State *L);
-Closure *luaF_newCclosure (lua_State *L, int nelems);
-Closure *luaF_newLclosure (lua_State *L, int nelems, TValue *e);
+Closure *luaF_newCclosure (lua_State *L, int nelems, Table *e);
+Closure *luaF_newLclosure (lua_State *L, int nelems, Table *e);
 UpVal *luaF_newupval (lua_State *L);
 UpVal *luaF_findupval (lua_State *L, StkId level);
 void luaF_close (lua_State *L, StkId level);

+ 3 - 2
lgc.c

@@ -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
 ** See Copyright Notice in lua.h
 */
@@ -79,6 +79,7 @@ static void reallymarkobject (global_State *g, GCObject *o) {
       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: {
@@ -223,6 +224,7 @@ static void traverseproto (global_State *g, Proto *f) {
 
 
 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 */
@@ -231,7 +233,6 @@ static void traverseclosure (global_State *g, Closure *cl) {
   else {
     int i;
     lua_assert(cl->l.nupvalues == cl->l.p->nups);
-    markobject(g, hvalue(&cl->l.g));
     markobject(g, cl->l.p);
     for (i=0; i<cl->l.nupvalues; i++)  /* mark its upvalues */
       markobject(g, cl->l.upvals[i]);

+ 3 - 1
linit.c

@@ -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
 ** See Copyright Notice in lua.h
 */
@@ -32,6 +32,8 @@ LUALIB_API int luaopen_stdlibs (lua_State *L) {
   for (; lib->func; lib++) {
     lib->func(L);  /* open library */
     lua_settop(L, 0);  /* discard any results */
+    lua_pushvalue(L, LUA_GLOBALSINDEX);
+    lua_replace(L, LUA_ENVIRONINDEX);  /* restore environment */
   }
  return 0;
 }

+ 17 - 17
liolib.c

@@ -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
 ** See Copyright Notice in lua.h
 */
@@ -105,8 +105,8 @@ static int aux_close (lua_State *L) {
 
 
 static int io_close (lua_State *L) {
-  if (lua_isnone(L, 1) && lua_type(L, lua_upvalueindex(1)) == LUA_TTABLE)
-    lua_rawgeti(L, lua_upvalueindex(1), IO_OUTPUT);
+  if (lua_isnone(L, 1))
+    lua_rawgeti(L, LUA_ENVIRONINDEX, IO_OUTPUT);
   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) {
   FILE *f;
-  lua_rawgeti(L, lua_upvalueindex(1), findex);
+  lua_rawgeti(L, LUA_ENVIRONINDEX, findex);
   lua_assert(luaL_checkudata(L, -1, LUA_FILEHANDLE));
   f = *(FILE **)lua_touserdata(L, -1);
   if (f == NULL)
@@ -170,10 +170,10 @@ static int g_iofile (lua_State *L, int f, const char *mode) {
       lua_pushvalue(L, 1);
     }
     lua_assert(luaL_checkudata(L, -1, LUA_FILEHANDLE));
-    lua_rawseti(L, lua_upvalueindex(1), f);
+    lua_rawseti(L, LUA_ENVIRONINDEX, f);
   }
   /* return current value */
-  lua_rawgeti(L, lua_upvalueindex(1), f);
+  lua_rawgeti(L, LUA_ENVIRONINDEX, f);
   return 1;
 }
 
@@ -192,10 +192,9 @@ static int io_readline (lua_State *L);
 
 
 static void aux_lines (lua_State *L, int idx, int close) {
-  lua_getfield(L, LUA_REGISTRYINDEX, LUA_FILEHANDLE);
   lua_pushvalue(L, idx);
   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) {
   if (lua_isnoneornil(L, 1)) {  /* no arguments? */
     /* will iterate over default input */
-    lua_rawgeti(L, lua_upvalueindex(1), IO_INPUT);
+    lua_rawgeti(L, LUA_ENVIRONINDEX, IO_INPUT);
     return f_lines(L);
   }
   else {
@@ -349,7 +348,7 @@ static int f_read (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;
   if (f == NULL)  /* 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));
   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;
@@ -489,12 +488,13 @@ LUALIB_API int luaopen_io (lua_State *L) {
   createmeta(L);
   createupval(L);
   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 */
-  lua_rawgeti(L, -2, IO_INPUT);  /* get current input from metatable */
-  lua_setfield(L, -2, "stdin");  /* io.stdin = metatable[IO_INPUT] */
-  lua_rawgeti(L, -2, IO_OUTPUT);  /* get current output from metatable */
-  lua_setfield(L, -2, "stdout");  /* io.stdout = metatable[IO_OUTPUT] */
+  lua_rawgeti(L, -2, IO_INPUT);  /* get current input from upval */
+  lua_setfield(L, -2, "stdin");  /* io.stdin = upval[IO_INPUT] */
+  lua_rawgeti(L, -2, IO_OUTPUT);  /* get current output from upval */
+  lua_setfield(L, -2, "stdout");  /* io.stdout = upval[IO_OUTPUT] */
   *newfile(L) = stderr;
   lua_setfield(L, -2, "stderr");  /* io.stderr = newfile(stderr) */
   return 1;

+ 7 - 5
loadlib.c

@@ -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
 ** See Copyright Notice in lua.h
 *
@@ -302,7 +302,7 @@ static int loader_Lua (lua_State *L) {
   path = lua_tostring(L, -1);
   if (!path) {
     lua_pop(L, 1);
-    luaL_getfield(L, LUA_REGISTRYINDEX, "_PACKAGE.path");
+    lua_getfield(L, LUA_ENVIRONINDEX, "path");
     path = lua_tostring(L, -1);
   }
   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 *path;
   const char *funcname;
-  luaL_getfield(L, LUA_REGISTRYINDEX, "_PACKAGE.cpath");
+  lua_getfield(L, LUA_ENVIRONINDEX, "cpath");
   path = lua_tostring(L, -1);
   if (path == NULL)
     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) {
-  luaL_getfield(L, LUA_REGISTRYINDEX, "_PACKAGE.preload");
+  lua_getfield(L, LUA_ENVIRONINDEX, "preload");
   if (!lua_istable(L, -1))
     luaL_error(L, "`package.preload' must be a table");
   lua_getfield(L, -1, luaL_checkstring(L, 1));
@@ -355,7 +355,7 @@ static int ll_require (lua_State *L) {
   lua_pushboolean(L, 1);
   lua_setfield(L, 2, name);  /* _LOADED[name] = true */
   /* iterate over available loaders */
-  luaL_getfield(L, LUA_REGISTRYINDEX, "_PACKAGE.loaders");
+  lua_getfield(L, LUA_ENVIRONINDEX, "loaders");
   if (!lua_istable(L, -1))
     luaL_error(L, "`package.loaders' must be a table");
   for (i=1;; i++) {
@@ -457,6 +457,8 @@ LUALIB_API int luaopen_loadlib (lua_State *L) {
   lua_setglobal(L, "package");
   lua_pushvalue(L, -1);
   lua_setfield(L, LUA_REGISTRYINDEX, "_PACKAGE");
+  lua_pushvalue(L, -1);
+  lua_replace(L, LUA_ENVIRONINDEX);
   /* create `loaders' table */
   lua_newtable(L);
   /* fill it with pre-defined loaders */

+ 4 - 3
lobject.h

@@ -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
 ** See Copyright Notice in lua.h
 */
@@ -218,6 +218,7 @@ typedef union Udata {
   struct {
     CommonHeader;
     struct Table *metatable;
+    struct Table *env;
     size_t len;
   } uv;
 } Udata;
@@ -286,7 +287,8 @@ typedef struct UpVal {
 */
 
 #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 {
   ClosureHeader;
@@ -298,7 +300,6 @@ typedef struct CClosure {
 typedef struct LClosure {
   ClosureHeader;
   struct Proto *p;
-  TValue g;  /* global table for this closure */
   UpVal *upvals[1];
 } LClosure;
 

+ 2 - 1
lstate.h

@@ -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
 ** See Copyright Notice in lua.h
 */
@@ -116,6 +116,7 @@ struct lua_State {
   int hookcount;
   lua_Hook hook;
   TValue _gt;  /* table of globals */
+  TValue env;  /* temporary place for environments */
   GCObject *openupval;  /* list of open upvalues in this stack */
   GCObject *gclist;
   struct lua_longjmp *errorJmp;  /* current error recover point */

+ 3 - 2
lstring.c

@@ -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)
 ** 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;
   if (s > MAX_SIZET - sizeof(Udata))
     luaM_toobig(L);
@@ -102,6 +102,7 @@ Udata *luaS_newudata (lua_State *L, size_t s) {
   u->uv.tt = LUA_TUSERDATA;
   u->uv.len = s;
   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);

+ 2 - 2
lstring.h

@@ -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)
 ** See Copyright Notice in lua.h
 */
@@ -24,7 +24,7 @@
 #define luaS_fix(s)	setbit((s)->tsv.marked, FIXEDBIT)
 
 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);
 
 

+ 43 - 43
ltests.c

@@ -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
 ** 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) {
   GCObject *clgc = obj2gco(cl);
+  checkobjref(g, clgc, cl->l.env);
   if (cl->c.isC) {
     int i;
     for (i=0; i<cl->c.nupvalues; i++)
@@ -257,7 +258,6 @@ static void checkclosure (global_State *g, Closure *cl) {
   else {
     int i;
     lua_assert(cl->l.nupvalues == cl->l.p->nups);
-    checkobjref(g, clgc, hvalue(&cl->l.g));
     checkobjref(g, clgc, cl->l.p);
     for (i=0; i<cl->l.nupvalues; i++) {
       if (cl->l.upvals[i]) {
@@ -622,20 +622,6 @@ static int unref (lua_State *L) {
   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) {
   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 getnum	(getnum_aux(L, &pc))
 #define getname	(getname_aux(buff, &pc))
+#define getindex (getindex_aux(L, &pc))
 
 
 static int testC (lua_State *L) {
@@ -836,44 +834,44 @@ static int testC (lua_State *L) {
     const char *inst = getname;
     if EQ("") return 0;
     else if EQ("isnumber") {
-      lua_pushinteger(L1, lua_isnumber(L1, getnum));
+      lua_pushinteger(L1, lua_isnumber(L1, getindex));
     }
     else if EQ("isstring") {
-      lua_pushinteger(L1, lua_isstring(L1, getnum));
+      lua_pushinteger(L1, lua_isstring(L1, getindex));
     }
     else if EQ("istable") {
-      lua_pushinteger(L1, lua_istable(L1, getnum));
+      lua_pushinteger(L1, lua_istable(L1, getindex));
     }
     else if EQ("iscfunction") {
-      lua_pushinteger(L1, lua_iscfunction(L1, getnum));
+      lua_pushinteger(L1, lua_iscfunction(L1, getindex));
     }
     else if EQ("isfunction") {
-      lua_pushinteger(L1, lua_isfunction(L1, getnum));
+      lua_pushinteger(L1, lua_isfunction(L1, getindex));
     }
     else if EQ("isuserdata") {
-      lua_pushinteger(L1, lua_isuserdata(L1, getnum));
+      lua_pushinteger(L1, lua_isuserdata(L1, getindex));
     }
     else if EQ("isudataval") {
-      lua_pushinteger(L1, lua_islightuserdata(L1, getnum));
+      lua_pushinteger(L1, lua_islightuserdata(L1, getindex));
     }
     else if EQ("isnil") {
-      lua_pushinteger(L1, lua_isnil(L1, getnum));
+      lua_pushinteger(L1, lua_isnil(L1, getindex));
     }
     else if EQ("isnull") {
-      lua_pushinteger(L1, lua_isnone(L1, getnum));
+      lua_pushinteger(L1, lua_isnone(L1, getindex));
     }
     else if EQ("tonumber") {
-      lua_pushnumber(L1, lua_tonumber(L1, getnum));
+      lua_pushnumber(L1, lua_tonumber(L1, getindex));
     }
     else if EQ("tostring") {
-      const char *s = lua_tostring(L1, getnum);
+      const char *s = lua_tostring(L1, getindex);
       lua_pushstring(L1, s);
     }
     else if EQ("objsize") {
-      lua_pushinteger(L1, lua_objsize(L1, getnum));
+      lua_pushinteger(L1, lua_objsize(L1, getindex));
     }
     else if EQ("tocfunction") {
-      lua_pushcfunction(L1, lua_tocfunction(L1, getnum));
+      lua_pushcfunction(L1, lua_tocfunction(L1, getindex));
     }
     else if EQ("return") {
       return getnum;
@@ -899,11 +897,14 @@ static int testC (lua_State *L) {
     else if EQ("pushbool") {
       lua_pushboolean(L1, getnum);
     }
+    else if EQ("newuserdata") {
+      lua_newuserdata(L1, getnum);
+    }
     else if EQ("tobool") {
-      lua_pushinteger(L1, lua_toboolean(L1, getnum));
+      lua_pushinteger(L1, lua_toboolean(L1, getindex));
     }
     else if EQ("pushvalue") {
-      lua_pushvalue(L1, getnum);
+      lua_pushvalue(L1, getindex);
     }
     else if EQ("pushcclosure") {
       lua_pushcclosure(L1, testC, getnum);
@@ -915,13 +916,13 @@ static int testC (lua_State *L) {
       lua_insert(L1, getnum);
     }
     else if EQ("replace") {
-      lua_replace(L1, getnum);
+      lua_replace(L1, getindex);
     }
     else if EQ("gettable") {
-      lua_gettable(L1, getnum);
+      lua_gettable(L1, getindex);
     }
     else if EQ("settable") {
-      lua_settable(L1, getnum);
+      lua_settable(L1, getindex);
     }
     else if EQ("next") {
       lua_next(L1, -2);
@@ -930,12 +931,12 @@ static int testC (lua_State *L) {
       lua_concat(L1, getnum);
     }
     else if EQ("lessthan") {
-      int a = getnum;
-      lua_pushboolean(L1, lua_lessthan(L1, a, getnum));
+      int a = getindex;
+      lua_pushboolean(L1, lua_lessthan(L1, a, getindex));
     }
     else if EQ("equal") {
-      int a = getnum;
-      lua_pushboolean(L1, lua_equal(L1, a, getnum));
+      int a = getindex;
+      lua_pushboolean(L1, lua_equal(L1, a, getindex));
     }
     else if EQ("rawcall") {
       int narg = getnum;
@@ -956,21 +957,21 @@ static int testC (lua_State *L) {
       luaL_loadfile(L1, luaL_checkstring(L1, getnum));
     }
     else if EQ("setmetatable") {
-      lua_setmetatable(L1, getnum);
+      lua_setmetatable(L1, getindex);
     }
     else if EQ("getmetatable") {
-      if (lua_getmetatable(L1, getnum) == 0)
+      if (lua_getmetatable(L1, getindex) == 0)
         lua_pushnil(L1);
     }
     else if EQ("type") {
       lua_pushstring(L1, luaL_typename(L1, getnum));
     }
     else if EQ("getn") {
-      int i = getnum;
+      int i = getindex;
       lua_pushinteger(L1, luaL_getn(L1, i));
     }
     else if EQ("setn") {
-      int i = getnum;
+      int i = getindex;
       int n = cast(int, lua_tonumber(L1, -1));
       luaL_setn(L1, i, n);
       lua_pop(L1, 1);
@@ -1095,7 +1096,6 @@ static const struct luaL_reg tests_funcs[] = {
   {"unref", unref},
   {"d2s", d2s},
   {"s2d", s2d},
-  {"metatable", metatable},
   {"upvalue", upvalue},
   {"newuserdata", newuserdata},
   {"pushuserdata", pushuserdata},

+ 3 - 2
lua.h

@@ -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
 ** Tecgraf: Computer Graphics Technology Group, PUC-Rio, Brazil
 ** http://www.lua.org	mailto:[email protected]
@@ -34,7 +34,8 @@
 ** pseudo-indices
 */
 #define LUA_REGISTRYINDEX	(-10000)
-#define LUA_GLOBALSINDEX	(-10001)
+#define LUA_ENVIRONINDEX	(-10001)
+#define LUA_GLOBALSINDEX	(-10002)
 #define lua_upvalueindex(i)	(LUA_GLOBALSINDEX-(i))
 
 

+ 10 - 6
lvm.c

@@ -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
 ** See Copyright Notice in lua.h
 */
@@ -428,9 +428,11 @@ StkId luaV_execute (lua_State *L, int nexeccalls) {
         continue;
       }
       case OP_GETGLOBAL: {
+        TValue g;
         TValue *rb = KBx(i);
-        lua_assert(ttisstring(rb) && ttistable(&cl->g));
-        base = luaV_gettable(L, &cl->g, rb, ra, pc);  /***/
+        sethvalue(L, &g, cl->env);
+        lua_assert(ttisstring(rb));
+        base = luaV_gettable(L, &g, rb, ra, pc);  /***/
         continue;
       }
       case OP_GETTABLE: {
@@ -438,8 +440,10 @@ StkId luaV_execute (lua_State *L, int nexeccalls) {
         continue;
       }
       case OP_SETGLOBAL: {
-        lua_assert(ttisstring(KBx(i)) && ttistable(&cl->g));
-        base = luaV_settable(L, &cl->g, KBx(i), ra, pc);  /***/
+        TValue g;
+        sethvalue(L, &g, cl->env);
+        lua_assert(ttisstring(KBx(i)));
+        base = luaV_settable(L, &g, KBx(i), ra, pc);  /***/
         continue;
       }
       case OP_SETUPVAL: {
@@ -740,7 +744,7 @@ StkId luaV_execute (lua_State *L, int nexeccalls) {
         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)