Przeglądaj źródła

new function 'loadin'

Roberto Ierusalimschy 15 lat temu
rodzic
commit
b9063a08f5
1 zmienionych plików z 61 dodań i 23 usunięć
  1. 61 23
      lbaselib.c

+ 61 - 23
lbaselib.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lbaselib.c,v 1.221 2009/10/23 19:12:19 roberto Exp roberto $
+** $Id: lbaselib.c,v 1.222 2009/11/09 18:55:17 roberto Exp roberto $
 ** Basic library
 ** See Copyright Notice in lua.h
 */
@@ -276,13 +276,11 @@ 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.
+** {======================================================
+** Generic Read function
+** =======================================================
 */
 
-
 static const char *checkrights (lua_State *L, const char *mode, const char *s) {
   if (strchr(mode, 'b') == NULL && *s == LUA_SIGNATURE[0])
     return lua_pushstring(L, "attempt to load a binary chunk");
@@ -292,24 +290,42 @@ static const char *checkrights (lua_State *L, const char *mode, const char *s) {
 }
 
 
+/*
+** reserves a slot, above all arguments, to hold a copy of the returned
+** string to avoid it being collected while parsed
+*/
+#define RESERVEDSLOT	4
+
+
+/*
+** 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.
+*/
+typedef struct {  /* reader state */
+  int f;  /* position of reader function on stack */
+  const char *mode;  /* allowed modes (binary/text) */
+} Readstat;
+
 static const char *generic_reader (lua_State *L, void *ud, size_t *size) {
   const char *s;
-  const char **mode = (const char **)ud;
+  Readstat *stat = (Readstat *)ud;
   luaL_checkstack(L, 2, "too many nested functions");
-  lua_pushvalue(L, 1);  /* get function */
+  lua_pushvalue(L, stat->f);  /* get function */
   lua_call(L, 0, 1);  /* call it */
   if (lua_isnil(L, -1)) {
     *size = 0;
     return NULL;
   }
   else if ((s = lua_tostring(L, -1)) != NULL) {
-    if (*mode != NULL) {  /* first time? */
-      s = checkrights(L, *mode, s);  /* check whether chunk format is allowed */
-      *mode = NULL;  /* to avoid further checks */
+    if (stat->mode != NULL) {  /* first time? */
+      s = checkrights(L, stat->mode, s);  /* check mode */
+      stat->mode = NULL;  /* to avoid further checks */
       if (s) luaL_error(L, s);
     }
-    lua_replace(L, 3);  /* save string in a reserved stack slot */
-    return lua_tolstring(L, 3, size);
+    lua_replace(L, RESERVEDSLOT);  /* save string in reserved slot */
+    return lua_tolstring(L, RESERVEDSLOT, size);
   }
   else {
     luaL_error(L, "reader function must return a string");
@@ -318,30 +334,51 @@ static const char *generic_reader (lua_State *L, void *ud, size_t *size) {
 }
 
 
-static int luaB_load (lua_State *L) {
+static int luaB_load_aux (lua_State *L, int farg) {
   int status;
-  const char *s = lua_tostring(L, 1);
-  const char *mode = luaL_optstring(L, 3, "bt");
+  Readstat stat;
+  const char *s = lua_tostring(L, farg);
+  stat.mode = luaL_optstring(L, farg + 2, "bt");
   if (s != NULL) {  /* loading a string? */
-    const char *chunkname = luaL_optstring(L, 2, s);
-    status = (checkrights(L, mode, s) != NULL)
-           || luaL_loadbuffer(L, s, lua_objlen(L, 1), chunkname);
+    const char *chunkname = luaL_optstring(L, farg + 1, s);
+    status = (checkrights(L, stat.mode, s) != NULL)
+           || luaL_loadbuffer(L, s, lua_objlen(L, farg), chunkname);
   }
   else {  /* loading from a reader function */
-    const char *chunkname = 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, &mode, chunkname);
+    const char *chunkname = luaL_optstring(L, farg + 1, "=(load)");
+    luaL_checktype(L, farg, LUA_TFUNCTION);
+    stat.f = farg;
+    lua_settop(L, RESERVEDSLOT);  /* create reserved slot */
+    status = lua_load(L, generic_reader, &stat, chunkname);
   }
   return load_aux(L, status);
 }
 
 
+static int luaB_load (lua_State *L) {
+  return luaB_load_aux(L, 1);
+}
+
+
+static int luaB_loadin (lua_State *L) {
+  int n;
+  luaL_checktype(L, 1, LUA_TTABLE);
+  n = luaB_load_aux(L, 2);
+  if (n == 1) {  /* success? */
+    lua_pushvalue(L, 1);  /* environment for loaded function */
+    lua_setfenv(L, -2);
+  }
+  return n;
+}
+
+
 static int luaB_loadstring (lua_State *L) {
   lua_settop(L, 2);
   lua_pushliteral(L, "tb");
   return luaB_load(L);  /* dostring(s, n) == load(s, n, "tb") */
+
 }
+/* }====================================================== */
 
 
 static int dofilecont (lua_State *L) {
@@ -481,6 +518,7 @@ static const luaL_Reg base_funcs[] = {
   {"getmetatable", luaB_getmetatable},
   {"loadfile", luaB_loadfile},
   {"load", luaB_load},
+  {"loadin", luaB_loadin},
   {"loadstring", luaB_loadstring},
   {"next", luaB_next},
   {"pcall", luaB_pcall},