Browse Source

new way to handle errors

Roberto Ierusalimschy 23 years ago
parent
commit
751cd867d3
13 changed files with 283 additions and 292 deletions
  1. 75 43
      lapi.c
  2. 2 14
      lauxlib.c
  3. 1 3
      lauxlib.h
  4. 44 96
      lbaselib.c
  5. 2 8
      ldblib.c
  6. 59 31
      ldo.c
  7. 3 2
      ldo.h
  8. 2 2
      lmem.c
  9. 4 1
      lmem.h
  10. 6 2
      lstate.c
  11. 6 2
      ltests.c
  12. 68 79
      lua.c
  13. 11 9
      lua.h

+ 75 - 43
lapi.c

@@ -1,10 +1,12 @@
 /*
-** $Id: lapi.c,v 1.184 2002/04/16 17:08:28 roberto Exp roberto $
+** $Id: lapi.c,v 1.185 2002/04/22 14:40:50 roberto Exp roberto $
 ** Lua API
 ** See Copyright Notice in lua.h
 */
 
 
+#include <errno.h>
+#include <stdio.h>
 #include <string.h>
 
 #include "lua.h"
@@ -516,7 +518,7 @@ LUA_API void lua_setmetatable (lua_State *L, int objindex) {
 
 
 /*
-** `do' functions (run Lua code)
+** `load' and `call' functions (run Lua code)
 */
 
 LUA_API void lua_rawcall (lua_State *L, int nargs, int nresults) {
@@ -529,17 +531,6 @@ LUA_API void lua_rawcall (lua_State *L, int nargs, int nresults) {
 }
 
 
-LUA_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);
-  return status;
-}
-
-
 LUA_API int lua_pcall (lua_State *L, int nargs, int nresults, int errf) {
   int status;
   const TObject *err;
@@ -551,31 +542,11 @@ LUA_API int lua_pcall (lua_State *L, int nargs, int nresults, int errf) {
 }
 
 
-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 */
-  }
-  return status;
-}
-
-
-LUA_API int lua_dofile (lua_State *L, const char *filename) {
-  return aux_do(L, lua_loadfile(L, filename));
-}
-
-
-LUA_API int lua_dobuffer (lua_State *L, const char *buff, size_t size,
-                          const char *name) {
-  return aux_do(L, lua_loadbuffer(L, buff, size, name));
-}
-
-
-LUA_API int lua_dostring (lua_State *L, const char *str) {
-  return lua_dobuffer(L, str, strlen(str), str);
+static int errfile (lua_State *L, const char *filename) {
+  char buff[150];
+  sprintf(buff, "cannot read file `%.80s' (%.40s)", filename, strerror(errno));
+  lua_pushstring(L, buff);
+  return LUA_ERRFILE;
 }
 
 
@@ -585,12 +556,12 @@ LUA_API int lua_loadfile (lua_State *L, const char *filename) {
   int bin;  /* flag for file mode */
   int nlevel;  /* level on the stack of filename */
   FILE *f = (filename == NULL) ? stdin : fopen(filename, "r");
-  if (f == NULL) return LUA_ERRFILE;  /* unable to open file */
+  if (f == NULL) return errfile(L, filename);  /* unable to open file */
   bin = (ungetc(getc(f), f) == LUA_SIGNATURE[0]);
   if (bin && f != stdin) {
     fclose(f);
     f = fopen(filename, "rb");  /* reopen in binary mode */
-    if (f == NULL) return LUA_ERRFILE;  /* unable to reopen file */
+    if (f == NULL) return errfile(L, filename);  /* unable to reopen file */
   }
   if (filename == NULL)
     lua_pushstring(L, "=stdin");
@@ -603,7 +574,8 @@ LUA_API int lua_loadfile (lua_State *L, const char *filename) {
   filename = lua_tostring(L, -1);  /* filename = `@'..filename */
   luaZ_Fopen(&z, f, filename);
   status = luaD_protectedparser(L, &z, bin);
-  if (ferror(f)) status = LUA_ERRFILE;
+  if (ferror(f))
+    return errfile(L, filename);
   lua_remove(L, nlevel);  /* remove filename */
   if (f != stdin)
     fclose(f);
@@ -661,9 +633,10 @@ LUA_API void lua_setgcthreshold (lua_State *L, int newthreshold) {
 */
 
 
-LUA_API void lua_error (lua_State *L, const char *s) {
+LUA_API void lua_errorobj (lua_State *L) {
   lua_lock(L);
-  luaD_runerror(L, s);
+  api_checknelems(L, 1);
+  luaD_errorobj(L, L->top - 1, LUA_ERRRUN);
   lua_unlock(L);
 }
 
@@ -767,3 +740,62 @@ LUA_API int lua_pushupvalues (lua_State *L) {
 }
 
 
+
+/*
+** {======================================================
+** compatibility code
+** =======================================================
+*/
+
+
+static void callalert (lua_State *L, int status) {
+  if (status != 0) {
+    int top = lua_gettop(L);
+    lua_getglobal(L, "_ALERT");
+    lua_insert(L, -2);
+    lua_pcall(L, 1, 0, 0);
+    lua_settop(L, top-1);
+  }
+}
+
+
+LUA_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 */
+  }
+  callalert(L, status);
+  return status;
+}
+
+
+LUA_API int lua_dofile (lua_State *L, const char *filename) {
+  return aux_do(L, lua_loadfile(L, filename));
+}
+
+
+LUA_API int lua_dobuffer (lua_State *L, const char *buff, size_t size,
+                          const char *name) {
+  return aux_do(L, lua_loadbuffer(L, buff, size, name));
+}
+
+
+LUA_API int lua_dostring (lua_State *L, const char *str) {
+  return lua_dobuffer(L, str, strlen(str), str);
+}
+
+/* }====================================================== */

+ 2 - 14
lauxlib.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lauxlib.c,v 1.65 2002/04/04 20:25:55 roberto Exp roberto $
+** $Id: lauxlib.c,v 1.66 2002/04/16 12:00:02 roberto Exp roberto $
 ** Auxiliary functions for building Lua libraries
 ** See Copyright Notice in lua.h
 */
@@ -21,19 +21,6 @@
 #include "lualib.h"
 
 
-LUALIB_API const char *luaL_errstr (int errcode) {
-  static const char *const errstr[] = {
-    "ok",
-    "run-time error",
-    "cannot read file",
-    "syntax error",
-    "not enough memory",
-    "error in error handling"
-  };
-  return errstr[errcode];
-}
-
-
 LUALIB_API int luaL_findstring (const char *name, const char *const list[]) {
   int i;
   for (i=0; list[i]; i++)
@@ -42,6 +29,7 @@ LUALIB_API int luaL_findstring (const char *name, const char *const list[]) {
   return -1;  /* name not found */
 }
 
+
 LUALIB_API void luaL_argerror (lua_State *L, int narg, const char *extramsg) {
   lua_Debug ar;
   lua_getstack(L, 0, &ar);

+ 1 - 3
lauxlib.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lauxlib.h,v 1.43 2002/03/20 12:54:08 roberto Exp roberto $
+** $Id: lauxlib.h,v 1.44 2002/04/02 20:42:49 roberto Exp roberto $
 ** Auxiliary functions for building Lua libraries
 ** See Copyright Notice in lua.h
 */
@@ -52,8 +52,6 @@ LUALIB_API int luaL_findstring (const char *name,
 LUALIB_API int luaL_ref (lua_State *L, int t);
 LUALIB_API void luaL_unref (lua_State *L, int t, int ref);
 
-/* error messages corresponding to error codes */
-LUALIB_API const char *luaL_errstr (int errcode);
 
 
 /*

+ 44 - 96
lbaselib.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lbaselib.c,v 1.68 2002/04/15 20:54:41 roberto Exp roberto $
+** $Id: lbaselib.c,v 1.69 2002/04/22 14:40:23 roberto Exp roberto $
 ** Basic library
 ** See Copyright Notice in lua.h
 */
@@ -26,6 +26,7 @@
 */
 static int luaB__ALERT (lua_State *L) {
   fputs(luaL_check_string(L, 1), stderr);
+  putc('\n', stderr);
   return 0;
 }
 
@@ -35,26 +36,22 @@ static int luaB__ALERT (lua_State *L) {
 ** The library `liolib' redefines _ERRORMESSAGE for better error information.
 */
 static int luaB__ERRORMESSAGE (lua_State *L) {
+  lua_Debug ar;
   luaL_check_type(L, 1, LUA_TSTRING);
-  lua_getglobal(L, LUA_ALERT);
-  if (lua_isfunction(L, -1)) {  /* avoid error loop if _ALERT is not defined */
-    lua_Debug ar;
-    lua_pushliteral(L, "error: ");
-    lua_pushvalue(L, 1);
-    if (lua_getstack(L, 1, &ar)) {
-      lua_getinfo(L, "Sl", &ar);
-      if (ar.source && ar.currentline > 0) {
-        char buff[100];
-        sprintf(buff, "\n  <%.70s: line %d>", ar.short_src, ar.currentline);
-        lua_pushstring(L, buff);
-        lua_concat(L, 2);
-      }
+  lua_pushliteral(L, "error: ");
+  lua_pushvalue(L, 1);
+  if (lua_getstack(L, 1, &ar)) {
+    lua_getinfo(L, "Sl", &ar);
+    if (ar.source && ar.currentline > 0) {
+      char buff[100];
+      sprintf(buff, "\n  <%.70s: line %d>", ar.short_src, ar.currentline);
+      lua_pushstring(L, buff);
+      lua_concat(L, 2);
     }
-    lua_pushliteral(L, "\n");
-    lua_concat(L, 3);
-    lua_rawcall(L, 1, 0);
   }
-  return 0;
+  lua_pushliteral(L, "\n");
+  lua_concat(L, 3);
+  return 1;
 }
 
 
@@ -114,7 +111,8 @@ static int luaB_tonumber (lua_State *L) {
 
 
 static int luaB_error (lua_State *L) {
-  lua_error(L, luaL_opt_string(L, 1, NULL));
+  lua_settop(L, 1);
+  lua_errorobj(L);
   return 0;  /* to avoid warnings */
 }
 
@@ -217,53 +215,27 @@ static int luaB_nexti (lua_State *L) {
 }
 
 
-static int passresults (lua_State *L, int status, int oldtop) {
-  if (status == 0) {
-    int nresults = lua_gettop(L) - oldtop;
-    if (nresults > 0)
-      return nresults;  /* results are already on the stack */
-    else {
-      lua_pushboolean(L, 1); /* at least one result to signal no errors */
-      return 1;
-    }
-  }
-  else {  /* error */
+static int passresults (lua_State *L, int status) {
+  if (status == 0) return 1;
+  else {
     lua_pushnil(L);
-    lua_pushstring(L, luaL_errstr(status));  /* error code */
+    lua_insert(L, -2);
     return 2;
   }
 }
 
 
-static int luaB_dostring (lua_State *L) {
-  int oldtop = lua_gettop(L);
-  size_t l;
-  const char *s = luaL_check_lstr(L, 1, &l);
-  const char *chunkname = luaL_opt_string(L, 2, s);
-  return passresults(L, lua_dobuffer(L, s, l, chunkname), oldtop);
-}
-
-
 static int luaB_loadstring (lua_State *L) {
-  int oldtop = lua_gettop(L);
   size_t l;
   const char *s = luaL_check_lstr(L, 1, &l);
   const char *chunkname = luaL_opt_string(L, 2, s);
-  return passresults(L, lua_loadbuffer(L, s, l, chunkname), oldtop);
-}
-
-
-static int luaB_dofile (lua_State *L) {
-  int oldtop = lua_gettop(L);
-  const char *fname = luaL_opt_string(L, 1, NULL);
-  return passresults(L, lua_dofile(L, fname), oldtop);
+  return passresults(L, lua_loadbuffer(L, s, l, chunkname));
 }
 
 
 static int luaB_loadfile (lua_State *L) {
-  int oldtop = lua_gettop(L);
   const char *fname = luaL_opt_string(L, 1, NULL);
-  return passresults(L, lua_loadfile(L, fname), oldtop);
+  return passresults(L, lua_loadfile(L, fname));
 }
 
 
@@ -276,53 +248,29 @@ static int luaB_assert (lua_State *L) {
 }
 
 
-static int aux_unpack (lua_State *L, int arg) {
+static int luaB_unpack (lua_State *L) {
   int n, i;
-  luaL_check_type(L, arg, LUA_TTABLE);
-  n = lua_getn(L, arg);
+  luaL_check_type(L, 1, LUA_TTABLE);
+  n = lua_getn(L, 1);
   luaL_check_stack(L, n+LUA_MINSTACK, "table too big to unpack");
   for (i=1; i<=n; i++)  /* push arg[1...n] */
-    lua_rawgeti(L, arg, i);
+    lua_rawgeti(L, 1, i);
   return n;
 }
 
 
-static int luaB_unpack (lua_State *L) {
-  return aux_unpack(L, 1);
-}
-
-
-static int luaB_call (lua_State *L) {
-  int oldtop;
-  const char *options = luaL_opt_string(L, 3, "");
-  int err = 0;  /* index of old error method */
+static int luaB_pcall (lua_State *L) {
   int status;
-  int n;
-  if (!lua_isnone(L, 4)) {  /* set new error method */
-    lua_getglobal(L, "_ERRORMESSAGE");
-    err = lua_gettop(L);  /* get index */
-    lua_pushvalue(L, 4);
-    lua_setglobal(L, "_ERRORMESSAGE");
-  }
-  oldtop = lua_gettop(L);  /* top before function-call preparation */
-  /* push function */
-  lua_pushvalue(L, 1);
-  n = aux_unpack(L, 2);  /* push arg[1...n] */
-  status = lua_call(L, n, LUA_MULTRET);
-  if (err != 0) {  /* restore old error method */
-    lua_pushvalue(L, err);
-    lua_setglobal(L, "_ERRORMESSAGE");
-  }
-  if (status != 0) {  /* error in call? */
-    if (strchr(options, 'x'))
-      lua_pushnil(L);  /* return nil to signal the error */
-    else
-      lua_error(L, NULL);  /* propagate error without additional messages */
-    return 1;
+  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 */
   }
-  if (strchr(options, 'p'))  /* pack results? */
-    lua_error(L, "obsolete option `p' in `call'");
-  return lua_gettop(L) - oldtop;  /* results are already on the stack */
 }
 
 
@@ -433,7 +381,9 @@ static int luaB_require (lua_State *L) {
   else {  /* must load it */
     while (status == LUA_ERRFILE && (path = nextpath(L, path)) != NULL) {
       composename(L);
-      status = lua_dofile(L, lua_tostring(L, -1));  /* try to load it */
+      status = lua_loadfile(L, lua_tostring(L, -1));  /* try to load it */
+      if (status == 0)
+        status = lua_pcall(L, 0, 0, 0);
       lua_settop(L, 3);  /* pop string and eventual results from dofile */
     }
   }
@@ -448,8 +398,8 @@ static int luaB_require (lua_State *L) {
       luaL_verror(L, "could not load package `%.20s' from path `%.200s'",
                   lua_tostring(L, 1), lua_tostring(L, 3));
     }
-    default: {  /* error loading package */
-      lua_error(L, NULL);
+    default: {
+      lua_error(L, "error loading package");
       return 0;  /* to avoid warnings */
     }
   }
@@ -474,13 +424,11 @@ static const luaL_reg base_funcs[] = {
   {"unpack", luaB_unpack},
   {"rawget", luaB_rawget},
   {"rawset", luaB_rawset},
-  {"call", luaB_call},
+  {"pcall", luaB_pcall},
   {"collectgarbage", luaB_collectgarbage},
   {"gcinfo", luaB_gcinfo},
   {"loadfile", luaB_loadfile},
   {"loadstring", luaB_loadstring},
-  {"dofile", luaB_dofile},
-  {"dostring", luaB_dostring},
   {"require", luaB_require},
   {NULL, NULL}
 };
@@ -497,7 +445,7 @@ static int luaB_resume (lua_State *L) {
   lua_State *co = (lua_State *)lua_getfrombox(L, lua_upvalueindex(1));
   lua_settop(L, 0);
   if (lua_resume(L, co) != 0)
-    lua_error(L, "error running co-routine");
+    lua_errorobj(L);
   return lua_gettop(L);
 }
 

+ 2 - 8
ldblib.c

@@ -1,5 +1,5 @@
 /*
-** $Id: ldblib.c,v 1.47 2002/04/09 19:48:08 roberto Exp roberto $
+** $Id: ldblib.c,v 1.48 2002/04/22 14:40:50 roberto Exp roberto $
 ** Interface from Lua to its debug API
 ** See Copyright Notice in lua.h
 */
@@ -189,7 +189,6 @@ static int errorfb (lua_State *L) {
   lua_Debug ar;
   luaL_Buffer b;
   luaL_buffinit(L, &b);
-  luaL_addstring(&b, "error: ");
   luaL_addstring(&b, luaL_check_string(L, 1));
   luaL_addstring(&b, "\n");
   while (lua_getstack(L, level++, &ar)) {
@@ -243,12 +242,7 @@ static int errorfb (lua_State *L) {
     luaL_addstring(&b, "\n");
   }
   luaL_pushresult(&b);
-  lua_getglobal(L, LUA_ALERT);
-  if (lua_isfunction(L, -1)) {  /* avoid loop if _ALERT is not defined */
-    lua_pushvalue(L, -2);  /* error message */
-    lua_rawcall(L, 1, 0);
-  }
-  return 0;
+  return 1;
 }
 
 

+ 59 - 31
ldo.c

@@ -1,12 +1,11 @@
 /*
-** $Id: ldo.c,v 1.171 2002/04/16 17:08:28 roberto Exp roberto $
+** $Id: ldo.c,v 1.172 2002/04/22 14:40:50 roberto Exp roberto $
 ** Stack and Call structure of Lua
 ** See Copyright Notice in lua.h
 */
 
 
 #include <setjmp.h>
-#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
@@ -38,7 +37,7 @@ struct lua_longjmp {
   jmp_buf b;
   int allowhooks;  /* `allowhook' state when protection was set */
   volatile int status;  /* error code */
-  TObject err;  /* function to be called in case of errors */
+  TObject *err;  /* error function -> message (start of `ud') */
 };
 
 
@@ -110,7 +109,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, NULL, LUA_ERRERR);  /* break run without error message */
+    luaD_error(L, "error in error handling", LUA_ERRERR);
   else {
     luaD_reallocCI(L, 2*L->size_ci);
     if (L->size_ci > LUA_MAXCALLS)
@@ -303,7 +302,12 @@ static void move_results (lua_State *L, TObject *from, TObject *to) {
 }
 
 
-static void resume (lua_State *L, void *numres) {
+struct ResS {
+  TObject err;
+  int numres;
+};
+
+static void resume (lua_State *L, void *ud) {
   StkId firstResult;
   CallInfo *ci = L->ci;
   if (ci->savedpc != ci_func(ci)->l.p->code) {  /* not first time? */
@@ -316,9 +320,9 @@ static void resume (lua_State *L, void *numres) {
   }
   firstResult = luaV_execute(L);
   if (firstResult == NULL)   /* yield? */
-    *(int *)numres = L->ci->yield_results;
+    cast(struct ResS *, ud)->numres = L->ci->yield_results;
   else {  /* return */
-    *(int *)numres = L->top - firstResult;
+    cast(struct ResS *, ud)->numres = L->top - firstResult;
     luaD_poscall(L, LUA_MULTRET, firstResult);  /* finalize this coroutine */
   }
 }
@@ -326,8 +330,7 @@ static void resume (lua_State *L, void *numres) {
 
 LUA_API int lua_resume (lua_State *L, lua_State *co) {
   CallInfo *ci;
-  int numres;
-  TObject o;
+  struct ResS ud;
   int status;
   lua_lock(L);
   ci = co->ci;
@@ -335,11 +338,17 @@ LUA_API int lua_resume (lua_State *L, lua_State *co) {
     luaD_runerror(L, "thread is dead - cannot be resumed");
   if (co->errorJmp != NULL)  /* ?? */
     luaD_runerror(L, "thread is active - cannot be resumed");
-  setsvalue(&o, luaS_newliteral(L, "_ERRORMESSAGE"));
-  luaV_gettable(L, gt(L), &o, &o);
-  status = luaD_runprotected(co, resume, &o, &numres);
+  if (L->errorJmp) {
+    setobj(&ud.err, L->errorJmp->err);
+  }
+  else
+    setnilvalue(&ud.err);
+  status = luaD_runprotected(co, resume, &ud.err);
   if (status == 0)  
-    move_results(L, co->top - numres, co->top);
+    move_results(L, co->top - ud.numres, co->top);
+  else {
+    setobj(L->top++, &ud.err);
+}
   lua_unlock(L);
   return status;
 }
@@ -361,6 +370,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... */
   StkId func;
   int nresults;
 };
@@ -377,10 +387,12 @@ int luaD_pcall (lua_State *L, int nargs, int nresults, const TObject *err) {
   int status;
   c.func = L->top - (nargs+1);  /* function to be called */
   c.nresults = nresults;
-  status = luaD_runprotected(L, &f_call, err, &c);
+  c.err = *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);
   }
   return status;
 }
@@ -390,6 +402,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... */
   ZIO *z;
   int bin;
 };
@@ -406,7 +419,6 @@ static void f_parser (lua_State *L, void *ud) {
 
 int luaD_protectedparser (lua_State *L, ZIO *z, int bin) {
   struct SParser p;
-  TObject o;
   lu_mem old_blocks;
   int status;
   lua_lock(L);
@@ -415,16 +427,18 @@ int luaD_protectedparser (lua_State *L, ZIO *z, int bin) {
   if (G(L)->nblocks/8 >= G(L)->GCthreshold/10)
     luaC_collectgarbage(L);
   old_blocks = G(L)->nblocks;
-  setsvalue(&o, luaS_newliteral(L, "_ERRORMESSAGE"));
-  luaV_gettable(L, gt(L), &o, &o);
-  status = luaD_runprotected(L, f_parser, &o, &p);
+  setnilvalue(&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 if (status == LUA_ERRRUN)  /* an error occurred: correct error code */
-    status = LUA_ERRSYNTAX;
+  else {
+    setobj(L->top++, &p.err);
+    if (status == LUA_ERRRUN)  /* an error occurred: correct error code */
+      status = LUA_ERRSYNTAX;
+  }
   lua_unlock(L);
   return status;
 }
@@ -438,14 +452,18 @@ int luaD_protectedparser (lua_State *L, ZIO *z, int bin) {
 */
 
 
-static void message (lua_State *L, const char *msg) {
-  TObject *m = &L->errorJmp->err;
-  if (ttype(m) == LUA_TFUNCTION) {
+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);
     incr_top(L);
-    setsvalue(L->top, luaS_new(L, msg));
+    setobj(L->top, msg);
     incr_top(L);
-    luaD_call(L, L->top - 2, 0);
+    luaD_call(L, L->top - 2, 1);
+    setobj(m, L->top - 1);
   }
 }
 
@@ -453,10 +471,10 @@ static void message (lua_State *L, const char *msg) {
 /*
 ** Reports an error, and jumps up to the available recovery label
 */
-void luaD_error (lua_State *L, const char *s, int errcode) {
+void luaD_errorobj (lua_State *L, const TObject *s, int errcode) {
   if (L->errorJmp) {
     L->errorJmp->status = errcode;
-    if (s) message(L, s);
+    message(L, s, (errcode >= LUA_ERRMEM));
     longjmp(L->errorJmp->b, 1);
   }
   else {
@@ -466,24 +484,34 @@ void luaD_error (lua_State *L, const char *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);
+}
+
+
 void luaD_runerror (lua_State *L, const char *s) {
   luaD_error(L, s, LUA_ERRRUN);
 }
 
 
-int luaD_runprotected (lua_State *L, Pfunc f, const TObject *err, void *ud) {
+int luaD_runprotected (lua_State *L, Pfunc f, TObject *ud) {
   struct lua_longjmp lj;
   lj.ci = L->ci;
   lj.top = L->top;
   lj.allowhooks = L->allowhooks;
   lj.status = 0;
-  lj.err = *err;
+  lj.err = ud;
   lj.previous = L->errorJmp;  /* chain new error handler */
   L->errorJmp = &lj;
   if (setjmp(lj.b) == 0)
     (*f)(L, ud);
-  else {  /* an error occurred: restore the state */
-    L->ci = lj.ci;
+  else {  /* an error occurred */
+    L->ci = lj.ci;  /* restore the state */
     L->top = lj.top;
     L->allowhooks = lj.allowhooks;
     restore_stack_limit(L);

+ 3 - 2
ldo.h

@@ -1,5 +1,5 @@
 /*
-** $Id: ldo.h,v 1.42 2002/03/25 17:47:14 roberto Exp roberto $
+** $Id: ldo.h,v 1.43 2002/04/22 14:40:50 roberto Exp roberto $
 ** Stack and Call structure of Lua
 ** See Copyright Notice in lua.h
 */
@@ -42,8 +42,9 @@ 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_runerror (lua_State *L, const char *s);
-int luaD_runprotected (lua_State *L, Pfunc f, const TObject *err, void *ud);
+int luaD_runprotected (lua_State *L, Pfunc f, TObject *ud);
 
 
 #endif

+ 2 - 2
lmem.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lmem.c,v 1.52 2001/11/28 20:13:13 roberto Exp roberto $
+** $Id: lmem.c,v 1.53 2002/04/22 14:40:23 roberto Exp roberto $
 ** Interface to Memory Manager
 ** See Copyright Notice in lua.h
 */
@@ -58,7 +58,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, NULL, LUA_ERRMEM);  /* break run without error message */
+        luaD_error(L, MEMERRMSG, LUA_ERRMEM);
       else return NULL;  /* error before creating state! */
     }
   }

+ 4 - 1
lmem.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lmem.h,v 1.24 2001/09/07 17:30:16 roberto Exp $
+** $Id: lmem.h,v 1.25 2001/11/28 20:13:13 roberto Exp roberto $
 ** Interface to Memory Manager
 ** See Copyright Notice in lua.h
 */
@@ -13,6 +13,9 @@
 #include "llimits.h"
 #include "lua.h"
 
+#define MEMERRMSG	"not enough memory"
+
+
 void *luaM_realloc (lua_State *L, void *oldblock, lu_mem oldsize, lu_mem size);
 
 void *luaM_growaux (lua_State *L, void *block, int *size, int size_elem,

+ 6 - 2
lstate.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lstate.c,v 1.90 2002/04/22 14:40:23 roberto Exp roberto $
+** $Id: lstate.c,v 1.91 2002/04/23 15:04:39 roberto Exp roberto $
 ** Global State
 ** See Copyright Notice in lua.h
 */
@@ -57,6 +57,7 @@ static void f_luaopen (lua_State *L, void *ud) {
   UNUSED(ud);
   /* create a new global state */
   L->l_G = luaM_new(L, global_State);
+  G(L)->GCthreshold = 0;  /* mark it as unfinished state */
   G(L)->strt.size = 0;
   G(L)->strt.nuse = 0;
   G(L)->strt.hash = NULL;
@@ -83,6 +84,7 @@ static void f_luaopen (lua_State *L, void *ud) {
   luaS_resize(L, MINSTRTABSIZE);  /* initial size of string table */
   luaT_init(L);
   luaX_init(L);
+  luaS_fix(luaS_newliteral(L, MEMERRMSG));
   G(L)->GCthreshold = 4*G(L)->nblocks;
 }
 
@@ -122,12 +124,14 @@ LUA_API lua_State *lua_newthread (lua_State *OL) {
 
 LUA_API lua_State *lua_open (void) {
   lua_State *L;
+  TObject dummy;
+  setnilvalue(&dummy);
   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, &luaO_nilobject, NULL) != 0) {
+    if (luaD_runprotected(L, f_luaopen, &dummy) != 0) {
       /* memory allocation error: free partial state */
       close_state(L);
       L = NULL;

+ 6 - 2
ltests.c

@@ -1,5 +1,5 @@
 /*
-** $Id: ltests.c,v 1.116 2002/04/05 18:54:31 roberto Exp roberto $
+** $Id: ltests.c,v 1.117 2002/04/24 20:07:46 roberto Exp roberto $
 ** Internal Module for Debugging of the Lua Implementation
 ** See Copyright Notice in lua.h
 */
@@ -383,7 +383,11 @@ static int udataval (lua_State *L) {
 
 static int doonnewstack (lua_State *L) {
   lua_State *L1 = lua_newthread(L);
-  int status = lua_dostring(L1, luaL_check_string(L, 1));
+  size_t l;
+  const char *s = luaL_check_lstr(L, 1, &l);
+  int status = lua_loadbuffer(L1, s, l, s);
+  if (status == 0)
+    status = lua_pcall(L1, 0, 0, 0);
   lua_pushnumber(L, status);
   lua_closethread(L, L1);
   return 1;

+ 68 - 79
lua.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lua.c,v 1.83 2002/04/22 14:40:50 roberto Exp roberto $
+** $Id: lua.c,v 1.84 2002/04/23 14:59:22 roberto Exp roberto $
 ** Lua stand-alone interpreter
 ** See Copyright Notice in lua.h
 */
@@ -66,23 +66,30 @@ static void laction (int i) {
 }
 
 
-/* Lua gives no message in such cases, so we provide one */
-static void report (int result) {
-  if (result == LUA_ERRMEM || result == LUA_ERRERR)
-    fprintf(stderr, "%s: %s\n", LUA_PROGNAME, luaL_errstr(result));
+static void report (int status) {
+  if (status == 0) return;
+  else {
+    const char *msg = lua_tostring(L, -1);
+    if (msg == NULL) msg = "(no message)";
+    fprintf(stderr, "error: %s\n", msg);
+    lua_pop(L, 1);
+  }
 }
 
 
-static int ldo (int (*f)(lua_State *l, const char *), const char *name,
-                int clear) {
-  int result;
+static int lcall (int clear) {
+  int status;
   int top = lua_gettop(L);
+  lua_getglobal(L, "_ERRORMESSAGE");
+  lua_insert(L, top);
   signal(SIGINT, laction);
-  result = f(L, name);  /* dostring | dofile */
+  status = lua_pcall(L, 0, LUA_MULTRET, top);
   signal(SIGINT, SIG_DFL);
-  if (clear) lua_settop(L, top);  /* remove eventual results */
-  report(result);
-  return result;
+  if (status == 0) {
+    if (clear) lua_settop(L, top);  /* remove eventual results */
+    else lua_remove(L, top);  /* else remove only error function */
+  }
+  return status;
 }
 
 
@@ -138,16 +145,18 @@ static int l_getargs (lua_State *l) {
 
 
 static int file_input (const char *name) {
-  int result = ldo(lua_dofile, name, 1);
-  if (result) {
-    if (result == LUA_ERRFILE) {
-      fprintf(stderr, "%s: %s ", LUA_PROGNAME, luaL_errstr(result));
-      perror(name);
-    }
-    return EXIT_FAILURE;
-  }
-  else
-    return EXIT_SUCCESS;
+  int status = lua_loadfile(L, name);
+  if (status == 0) status = lcall(1);
+  report(status);
+  return status;
+}
+
+
+static int dostring (const char *s) {
+  int status = lua_loadbuffer(L, s, strlen(s), s);
+  if (status == 0) status = lcall(1);
+  report(status);
+  return status;
 }
 
 
@@ -177,85 +186,65 @@ static char *readline (const char *prompt) {
 #endif
 
 
-static const char *get_prompt (int incomplete) {
+static const char *get_prompt (int firstline) {
   const char *p = NULL;
-  lua_getglobal(L, incomplete ? "_PROMPT2" : "_PROMPT");
+  lua_getglobal(L, firstline ? "_PROMPT" : "_PROMPT2");
   p = lua_tostring(L, -1);
-  if (p == NULL) p = (incomplete ? PROMPT2 : PROMPT);
+  if (p == NULL) p = (firstline ? PROMPT : PROMPT2);
   lua_pop(L, 1);  /* remove global */
   return p;
 }
 
 
-static int incomplete = 0;
-
-static int trap_eof (lua_State *l) {
- const char *s = lua_tostring(l, 1);
- if (strstr(s, "last token read: `<eof>'") != NULL)
-   incomplete = 1;
- else
-   fprintf(stderr, "error: %s\n", s);
- return 0;
+static int incomplete (int status) {
+  if (status == LUA_ERRSYNTAX &&
+         strstr(lua_tostring(L, -1), "last token read: `<eof>'") != NULL) {
+    lua_pop(L, 1);
+    return 1;
+  }
+  else
+    return 0;
 }
 
 
 static int load_string (void) {
-  lua_getglobal(L, "_ERRORMESSAGE");
-  lua_pushvalue(L, 1);
-  lua_setglobal(L, "_ERRORMESSAGE");
-  incomplete = 0;
-  for (;;) {  /* repeat until gets a complete line */
-    int result;
-    char *buffer = readline(get_prompt(incomplete));
+  int firstline = 1;
+  int status;
+  lua_settop(L, 0);
+  do {  /* repeat until gets a complete line */
+    char *buffer = readline(get_prompt(firstline));
     if (buffer == NULL) {  /* input end? */
-      lua_settop(L, 2);
-      lua_setglobal(L, "_ERRORMESSAGE");
-      return 0;
+      lua_settop(L, 0);
+      return -1;  /* input end */
     }
-    if (!incomplete && buffer[0] == '=') {
+    if (firstline && buffer[0] == '=') {
       buffer[0] = ' ';
       lua_pushstring(L, "return");
     }
+    firstline = 0;
     push_line(buffer);
-    lua_concat(L, lua_gettop(L)-2);
-    incomplete = 0;
-    result = lua_loadbuffer(L, lua_tostring(L, 3), lua_strlen(L, 3), "=stdin");
-    if (incomplete) continue;  /* repeat loop to get rest of `line' */
-    save_line(lua_tostring(L, 3));
-    lua_remove(L, 3);
-    if (result == 0) {
-      lua_insert(L, 2);  /* swap compiled chunk with old _ERRORMESSAGE */
-      lua_setglobal(L, "_ERRORMESSAGE");  /* restore old _ERRORMESSAGE */
-      return 1;
-    }
-    else
-      report(result);
- }
-}
-
-
-static int lcall (lua_State *l, const char *name) {
-  (void)name;  /* to avoid warnings */
-  return lua_call(l, 0, LUA_MULTRET);
+    lua_concat(L, lua_gettop(L));
+    status = lua_loadbuffer(L, lua_tostring(L, 1), lua_strlen(L, 1), "=stdin");
+  } while (incomplete(status));  /* repeat loop to get rest of `line' */
+  save_line(lua_tostring(L, 1));
+  lua_remove(L, 1);
+  return status;
 }
 
 
 static void manual_input (int version) {
+  int status;
   if (version) print_version();
-  lua_settop(L, 0);
-  lua_pushcfunction(L, trap_eof);  /* set up handler for incomplete lines */
-  while (load_string()) {
-    ldo(lcall, NULL, 0);
-    if (lua_gettop(L) > 1) {  /* any result to print? */
+  while ((status = load_string()) != -1) {
+    if (status == 0) status = lcall(0);
+    report(status);
+    if (status == 0 && lua_gettop(L) > 0) {  /* any result to print? */
       lua_getglobal(L, "print");
-      lua_insert(L, 2);
-      lua_call(L, lua_gettop(L)-2, 0);
+      lua_insert(L, 1);
+      lua_call(L, lua_gettop(L)-1, 0);
     }
-    else
-      lua_settop(L, 1);  /* remove eventual results */
   }
   printf("\n");
-  lua_pop(L, 1);  /* remove trap_eof */
 }
 
 
@@ -265,7 +254,7 @@ static int handle_argv (char *argv[], int *toclose) {
       manual_input(1);
     }
     else
-      ldo(lua_dofile, NULL, 1);  /* executes stdin as a file */
+      file_input(NULL);  /* executes stdin as a file */
   }
   else {  /* other arguments; loop over them */
     int i;
@@ -274,12 +263,12 @@ static int handle_argv (char *argv[], int *toclose) {
         if (strchr(argv[i], '='))
           assign(argv[i]);
         else
-          if (file_input(argv[i]) != EXIT_SUCCESS)
+          if (file_input(argv[i]))
             return EXIT_FAILURE;  /* stop if file fails */
         }
         else switch (argv[i][1]) {  /* option */
           case '\0': {
-            ldo(lua_dofile, NULL, 1);  /* executes stdin as a file */
+            file_input(NULL);  /* executes stdin as a file */
             break;
           }
           case 'i': {
@@ -300,7 +289,7 @@ static int handle_argv (char *argv[], int *toclose) {
               print_usage();
               return EXIT_FAILURE;
             }
-            if (ldo(lua_dostring, argv[i], 1) != 0) {
+            if (dostring(argv[i]) != 0) {
               fprintf(stderr, "%s: error running argument `%.99s'\n",
                       LUA_PROGNAME, argv[i]);
               return EXIT_FAILURE;

+ 11 - 9
lua.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lua.h,v 1.128 2002/04/22 14:40:23 roberto Exp roberto $
+** $Id: lua.h,v 1.129 2002/05/01 20:40:42 roberto Exp roberto $
 ** Lua - An Extensible Extension Language
 ** TeCGraf: Grupo de Tecnologia em Computacao Grafica, PUC-Rio, Brazil
 ** e-mail: [email protected]
@@ -35,7 +35,7 @@
 #define lua_upvalueindex(i)	(LUA_GLOBALSINDEX-(i))
 
 
-/* error codes for `lua_do*' and the like */
+/* error codes for `lua_load*' and `lua_pcall' */
 #define LUA_ERRRUN	1
 #define LUA_ERRFILE	2
 #define LUA_ERRSYNTAX	3
@@ -166,18 +166,13 @@ LUA_API void  lua_setmetatable (lua_State *L, int objindex);
 
 
 /*
-** `load' and `do' functions (load and run Lua code)
+** `load' and `call' functions (load and run Lua code)
 */
-LUA_API int   lua_call (lua_State *L, int nargs, int nresults);
 LUA_API void  lua_rawcall (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_loadfile (lua_State *L, const char *filename);
 LUA_API int   lua_loadbuffer (lua_State *L, const char *buff, size_t size,
-                            const char *name);
-LUA_API int   lua_dofile (lua_State *L, const char *filename);
-LUA_API int   lua_dostring (lua_State *L, const char *str);
-LUA_API int   lua_dobuffer (lua_State *L, const char *buff, size_t size,
-                            const char *name);
+                              const char *name);
 
 
 /*
@@ -243,10 +238,17 @@ LUA_API void *lua_newuserdata (lua_State *L, size_t size);
                                                 (sizeof(s)/sizeof(char))-1)
 
 
+
 /*
 ** compatibility macros and functions
 */
 
+LUA_API int   lua_call (lua_State *L, int nargs, int nresults);
+LUA_API int   lua_dofile (lua_State *L, const char *filename);
+LUA_API int   lua_dostring (lua_State *L, const char *str);
+LUA_API int   lua_dobuffer (lua_State *L, const char *buff, size_t size,
+                            const char *name);
+
 LUA_API int lua_pushupvalues (lua_State *L);
 
 #define lua_getregistry(L)	lua_pushvalue(L, LUA_REGISTRYINDEX)