lua

A copy of the Lua development repository
Log | Files | Refs | README

commit 014a09c5095be3ef11366530e4630ee817a526a7
parent b62228297372c7b24b6661ac1bdd7df2e8ece64e
Author: Roberto Ierusalimschy <roberto@inf.puc-rio.br>
Date:   Wed, 28 Jun 2000 17:20:44 -0300

better error messages

Diffstat:
Mlcode.c | 108+++++++++++++++++++++++++++++++++++++++----------------------------------------
Mlcode.h | 7+++++--
Mldebug.c | 148++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
Mldebug.h | 8++++----
Mldo.c | 8++++----
Mldo.h | 4++--
Mlobject.h | 8++++----
Mlparser.c | 8++++----
Mlparser.h | 3++-
Mlvm.c | 32++++++++++++++++----------------
10 files changed, 230 insertions(+), 104 deletions(-)

diff --git a/lcode.c b/lcode.c @@ -1,5 +1,5 @@ /* -** $Id: lcode.c,v 1.38 2000/06/21 18:13:56 roberto Exp roberto $ +** $Id: lcode.c,v 1.39 2000/06/26 19:28:31 roberto Exp roberto $ ** Code generator for Lua ** See Copyright Notice in lua.h */ @@ -423,12 +423,9 @@ int luaK_code1 (FuncState *fs, OpCode o, int arg1) { } -#define VD 100 /* flag for variable delta */ - - int luaK_code2 (FuncState *fs, OpCode o, int arg1, int arg2) { Instruction i = previous_instruction(fs); - int delta = luaK_opproperties[o].delta; + int delta = luaK_opproperties[o].push - luaK_opproperties[o].pop; int optm = 0; /* 1 when there is an optimization */ switch (o) { case OP_CLOSURE: { @@ -621,7 +618,7 @@ int luaK_code2 (FuncState *fs, OpCode o, int arg1, int arg2) { case iS: i = CREATE_S(o, arg1); break; case iAB: i = CREATE_AB(o, arg1, arg2); break; } - if (fs->f->debug) { + if (fs->debug) { LexState *ls = fs->ls; luaX_checklimit(ls, ls->lastline, MAXARG_U, "lines in a chunk"); luaM_growvector(fs->L, fs->f->lines, fs->pc, 1, int, "??", MAXARG_U); @@ -636,53 +633,54 @@ int luaK_code2 (FuncState *fs, OpCode o, int arg1, int arg2) { const struct OpProperties luaK_opproperties[NUM_OPCODES] = { - {iO, 0}, /* OP_END */ - {iU, 0}, /* OP_RETURN */ - {iAB, 0}, /* OP_CALL */ - {iAB, 0}, /* OP_TAILCALL */ - {iU, VD}, /* OP_PUSHNIL */ - {iU, VD}, /* OP_POP */ - {iS, 1}, /* OP_PUSHINT */ - {iU, 1}, /* OP_PUSHSTRING */ - {iU, 1}, /* OP_PUSHNUM */ - {iU, 1}, /* OP_PUSHNEGNUM */ - {iU, 1}, /* OP_PUSHUPVALUE */ - {iU, 1}, /* OP_GETLOCAL */ - {iU, 1}, /* OP_GETGLOBAL */ - {iO, -1}, /* OP_GETTABLE */ - {iU, 0}, /* OP_GETDOTTED */ - {iU, 0}, /* OP_GETINDEXED */ - {iU, 1}, /* OP_PUSHSELF */ - {iU, 1}, /* OP_CREATETABLE */ - {iU, -1}, /* OP_SETLOCAL */ - {iU, -1}, /* OP_SETGLOBAL */ - {iAB, VD}, /* OP_SETTABLE */ - {iAB, VD}, /* OP_SETLIST */ - {iU, VD}, /* OP_SETMAP */ - {iO, -1}, /* OP_ADD */ - {iS, 0}, /* OP_ADDI */ - {iO, -1}, /* OP_SUB */ - {iO, -1}, /* OP_MULT */ - {iO, -1}, /* OP_DIV */ - {iO, -1}, /* OP_POW */ - {iU, VD}, /* OP_CONCAT */ - {iO, 0}, /* OP_MINUS */ - {iO, 0}, /* OP_NOT */ - {iS, -2}, /* OP_JMPNE */ - {iS, -2}, /* OP_JMPEQ */ - {iS, -2}, /* OP_JMPLT */ - {iS, -2}, /* OP_JMPLE */ - {iS, -2}, /* OP_JMPGT */ - {iS, -2}, /* OP_JMPGE */ - {iS, -1}, /* OP_JMPT */ - {iS, -1}, /* OP_JMPF */ - {iS, -1}, /* OP_JMPONT */ - {iS, -1}, /* OP_JMPONF */ - {iS, 0}, /* OP_JMP */ - {iO, 1}, /* OP_PUSHNILJMP */ - {iS, 0}, /* OP_FORPREP */ - {iS, -3}, /* OP_FORLOOP */ - {iS, 3}, /* OP_LFORPREP */ - {iS, -4}, /* OP_LFORLOOP */ - {iAB, VD} /* OP_CLOSURE */ + {iO, 0, 0}, /* OP_END */ + {iU, 0, 0}, /* OP_RETURN */ + {iAB, 0, 0}, /* OP_CALL */ + {iAB, 0, 0}, /* OP_TAILCALL */ + {iU, VD, 0}, /* OP_PUSHNIL */ + {iU, VD, 0}, /* OP_POP */ + {iS, 1, 0}, /* OP_PUSHINT */ + {iU, 1, 0}, /* OP_PUSHSTRING */ + {iU, 1, 0}, /* OP_PUSHNUM */ + {iU, 1, 0}, /* OP_PUSHNEGNUM */ + {iU, 1, 0}, /* OP_PUSHUPVALUE */ + {iU, 1, 0}, /* OP_GETLOCAL */ + {iU, 1, 0}, /* OP_GETGLOBAL */ + {iO, 1, 2}, /* OP_GETTABLE */ + {iU, 1, 1}, /* OP_GETDOTTED */ + {iU, 1, 1}, /* OP_GETINDEXED */ + {iU, 2, 1}, /* OP_PUSHSELF */ + {iU, 1, 0}, /* OP_CREATETABLE */ + {iU, 0, 1}, /* OP_SETLOCAL */ + {iU, 0, 1}, /* OP_SETGLOBAL */ + {iAB, VD, 0}, /* OP_SETTABLE */ + {iAB, VD, 0}, /* OP_SETLIST */ + {iU, VD, 0}, /* OP_SETMAP */ + {iO, 1, 2}, /* OP_ADD */ + {iS, 1, 1}, /* OP_ADDI */ + {iO, 1, 2}, /* OP_SUB */ + {iO, 1, 2}, /* OP_MULT */ + {iO, 1, 2}, /* OP_DIV */ + {iO, 1, 2}, /* OP_POW */ + {iU, VD, 0}, /* OP_CONCAT */ + {iO, 1, 1}, /* OP_MINUS */ + {iO, 1, 1}, /* OP_NOT */ + {iS, 0, 2}, /* OP_JMPNE */ + {iS, 0, 2}, /* OP_JMPEQ */ + {iS, 0, 2}, /* OP_JMPLT */ + {iS, 0, 2}, /* OP_JMPLE */ + {iS, 0, 2}, /* OP_JMPGT */ + {iS, 0, 2}, /* OP_JMPGE */ + {iS, 0, 1}, /* OP_JMPT */ + {iS, 0, 1}, /* OP_JMPF */ + {iS, 0, 1}, /* OP_JMPONT */ + {iS, 0, 1}, /* OP_JMPONF */ + {iS, 0, 0}, /* OP_JMP */ + {iO, 1, 0}, /* OP_PUSHNILJMP */ + {iS, 0, 0}, /* OP_FORPREP */ + {iS, 0, 3}, /* OP_FORLOOP */ + {iS, 3, 0}, /* OP_LFORPREP */ + {iS, 0, 4}, /* OP_LFORLOOP */ + {iAB, VD, 0} /* OP_CLOSURE */ }; + diff --git a/lcode.h b/lcode.h @@ -1,5 +1,5 @@ /* -** $Id: lcode.h,v 1.13 2000/05/22 18:44:46 roberto Exp roberto $ +** $Id: lcode.h,v 1.14 2000/06/16 17:51:40 roberto Exp roberto $ ** Code generator for Lua ** See Copyright Notice in lua.h */ @@ -22,9 +22,12 @@ enum Mode {iO, iU, iS, iAB}; /* instruction format */ +#define VD 100 /* flag for variable delta */ + extern const struct OpProperties { char mode; - signed char delta; + unsigned char push; + unsigned char pop; } luaK_opproperties[]; diff --git a/ldebug.c b/ldebug.c @@ -1,5 +1,5 @@ /* -** $Id: ldebug.c,v 1.23 2000/06/12 13:52:05 roberto Exp roberto $ +** $Id: ldebug.c,v 1.24 2000/06/26 19:28:31 roberto Exp roberto $ ** Debug Interface ** See Copyright Notice in lua.h */ @@ -13,10 +13,12 @@ #include "lapi.h" #include "lauxlib.h" +#include "lcode.h" #include "ldebug.h" #include "ldo.h" #include "lfunc.h" #include "lobject.h" +#include "lopcodes.h" #include "lstate.h" #include "ltable.h" #include "ltm.h" @@ -97,6 +99,13 @@ static int lua_nups (StkId f) { } +static int lua_currentpc (StkId f) { + CallInfo *ci = infovalue(f); + LUA_ASSERT(L, ttype(f) == TAG_LMARK, "function has no pc"); + return (*ci->pc - 1) - ci->func->f.l->code; +} + + static int lua_currentline (StkId f) { if (ttype(f) != TAG_LMARK) return -1; /* only active lua functions have current-line information */ @@ -104,15 +113,11 @@ static int lua_currentline (StkId f) { CallInfo *ci = infovalue(f); int *lines = ci->func->f.l->lines; if (!lines) return -1; /* no static debug information */ - else return lines[ci->pc]; + else return lines[lua_currentpc(f)]; } } -static int lua_currentpc (StkId f) { - return infovalue(f)->pc; -} - static Proto *getluaproto (StkId f) { return (ttype(f) == TAG_LMARK) ? infovalue(f)->func->f.l : NULL; @@ -225,17 +230,136 @@ int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) { } +/* +** {====================================================== +** Symbolic Execution +** ======================================================= +*/ + +static Instruction luaG_symbexec (const Proto *pt, int lastpc, int stackpos) { + int stack[MAXSTACK]; /* stores last instruction that changes each value */ + const Instruction *code = pt->code; + int top = pt->numparams; + int pc = 0; + if (pt->is_vararg) /* varargs? */ + top++; /* `arg' */ + while (pc < lastpc) { + const Instruction i = code[pc++]; + switch (GET_OPCODE(i)) { + case OP_CALL: { + int nresults = GETARG_B(i); + if (nresults == MULT_RET) nresults = 1; + top = GETARG_A(i); + while (nresults--) + stack[top++] = pc-1; + break; + } + case OP_PUSHNIL: { + int n; + for (n=0; n<GETARG_U(i); n++) + stack[top++] = pc-1; + break; + } + case OP_POP: { + top -= GETARG_U(i); + break; + } + case OP_SETTABLE: + case OP_SETLIST: { + top -= GETARG_B(i); + break; + } + case OP_SETMAP: { + top -= 2*GETARG_U(i); + break; + } + case OP_CONCAT: { + top -= GETARG_U(i); + stack[top++] = pc-1; + break; + } + case OP_JMPONT: + case OP_JMPONF: { + int newpc = pc + GETARG_S(i); + if (newpc >= lastpc) { + stack[top-1] = pc-1; /* value generated by or-and */ + pc = newpc; /* do the jump */ + } + else + top--; /* original code did not jump; condition was false */ + break; + } + case OP_PUSHNILJMP: { + break; /* do not `push', to compensate next instruction */ + } + case OP_CLOSURE: { + top -= GETARG_B(i); + stack[top++] = pc-1; + break; + } + default: { + int n; + LUA_ASSERT(NULL, luaK_opproperties[GET_OPCODE(i)].push != VD, + "invalid opcode for default"); + top -= luaK_opproperties[GET_OPCODE(i)].pop; + for (n=0; n<luaK_opproperties[GET_OPCODE(i)].push; n++) + stack[top++] = pc-1; + } + } + } + return code[stack[stackpos]]; +} + + +static const char *getname (lua_State *L, StkId obj, const char **name) { + StkId func = aux_stackedfunction(L, 0, obj); + if (func == NULL || ttype(func) != TAG_LMARK) + return NULL; /* not a Lua function */ + else { + Proto *p = infovalue(func)->func->f.l; + int pc = lua_currentpc(func); + int stackpos = obj - (func+1); /* func+1 == function base */ + Instruction i = luaG_symbexec(p, pc, stackpos); + switch (GET_OPCODE(i)) { + case OP_GETGLOBAL: { + *name = p->kstr[GETARG_U(i)]->str; + return "global"; + } + case OP_GETLOCAL: { + *name = luaF_getlocalname(p, GETARG_U(i)+1, pc); + return (*name) ? "local" : NULL; + } + case OP_PUSHSELF: + case OP_GETDOTTED: { + *name = p->kstr[GETARG_U(i)]->str; + return "field"; + } + default: + return NULL; /* no usefull name found */ + } + } +} + + +/* }====================================================== */ + -static void call_index_error (lua_State *L, TObject *o, const char *v) { - luaL_verror(L, "attempt to %.10s a %.10s value", v, lua_type(L, o)); +static void call_index_error (lua_State *L, StkId o, const char *op, + const char *tp) { + const char *name; + const char *kind = getname(L, o, &name); + if (kind) + luaL_verror(L, "%s `%s' is not a %s", kind, name, tp); + else + luaL_verror(L, "attempt to %.10s a %.10s value", op, lua_type(L, o)); } -void luaG_callerror (lua_State *L, TObject *func) { - call_index_error(L, func, "call"); +void luaG_callerror (lua_State *L, StkId func) { + call_index_error(L, func, "call", "function"); } -void luaG_indexerror (lua_State *L, TObject *t) { - call_index_error(L, t, "index"); +void luaG_indexerror (lua_State *L, StkId t) { + call_index_error(L, t, "index", "table"); } diff --git a/ldebug.h b/ldebug.h @@ -1,5 +1,5 @@ /* -** $Id: $ +** $Id: ldebug.h,v 1.1 2000/01/14 17:15:44 roberto Exp roberto $ ** Auxiliary functions from Debug Interface module ** See Copyright Notice in lua.h */ @@ -8,12 +8,12 @@ #define ldebug_h -#include "lobject.h" +#include "lstate.h" #include "luadebug.h" -void luaG_callerror (lua_State *L, TObject *func); -void luaG_indexerror (lua_State *L, TObject *t); +void luaG_callerror (lua_State *L, StkId func); +void luaG_indexerror (lua_State *L, StkId t); #endif diff --git a/ldo.c b/ldo.c @@ -1,5 +1,5 @@ /* -** $Id: ldo.c,v 1.79 2000/06/16 17:16:34 roberto Exp roberto $ +** $Id: ldo.c,v 1.80 2000/06/26 19:28:31 roberto Exp roberto $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ @@ -103,7 +103,7 @@ void luaD_openstack (lua_State *L, StkId pos) { } -void luaD_lineHook (lua_State *L, StkId func, int line) { +void luaD_lineHook (lua_State *L, StkId func, int line, lua_Hook linehook) { if (L->allowhooks) { lua_Debug ar; struct C_Lua_Stack oldCLS = L->Cstack; @@ -113,7 +113,7 @@ void luaD_lineHook (lua_State *L, StkId func, int line) { ar.event = "line"; ar.currentline = line; L->allowhooks = 0; /* cannot call hooks inside a hook */ - (*L->linehook)(L, &ar); + (*linehook)(L, &ar); L->allowhooks = 1; L->top = old_top; L->Cstack = oldCLS; @@ -187,7 +187,7 @@ void luaD_call (lua_State *L, StkId func, int nResults) { case TAG_LCLOSURE: { CallInfo ci; ci.func = clvalue(func); - ci.pc = 0; + ci.line = 0; ttype(func) = TAG_LMARK; infovalue(func) = &ci; if (callhook) diff --git a/ldo.h b/ldo.h @@ -1,5 +1,5 @@ /* -** $Id: ldo.h,v 1.19 2000/03/29 20:19:20 roberto Exp roberto $ +** $Id: ldo.h,v 1.20 2000/04/14 18:12:35 roberto Exp $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ @@ -22,7 +22,7 @@ void luaD_init (lua_State *L, int stacksize); void luaD_adjusttop (lua_State *L, StkId base, int extra); void luaD_openstack (lua_State *L, StkId pos); -void luaD_lineHook (lua_State *L, StkId func, int line); +void luaD_lineHook (lua_State *L, StkId func, int line, lua_Hook linehook); void luaD_call (lua_State *L, StkId func, int nResults); void luaD_callTM (lua_State *L, const TObject *f, int nParams, int nResults); int luaD_protectedrun (lua_State *L); diff --git a/lobject.h b/lobject.h @@ -1,5 +1,5 @@ /* -** $Id: lobject.h,v 1.67 2000/06/08 18:27:13 roberto Exp roberto $ +** $Id: lobject.h,v 1.68 2000/06/26 19:28:31 roberto Exp roberto $ ** Type definitions for Lua objects ** See Copyright Notice in lua.h */ @@ -122,7 +122,6 @@ typedef struct Proto { int *lines; /* source line that generated each opcode */ int lineDefined; TString *source; - int debug; /* flag for debug information */ int numparams; int is_vararg; int maxstacksize; @@ -171,9 +170,10 @@ typedef struct Hash { ** informations about a call (for debugging) */ typedef struct CallInfo { - int pc; /* current pc of called function */ - int line; /* current line */ struct Closure *func; /* function being called */ + const Instruction **pc; /* current pc of called function */ + int lastpc; /* last pc traced */ + int line; /* current line */ } CallInfo; diff --git a/lparser.c b/lparser.c @@ -1,5 +1,5 @@ /* -** $Id: lparser.c,v 1.99 2000/06/26 19:28:31 roberto Exp roberto $ +** $Id: lparser.c,v 1.100 2000/06/28 17:06:07 roberto Exp roberto $ ** LL(1) Parser and code generator for Lua ** See Copyright Notice in lua.h */ @@ -154,7 +154,7 @@ static int checkname (LexState *ls) { static void luaI_registerlocalvar (LexState *ls, TString *varname, int pc) { FuncState *fs = ls->fs; - if (fs->f->debug) { + if (fs->debug) { Proto *f = fs->f; luaM_growvector(ls->L, f->locvars, fs->nvars, 1, LocVar, "", MAX_INT); f->locvars[fs->nvars].varname = varname; @@ -359,7 +359,7 @@ Proto *luaY_parser (lua_State *L, ZIO *z) { luaX_setinput(L, &lexstate, z, luaS_new(L, zname(z))); open_func(&lexstate, &funcstate); next(&lexstate); /* read first token */ - funcstate.f->debug = L->debug; /* previous `next' may scan a pragma */ + funcstate.debug = L->debug; /* previous `next' may scan a pragma */ chunk(&lexstate); check_condition(&lexstate, (lexstate.t.token == TK_EOS), "<eof> expected"); close_func(&lexstate); @@ -1085,7 +1085,7 @@ static void body (LexState *ls, int needself, int line) { FuncState new_fs; open_func(ls, &new_fs); new_fs.f->lineDefined = line; - new_fs.f->debug = ls->L->debug; + new_fs.debug = ls->L->debug; check(ls, '('); if (needself) { new_localvarstr(ls, "self", 0); diff --git a/lparser.h b/lparser.h @@ -1,5 +1,5 @@ /* -** $Id: lparser.h,v 1.18 2000/06/21 18:13:56 roberto Exp roberto $ +** $Id: lparser.h,v 1.19 2000/06/26 19:28:31 roberto Exp roberto $ ** LL(1) Parser and code generator for Lua ** See Copyright Notice in lua.h */ @@ -47,6 +47,7 @@ typedef struct FuncState { int stacklevel; /* number of values on activation register */ int nlocalvar; /* number of active local variables */ int nupvalues; /* number of upvalues */ + int debug; /* flag for debug information */ int nvars; /* number of entries in f->locvars */ struct Breaklabel *bl; /* chain of breakable blocks */ expdesc upvalues[MAXUPVALUES]; /* upvalues */ diff --git a/lvm.c b/lvm.c @@ -1,5 +1,5 @@ /* -** $Id: lvm.c,v 1.117 2000/06/26 19:28:31 roberto Exp roberto $ +** $Id: lvm.c,v 1.118 2000/06/27 19:00:36 roberto Exp roberto $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -67,20 +67,19 @@ int luaV_tostring (lua_State *L, TObject *obj) { /* LUA_NUMBER */ } -static void traceexec (lua_State *L, StkId base, int pc, StkId top) { +static void traceexec (lua_State *L, StkId base, StkId top, lua_Hook linehook) { CallInfo *ci = infovalue(base-1); - int oldpc = ci->pc; - ci->pc = pc; - if (L->linehook && ci->func->f.l->debug) { - int *lines = ci->func->f.l->lines; - LUA_ASSERT(L, lines, "must have debug information"); - /* calls linehook when jumps back (loop) or enters a new line */ - if (pc <= oldpc || lines[pc] != ci->line) { + int *lines = ci->func->f.l->lines; + int pc = (*ci->pc - 1) - ci->func->f.l->code; + if (lines) { + /* calls linehook when enters a new line or jumps back (loop) */ + if (lines[pc] != ci->line || pc <= ci->lastpc) { ci->line = lines[pc]; L->top = top; - luaD_lineHook(L, base-2, lines[pc]); + luaD_lineHook(L, base-2, lines[pc], linehook); } } + ci->lastpc = pc; } @@ -113,7 +112,7 @@ void luaV_Lclosure (lua_State *L, Proto *l, int nelems) { ** Receives the table at top-2 and the index at top-1. */ void luaV_gettable (lua_State *L, StkId top) { - TObject *table = top-2; + StkId table = top-2; const TObject *im; if (ttype(table) != TAG_TABLE) { /* not a table, get gettable TM */ im = luaT_getimbyObj(L, table, IM_GETTABLE); @@ -348,7 +347,8 @@ StkId luaV_execute (lua_State *L, const Closure *cl, StkId base) { StkId top; /* keep top local, for performance */ const Instruction *pc = tf->code; TString **kstr = tf->kstr; - int debug = tf->debug; + lua_Hook linehook = L->linehook; + infovalue(base-1)->pc = &pc; luaD_checkstack(L, tf->maxstacksize+EXTRA_STACK); if (tf->is_vararg) { /* varargs? */ adjust_varargs(L, base, tf->numparams); @@ -359,9 +359,9 @@ StkId luaV_execute (lua_State *L, const Closure *cl, StkId base) { top = L->top; /* main loop of interpreter */ for (;;) { - if (debug) - traceexec(L, base, pc - tf->code, top); - {const Instruction i = *pc++; + const Instruction i = *pc++; + if (linehook) + traceexec(L, base, top, linehook); switch (GET_OPCODE(i)) { case OP_END: @@ -705,5 +705,5 @@ StkId luaV_execute (lua_State *L, const Closure *cl, StkId base) { break; } - }} + } }