From 751cd867d3e0338279fa6f3390c8b7ddc0108659 Mon Sep 17 00:00:00 2001 From: Roberto Ierusalimschy Date: Wed, 1 May 2002 17:48:12 -0300 Subject: [PATCH] new way to handle errors --- lapi.c | 118 ++++++++++++++++++++++++++---------------- lauxlib.c | 16 +----- lauxlib.h | 4 +- lbaselib.c | 140 ++++++++++++++++---------------------------------- ldblib.c | 10 +--- ldo.c | 90 +++++++++++++++++++++----------- ldo.h | 5 +- lmem.c | 4 +- lmem.h | 5 +- lstate.c | 8 ++- ltests.c | 8 ++- lua.c | 147 +++++++++++++++++++++++++---------------------------- lua.h | 20 ++++---- 13 files changed, 283 insertions(+), 292 deletions(-) diff --git a/lapi.c b/lapi.c index 4eeada6c..42ed4a82 100644 --- a/lapi.c +++ b/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 +#include #include #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); +} + +/* }====================================================== */ diff --git a/lauxlib.c b/lauxlib.c index d0df881e..46454d83 100644 --- a/lauxlib.c +++ b/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); diff --git a/lauxlib.h b/lauxlib.h index 6af70d44..6affc407 100644 --- a/lauxlib.h +++ b/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); /* diff --git a/lbaselib.c b/lbaselib.c index d6168294..6ec250cb 100644 --- a/lbaselib.c +++ b/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"); + 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 */ } - 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; - } - 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); } diff --git a/ldblib.c b/ldblib.c index c38cf419..4e565256 100644 --- a/ldblib.c +++ b/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; } diff --git a/ldo.c b/ldo.c index c89d3a3c..4dfb7d9e 100644 --- a/ldo.c +++ b/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 -#include #include #include @@ -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); diff --git a/ldo.h b/ldo.h index 5464e544..0c4dfbca 100644 --- a/ldo.h +++ b/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 diff --git a/lmem.c b/lmem.c index 435cceef..f3d4d309 100644 --- a/lmem.c +++ b/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! */ } } diff --git a/lmem.h b/lmem.h index bb0ba5a9..1c896571 100644 --- a/lmem.h +++ b/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, diff --git a/lstate.c b/lstate.c index 5360d343..bb568aa0 100644 --- a/lstate.c +++ b/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; diff --git a/ltests.c b/ltests.c index bd8469f3..b4d81ada 100644 --- a/ltests.c +++ b/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; diff --git a/lua.c b/lua.c index 5f050fc4..7508c4aa 100644 --- a/lua.c +++ b/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: `'") != 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: `'") != 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; diff --git a/lua.h b/lua.h index cb6cbaff..9ea98c11 100644 --- a/lua.h +++ b/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: info@lua.org @@ -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)