Browse Source

new implementation for error handling: on error, function _ERRORMESSAGE

is called, which in turn calls _ALERT to write a message to stderr.
v5-2
Roberto Ierusalimschy 27 years ago
parent
commit
cc117253c8
  1. 17
      lapi.c
  2. 19
      lbuiltin.c
  3. 33
      ldo.c
  4. 87
      liolib.c
  5. 3
      lstate.h
  6. 4
      ltm.c
  7. 7
      lua.h
  8. 99
      manual.tex

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

19
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}
};

33
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);
}
}

87
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();
}

3
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 */

4
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--)

7
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

99
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}

Loading…
Cancel
Save