Просмотр исходного кода

From Lua 5.2: Add luaL_traceback().

Mike Pall 13 лет назад
Родитель
Сommit
fcddd5a3a0
5 измененных файлов с 59 добавлено и 60 удалено
  1. 2 0
      src/lauxlib.h
  2. 1 1
      src/lib_base.c
  3. 4 46
      src/lib_debug.c
  4. 51 0
      src/lj_debug.c
  5. 1 13
      src/luajit.c

+ 2 - 0
src/lauxlib.h

@@ -82,6 +82,8 @@ LUALIB_API int (luaL_loadfilex) (lua_State *L, const char *filename,
 				 const char *mode);
 LUALIB_API int (luaL_loadbufferx) (lua_State *L, const char *buff, size_t sz,
 				   const char *name, const char *mode);
+LUALIB_API void luaL_traceback (lua_State *L, lua_State *L1, const char *msg,
+				int level);
 
 
 /*

+ 1 - 1
src/lib_base.c

@@ -320,7 +320,7 @@ LJLIB_ASM(tostring)		LJLIB_REC(.)
       s = strV(lj_lib_upvalue(L, -(int32_t)itype(o)));
     } else {
       if (tvisfunc(o) && isffunc(funcV(o)))
-	lua_pushfstring(L, "function: fast#%d", funcV(o)->c.ffid);
+	lua_pushfstring(L, "function: builtin#%d", funcV(o)->c.ffid);
       else
 	lua_pushfstring(L, "%s: %p", lj_typename(o), lua_topointer(L, 1));
       /* Note: lua_pushfstring calls the GC which may invalidate o. */

+ 4 - 46
src/lib_debug.c

@@ -383,55 +383,13 @@ LJLIB_CF(debug_debug)
 
 LJLIB_CF(debug_traceback)
 {
-  int level;
-  int firstpart = 1;  /* still before eventual `...' */
   int arg;
   lua_State *L1 = getthread(L, &arg);
-  lua_Debug ar;
-  if (lua_isnumber(L, arg+2)) {
-    level = (int)lua_tointeger(L, arg+2);
-    lua_pop(L, 1);
-  }
+  const char *msg = lua_tostring(L, arg+1);
+  if (msg == NULL && L->top > L->base+arg)
+    L->top = L->base+arg+1;
   else
-    level = (L == L1) ? 1 : 0;  /* level 0 may be this own function */
-  if (lua_gettop(L) == arg)
-    lua_pushliteral(L, "");
-  else if (!lua_isstring(L, arg+1)) return 1;  /* message is not a string */
-  else lua_pushliteral(L, "\n");
-  lua_pushliteral(L, "stack traceback:");
-  while (lua_getstack(L1, level++, &ar)) {
-    if (level > LEVELS1 && firstpart) {
-      /* no more than `LEVELS2' more levels? */
-      if (!lua_getstack(L1, level+LEVELS2, &ar)) {
-	level--;  /* keep going */
-      } else {
-	lua_pushliteral(L, "\n\t...");  /* too many levels */
-	/* This only works with LuaJIT 2.x. Avoids O(n^2) behaviour. */
-	lua_getstack(L1, -10, &ar);
-	level = ar.i_ci - LEVELS2;
-      }
-      firstpart = 0;
-      continue;
-    }
-    lua_pushliteral(L, "\n\t");
-    lua_getinfo(L1, "Snl", &ar);
-    lua_pushfstring(L, "%s:", ar.short_src);
-    if (ar.currentline > 0)
-      lua_pushfstring(L, "%d:", ar.currentline);
-    if (*ar.namewhat != '\0') {  /* is there a name? */
-      lua_pushfstring(L, " in function " LUA_QS, ar.name);
-    } else {
-      if (*ar.what == 'm')  /* main? */
-	lua_pushfstring(L, " in main chunk");
-      else if (*ar.what == 'C' || *ar.what == 't')
-	lua_pushliteral(L, " ?");  /* C function or tail call */
-      else
-	lua_pushfstring(L, " in function <%s:%d>",
-			ar.short_src, ar.linedefined);
-    }
-    lua_concat(L, lua_gettop(L) - arg);
-  }
-  lua_concat(L, lua_gettop(L) - arg);
+    luaL_traceback(L, L1, msg, lj_lib_optint(L, arg+2, (L == L1)));
   return 1;
 }
 

+ 51 - 0
src/lj_debug.c

@@ -543,3 +543,54 @@ LUA_API int lua_getstack(lua_State *L, int level, lua_Debug *ar)
   }
 }
 
+/* Number of frames for the leading and trailing part of a traceback. */
+#define TRACEBACK_LEVELS1	12
+#define TRACEBACK_LEVELS2	10
+
+LUALIB_API void luaL_traceback (lua_State *L, lua_State *L1, const char *msg,
+				int level)
+{
+  int top = (int)(L->top - L->base);
+  int lim = TRACEBACK_LEVELS1;
+  lua_Debug ar;
+  if (msg) lua_pushfstring(L, "%s\n", msg);
+  lua_pushliteral(L, "stack traceback:");
+  while (lua_getstack(L1, level++, &ar)) {
+    GCfunc *fn;
+    if (level > lim) {
+      if (!lua_getstack(L1, level + TRACEBACK_LEVELS2, &ar)) {
+	level--;
+      } else {
+	lua_pushliteral(L, "\n\t...");
+	lua_getstack(L1, -10, &ar);
+	level = ar.i_ci - TRACEBACK_LEVELS2;
+      }
+      lim = 2147483647;
+      continue;
+    }
+    lua_getinfo(L1, "Snlf", &ar);
+    fn = funcV(L1->top-1); L1->top--;
+    if (isffunc(fn) && !*ar.namewhat)
+      lua_pushfstring(L, "\n\t[builtin#%d]:", fn->c.ffid);
+    else
+      lua_pushfstring(L, "\n\t%s:", ar.short_src);
+    if (ar.currentline > 0)
+      lua_pushfstring(L, "%d:", ar.currentline);
+    if (*ar.namewhat) {
+      lua_pushfstring(L, " in function " LUA_QS, ar.name);
+    } else {
+      if (*ar.what == 'm') {
+	lua_pushliteral(L, " in main chunk");
+      } else if (*ar.what == 'C') {
+	lua_pushfstring(L, " at %p", fn->c.f);
+      } else {
+	lua_pushfstring(L, " in function <%s:%d>",
+			ar.short_src, ar.linedefined);
+      }
+    }
+    if ((int)(L->top - L->base) - top >= 15)
+      lua_concat(L, (int)(L->top - L->base) - top);
+  }
+  lua_concat(L, (int)(L->top - L->base) - top);
+}
+

+ 1 - 13
src/luajit.c

@@ -106,19 +106,7 @@ static int traceback(lua_State *L)
       return 1;  /* Return non-string error object. */
     lua_remove(L, 1);  /* Replace object by result of __tostring metamethod. */
   }
-  lua_getfield(L, LUA_GLOBALSINDEX, "debug");
-  if (!lua_istable(L, -1)) {
-    lua_pop(L, 1);
-    return 1;
-  }
-  lua_getfield(L, -1, "traceback");
-  if (!lua_isfunction(L, -1)) {
-    lua_pop(L, 2);
-    return 1;
-  }
-  lua_pushvalue(L, 1);  /* Push error message. */
-  lua_pushinteger(L, 2);  /* Skip this function and debug.traceback(). */
-  lua_call(L, 2, 1);  /* Call debug.traceback(). */
+  luaL_traceback(L, L, lua_tostring(L, 1), 1);
   return 1;
 }