ソースを参照

avoid using function environments in C libraries (as it probably will
be deprecated)

Roberto Ierusalimschy 15 年 前
コミット
1514e49d43
4 ファイル変更69 行追加51 行削除
  1. 13 8
      lauxlib.c
  2. 11 8
      lauxlib.h
  3. 35 24
      liolib.c
  4. 10 11
      loadlib.c

+ 13 - 8
lauxlib.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lauxlib.c,v 1.201 2010/02/18 19:37:57 roberto Exp roberto $
+** $Id: lauxlib.c,v 1.202 2010/03/12 18:59:32 roberto Exp roberto $
 ** Auxiliary functions for building Lua libraries
 ** See Copyright Notice in lua.h
 */
@@ -670,13 +670,13 @@ LUALIB_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len) {
 
 static int libsize (const luaL_Reg *l) {
   int size = 0;
-  for (; l->name; l++) size++;
+  for (; l && l->name; l++) size++;
   return size;
 }
 
 
-LUALIB_API void luaL_register (lua_State *L, const char *libname,
-                               const luaL_Reg *l) {
+LUALIB_API void luaL_openlib (lua_State *L, const char *libname,
+                               const luaL_Reg *l, int nup) {
   luaL_checkversion(L);
   if (libname) {
     /* check whether lib already exists */
@@ -692,12 +692,17 @@ LUALIB_API void luaL_register (lua_State *L, const char *libname,
       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 */
   }
-  if (l == NULL) return;  /* nothing to register? */
-  for (; l->name; l++) {  /* else fill the table with given functions */
-    lua_pushcfunction(L, l->func);
-    lua_setfield(L, -2, l->name);
+  luaL_checkstack(L, nup, "too many upvalues");
+  for (; l && l->name; l++) {  /* else fill the table with given functions */
+    int i;
+    for (i = 0; i < nup; i++)  /* copy upvalues to the top */
+      lua_pushvalue(L, -nup);
+    lua_pushcclosure(L, l->func, nup);
+    lua_setfield(L, -(nup + 2), l->name);
   }
+  lua_pop(L, nup);  /* remove upvalues */
 }
 
 

+ 11 - 8
lauxlib.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lauxlib.h,v 1.99 2010/01/11 16:00:45 roberto Exp roberto $
+** $Id: lauxlib.h,v 1.100 2010/01/21 16:49:21 roberto Exp roberto $
 ** Auxiliary functions for building Lua libraries
 ** See Copyright Notice in lua.h
 */
@@ -29,8 +29,8 @@ typedef struct luaL_Reg {
 LUALIB_API void (luaL_checkversion_) (lua_State *L, lua_Number ver);
 #define luaL_checkversion(L)	luaL_checkversion_(L, LUA_VERSION_NUM)
 
-LUALIB_API void (luaL_register) (lua_State *L, const char *libname,
-                                const luaL_Reg *l);
+LUALIB_API void (luaL_openlib) (lua_State *L, const char *libname,
+                                const luaL_Reg *l, int nup);
 LUALIB_API int (luaL_getmetafield) (lua_State *L, int obj, const char *e);
 LUALIB_API int (luaL_callmeta) (lua_State *L, int obj, const char *e);
 LUALIB_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len);
@@ -71,7 +71,7 @@ LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s);
 
 LUALIB_API lua_State *(luaL_newstate) (void);
 
-LUALIB_API int luaL_len (lua_State *L, int idx);
+LUALIB_API int (luaL_len) (lua_State *L, int idx);
 
 LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s, const char *p,
                                                   const char *r);
@@ -79,11 +79,11 @@ LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s, const char *p,
 LUALIB_API const char *(luaL_findtable) (lua_State *L, int idx,
                                          const char *fname, int szhint);
 
-LUALIB_API void luaL_traceback (lua_State *L, lua_State *L1,
-                                const char *msg, int level);
+LUALIB_API void (luaL_traceback) (lua_State *L, lua_State *L1,
+                                  const char *msg, int level);
 
-LUALIB_API int luaL_cpcall (lua_State *L, lua_CFunction f, int nargs,
-                            int nresults);
+LUALIB_API int (luaL_cpcall) (lua_State *L, lua_CFunction f, int nargs,
+                              int nresults);
 
 
 /*
@@ -113,6 +113,9 @@ LUALIB_API int luaL_cpcall (lua_State *L, lua_CFunction f, int nargs,
 
 #define luaL_opt(L,f,n,d)	(lua_isnoneornil(L,(n)) ? (d) : f(L,(n)))
 
+#define luaL_register(L,n,l)	(luaL_openlib(L,(n),(l),0))
+
+
 /*
 ** {======================================================
 ** Generic Buffer manipulation

+ 35 - 24
liolib.c

@@ -1,5 +1,5 @@
 /*
-** $Id: liolib.c,v 2.85 2009/12/17 16:20:01 roberto Exp roberto $
+** $Id: liolib.c,v 2.86 2010/03/03 18:48:57 roberto Exp roberto $
 ** Standard I/O (and system) library
 ** See Copyright Notice in lua.h
 */
@@ -103,13 +103,12 @@ static FILE *tofile (lua_State *L) {
 }
 
 
-
 /*
 ** 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 FILE **newfile (lua_State *L) {
+static FILE **newprefile (lua_State *L) {
   FILE **pf = (FILE **)lua_newuserdata(L, sizeof(FILE *));
   *pf = NULL;  /* file handle is currently `closed' */
   luaL_getmetatable(L, LUA_FILEHANDLE);
@@ -118,6 +117,14 @@ static FILE **newfile (lua_State *L) {
 }
 
 
+static FILE **newfile (lua_State *L) {
+  FILE **pf = newprefile(L);
+  lua_pushvalue(L, lua_upvalueindex(1));  /* set upvalue... */
+  lua_setfenv(L, -2);  /* ... as environment for new file */
+  return pf;
+}
+
+
 /*
 ** function to (not) close the standard files stdin, stdout, and stderr
 */
@@ -164,7 +171,7 @@ static int aux_close (lua_State *L) {
 
 static int io_close (lua_State *L) {
   if (lua_isnone(L, 1))
-    lua_rawgeti(L, LUA_ENVIRONINDEX, IO_OUTPUT);
+    lua_rawgeti(L, lua_upvalueindex(1), IO_OUTPUT);
   tofile(L);  /* make sure argument is a file */
   return aux_close(L);
 }
@@ -229,7 +236,7 @@ static int io_tmpfile (lua_State *L) {
 
 static FILE *getiofile (lua_State *L, int findex) {
   FILE *f;
-  lua_rawgeti(L, LUA_ENVIRONINDEX, findex);
+  lua_rawgeti(L, lua_upvalueindex(1), findex);
   f = *(FILE **)lua_touserdata(L, -1);
   if (f == NULL)
     luaL_error(L, "standard %s file is closed", fnames[findex - 1]);
@@ -250,10 +257,10 @@ static int g_iofile (lua_State *L, int f, const char *mode) {
       tofile(L);  /* check that it's a valid file handle */
       lua_pushvalue(L, 1);
     }
-    lua_rawseti(L, LUA_ENVIRONINDEX, f);
+    lua_rawseti(L, lua_upvalueindex(1), f);
   }
   /* return current value */
-  lua_rawgeti(L, LUA_ENVIRONINDEX, f);
+  lua_rawgeti(L, lua_upvalueindex(1), f);
   return 1;
 }
 
@@ -295,7 +302,7 @@ static int io_lines (lua_State *L) {
   int toclose;
   if (lua_isnone(L, 1)) lua_pushnil(L);  /* at least one argument */
   if (lua_isnil(L, 1)) {  /* no file name? */
-    lua_rawgeti(L, LUA_ENVIRONINDEX, IO_INPUT);  /* get default input */
+    lua_rawgeti(L, lua_upvalueindex(1), IO_INPUT);  /* get default input */
     lua_replace(L, 1);   /* put it at index 1 */
     tofile(L);  /* check that it's a valid file handle */
     toclose = 0;  /* do not close it after iteration */
@@ -576,23 +583,27 @@ static void createmeta (lua_State *L) {
   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 */
+  luaL_register(L, NULL, flib);  /* add file methods to new metatable */
+  lua_pop(L, 1);  /* pop new metatable */
 }
 
 
 static void createstdfile (lua_State *L, FILE *f, int k, const char *fname) {
-  *newfile(L) = f;
+  *newprefile(L) = f;
   if (k > 0) {
-    lua_pushvalue(L, -1);
-    lua_rawseti(L, LUA_ENVIRONINDEX, k);
+    lua_pushvalue(L, -1);  /* copy new file */
+    lua_rawseti(L, 1, k);  /* add it to common upvalue */
   }
-  lua_pushvalue(L, -2);  /* copy environment */
-  lua_setfenv(L, -2);  /* set it */
-  lua_setfield(L, -3, fname);
+  lua_pushvalue(L, 3);  /* get environment for default files */
+  lua_setfenv(L, -2);  /* set it as environment for file */
+  lua_setfield(L, 2, fname);  /* add file to module */
 }
 
 
-static void newfenv (lua_State *L, lua_CFunction cls) {
+/*
+** pushes a new table with {__close = cls}
+*/
+static void newenv (lua_State *L, lua_CFunction cls) {
   lua_createtable(L, 0, 1);
   lua_pushcfunction(L, cls);
   lua_setfield(L, -2, "__close");
@@ -600,21 +611,21 @@ static void newfenv (lua_State *L, lua_CFunction cls) {
 
 
 LUAMOD_API int luaopen_io (lua_State *L) {
+  lua_settop(L, 0);
   createmeta(L);
   /* create (private) environment (with fields IO_INPUT, IO_OUTPUT, __close) */
-  newfenv(L, io_fclose);
-  lua_replace(L, LUA_ENVIRONINDEX);
-  /* open library */
-  luaL_register(L, LUA_IOLIBNAME, iolib);
+  newenv(L, io_fclose);  /* upvalue for all io functions at index 1 */
+  lua_pushvalue(L, -1);  /* copy to be consumed by 'openlib' */
+  luaL_openlib(L, LUA_IOLIBNAME, iolib, 1);  /* new module at index 2 */
   /* create (and set) default files */
-  newfenv(L, io_noclose);  /* close function for default files */
+  newenv(L, io_noclose);  /* environment for default files at index 3 */
   createstdfile(L, stdin, IO_INPUT, "stdin");
   createstdfile(L, stdout, IO_OUTPUT, "stdout");
   createstdfile(L, stderr, 0, "stderr");
   lua_pop(L, 1);  /* pop environment for default files */
-  lua_getfield(L, -1, "popen");
-  newfenv(L, io_pclose);  /* create environment for 'popen' */
-  lua_setfenv(L, -2);  /* set fenv for 'popen' */
+  lua_getfield(L, 2, "popen");
+  newenv(L, io_pclose);  /* create environment for 'popen' streams */
+  lua_setupvalue(L, -2, 1);  /* set it as upvalue for 'popen' */
   lua_pop(L, 1);  /* pop 'popen' */
   return 1;
 }

+ 10 - 11
loadlib.c

@@ -1,5 +1,5 @@
 /*
-** $Id: loadlib.c,v 1.79 2010/01/13 16:09:05 roberto Exp roberto $
+** $Id: loadlib.c,v 1.80 2010/01/13 16:30:27 roberto Exp roberto $
 ** Dynamic library loader for Lua
 ** See Copyright Notice in lua.h
 **
@@ -353,9 +353,7 @@ static int ll_loadfunc (lua_State *L, const char *path, const char *sym) {
     lua_CFunction f = ll_sym(L, *reg, sym);
     if (f == NULL)
       return ERRFUNC;  /* unable to find function */
-    lua_pushcfunction(L, f);  /* else create new function... */
-    lua_pushglobaltable(L);   /* ... and set the standard global table... */
-    lua_setfenv(L, -2);       /* ... as its environment */
+    lua_pushcfunction(L, f);  /* else create new function */
     return 0;  /* no errors */
   }
 }
@@ -435,7 +433,7 @@ static int ll_searchpath (lua_State *L) {
 static const char *findfile (lua_State *L, const char *name,
                                            const char *pname) {
   const char *path;
-  lua_getfield(L, LUA_ENVIRONINDEX, pname);
+  lua_getfield(L, lua_upvalueindex(1), pname);
   path = lua_tostring(L, -1);
   if (path == NULL)
     luaL_error(L, LUA_QL("package.%s") " must be a string", pname);
@@ -509,7 +507,7 @@ static int loader_Croot (lua_State *L) {
 
 static int loader_preload (lua_State *L) {
   const char *name = luaL_checkstring(L, 1);
-  lua_getfield(L, LUA_ENVIRONINDEX, "preload");
+  lua_getfield(L, lua_upvalueindex(1), "preload");
   if (!lua_istable(L, -1))
     luaL_error(L, LUA_QL("package.preload") " must be a table");
   lua_getfield(L, -1, name);
@@ -535,7 +533,7 @@ static int ll_require (lua_State *L) {
     return 1;  /* package is already loaded */
   }
   /* else must load it; iterate over available loaders */
-  lua_getfield(L, LUA_ENVIRONINDEX, "loaders");
+  lua_getfield(L, lua_upvalueindex(1), "loaders");
   if (!lua_istable(L, -1))
     luaL_error(L, LUA_QL("package.loaders") " must be a table");
   lua_pushliteral(L, "");  /* error message accumulator */
@@ -709,12 +707,12 @@ LUAMOD_API int luaopen_package (lua_State *L) {
   lua_setfield(L, -2, "__gc");
   /* create `package' table */
   luaL_register(L, LUA_LOADLIBNAME, pk_funcs);
-  lua_copy(L, -1, LUA_ENVIRONINDEX);
   /* create `loaders' table */
   lua_createtable(L, sizeof(loaders)/sizeof(loaders[0]) - 1, 0);
   /* fill it with pre-defined loaders */
   for (i=0; loaders[i] != NULL; i++) {
-    lua_pushcfunction(L, loaders[i]);
+    lua_pushvalue(L, -2);  /* set 'package' as upvalue for all loaders */
+    lua_pushcclosure(L, loaders[i], 1);
     lua_rawseti(L, -2, i+1);
   }
   lua_setfield(L, -2, "loaders");  /* put it in field `loaders' */
@@ -731,8 +729,9 @@ LUAMOD_API int luaopen_package (lua_State *L) {
   lua_newtable(L);
   lua_setfield(L, -2, "preload");
   lua_pushglobaltable(L);
-  luaL_register(L, NULL, ll_funcs);  /* open lib into global table */
-  lua_pop(L, 1);
+  lua_pushvalue(L, -2);  /* set 'package' as upvalue for next lib */
+  luaL_openlib(L, NULL, ll_funcs, 1);  /* open lib into global table */
+  lua_pop(L, 1);  /* pop global table */
   return 1;  /* return 'package' table */
 }