Jelajahi Sumber

new implementation for error handling: on error, function _ERRORMESSAGE
is called, which in turn calls _ALERT to write a message to stderr.

Roberto Ierusalimschy 27 tahun lalu
induk
melakukan
cc117253c8
8 mengubah file dengan 133 tambahan dan 136 penghapusan
  1. 8 9
      lapi.c
  2. 17 2
      lbuiltin.c
  3. 11 22
      ldo.c
  4. 44 43
      liolib.c
  5. 1 2
      lstate.h
  6. 1 3
      ltm.c
  7. 4 3
      lua.h
  8. 47 52
      manual.tex

+ 8 - 9
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;
 }
 
 

+ 17 - 2
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}
 };
 
 

+ 11 - 22
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);
   }
 }

+ 44 - 43
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();
 }

+ 1 - 2
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 */

+ 1 - 3
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--)

+ 4 - 3
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: [email protected]
@@ -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

+ 47 - 52
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}