Browse Source

new way to handle errors

Roberto Ierusalimschy 23 năm trước cách đây
mục cha
commit
751cd867d3
13 tập tin đã thay đổi với 283 bổ sung292 xóa
  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)