Explorar el Código

new protocol for error handling

Roberto Ierusalimschy hace 23 años
padre
commit
1dbe708aa8
Se han modificado 13 ficheros con 178 adiciones y 158 borrados
  1. 5 7
      lapi.c
  2. 14 35
      lauxlib.c
  3. 3 3
      lauxlib.h
  4. 24 30
      lbaselib.c
  5. 35 10
      ldebug.c
  6. 2 1
      ldebug.h
  7. 42 49
      ldo.c
  8. 3 4
      ldo.h
  9. 2 2
      llex.c
  10. 2 2
      lmem.c
  11. 5 5
      lstate.c
  12. 33 4
      ltests.c
  13. 8 6
      lua.h

+ 5 - 7
lapi.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lapi.c,v 1.198 2002/06/13 13:39:55 roberto Exp roberto $
+** $Id: lapi.c,v 1.199 2002/06/13 13:44:50 roberto Exp roberto $
 ** Lua API
 ** See Copyright Notice in lua.h
 */
@@ -565,12 +565,10 @@ LUA_API void lua_upcall (lua_State *L, int nargs, int nresults) {
 }
 
 
-LUA_API int lua_pcall (lua_State *L, int nargs, int nresults, int errf) {
+LUA_API int lua_pcall (lua_State *L, int nargs, int nresults) {
   int status;
-  const TObject *err;
   lua_lock(L);
-  err = (errf == 0) ? &luaO_nilobject : luaA_index(L, errf);
-  status = luaD_pcall(L, nargs, nresults, err);
+  status = luaD_pcall(L, nargs, nresults);
   lua_unlock(L);
   return status;
 }
@@ -631,10 +629,10 @@ LUA_API void lua_setgcthreshold (lua_State *L, int newthreshold) {
 */
 
 
-LUA_API int lua_errorobj (lua_State *L) {
+LUA_API int lua_error (lua_State *L) {
   lua_lock(L);
   api_checknelems(L, 1);
-  luaD_errorobj(L, L->top - 1, LUA_ERRRUN);
+  luaG_errormsg(L, 0);
   lua_unlock(L);
   return 0;  /* to avoid warnings */
 }

+ 14 - 35
lauxlib.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lauxlib.c,v 1.73 2002/06/05 16:59:37 roberto Exp roberto $
+** $Id: lauxlib.c,v 1.74 2002/06/13 13:44:50 roberto Exp roberto $
 ** Auxiliary functions for building Lua libraries
 ** See Copyright Notice in lua.h
 */
@@ -40,13 +40,13 @@ LUALIB_API int luaL_argerror (lua_State *L, int narg, const char *extramsg) {
   if (strcmp(ar.namewhat, "method") == 0) {
     narg--;  /* do not count `self' */
     if (narg == 0)  /* error is in the self argument itself? */
-      return luaL_verror(L,
+      return luaL_error(L,
         "calling %s on bad self (perhaps using `:' instead of `.')",
         ar.name);
   }
   if (ar.name == NULL)
     ar.name = "?";
-  return luaL_verror(L, "bad argument #%d to `%s' (%s)",
+  return luaL_error(L, "bad argument #%d to `%s' (%s)",
                         narg, ar.name, extramsg);
 }
 
@@ -63,19 +63,12 @@ static void tag_error (lua_State *L, int narg, int tag) {
 }
 
 
-LUALIB_API int luaL_verror (lua_State *L, const char *fmt, ...) {
-  lua_Debug ar;
-  const char *msg;
+LUALIB_API int luaL_error (lua_State *L, const char *fmt, ...) {
   va_list argp;
   va_start(argp, fmt);
-  msg = lua_pushvfstring(L, fmt, argp);
+  lua_pushvfstring(L, fmt, argp);
   va_end(argp);
-  if (lua_getstack(L, 1, &ar)) {  /* check calling function */
-    lua_getinfo(L, "Snl", &ar);
-    if (ar.currentline > 0)
-      lua_pushfstring(L, "%s:%d: %s", ar.short_src, ar.currentline, msg);
-  }
-  return lua_errorobj(L);
+  return lua_error(L);
 }
 
 /* }====================================================== */
@@ -92,7 +85,7 @@ LUALIB_API int luaL_findstring (const char *name, const char *const list[]) {
 
 LUALIB_API void luaL_check_stack (lua_State *L, int space, const char *mes) {
   if (!lua_checkstack(L, space))
-    luaL_verror(L, "stack overflow (%s)", mes);
+    luaL_error(L, "stack overflow (%s)", mes);
 }
 
 
@@ -397,35 +390,21 @@ LUALIB_API int luaL_loadbuffer (lua_State *L, const char *buff, size_t size,
 
 static void callalert (lua_State *L, int status) {
   if (status != 0) {
-    int top = lua_gettop(L);
+    int top;
+    if (status == LUA_ERRRUN)
+      lua_concat(L, 2);  /* concat error message and traceback */
+    top = lua_gettop(L);
     lua_getglobal(L, "_ALERT");
     lua_insert(L, -2);
-    lua_pcall(L, 1, 0, 0);
+    lua_pcall(L, 1, 0);
     lua_settop(L, top-1);
   }
 }
 
 
-LUALIB_API int lua_call (lua_State *L, int nargs, int nresults) {
-  int status;
-  int errpos = lua_gettop(L) - nargs;
-  lua_getglobal(L, "_ERRORMESSAGE");
-  lua_insert(L, errpos);  /* put below function and args */
-  status = lua_pcall(L, nargs, nresults, errpos);
-  lua_remove(L, errpos);
-  callalert(L, status);
-  return status;
-}
-
-
 static int aux_do (lua_State *L, int status) {
-  if (status == 0) {  /* parse OK? */
-    int err = lua_gettop(L);
-    lua_getglobal(L, "_ERRORMESSAGE");
-    lua_insert(L, err);
-    status = lua_pcall(L, 0, LUA_MULTRET, err);  /* call main */
-    lua_remove(L, err);  /* remove error function */
-  }
+  if (status == 0)  /* parse OK? */
+    status = lua_pcall(L, 0, LUA_MULTRET);  /* call main */
   callalert(L, status);
   return status;
 }

+ 3 - 3
lauxlib.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lauxlib.h,v 1.47 2002/05/16 18:39:46 roberto Exp roberto $
+** $Id: lauxlib.h,v 1.48 2002/06/03 20:11:41 roberto Exp roberto $
 ** Auxiliary functions for building Lua libraries
 ** See Copyright Notice in lua.h
 */
@@ -44,7 +44,8 @@ LUALIB_API void luaL_check_stack (lua_State *L, int space, const char *msg);
 LUALIB_API void luaL_check_type (lua_State *L, int narg, int t);
 LUALIB_API void luaL_check_any (lua_State *L, int narg);
 
-LUALIB_API int luaL_verror (lua_State *L, const char *fmt, ...);
+LUALIB_API int luaL_error (lua_State *L, const char *fmt, ...);
+
 LUALIB_API int luaL_findstring (const char *name, 
                                 const char *const list[]);
 
@@ -117,7 +118,6 @@ LUALIB_API void luaL_pushresult (luaL_Buffer *B);
 #define luaL_checktype  luaL_check_type
 #define luaL_checkany   luaL_check_any
 
-LUALIB_API int   lua_call (lua_State *L, int nargs, int nresults);
 LUALIB_API int   lua_dofile (lua_State *L, const char *filename);
 LUALIB_API int   lua_dostring (lua_State *L, const char *str);
 LUALIB_API int   lua_dobuffer (lua_State *L, const char *buff, size_t size,

+ 24 - 30
lbaselib.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lbaselib.c,v 1.80 2002/06/13 13:39:55 roberto Exp roberto $
+** $Id: lbaselib.c,v 1.81 2002/06/13 13:44:50 roberto Exp roberto $
 ** Basic library
 ** See Copyright Notice in lua.h
 */
@@ -37,7 +37,7 @@ static int luaB_print (lua_State *L) {
     lua_upcall(L, 1, 1);
     s = lua_tostring(L, -1);  /* get result */
     if (s == NULL)
-      return luaL_verror(L, "`tostring' must return a string to `print'");
+      return luaL_error(L, "`tostring' must return a string to `print'");
     if (i>1) fputs("\t", stdout);
     fputs(s, stdout);
     lua_pop(L, 1);  /* pop result */
@@ -76,8 +76,8 @@ static int luaB_tonumber (lua_State *L) {
 
 
 static int luaB_error (lua_State *L) {
-  lua_settop(L, 1);
-  return lua_errorobj(L);
+  luaL_check_any(L, 1);
+  return lua_error(L);
 }
 
 
@@ -193,9 +193,10 @@ static int luaB_nexti (lua_State *L) {
 static int passresults (lua_State *L, int status) {
   if (status == 0) return 1;
   else {
+    int numres = (status == LUA_ERRRUN) ? 3 : 2;
     lua_pushnil(L);
-    lua_insert(L, -2);
-    return 2;
+    lua_insert(L, -numres);
+    return numres;
   }
 }
 
@@ -217,7 +218,7 @@ static int luaB_loadfile (lua_State *L) {
 static int luaB_assert (lua_State *L) {
   luaL_check_any(L, 1);
   if (!lua_toboolean(L, 1))
-    return luaL_verror(L, "%s", luaL_opt_string(L, 2, "assertion failed!"));
+    return luaL_error(L, "%s", luaL_opt_string(L, 2, "assertion failed!"));
   lua_settop(L, 1);
   return 1;
 }
@@ -234,25 +235,10 @@ static int luaB_unpack (lua_State *L) {
 }
 
 
-static int luaB_xpcall (lua_State *L) {
-  int status;
-  luaL_check_any(L, 1);
-  luaL_check_any(L, 2);
-  status = lua_pcall(L, lua_gettop(L) - 2, LUA_MULTRET, 1);
-  if (status != 0)
-    return passresults(L, status);
-  else {
-    lua_pushboolean(L, 1);
-    lua_replace(L, 1);
-    return lua_gettop(L);  /* return `true' + all results */
-  }
-}
-
-
 static int luaB_pcall (lua_State *L) {
   int status;
   luaL_check_any(L, 1);
-  status = lua_pcall(L, lua_gettop(L) - 1, LUA_MULTRET, 0);
+  status = lua_pcall(L, lua_gettop(L) - 1, LUA_MULTRET);
   if (status != 0)
     return passresults(L, status);
   else {
@@ -362,7 +348,7 @@ static int luaB_require (lua_State *L) {
   lua_pushvalue(L, 1);
   lua_setglobal(L, "_REQUIREDNAME");
   lua_getglobal(L, REQTAB);
-  if (!lua_istable(L, 2)) return luaL_verror(L, REQTAB " is not a table");
+  if (!lua_istable(L, 2)) return luaL_error(L, REQTAB " is not a table");
   path = getpath(L);
   lua_pushvalue(L, 1);  /* check package's name in book-keeping table */
   lua_gettable(L, 2);
@@ -385,11 +371,11 @@ static int luaB_require (lua_State *L) {
       return 0;
     }
     case LUA_ERRFILE: {  /* file not found */
-      return luaL_verror(L, "could not load package `%s' from path `%s'",
+      return luaL_error(L, "could not load package `%s' from path `%s'",
                             lua_tostring(L, 1), getpath(L));
     }
     default: {
-      return luaL_verror(L, "error loading package\n%s", lua_tostring(L, -1));
+      return luaL_error(L, "error loading package\n%s", lua_tostring(L, -1));
     }
   }
 }
@@ -413,7 +399,6 @@ static const luaL_reg base_funcs[] = {
   {"rawget", luaB_rawget},
   {"rawset", luaB_rawset},
   {"pcall", luaB_pcall},
-  {"xpcall", luaB_xpcall},
   {"collectgarbage", luaB_collectgarbage},
   {"gcinfo", luaB_gcinfo},
   {"loadfile", luaB_loadfile},
@@ -432,9 +417,18 @@ static const luaL_reg base_funcs[] = {
 
 static int luaB_resume (lua_State *L) {
   lua_State *co = (lua_State *)lua_getfrombox(L, lua_upvalueindex(1));
+  int status;
   lua_settop(L, 0);
-  if (lua_resume(L, co) != 0)
-    return lua_errorobj(L);
+  status = lua_resume(L, co);
+  if (status != 0) {
+    if (status == LUA_ERRRUN) {
+      if (lua_isstring(L, -1) && lua_isstring(L, -2))
+        lua_concat(L, 2);
+      else
+        lua_pop(L, 1);
+    }
+    return lua_error(L);
+  }
   return lua_gettop(L);
 }
 
@@ -455,7 +449,7 @@ static int luaB_coroutine (lua_State *L) {
   luaL_arg_check(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), 1,
     "Lua function expected");
   NL = lua_newthread(L);
-  if (NL == NULL) return luaL_verror(L, "unable to create new thread");
+  if (NL == NULL) return luaL_error(L, "unable to create new thread");
   /* move function and arguments from L to NL */
   for (i=0; i<n; i++) {
     ref = lua_ref(L, 1);

+ 35 - 10
ldebug.c

@@ -1,11 +1,12 @@
 /*
-** $Id: ldebug.c,v 1.118 2002/06/06 18:17:33 roberto Exp roberto $
+** $Id: ldebug.c,v 1.119 2002/06/13 13:39:55 roberto Exp roberto $
 ** Debug Interface
 ** See Copyright Notice in lua.h
 */
 
 
 #include <stdlib.h>
+#include <string.h>
 
 #include "lua.h"
 
@@ -510,18 +511,42 @@ void luaG_ordererror (lua_State *L, const TObject *p1, const TObject *p2) {
 }
 
 
+static void addinfo (lua_State *L, int internal) {
+  CallInfo *ci = (internal) ? L->ci : L->ci - 1;
+  const char *msg = svalue(L->top - 1);
+  if (strchr(msg, '\n')) return;  /* message already `formatted' */
+  if (!isLmark(ci)) {  /* no Lua code? */
+    luaO_pushfstring(L, "%s\n", msg);  /* no extra info */
+  }
+  else {  /* add file:line information */
+    char buff[LUA_IDSIZE];
+    int line = currentline(L, ci);
+    luaO_chunkid(buff, getstr(getluaproto(ci)->source), LUA_IDSIZE);
+    luaO_pushfstring(L, "%s:%d: %s\n", buff, line, msg);
+  }
+}
+
+
+void luaG_errormsg (lua_State *L, int internal) {
+  const TObject *errfunc;
+  if (ttype(L->top - 1) == LUA_TSTRING)
+    addinfo(L, internal);
+  errfunc = luaH_getstr(hvalue(registry(L)), luaS_new(L, LUA_TRACEBACK));
+  if (ttype(errfunc) != LUA_TNIL) {  /* is there an error function? */
+    setobj(L->top, errfunc);  /* push function */
+    setobj(L->top + 1, L->top - 1);  /* push error message */
+    L->top += 2;
+    luaD_call(L, L->top - 2, 1);  /* call error function? */
+  }
+  luaD_throw(L, LUA_ERRRUN);
+}
+
+
 void luaG_runerror (lua_State *L, const char *fmt, ...) {
-  const char *msg;
   va_list argp;
   va_start(argp, fmt);
-  msg = luaO_pushvfstring(L, fmt, argp);
+  luaO_pushvfstring(L, fmt, argp);
   va_end(argp);
-  if (isLmark(L->ci)) {
-    char buff[LUA_IDSIZE];
-    int line = currentline(L, L->ci);
-    luaO_chunkid(buff, getstr(getluaproto(L->ci)->source), LUA_IDSIZE);
-    msg = luaO_pushfstring(L, "%s:%d: %s", buff, line, msg);
-  }
-  luaD_error(L, msg, LUA_ERRRUN);
+  luaG_errormsg(L, 1);
 }
 

+ 2 - 1
ldebug.h

@@ -1,5 +1,5 @@
 /*
-** $Id: ldebug.h,v 1.20 2002/05/02 13:06:20 roberto Exp roberto $
+** $Id: ldebug.h,v 1.21 2002/05/15 18:57:44 roberto Exp roberto $
 ** Auxiliary functions from Debug Interface module
 ** See Copyright Notice in lua.h
 */
@@ -21,6 +21,7 @@ void luaG_concaterror (lua_State *L, StkId p1, StkId p2);
 void luaG_aritherror (lua_State *L, StkId p1, const TObject *p2);
 void luaG_ordererror (lua_State *L, const TObject *p1, const TObject *p2);
 void luaG_runerror (lua_State *L, const char *fmt, ...);
+void luaG_errormsg (lua_State *L, int internal);
 int luaG_checkcode (const Proto *pt);
 
 

+ 42 - 49
ldo.c

@@ -1,5 +1,5 @@
 /*
-** $Id: ldo.c,v 1.178 2002/06/03 17:46:34 roberto Exp roberto $
+** $Id: ldo.c,v 1.179 2002/06/03 20:12:50 roberto Exp roberto $
 ** Stack and Call structure of Lua
 ** See Copyright Notice in lua.h
 */
@@ -37,10 +37,16 @@ struct lua_longjmp {
   jmp_buf b;
   int allowhooks;  /* `allowhook' state when protection was set */
   volatile int status;  /* error code */
-  TObject *err;  /* error function -> message (start of `ud') */
+  TObject *err;  /* error messages (start of `ud') */
 };
 
 
+static void pusherrormsg (lua_State *L, int status, TObject *err) {
+  setobj(L->top++, &err[0]);
+  if (status == LUA_ERRRUN)
+    setobj(L->top++, &err[1]);
+}
+
 
 static void correctstack (lua_State *L, TObject *oldstack) {
   struct lua_longjmp *lj;
@@ -109,7 +115,7 @@ void luaD_growstack (lua_State *L, int n) {
 static void luaD_growCI (lua_State *L) {
   L->ci--;
   if (L->size_ci > LUA_MAXCALLS)  /* overflow while handling overflow? */
-    luaD_error(L, "error in error handling", LUA_ERRERR);
+    luaD_throw(L, LUA_ERRERR);
   else {
     luaD_reallocCI(L, 2*L->size_ci);
     if (L->size_ci > LUA_MAXCALLS)
@@ -302,7 +308,7 @@ static void move_results (lua_State *L, TObject *from, TObject *to) {
 
 
 struct ResS {
-  TObject err;
+  TObject err[2];
   int numres;
 };
 
@@ -337,17 +343,11 @@ LUA_API int lua_resume (lua_State *L, lua_State *co) {
     luaG_runerror(L, "thread is dead - cannot be resumed");
   if (co->errorJmp != NULL)  /* ?? */
     luaG_runerror(L, "thread is active - cannot be resumed");
-  if (L->errorJmp) {
-    setobj(&ud.err, L->errorJmp->err);
-  }
-  else
-    setnilvalue(&ud.err);
-  status = luaD_runprotected(co, resume, &ud.err);
+  status = luaD_runprotected(co, resume, ud.err);
   if (status == 0)  
     move_results(L, co->top - ud.numres, co->top);
-  else {
-    setobj(L->top++, &ud.err);
-}
+  else
+    pusherrormsg(L, status, ud.err);
   lua_unlock(L);
   return status;
 }
@@ -369,7 +369,7 @@ LUA_API int lua_yield (lua_State *L, int nresults) {
 ** Execute a protected call.
 */
 struct CallS {  /* data to `f_call' */
-  TObject err;  /* error field... */
+  TObject err[2];
   StkId func;
   int nresults;
 };
@@ -381,17 +381,16 @@ static void f_call (lua_State *L, void *ud) {
 }
 
 
-int luaD_pcall (lua_State *L, int nargs, int nresults, const TObject *err) {
+int luaD_pcall (lua_State *L, int nargs, int nresults) {
   struct CallS c;
   int status;
   c.func = L->top - (nargs+1);  /* function to be called */
   c.nresults = nresults;
-  c.err = *err;
-  status = luaD_runprotected(L, &f_call, &c.err);
+  status = luaD_runprotected(L, &f_call, c.err);
   if (status != 0) {  /* an error occurred? */
     L->top -= nargs+1;  /* remove parameters and func from the stack */
     luaF_close(L, L->top);  /* close eventual pending closures */
-    setobj(L->top++, &c.err);
+    pusherrormsg(L, status, c.err);
   }
   return status;
 }
@@ -401,7 +400,7 @@ int luaD_pcall (lua_State *L, int nargs, int nresults, const TObject *err) {
 ** Execute a protected parser.
 */
 struct SParser {  /* data to `f_parser' */
-  TObject err;  /* error field... */
+  TObject err[2];
   ZIO *z;
   int bin;
 };
@@ -425,15 +424,14 @@ int luaD_protectedparser (lua_State *L, ZIO *z, int bin) {
   if (G(L)->nblocks + G(L)->nblocks/4 >= G(L)->GCthreshold)
     luaC_collectgarbage(L);
   old_blocks = G(L)->nblocks;
-  setnilvalue(&p.err);
-  status = luaD_runprotected(L, f_parser, &p.err);
+  status = luaD_runprotected(L, f_parser, p.err);
   if (status == 0) {
     /* add new memory to threshold (as it probably will stay) */
     lua_assert(G(L)->nblocks >= old_blocks);
     G(L)->GCthreshold += (G(L)->nblocks - old_blocks);
   }
   else
-    setobj(L->top++, &p.err);
+    pusherrormsg(L, status, p.err);
   return status;
 }
 
@@ -445,29 +443,34 @@ int luaD_protectedparser (lua_State *L, ZIO *z, int bin) {
 ** =======================================================
 */
 
-
-static void message (lua_State *L, const TObject *msg, int nofunc) {
-  TObject *m = L->errorJmp->err;
-  if (nofunc || ttype(m) != LUA_TFUNCTION) {  /* no error function? */
-    setobj(m, msg);  /* keep error message */
-  }
-  else {  /* call error function */
-    setobj(L->top, m);
-    setobj(L->top + 1, msg);
-    L->top += 2;
-    luaD_call(L, L->top - 2, 1);
-    setobj(m, L->top - 1);
+static void seterrorobj (lua_State *L, int errcode, TObject *m) {
+  switch (errcode) {
+    case LUA_ERRMEM: {
+      if (G(L) != NULL && G(L)->GCthreshold > 0)  /* state is OK? */
+        setsvalue(&m[0], luaS_new(L, MEMERRMSG));
+      break;
+    }
+    case LUA_ERRERR: {
+      setsvalue(&m[0], luaS_new(L, "error in error handling"));
+      break;
+    }
+    case LUA_ERRSYNTAX: {  /* message is on stack top */
+      setobj(&m[0], L->top - 1);
+      break;
+    }
+    case LUA_ERRRUN: {  /* traceback is on stack top */
+      setobj(&m[0], L->top - 2);
+      setobj(&m[1], L->top - 1);
+      break;
+    }
   }
 }
 
 
-/*
-** Reports an error, and jumps up to the available recovery label
-*/
-void luaD_errorobj (lua_State *L, const TObject *s, int errcode) {
+void luaD_throw (lua_State *L, int errcode) {
+  seterrorobj(L, errcode, L->errorJmp->err);
   if (L->errorJmp) {
     L->errorJmp->status = errcode;
-    message(L, s, (errcode >= LUA_ERRMEM));
     longjmp(L->errorJmp->b, 1);
   }
   else {
@@ -477,16 +480,6 @@ void luaD_errorobj (lua_State *L, const TObject *s, int errcode) {
 }
 
 
-void luaD_error (lua_State *L, const char *s, int errcode) {
-  TObject errobj;
-  if (errcode == LUA_ERRMEM && (G(L) == NULL || G(L)->GCthreshold == 0))
-    setnilvalue(&errobj);  /* error bulding state */
-  else
-    setsvalue(&errobj, luaS_new(L, s));
-  luaD_errorobj(L, &errobj, errcode);
-}
-
-
 int luaD_runprotected (lua_State *L, Pfunc f, TObject *ud) {
   struct lua_longjmp lj;
   lj.ci = L->ci;

+ 3 - 4
ldo.h

@@ -1,5 +1,5 @@
 /*
-** $Id: ldo.h,v 1.44 2002/05/01 20:40:42 roberto Exp roberto $
+** $Id: ldo.h,v 1.45 2002/05/15 18:57:44 roberto Exp roberto $
 ** Stack and Call structure of Lua
 ** See Copyright Notice in lua.h
 */
@@ -35,14 +35,13 @@ int luaD_protectedparser (lua_State *L, ZIO *z, int bin);
 void luaD_lineHook (lua_State *L, int line);
 StkId luaD_precall (lua_State *L, StkId func);
 void luaD_call (lua_State *L, StkId func, int nResults);
-int luaD_pcall (lua_State *L, int nargs, int nresults, const TObject *err);
+int luaD_pcall (lua_State *L, int nargs, int nresults);
 void luaD_poscall (lua_State *L, int wanted, StkId firstResult);
 void luaD_reallocCI (lua_State *L, int newsize);
 void luaD_reallocstack (lua_State *L, int newsize);
 void luaD_growstack (lua_State *L, int n);
 
-void luaD_error (lua_State *L, const char *s, int errcode);
-void luaD_errorobj (lua_State *L, const TObject *s, int errcode);
+void luaD_throw (lua_State *L, int errcode);
 int luaD_runprotected (lua_State *L, Pfunc f, TObject *ud);
 
 

+ 2 - 2
llex.c

@@ -1,5 +1,5 @@
 /*
-** $Id: llex.c,v 1.103 2002/06/03 14:09:57 roberto Exp roberto $
+** $Id: llex.c,v 1.104 2002/06/03 20:12:21 roberto Exp roberto $
 ** Lexical Analyzer
 ** See Copyright Notice in lua.h
 */
@@ -61,7 +61,7 @@ static void luaX_error (LexState *ls, const char *s, const char *token) {
   char buff[MAXSRC];
   luaO_chunkid(buff, getstr(ls->source), MAXSRC);
   luaO_pushfstring(L, "%s:%d: %s near `%s'", buff, ls->linenumber, s, token); 
-  luaD_errorobj(L, L->top - 1, LUA_ERRSYNTAX);
+  luaD_throw(L, LUA_ERRSYNTAX);
 }
 
 

+ 2 - 2
lmem.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lmem.c,v 1.55 2002/05/15 18:57:44 roberto Exp roberto $
+** $Id: lmem.c,v 1.56 2002/06/11 16:23:47 roberto Exp roberto $
 ** Interface to Memory Manager
 ** See Copyright Notice in lua.h
 */
@@ -66,7 +66,7 @@ void *luaM_realloc (lua_State *L, void *block, lu_mem oldsize, lu_mem size) {
     block = l_realloc(block, oldsize, size);
     if (block == NULL) {
       if (L)
-        luaD_error(L, MEMERRMSG, LUA_ERRMEM);
+        luaD_throw(L, LUA_ERRMEM);
       else return NULL;  /* error before creating state! */
     }
   }

+ 5 - 5
lstate.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lstate.c,v 1.95 2002/06/03 14:09:57 roberto Exp roberto $
+** $Id: lstate.c,v 1.96 2002/06/06 18:17:33 roberto Exp roberto $
 ** Global State
 ** See Copyright Notice in lua.h
 */
@@ -7,6 +7,7 @@
 
 #include "lua.h"
 
+#include "ldebug.h"
 #include "ldo.h"
 #include "lfunc.h"
 #include "lgc.h"
@@ -122,14 +123,13 @@ LUA_API lua_State *lua_newthread (lua_State *OL) {
 
 LUA_API lua_State *lua_open (void) {
   lua_State *L;
-  TObject dummy;
-  setnilvalue(&dummy);
+  TObject dummy[2];
   L = luaM_new(NULL, lua_State);
   if (L) {  /* allocation OK? */
     preinit_state(L);
     L->l_G = NULL;
     L->next = L->previous = L;
-    if (luaD_runprotected(L, f_luaopen, &dummy) != 0) {
+    if (luaD_runprotected(L, f_luaopen, dummy) != 0) {
       /* memory allocation error: free partial state */
       close_state(L);
       L = NULL;
@@ -169,8 +169,8 @@ static void close_state (lua_State *L) {
 
 
 LUA_API void lua_closethread (lua_State *L, lua_State *thread) {
-  if (L == thread) lua_error(L, "cannot close only thread of a state");
   lua_lock(L);
+  if (L == thread) luaG_runerror(L, "cannot close only thread of a state");
   luaE_closethread(L, thread);
   lua_unlock(L);
 }

+ 33 - 4
ltests.c

@@ -1,5 +1,5 @@
 /*
-** $Id: ltests.c,v 1.124 2002/06/11 16:23:47 roberto Exp roberto $
+** $Id: ltests.c,v 1.125 2002/06/13 13:44:50 roberto Exp roberto $
 ** Internal Module for Debugging of the Lua Implementation
 ** See Copyright Notice in lua.h
 */
@@ -338,6 +338,34 @@ static int string_query (lua_State *L) {
 }
 
 
+static int xpcall (lua_State *L) {
+  int status;
+  luaL_check_type(L, 1, LUA_TFUNCTION);
+  luaL_check_any(L, 2);
+  lua_pushliteral(L, LUA_TRACEBACK);
+  lua_gettable(L, LUA_REGISTRYINDEX);
+  lua_pushliteral(L, LUA_TRACEBACK);
+  lua_pushvalue(L, 1);
+  lua_settable(L, LUA_REGISTRYINDEX);
+  lua_replace(L, 1);
+  status = lua_pcall(L, lua_gettop(L) - 2, LUA_MULTRET);
+  lua_pushliteral(L, LUA_TRACEBACK);
+  lua_pushvalue(L, 1);
+  lua_settable(L, LUA_REGISTRYINDEX);
+  if (status != 0) {
+    int numres = (status == LUA_ERRRUN) ? 3 : 2;
+    lua_pushnil(L);
+    lua_insert(L, -numres);
+    return numres;
+  }
+  else {
+    lua_pushboolean(L, 1);
+    lua_insert(L, 2);
+    return lua_gettop(L) - 1;  /* return `true' + all results */
+  }
+}
+
+
 static int tref (lua_State *L) {
   int level = lua_gettop(L);
   int lock = luaL_opt_int(L, 2, 1);
@@ -402,7 +430,7 @@ static int doonnewstack (lua_State *L) {
   const char *s = luaL_check_lstr(L, 1, &l);
   int status = luaL_loadbuffer(L1, s, l, s);
   if (status == 0)
-    status = lua_pcall(L1, 0, 0, 0);
+    status = lua_pcall(L1, 0, 0);
   lua_pushnumber(L, status);
   lua_closethread(L, L1);
   return 1;
@@ -639,7 +667,7 @@ static int testC (lua_State *L) {
     else if EQ("call") {
       int narg = getnum;
       int nres = getnum;
-      lua_call(L, narg, nres);
+      lua_pcall(L, narg, nres);
     }
     else if EQ("loadstring") {
       size_t sl;
@@ -659,7 +687,7 @@ static int testC (lua_State *L) {
     else if EQ("type") {
       lua_pushstring(L, lua_typename(L, lua_type(L, getnum)));
     }
-    else luaL_verror(L, "unknown instruction %s", buff);
+    else luaL_error(L, "unknown instruction %s", buff);
   }
   return 0;
 }
@@ -677,6 +705,7 @@ static const struct luaL_reg tests_funcs[] = {
   {"loadlib", loadlib},
   {"stacklevel", stacklevel},
   {"querystr", string_query},
+  {"xpcall", xpcall},
   {"querytab", table_query},
   {"testC", testC},
   {"ref", tref},

+ 8 - 6
lua.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lua.h,v 1.139 2002/06/13 13:39:55 roberto Exp roberto $
+** $Id: lua.h,v 1.140 2002/06/13 13:44:50 roberto Exp roberto $
 ** Lua - An Extensible Extension Language
 ** Tecgraf: Computer Graphics Technology Group, PUC-Rio, Brazil
 ** http://www.lua.org	mailto:[email protected]
@@ -29,6 +29,9 @@
 #define LUA_MULTRET	(-1)
 
 
+/* index for a traceback function in the registry */
+#define LUA_TRACEBACK	"_TRACEBACK"
+
 /*
 ** pseudo-indices
 */
@@ -43,6 +46,7 @@
 #define LUA_ERRSYNTAX	3
 #define LUA_ERRMEM	4
 #define LUA_ERRERR	5
+#define LUA_ERRTHROW	6
 
 
 typedef struct lua_State lua_State;
@@ -180,7 +184,7 @@ LUA_API void  lua_setmetatable (lua_State *L, int objindex);
 ** `load' and `call' functions (load and run Lua code)
 */
 LUA_API void  lua_upcall (lua_State *L, int nargs, int nresults);
-LUA_API int   lua_pcall (lua_State *L, int nargs, int nresults, int errf);
+LUA_API int   lua_pcall (lua_State *L, int nargs, int nresults);
 LUA_API int   lua_load (lua_State *L, lua_Chunkreader reader, void *data,
                         const char *chunkname);
 
@@ -203,7 +207,7 @@ LUA_API void  lua_setgcthreshold (lua_State *L, int newthreshold);
 ** miscellaneous functions
 */
 
-LUA_API int   lua_errorobj (lua_State *L);
+LUA_API int   lua_error (lua_State *L);
 
 LUA_API int   lua_next (lua_State *L, int index);
 LUA_API int   lua_getn (lua_State *L, int index);
@@ -220,8 +224,6 @@ LUA_API void *lua_newuserdata (lua_State *L, size_t size);
 ** ===============================================================
 */
 
-#define lua_error(L,s)	(lua_pushstring(L, s), lua_errorobj(L))
-
 #define lua_newpointerbox(L,u) \
 	(*(void **)(lua_newuserdata(L, sizeof(void *))) = (u))
 
@@ -275,7 +277,7 @@ LUA_API int lua_pushupvalues (lua_State *L);
 #define LUA_REFNIL	(-1)
 
 #define lua_ref(L,lock)	((lock) ? luaL_ref(L, LUA_REGISTRYINDEX) : \
-		(lua_error(L, "unlocked references are obsolete"), 0))
+      (lua_pushstring(L, "unlocked references are obsolete"), lua_error(L), 0))
 
 #define lua_unref(L,ref)	luaL_unref(L, LUA_REGISTRYINDEX, (ref))