Bladeren bron

error handler in 'lua.c' tries '__tostring' metamethod if error
message is not a string

Roberto Ierusalimschy 18 jaren geleden
bovenliggende
commit
4eb49163c6
2 gewijzigde bestanden met toevoegingen van 33 en 29 verwijderingen
  1. 10 13
      ldblib.c
  2. 23 16
      lua.c

+ 10 - 13
ldblib.c

@@ -1,5 +1,5 @@
 /*
-** $Id: ldblib.c,v 1.104 2005/12/29 15:32:11 roberto Exp roberto $
+** $Id: ldblib.c,v 1.105 2006/09/11 14:07:24 roberto Exp roberto $
 ** Interface from Lua to its debug API
 ** See Copyright Notice in lua.h
 */
@@ -319,21 +319,18 @@ static int db_debug (lua_State *L) {
 #define LEVELS2	10	/* size of the second part of the stack */
 
 static int db_errorfb (lua_State *L) {
-  int level;
+  lua_Debug ar;
   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);
-  }
-  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");
+  const char *msg = lua_tostring(L, arg + 1);
+  int level = (lua_isnumber(L, arg + 2)) ?
+                     (int)lua_tointeger(L, arg + 2) :
+                     (L == L1) ? 1 : 0;  /* level 0 may be this own function */
+  lua_settop(L, ++arg);
+  if (msg) lua_pushfstring(L, "%s\n", msg);
+  else if (!lua_isnil(L, arg))  /* is there a non-string 'msg'? */
+    return 1;  /* return it untouched */
   lua_pushliteral(L, "stack traceback:");
   while (lua_getstack(L1, level++, &ar)) {
     if (level > LEVELS1 && firstpart) {

+ 23 - 16
lua.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lua.c,v 1.163 2006/09/18 14:03:18 roberto Exp roberto $
+** $Id: lua.c,v 1.164 2006/10/10 17:40:17 roberto Exp roberto $
 ** Lua stand-alone interpreter
 ** See Copyright Notice in lua.h
 */
@@ -41,7 +41,7 @@ static void laction (int i) {
 
 static void print_usage (void) {
   fprintf(stderr,
-  "usage: %s [options] [script [args]].\n"
+  "usage: %s [options] [script [args]]\n"
   "Available options are:\n"
   "  -e stat  execute string " LUA_QL("stat") "\n"
   "  -l name  require library " LUA_QL("name") "\n"
@@ -73,20 +73,27 @@ static int report (lua_State *L, int status) {
 }
 
 
-static int traceback (lua_State *L) {
+static int gettraceback (lua_State *L) {
   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;
+  if (!lua_istable(L, -1)) return 0;
+  lua_getfield(L, -1, "traceback");  /* check 'debug.traceback' */
+  if (!lua_isfunction(L, -1)) return 0;
+  return 1;  /* there is a function 'debug.traceback' */
+}
+
+
+static int traceback (lua_State *L) {
+  if (lua_isnoneornil(L, 1))  /* no error object? */
+    return 1;  /* keep it that way */
+  if (!gettraceback(L))  /* no 'debug.traceback' function? */
+    lua_pushvalue(L, 1);  /* keep original message */
+  else {
+    lua_pushvalue(L, 1);  /* pass error message */
+    lua_pushinteger(L, 2);  /* skip this function and traceback */
+    lua_call(L, 2, 1);  /* call traceback */
   }
-  lua_pushvalue(L, 1);  /* pass error message */
-  lua_pushinteger(L, 2);  /* skip this function and traceback */
-  lua_call(L, 2, 1);  /* call debug.traceback */
+  if (!lua_isstring(L, -1) && !luaL_callmeta(L, 1, "__tostring"))
+    lua_pushliteral(L, "(no error message)");
   return 1;
 }
 
@@ -96,6 +103,7 @@ static int docall (lua_State *L, int narg, int clear) {
   int base = lua_gettop(L) - narg;  /* function index */
   lua_pushcfunction(L, traceback);  /* push traceback function */
   lua_insert(L, base);  /* put it under chunk and args */
+  globalL = L;  /* to be available to 'laction' */
   signal(SIGINT, laction);
   status = lua_pcall(L, narg, (clear ? 0 : LUA_MULTRET), base);
   signal(SIGINT, SIG_DFL);
@@ -160,7 +168,7 @@ static const char *get_prompt (lua_State *L, int firstline) {
 }
 
 /* mark in error messages for incomplete statements */
-#define mark	LUA_QL("<eof>")
+#define mark	"<eof>"
 #define marklen	(sizeof(mark) - 1)
 
 static int incomplete (lua_State *L, int status) {
@@ -344,7 +352,6 @@ static int pmain (lua_State *L) {
   char **argv = s->argv;
   int script;
   int has_i = 0, has_v = 0, has_e = 0;
-  globalL = L;
   if (argv[0] && argv[0][0]) progname = argv[0];
   lua_gc(L, LUA_GCSTOP, 0);  /* stop collector during initialization */
   luaL_openlibs(L);  /* open libraries */