From cc117253c83ec32d226a8f2226d5ca144804f873 Mon Sep 17 00:00:00 2001 From: Roberto Ierusalimschy Date: Fri, 21 Aug 1998 14:43:44 -0300 Subject: new implementation for error handling: on error, function _ERRORMESSAGE is called, which in turn calls _ALERT to write a message to stderr. --- lapi.c | 17 +++++------ lbuiltin.c | 19 ++++++++++-- ldo.c | 33 +++++++-------------- liolib.c | 87 +++++++++++++++++++++++++++--------------------------- lstate.h | 3 +- ltm.c | 4 +-- lua.h | 7 +++-- manual.tex | 99 +++++++++++++++++++++++++++++--------------------------------- 8 files changed, 133 insertions(+), 136 deletions(-) diff --git a/lapi.c b/lapi.c index c74cfba7..8747e67e 100644 --- a/lapi.c +++ b/lapi.c @@ -1,5 +1,5 @@ /* -** $Id: lapi.c,v 1.25 1998/06/05 22:17:44 roberto Exp roberto $ +** $Id: lapi.c,v 1.26 1998/07/12 16:16:02 roberto Exp roberto $ ** Lua API ** See Copyright Notice in lua.h */ @@ -29,9 +29,8 @@ char lua_ident[] = "$Lua: " LUA_VERSION " " LUA_COPYRIGHT " $\n" -TObject *luaA_Address (lua_Object o) -{ - return Address(o); +TObject *luaA_Address (lua_Object o) { + return (o != LUA_NOOBJECT) ? Address(o) : NULL; } @@ -150,12 +149,12 @@ lua_Object lua_settagmethod (int tag, char *event) } -lua_Object lua_seterrormethod (void) -{ - TObject temp = L->errorim; +lua_Object lua_seterrormethod (void) { + lua_Object temp; checkCparams(1); - L->errorim = *(--L->stack.top); - return put_luaObject(&temp); + temp = lua_getglobal("_ERRORMESSAGE"); + lua_setglobal("_ERRORMESSAGE"); + return temp; } diff --git a/lbuiltin.c b/lbuiltin.c index 43023e8e..58c9509c 100644 --- a/lbuiltin.c +++ b/lbuiltin.c @@ -1,5 +1,5 @@ /* -** $Id: lbuiltin.c,v 1.32 1998/06/29 18:24:06 roberto Exp roberto $ +** $Id: lbuiltin.c,v 1.33 1998/07/12 16:16:43 roberto Exp roberto $ ** Built-in functions ** See Copyright Notice in lua.h */ @@ -192,6 +192,19 @@ static void luaI_print (void) { } +static void luaB_message (void) { + fputs(luaL_check_string(1), stderr); +} + + +static void error_message (void) { + char buff[200]; + sprintf(buff, "lua error: %.180s\n", luaL_check_string(1)); + lua_pushstring(buff); + lua_call("_ALERT"); +} + + static void luaI_type (void) { lua_Object o = luaL_nonnullarg(1); @@ -568,6 +581,7 @@ static struct luaL_reg int_funcs[] = { {"copytagmethods", copytagmethods}, {"dostring", internaldostring}, {"error", luaI_error}, + {"_ERRORMESSAGE", error_message}, {"foreach", foreach}, {"foreachvar", foreachvar}, {"getglobal", getglobal}, @@ -588,7 +602,8 @@ static struct luaL_reg int_funcs[] = { {"tonumber", luaB_tonumber}, {"tostring", to_string}, {"tag", luatag}, - {"type", luaI_type} + {"type", luaI_type}, + {"_ALERT", luaB_message} }; diff --git a/ldo.c b/ldo.c index 20b769d8..9a07e7e1 100644 --- a/ldo.c +++ b/ldo.c @@ -1,5 +1,5 @@ /* -** $Id: ldo.c,v 1.27 1998/06/19 18:47:06 roberto Exp roberto $ +** $Id: ldo.c,v 1.28 1998/07/12 16:14:34 roberto Exp roberto $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ @@ -17,6 +17,7 @@ #include "lobject.h" #include "lparser.h" #include "lstate.h" +#include "lstring.h" #include "ltm.h" #include "lua.h" #include "luadebug.h" @@ -32,27 +33,13 @@ -/* -** Error messages -*/ - -static void stderrorim (void) -{ - fprintf(stderr, "lua error: %s\n", lua_getstring(lua_getparam(1))); -} - - - #define STACK_UNIT 128 -void luaD_init (void) -{ +void luaD_init (void) { L->stack.stack = luaM_newvector(STACK_UNIT, TObject); L->stack.top = L->stack.stack; L->stack.last = L->stack.stack+(STACK_UNIT-1); - ttype(&L->errorim) = LUA_T_CPROTO; - fvalue(&L->errorim) = stderrorim; } @@ -246,12 +233,13 @@ void luaD_travstack (int (*fn)(TObject *)) -static void message (char *s) -{ - TObject im = L->errorim; - if (ttype(&im) != LUA_T_NIL) { +static void message (char *s) { + TObject *em = &(luaS_new("_ERRORMESSAGE")->u.s.globalval); + if (ttype(em) != LUA_T_NIL) { + *L->stack.top = *em; + incr_top; lua_pushstring(s); - luaD_callTM(&im, 1, 0); + luaD_calln(1, 0); } } @@ -264,7 +252,8 @@ void lua_error (char *s) if (L->errorJmp) longjmp(*((jmp_buf *)L->errorJmp), 1); else { - fprintf (stderr, "lua: exit(1). Unable to recover\n"); + lua_pushstring("lua: exit(1). Unable to recover.\n"); + lua_call("_ALERT"); exit(1); } } diff --git a/liolib.c b/liolib.c index d252931c..0fbc425f 100644 --- a/liolib.c +++ b/liolib.c @@ -1,5 +1,5 @@ /* -** $Id: liolib.c,v 1.20 1998/06/05 22:17:44 roberto Exp roberto $ +** $Id: liolib.c,v 1.21 1998/06/18 17:04:28 roberto Exp roberto $ ** Standard I/O (and system) library ** See Copyright Notice in lua.h */ @@ -353,71 +353,75 @@ static void io_debug (void) } -static void lua_printstack (FILE *f) -{ +#define MESSAGESIZE 150 +#define MAXMESSAGE (MESSAGESIZE*10) + +static void errorfb (void) { + char buff[MAXMESSAGE]; int level = 1; /* skip level 0 (it's this function) */ lua_Object func; + sprintf(buff, "lua: %.200s\n", lua_getstring(lua_getparam(1))); while ((func = lua_stackedfunction(level++)) != LUA_NOOBJECT) { char *name; int currentline; - char *filename; + char *chunkname; int linedefined; - lua_funcinfo(func, &filename, &linedefined); - fprintf(f, (level==2) ? "Active Stack:\n\t" : "\t"); + lua_funcinfo(func, &chunkname, &linedefined); + strcat(buff, (level==2) ? "Active Stack:\n\t" : "\t"); + if (strlen(buff) > MAXMESSAGE-MESSAGESIZE) { + strcat(buff, "...\n"); + break; /* buffer is full */ + } switch (*lua_getobjname(func, &name)) { case 'g': - fprintf(f, "function %s", name); + sprintf(buff+strlen(buff), "function %.50s", name); break; case 't': - fprintf(f, "`%s' tag method", name); + sprintf(buff+strlen(buff), "`%.50s' tag method", name); break; default: { if (linedefined == 0) - fprintf(f, "main of %s", filename); + sprintf(buff+strlen(buff), "main of %.50s", chunkname); else if (linedefined < 0) - fprintf(f, "%s", filename); + sprintf(buff+strlen(buff), "%.50s", chunkname); else - fprintf(f, "function (%s:%d)", filename, linedefined); - filename = NULL; + sprintf(buff+strlen(buff), "function (%.50s:%d)", + chunkname, linedefined); + chunkname = NULL; } } if ((currentline = lua_currentline(func)) > 0) - fprintf(f, " at line %d", currentline); - if (filename) - fprintf(f, " [in file %s]", filename); - fprintf(f, "\n"); + sprintf(buff+strlen(buff), " at line %d", currentline); + if (chunkname) + sprintf(buff+strlen(buff), " [in chunk %.50s]", chunkname); + strcat(buff, "\n"); } -} - - -static void errorfb (void) -{ - fprintf(stderr, "lua: %s\n", lua_getstring(lua_getparam(1))); - lua_printstack(stderr); + lua_pushstring(buff); + lua_call("_ALERT"); } static struct luaL_reg iolib[] = { -{"setlocale", setloc}, -{"execute", io_execute}, -{"remove", io_remove}, -{"rename", io_rename}, -{"tmpname", io_tmpname}, -{"getenv", io_getenv}, -{"date", io_date}, -{"clock", io_clock}, -{"exit", io_exit}, -{"debug", io_debug}, -{"print_stack", errorfb} + {"setlocale", setloc}, + {"execute", io_execute}, + {"remove", io_remove}, + {"rename", io_rename}, + {"tmpname", io_tmpname}, + {"getenv", io_getenv}, + {"date", io_date}, + {"clock", io_clock}, + {"exit", io_exit}, + {"debug", io_debug}, + {"_ERRORMESSAGE", errorfb} }; static struct luaL_reg iolibtag[] = { -{"readfrom", io_readfrom}, -{"writeto", io_writeto}, -{"appendto", io_appendto}, -{"read", io_read}, -{"write", io_write} + {"readfrom", io_readfrom}, + {"writeto", io_writeto}, + {"appendto", io_appendto}, + {"read", io_read}, + {"write", io_write} }; static void openwithtags (void) @@ -439,10 +443,7 @@ static void openwithtags (void) setfile(stderr, "_STDERR", iotag); } -void lua_iolibopen (void) -{ +void lua_iolibopen (void) { luaL_openlib(iolib, (sizeof(iolib)/sizeof(iolib[0]))); openwithtags(); - lua_pushcfunction(errorfb); - lua_seterrormethod(); } diff --git a/lstate.h b/lstate.h index 129dc43b..41acf0b8 100644 --- a/lstate.h +++ b/lstate.h @@ -1,5 +1,5 @@ /* -** $Id: lstate.h,v 1.10 1998/06/19 16:14:09 roberto Exp roberto $ +** $Id: lstate.h,v 1.11 1998/06/24 13:33:00 roberto Exp roberto $ ** Global State ** See Copyright Notice in lua.h */ @@ -61,7 +61,6 @@ struct lua_State { struct C_Lua_Stack Cblocks[MAX_C_BLOCKS]; int numCblocks; /* number of nested Cblocks */ /* global state */ - TObject errorim; /* error tag method */ GCnode rootproto; /* list of all prototypes */ GCnode rootcl; /* list of all closures */ GCnode roottable; /* list of all tables */ diff --git a/ltm.c b/ltm.c index cc290dde..94e3d041 100644 --- a/ltm.c +++ b/ltm.c @@ -1,5 +1,5 @@ /* -** $Id: ltm.c,v 1.15 1998/03/11 13:59:50 roberto Exp roberto $ +** $Id: ltm.c,v 1.16 1998/06/18 16:57:03 roberto Exp roberto $ ** Tag methods ** See Copyright Notice in lua.h */ @@ -158,8 +158,6 @@ void luaT_settagmethod (int t, char *event, TObject *func) char *luaT_travtagmethods (int (*fn)(TObject *)) { int e; - if (fn(&L->errorim)) - return "error"; for (e=IM_GETTABLE; e<=IM_FUNCTION; e++) { /* ORDER IM */ int t; for (t=0; t>=L->last_tag; t--) diff --git a/lua.h b/lua.h index 477627ef..fa2baaf3 100644 --- a/lua.h +++ b/lua.h @@ -1,5 +1,5 @@ /* -** $Id: lua.h,v 1.22 1998/06/15 21:34:14 roberto Exp roberto $ +** $Id: lua.h,v 1.23 1998/06/18 16:51:53 roberto Exp roberto $ ** Lua - An Extensible Extension Language ** TeCGraf: Grupo de Tecnologia em Computacao Grafica, PUC-Rio, Brazil ** e-mail: lua@tecgraf.puc-rio.br @@ -11,7 +11,7 @@ #ifndef lua_h #define lua_h -#define LUA_VERSION "Lua 3.1" +#define LUA_VERSION "Lua 3.2 (alpha)" #define LUA_COPYRIGHT "Copyright (C) 1994-1998 TeCGraf, PUC-Rio" #define LUA_AUTHORS "W. Celes, R. Ierusalimschy & L. H. de Figueiredo" @@ -32,7 +32,6 @@ lua_State *lua_setstate (lua_State *st); lua_Object lua_settagmethod (int tag, char *event); /* In: new method */ lua_Object lua_gettagmethod (int tag, char *event); -lua_Object lua_seterrormethod (void); /* In: new method */ int lua_newtag (void); int lua_copytagmethods (int tagto, int tagfrom); @@ -125,6 +124,8 @@ int (lua_clonetag) (int t); #define lua_clonetag(t) lua_copytagmethods(lua_newtag(), (t)) +lua_Object lua_seterrormethod (void); /* In: new method */ + /* ========================================================================== ** for compatibility with old versions. Avoid using these macros/functions ** If your program does need any of these, define LUA_COMPAT2_5 diff --git a/manual.tex b/manual.tex index 50d4e67e..5f56593c 100644 --- a/manual.tex +++ b/manual.tex @@ -1,8 +1,10 @@ -% $Id: manual.tex,v 1.16 1998/06/19 18:47:06 roberto Exp roberto $ +% $Id: manual.tex,v 1.17 1998/06/29 18:09:28 roberto Exp roberto $ \documentclass[11pt]{article} \usepackage{fullpage,bnf} +\catcode`\_=12 + \newcommand{\See}[1]{Section~\ref{#1}} \newcommand{\see}[1]{(see \See{#1})} \newcommand{\M}[1]{\emph{#1}} @@ -19,7 +21,7 @@ \newcommand{\ff}{$\bullet$\ } -\newcommand{\Version}{3.1} +\newcommand{\Version}{3.2 (alpha)} \makeindex @@ -39,7 +41,7 @@ Waldemar Celes \tecgraf\ --- Computer Science Department --- PUC-Rio } -%\date{\small \verb$Date: 1998/06/19 18:47:06 $} +%\date{\small \verb$Date: 1998/06/29 18:09:28 $} \maketitle @@ -810,7 +812,7 @@ If the function is called in a place that can hold many values (syntactically denoted by the non-terminal \M{exp}), then no adjustment is made. Note that the only place that can hold many values -is the last expression (or the only one) in an assignment +is the last (or the only) expression in an assignment or in a return statement; see examples below. \begin{verbatim} f(); -- adjusted to 0 @@ -1263,22 +1265,20 @@ Because Lua is an extension language, all Lua actions start from C code in the host program calling a function from the Lua library. Whenever an error occurs during Lua compilation or execution, -the \Def{error method} is called, +function \verb|_ERRORMESSAGE| is called \Deffunc{_ERRORMESSAGE} +(provided it is different from \nil), and then the corresponding function from the library (\verb|lua_dofile|, \verb|lua_dostring|, \verb|lua_dobuffer|, or \verb|lua_callfunction|) is terminated, returning an error condition. -The only argument to the error method is a string +The only argument to \verb|_ERRORMESSAGE| is a string describing the error. -The default method prints this message to \verb|stderr|. -If needed, it is possible to change the error method with the -function \verb|seterrormethod|, -which gets the new error handler as its only parameter -\see{pdf-seterrormethod}. -The standard I/O library uses this facility to redefine the error method, -using the debug facilities \see{debugI}, -in order to print some extra information, +The default definition for this function calls \verb|_ALERT|, +which prints the message to \verb|stderr| \see{alert}. +The standard I/O library redefines \verb|_ERRORMESSAGE|, +and uses the debug facilities \see{debugI} +to print some extra information, such as the call stack. To provide more information about errors, @@ -1347,11 +1347,11 @@ For that, you must set \verb|lua_state| back to \verb|NULL| before calling \verb|lua_open|. An easy way to do that is defining an auxiliary function: \begin{verbatim} -lua_State *lua_newstate (void) { - lua_State *old = lua_setstate(NULL); - lua_open(); - return lua_setstate(old); -} + lua_State *lua_newstate (void) { + lua_State *old = lua_setstate(NULL); + lua_open(); + return lua_setstate(old); + } \end{verbatim} This function creates a new state without changing the current state of the interpreter. @@ -1373,14 +1373,14 @@ If \verb|lua_state| is already \verb|NULL|, \verb|lua_close| has no effect. If you are using multiple states, -you may find useful the following function, +you may find useful to define the following function, which releases a given state: \begin{verbatim} -void lua_freestate (lua_State *st) { - lua_State *old = lua_setstate(st); - lua_close(); - if (old != st) lua_setstate(old); -} + void lua_freestate (lua_State *st) { + lua_State *old = lua_setstate(st); + lua_close(); + if (old != st) lua_setstate(old); + } \end{verbatim} \subsection{Exchanging Values between C and Lua} \label{valuesCLua} @@ -1736,18 +1736,10 @@ If the C function has been called from Lua, then the corresponding Lua execution terminates, as if an error had occurred inside Lua code. Otherwise, the whole program terminates with a call to \verb|exit(1)|. -The \verb|message| is passed to the error handler method. +The \verb|message| is passed to the error handler function, +\verb|_ERRORMESSAGE|. If \verb|message| is \verb|NULL|, -the error handler method is not called. - -The error handler method \see{error} can be -changed with: \Deffunc{lua_seterrormethod} -\begin{verbatim} -lua_Object lua_seterrormethod (void); -\end{verbatim} -This function sets the object at the top of C2lua -as the new error method, -and returns the old error method value. +\verb|_ERRORMESSAGE| is not called. Tag methods can be changed with: \Deffunc{lua_settagmethod} \begin{verbatim} @@ -1885,7 +1877,7 @@ and \verb|lua_iolibopen|, declared in \verb|lualib.h|. \subsection{Predefined Functions} \label{predefined} -\subsubsection*{\ff \T{call (func, arg [, mode [, errmethod]])}}\Deffunc{call} +\subsubsection*{\ff \T{call (func, arg [, mode [, errhandler]])}}\Deffunc{call} \label{pdf-call} This function calls function \verb|func| with the arguments given by the table \verb|arg|. @@ -1917,14 +1909,15 @@ if an error occurs during the function call, the error is propagated. If the string \verb|mode| contains \verb|"x"|, then the call is \emph{protected}.\index{protected calls} -In this mode, function \verb|call| does not generate an error, +In this mode, function \verb|call| does not propagate an error, whatever happens during the call. Instead, it returns \nil\ to signal the error -(besides calling the appropriated error method). +(besides calling the appropriated error handler). -If provided, \verb|errmethod| is temporarily set as the error method, -while \verb|func| runs. -As a particular case, if \verb|errmethod| is \nil, +If provided, +\verb|errhandler| is temporarily set as the error function +\verb|_ERRORMESSAGE|, while \verb|func| runs. +As a particular example, if \verb|errhandler| is \nil, no error messages will be issued during the execution of the called function. \subsubsection*{\ff \T{collectgarbage ([limit])}}\Deffunc{collectgarbage} @@ -2055,9 +2048,16 @@ This function receives any number of arguments, and prints their values using the strings returned by \verb|tostring|. This function is not intended for formatted output, but only as a quick way to show a value, -for instance for error messages or debugging. +for instance for debugging. See \See{libio} for functions for formatted output. +\subsubsection*{\ff \T{_ALERT (message)}}\Deffunc{alert}\label{alert} +This function prints its only string argument to \IndexVerb{stderr}. +All error messages in Lua are printed through this function. +Therefore, a program may redefine it +to change the way such messages are shown +(for instance, for systems without \verb|stderr|). + \subsubsection*{\ff \T{tonumber (e [, base])}}\Deffunc{tonumber} This function receives one argument, and tries to convert it to a number. @@ -2164,13 +2164,6 @@ Its full semantics is explained in \See{tag-method}. The string \verb|name| does not need to be a syntactically valid variable name. -\subsubsection*{\ff \T{seterrormethod (newmethod)}} -\label{pdf-seterrormethod} -Sets the error handler \see{error}. -\verb|newmethod| must be a function or \nil, -in which case the error handler does nothing. -Returns the old error handler. - \subsubsection*{\ff \T{settagmethod (tag, event, newmethod)}} \Deffunc{settagmethod} This function sets a new tag method to the given pair \M{(tag, event)}. @@ -2930,7 +2923,7 @@ so any existing program that opens at least one standard library before calling Lua does not need to be modified. \item Function \verb|dostring| no longer accepts an optional second argument, -with a temporary error method. +with a temporary error handler. This facility is now provided by function \verb|call|. \item Function \verb|gsub| no longer accepts an optional fourth argument @@ -2951,8 +2944,10 @@ programs should use an explicit assignment instead, such as \end{itemize} +% restore underscore to usual meaning +\catcode`\_=8 + \newcommand{\indexentry}[2]{\item {#1} #2} -%\catcode`\_=12 \begin{theindex} \input{manual.id} \end{theindex} -- cgit v1.2.3-55-g6feb