Răsfoiți Sursa

error functions search global space for a name for a function when
no other name is available

Roberto Ierusalimschy 16 ani în urmă
părinte
comite
b403317325
1 a modificat fișierele cu 55 adăugiri și 3 ștergeri
  1. 55 3
      lauxlib.c

+ 55 - 3
lauxlib.c

@@ -40,13 +40,65 @@
 #define LEVELS2	10	/* size of the second part of the stack */
 
 
+
+/*
+** search for 'objidx' in table at index -1.
+** return 1 + string at top if find a good name.
+*/
+static int findfield (lua_State *L, int objidx, int level) {
+  int found = 0;
+  if (level == 0 || !lua_istable(L, -1))
+    return 0;  /* not found */
+  lua_pushnil(L);  /* start 'next' loop */
+  while (!found && lua_next(L, -2)) {  /* for each pair in table */
+    if (lua_type(L, -2) == LUA_TSTRING) {  /* ignore non-string keys */
+      if (lua_rawequal(L, objidx, -1)) {  /* found object? */
+        lua_pop(L, 1);  /* remove value (but keep name) */
+        return 1;
+      }
+      else if (findfield(L, objidx, level - 1)) {  /* try recursively */
+        lua_remove(L, -2);  /* remove table (but keep name) */
+        lua_pushliteral(L, ".");
+        lua_insert(L, -2);  /* place '.' between the two names */
+        lua_concat(L, 3);
+        return 1;
+      }
+    }
+    lua_pop(L, 1);  /* remove value */
+  }
+  return 0;  /* not found */
+}
+
+
+static int pushglobalfuncname (lua_State *L, lua_Debug *ar) {
+  int top = lua_gettop(L);
+  lua_getinfo(L, "f", ar);  /* push function */
+  lua_pushvalue(L, LUA_GLOBALSINDEX);  /* push global table */
+  if (findfield(L, top + 1, 2)) {
+    lua_replace(L, top + 1);  /* move name to proper place */
+    lua_pop(L, 1);  /* remove other pushed value */
+    return 1;
+  }
+  else {
+    lua_settop(L, top);  /* remove function and global table */
+    return 0;
+  }
+}
+
+
 static void pushfuncname (lua_State *L, lua_Debug *ar) {
   if (*ar->namewhat != '\0')  /* is there a name? */
     lua_pushfstring(L, "function " LUA_QS, ar->name);
   else if (*ar->what == 'm')  /* main? */
       lua_pushfstring(L, "main chunk");
-  else if (*ar->what == 'C' || *ar->what == 't')
-    lua_pushliteral(L, "?");  /* C function or tail call */
+  else if (*ar->what == 'C' || *ar->what == 't') {
+    if (pushglobalfuncname(L, ar)) {
+      lua_pushfstring(L, "function " LUA_QS, lua_tostring(L, -1));
+      lua_remove(L, -2);  /* remove name */
+    }
+    else
+      lua_pushliteral(L, "?");  /* C function or tail call */
+  }
   else
     lua_pushfstring(L, "function <%s:%d>", ar->short_src, ar->linedefined);
 }
@@ -106,7 +158,7 @@ LUALIB_API int luaL_argerror (lua_State *L, int narg, const char *extramsg) {
       return luaL_error(L, "calling " LUA_QS " on bad self", ar.name);
   }
   if (ar.name == NULL)
-    ar.name = "?";
+    ar.name = (pushglobalfuncname(L, &ar)) ? lua_tostring(L, -1) : "?";
   return luaL_error(L, "bad argument #%d to " LUA_QS " (%s)",
                         narg, ar.name, extramsg);
 }