浏览代码

default for 'module' is opaque (with option 'seeall')

Roberto Ierusalimschy 20 年之前
父节点
当前提交
351f7dad6b
共有 1 个文件被更改,包括 71 次插入44 次删除
  1. 71 44
      loadlib.c

+ 71 - 44
loadlib.c

@@ -1,5 +1,5 @@
 /*
-** $Id: loadlib.c,v 1.41 2005/08/26 17:32:05 roberto Exp roberto $
+** $Id: loadlib.c,v 1.42 2005/08/26 17:36:32 roberto Exp roberto $
 ** Dynamic library loader for Lua
 ** See Copyright Notice in lua.h
 **
@@ -372,7 +372,7 @@ static const char *findfile (lua_State *L, const char *name,
 
 
 static void loaderror (lua_State *L) {
-  luaL_error(L, "error loading package " LUA_QS " (%s)",
+  luaL_error(L, "error loading module " LUA_QS " (%s)",
                 lua_tostring(L, 1), lua_tostring(L, -1));
 }
 
@@ -440,13 +440,20 @@ static int loader_preload (lua_State *L) {
 }
 
 
-static int require_aux (lua_State *L, const char *name) {
+static const int sentinel = 0;
+
+
+static int ll_require (lua_State *L) {
+  const char *name = luaL_checkstring(L, 1);
   int i;
-  int loadedtable = lua_gettop(L) + 1;
+  lua_settop(L, 1);  /* _LOADED table will be at index 2 */
   lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED");
-  lua_getfield(L, loadedtable, name);
-  if (lua_toboolean(L, -1))  /* is it there? */
+  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))
@@ -454,32 +461,24 @@ static int require_aux (lua_State *L, const char *name) {
   for (i=1; ; i++) {
     lua_rawgeti(L, -1, i);  /* get a loader */
     if (lua_isnil(L, -1))
-      return 0;  /* package not found */
+      luaL_error(L, "module " LUA_QS " not found", name);
     lua_pushstring(L, name);
     lua_call(L, 1, 1);  /* call it */
     if (lua_isnil(L, -1)) lua_pop(L, 1);  /* did not found module */
     else break;  /* module loaded successfully */
   }
-  lua_pushboolean(L, 1);
-  lua_setfield(L, loadedtable, name);  /* _LOADED[name] = true */
+  lua_pushlightuserdata(L, (void *)&sentinel);
+  lua_setfield(L, 2, name);  /* _LOADED[name] = sentinel */
   lua_pushstring(L, name);  /* pass name as argument to module */
-  if (lua_pcall(L, 1, 1, 0) != 0) {  /* run loaded module */
-    lua_pushnil(L);  /* in case of errors... */
-    lua_setfield(L, loadedtable, name);  /* ...clear _LOADED[name] */
-    luaL_error(L, "error loading package " LUA_QS " (%s)",
-                  name, lua_tostring(L, -1));  /* propagate error */
-  }
+  lua_call(L, 1, 1);  /* run loaded module */
   if (!lua_isnil(L, -1))  /* non-nil return? */
-    lua_setfield(L, loadedtable, name);  /* _LOADED[name] = returned value */
-  lua_getfield(L, loadedtable, name);  /* return _LOADED[name] */
-  return 1;
-}
-
-
-static int ll_require (lua_State *L) {
-  const char *name = luaL_checkstring(L, 1);
-  if (!require_aux(L, name))  /* error? */
-    luaL_error(L, "package " LUA_QS " not found", name);
+    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;
 }
 
@@ -500,22 +499,47 @@ static void setfenv (lua_State *L) {
   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);
-  const char *dot;
-  lua_settop(L, 1);
+  int loaded = lua_gettop(L) + 1;  /* index of _LOADED table */
   lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED");
-  lua_getfield(L, 2, modname);  /* get _LOADED[modname] */
+  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) != NULL)
       return luaL_error(L, "name conflict for module " LUA_QS, modname);
     lua_pushvalue(L, -1);
-    lua_setfield(L, 2, modname);  /* _LOADED[modname] = new table */
+    lua_setfield(L, loaded, modname);  /* _LOADED[modname] = new table */
   }
   /* check whether table already has a _NAME field */
   lua_getfield(L, -1, "_NAME");
@@ -523,26 +547,28 @@ static int ll_module (lua_State *L) {
     lua_pop(L, 1);
   else {  /* no; initialize it */
     lua_pop(L, 1);
-    /* create new metatable */
-    lua_newtable(L);
-    lua_pushvalue(L, LUA_GLOBALSINDEX);
-    lua_setfield(L, -2, "__index");  /* mt.__index = _G */
-    lua_setmetatable(L, -2);
-    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");
+    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_newtable(L); /* 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;
+}
+
+
 /* }====================================================== */
 
 
@@ -569,6 +595,7 @@ static void setpath (lua_State *L, const char *fieldname, const char *envname,
 
 static const luaL_Reg pk_funcs[] = {
   {"loadlib", ll_loadlib},
+  {"seeall", ll_seeall},
   {NULL, NULL}
 };