From 298d0abff7f292fa4bfbdb40979f41bc8f80f9c2 Mon Sep 17 00:00:00 2001 From: Roberto Ierusalimschy Date: Wed, 29 Dec 1999 14:31:15 -0200 Subject: [PATCH] first version of extra debug information (NAME) --- ldebug.c | 66 ++- ldo.c | 5 +- lobject.h | 29 +- lopcodes.h | 5 +- lparser.c | 1209 +++++++++++++++++++++++++++------------------------- lvm.c | 38 +- 6 files changed, 745 insertions(+), 607 deletions(-) diff --git a/ldebug.c b/ldebug.c index 4b31f458..2557d221 100644 --- a/ldebug.c +++ b/ldebug.c @@ -1,5 +1,5 @@ /* -** $Id: ldebug.c,v 1.1 1999/12/14 18:31:20 roberto Exp roberto $ +** $Id: ldebug.c,v 1.2 1999/12/23 18:19:57 roberto Exp roberto $ ** Debug Interface ** See Copyright Notice in lua.h */ @@ -8,6 +8,8 @@ #define LUA_REENTRANT #include "lapi.h" +#include "lauxlib.h" +#include "ldebug.h" #include "lfunc.h" #include "lobject.h" #include "lstate.h" @@ -17,6 +19,10 @@ #include "luadebug.h" +static int hasdebuginfo (lua_State *L, lua_Function f) { + return (f+1 < L->top && (f+1)->ttype == LUA_T_LINE); +} + lua_LHFunction lua_setlinehook (lua_State *L, lua_LHFunction func) { lua_LHFunction old = L->linehook; @@ -52,6 +58,29 @@ lua_Function lua_stackedfunction (lua_State *L, int level) { } +const char *luaG_getname (lua_State *L, const char **name) { + lua_Function f = lua_stackedfunction(L, 0); + if (f == LUA_NOOBJECT || !hasdebuginfo(L, f) || ttype(f+2) == LUA_T_NIL) + return NULL; /* no name available */ + else { + int i = (f+2)->value.i; + if (ttype(f) == LUA_T_LCLMARK) + f = protovalue(f); + LUA_ASSERT(L, ttype(f) == LUA_T_LMARK, "must be a Lua function"); + LUA_ASSERT(L, ttype(&tfvalue(f)->consts[i]) == LUA_T_STRING, ""); + *name = tsvalue(&tfvalue(f)->consts[i])->str; + switch (ttype(f+2)) { + case LUA_T_NGLOBAL: return "global"; + case LUA_T_NLOCAL: return "local"; + case LUA_T_NDOT: return "field"; + default: + LUA_INTERNALERROR(L, "invalid tag for NAME"); + return NULL; /* unreacheable; to avoid warnings */ + } + } +} + + int lua_nups (lua_State *L, lua_Function f) { UNUSED(L); switch (luaA_normalizedtype(f)) { @@ -64,7 +93,7 @@ int lua_nups (lua_State *L, lua_Function f) { int lua_currentline (lua_State *L, lua_Function f) { - return (f+1 < L->top && (f+1)->ttype == LUA_T_LINE) ? (f+1)->value.i : -1; + return hasdebuginfo(L, f) ? (f+1)->value.i : -1; } @@ -77,9 +106,10 @@ lua_Object lua_getlocal (lua_State *L, lua_Function f, int local_number, TProtoFunc *fp = luaA_protovalue(f)->value.tf; *name = luaF_getlocalname(fp, local_number, lua_currentline(L, f)); if (*name) { - /* if "*name", there must be a LUA_T_LINE */ - /* therefore, f+2 points to function base */ - return luaA_putluaObject(L, (f+2)+(local_number-1)); + /* if "*name", there must be a LUA_T_LINE and a NAME */ + /* therefore, f+3 points to function base */ + LUA_ASSERT(L, ttype(f+1) == LUA_T_LINE, ""); + return luaA_putluaObject(L, (f+3)+(local_number-1)); } else return LUA_NOOBJECT; @@ -98,9 +128,8 @@ int lua_setlocal (lua_State *L, lua_Function f, int local_number) { luaA_checkCparams(L, 1); --L->top; if (name) { - /* if "name", there must be a LUA_T_LINE */ - /* therefore, f+2 points to function base */ - *((f+2)+(local_number-1)) = *L->top; + LUA_ASSERT(L, ttype(f+1) == LUA_T_LINE, ""); + *((f+3)+(local_number-1)) = *L->top; return 1; } else @@ -148,3 +177,24 @@ const char *lua_getobjname (lua_State *L, lua_Object o, const char **name) { else return ""; /* not found at all */ } +static void call_index_error (lua_State *L, TObject *o, const char *tp, + const char *v) { + const char *name; + const char *kind = luaG_getname(L, &name); + if (kind) { /* is there a name? */ + luaL_verror(L, "%.10s `%.30s' is not a %.10s", kind, name, tp); + } + else { + luaL_verror(L, "attempt to %.10s a %.10s value", v, lua_type(L, o)); + } +} + + +void luaG_callerror (lua_State *L, TObject *func) { + call_index_error(L, func, "function", "call"); +} + + +void luaG_indexerror (lua_State *L, TObject *t) { + call_index_error(L, t, "table", "index"); +} diff --git a/ldo.c b/ldo.c index e4751e48..d2bdd440 100644 --- a/ldo.c +++ b/ldo.c @@ -1,5 +1,5 @@ /* -** $Id: ldo.c,v 1.60 1999/12/23 18:19:57 roberto Exp roberto $ +** $Id: ldo.c,v 1.61 1999/12/27 17:33:22 roberto Exp roberto $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ @@ -13,6 +13,7 @@ #define LUA_REENTRANT #include "lauxlib.h" +#include "ldebug.h" #include "ldo.h" #include "lgc.h" #include "lmem.h" @@ -220,7 +221,7 @@ void luaD_call (lua_State *L, StkId func, int nResults) { default: { /* `func' is not a function; check the `function' tag method */ const TObject *im = luaT_getimbyObj(L, func, IM_FUNCTION); if (ttype(im) == LUA_T_NIL) - lua_error(L, "call expression not a function"); + luaG_callerror(L, func); luaD_openstack(L, func); *func = *im; /* tag method is the new function to be called */ goto retry; /* retry the call (without calling callhook again) */ diff --git a/lobject.h b/lobject.h index e971c85b..da61835c 100644 --- a/lobject.h +++ b/lobject.h @@ -1,5 +1,5 @@ /* -** $Id: lobject.h,v 1.41 1999/12/23 18:19:57 roberto Exp roberto $ +** $Id: lobject.h,v 1.42 1999/12/27 17:33:22 roberto Exp roberto $ ** Type definitions for Lua objects ** See Copyright Notice in lua.h */ @@ -72,16 +72,25 @@ typedef enum { LUA_T_LPROTO = -4, /* fixed tag for Lua functions */ LUA_T_CPROTO = -5, /* fixed tag for C functions */ LUA_T_NIL = -6, /* last "pre-defined" tag */ + LUA_T_LCLOSURE = -7, /* Lua closure */ LUA_T_CCLOSURE = -8, /* C closure */ + LUA_T_LCLMARK = -9 ,/* mark for Lua closures */ LUA_T_CCLMARK = -10,/* mark for C closures */ LUA_T_LMARK = -11, /* mark for Lua prototypes */ LUA_T_CMARK = -12, /* mark for C prototypes */ - LUA_T_LINE = -13 + + LUA_T_LINE = -13, + LUA_T_NGLOBAL = -14, + LUA_T_NLOCAL = -15, + LUA_T_NDOT = -16 } lua_Type; -#define NUM_TAGS 7 +#define NUM_TAGS 7 /* tags for values visible from Lua */ + + +#define LAST_REGULAR_TAG LUA_T_CCLOSURE /* after that, are all marks */ /* ** chech whether `t' is a mark; ttypes are negative numbers, so the @@ -91,13 +100,13 @@ typedef enum { typedef union { - lua_CFunction f; /* LUA_T_CPROTO, LUA_T_CMARK */ - real n; /* LUA_T_NUMBER */ - struct TaggedString *ts; /* LUA_T_STRING, LUA_T_USERDATA */ - struct TProtoFunc *tf; /* LUA_T_LPROTO, LUA_T_LMARK */ - struct Closure *cl; /* LUA_T_[CL]CLOSURE, LUA_T_[CL]CLMARK */ - struct Hash *a; /* LUA_T_ARRAY */ - int i; /* LUA_T_LINE */ + lua_CFunction f; /* LUA_T_CPROTO, LUA_T_CMARK */ + real n; /* LUA_T_NUMBER */ + struct TaggedString *ts; /* LUA_T_STRING, LUA_T_USERDATA */ + struct TProtoFunc *tf; /* LUA_T_LPROTO, LUA_T_LMARK */ + struct Closure *cl; /* LUA_T_[CL]CLOSURE, LUA_T_[CL]CLMARK */ + struct Hash *a; /* LUA_T_ARRAY */ + int i; /* LUA_T_LINE */ } Value; diff --git a/lopcodes.h b/lopcodes.h index f44b5f76..cb5fabeb 100644 --- a/lopcodes.h +++ b/lopcodes.h @@ -1,5 +1,5 @@ /* -** $Id: lopcodes.h,v 1.34 1999/11/25 18:59:43 roberto Exp roberto $ +** $Id: lopcodes.h,v 1.35 1999/12/27 17:33:22 roberto Exp roberto $ ** Opcodes for Lua virtual machine ** See Copyright Notice in lua.h */ @@ -102,6 +102,9 @@ CLOSURE,/* b c v_c-v_1 closure(CNST[b], v_c-v_1) */ SETLINEW,/* w - - LINE=w */ SETLINE,/* b - - LINE=b */ +SETNAMEW,/* w c - - NAME=CNST[w],c */ +SETNAME,/* b c - - NAME=CNST[b],c */ + LONGARGW,/* w (add w*(1<<16) to arg of next instruction) */ LONGARG /* b (add b*(1<<16) to arg of next instruction) */ diff --git a/lparser.c b/lparser.c index 4229ddd6..e21ad7a1 100644 --- a/lparser.c +++ b/lparser.c @@ -1,5 +1,5 @@ /* -** $Id: lparser.c,v 1.49 1999/12/22 16:58:36 roberto Exp roberto $ +** $Id: lparser.c,v 1.50 1999/12/23 18:19:57 roberto Exp roberto $ ** LL(1) Parser and code generator for Lua ** See Copyright Notice in lua.h */ @@ -63,6 +63,8 @@ typedef enum { typedef struct vardesc { varkind k; int info; + varkind prev_k; /* for debug information (NAMEs) */ + int prev_info; } vardesc; @@ -70,7 +72,7 @@ typedef struct vardesc { ** Expression List descriptor: ** tells number of expressions in the list, ** and, if last expression is open (a function call), -** where is its pc index of "nparam" +** where is its pc index of `nparam' */ typedef struct listdesc { int n; @@ -93,7 +95,7 @@ typedef struct constdesc { /* state needed to generate code for a given function */ typedef struct FuncState { TProtoFunc *f; /* current function header */ - struct FuncState *prev; /* enclosuring function */ + struct FuncState *prev; /* enclosing function */ int pc; /* next position to code */ int stacksize; /* number of values on activation register */ int maxstacksize; /* maximum number of values on activation register */ @@ -107,34 +109,13 @@ typedef struct FuncState { /* -** prototypes for non-terminal functions +** prototypes for recursive non-terminal functions */ -static int assignment (LexState *ls, vardesc *v, int nvars); -static int cond (LexState *ls); -static int funcname (LexState *ls, vardesc *v); -static int funcparams (LexState *ls, int slf); -static int listfields (LexState *ls); -static int localnamelist (LexState *ls); -static int optional (LexState *ls, int c); -static int recfields (LexState *ls); -static int stat (LexState *ls); -static void block (LexState *ls); static void body (LexState *ls, int needself, int line); static void chunk (LexState *ls); static void constructor (LexState *ls); -static void decinit (LexState *ls, listdesc *d); -static void exp0 (LexState *ls, vardesc *v); +static void exp (LexState *ls, vardesc *v); static void exp1 (LexState *ls); -static void exp2 (LexState *ls, vardesc *v); -static void explist (LexState *ls, listdesc *e); -static void explist1 (LexState *ls, listdesc *e); -static void ifpart (LexState *ls, int line); -static void parlist (LexState *ls); -static void part (LexState *ls, constdesc *cd); -static void recfield (LexState *ls); -static void ret (LexState *ls); -static void var_or_func (LexState *ls, vardesc *v); -static void var_or_func_tail (LexState *ls, vardesc *v); @@ -268,7 +249,7 @@ static void code_string (LexState *ls, TaggedString *s) { #define LIM 20 static int real_constant (LexState *ls, real r) { - /* check whether 'r' has appeared within the last LIM entries */ + /* check whether `r' has appeared within the last LIM entries */ TProtoFunc *f = ls->fs->f; TObject *cnt = f->consts; int c = f->nconsts; @@ -279,7 +260,7 @@ static int real_constant (LexState *ls, real r) { } /* not found; create a new entry */ c = next_constant(ls, f); - cnt = f->consts; /* 'next_constant' may reallocate this vector */ + cnt = f->consts; /* `next_constant' may reallocate this vector */ ttype(&cnt[c]) = LUA_T_NUMBER; nvalue(&cnt[c]) = r; return c; @@ -412,6 +393,31 @@ static void check_debugline (LexState *ls) { } +static void code_setname (LexState *ls, const vardesc *v) { + if (ls->L->debug) { + switch (v->prev_k) { + case VGLOBAL: + code_oparg(ls, SETNAME, v->prev_info, 0); + code_byte(ls, -LUA_T_NGLOBAL); + break; + case VLOCAL: { + TaggedString *varname = ls->fs->localvar[v->prev_info]; + code_oparg(ls, SETNAME, string_constant(ls, ls->fs, varname), 0); + code_byte(ls, -LUA_T_NLOCAL); + break; + } + case VDOT: + code_oparg(ls, SETNAME, v->prev_info, 0); + code_byte(ls, -LUA_T_NDOT); + break; + default: /* VINDEXED or VEXP: no debug information */ + code_oparg(ls, SETNAME, 0, 0); + code_byte(ls, -LUA_T_NIL); + } + } +} + + static void adjuststack (LexState *ls, int n) { if (n > 0) code_oparg(ls, POP, n, -n); @@ -468,7 +474,7 @@ static void code_args (LexState *ls, int nparams, int dots) { static void unloaddot (LexState *ls, vardesc *v) { - /* dotted variables must be stored like regular indexed vars */ + /* dotted variables must be stored as regular indexed vars */ if (v->k == VDOT) { code_constant(ls, v->info); v->k = VINDEXED; @@ -486,15 +492,19 @@ static void lua_pushvar (LexState *ls, vardesc *var) { assertglobal(ls, var->info); /* make sure that there is a global */ break; case VDOT: + code_setname(ls, var); code_oparg(ls, GETDOTTED, var->info, 0); break; case VINDEXED: + code_setname(ls, var); code_opcode(ls, GETTABLE, -1); break; case VEXP: close_exp(ls, var->info, 1); /* function must return 1 value */ break; } + var->prev_k = var->k; /* save previous var kind and info */ + var->prev_info = var->info; var->k = VEXP; var->info = 0; /* now this is a closed expression */ } @@ -510,6 +520,7 @@ static void storevar (LexState *ls, const vardesc *var) { assertglobal(ls, var->info); /* make sure that there is a global */ break; case VINDEXED: + code_setname(ls, var); code_opcode(ls, SETTABLEPOP, -3); break; default: @@ -656,7 +667,7 @@ static void check (LexState *ls, int c) { static void check_match (LexState *ls, int what, int who, int where) { if (ls->token != what) error_unmatched(ls, what, who, where); - check_debugline(ls); /* to 'mark' the 'what' */ + check_debugline(ls); /* to `mark' the `what' */ next(ls); } @@ -705,14 +716,504 @@ TProtoFunc *luaY_parser (lua_State *L, ZIO *z) { /*============================================================*/ -static void chunk (LexState *ls) { - /* chunk -> { stat [;] } ret */ - while (stat(ls)) { - LUA_ASSERT(ls->L, ls->fs->stacksize == ls->fs->nlocalvar, - "stack size != # local vars"); - optional(ls, ';'); + +static int SaveWord (LexState *ls) { + int res = ls->fs->pc; + check_pc(ls, JMPSIZE); + ls->fs->pc += JMPSIZE; /* open space */ + return res; +} + + +static int SaveWordPop (LexState *ls) { + deltastack(ls, -1); /* pop condition */ + return SaveWord(ls); +} + + +static int cond (LexState *ls) { + /* cond -> exp1 */ + exp1(ls); + return SaveWordPop(ls); +} + + +static void explist1 (LexState *ls, listdesc *d) { + vardesc v; + exp(ls, &v); + d->n = 1; + while (ls->token == ',') { + d->n++; + lua_pushvar(ls, &v); + next(ls); + exp(ls, &v); } - ret(ls); /* optional return */ + if (v.k == VEXP) + d->pc = v.info; + else { + lua_pushvar(ls, &v); + d->pc = 0; + } +} + + +static void explist (LexState *ls, listdesc *d) { + switch (ls->token) { + case ELSE: case ELSEIF: case END: case UNTIL: + case EOS: case ';': case ')': + d->pc = 0; + d->n = 0; + break; + + default: + explist1(ls, d); + } +} + + +static int funcparams (LexState *ls, int slf, vardesc *v) { + FuncState *fs = ls->fs; + int slevel = fs->stacksize - slf - 1; /* where is func in the stack */ + switch (ls->token) { + case '(': { /* funcparams -> '(' explist ')' */ + int line = ls->linenumber; + listdesc e; + next(ls); + explist(ls, &e); + check_match(ls, ')', '(', line); + close_exp(ls, e.pc, MULT_RET); /* close 1 for old semantics */ + break; + } + + case '{': /* funcparams -> constructor */ + constructor(ls); + break; + + case STRING: /* funcparams -> STRING */ + code_string(ls, ls->seminfo.ts); /* must use 'seminfo' before `next' */ + next(ls); + break; + + default: + luaX_error(ls, "function arguments expected"); + break; + } + code_setname(ls, v); + code_byte(ls, CALL); + code_byte(ls, 0); /* save space for nresult */ + code_byte(ls, (Byte)slevel); + fs->stacksize = slevel; /* call will remove func and params */ + return fs->pc-1; +} + + +static void var_or_func_tail (LexState *ls, vardesc *v) { + for (;;) { + switch (ls->token) { + case '.': /* var_or_func_tail -> '.' NAME */ + next(ls); + lua_pushvar(ls, v); /* `v' must be on stack */ + v->k = VDOT; + v->info = checkname(ls); + break; + + case '[': /* var_or_func_tail -> '[' exp1 ']' */ + next(ls); + lua_pushvar(ls, v); /* `v' must be on stack */ + exp1(ls); + check(ls, ']'); + v->k = VINDEXED; + break; + + case ':': { /* var_or_func_tail -> ':' NAME funcparams */ + int name; + next(ls); + name = checkname(ls); + lua_pushvar(ls, v); /* `v' must be on stack */ + code_setname(ls, v); + code_oparg(ls, PUSHSELF, name, 1); + v->prev_k = VDOT; /* ':' is syntactic sugar for '.' */ + v->prev_info = name; + v->k = VEXP; + v->info = funcparams(ls, 1, v); + break; + } + + case '(': case STRING: case '{': /* var_or_func_tail -> funcparams */ + lua_pushvar(ls, v); /* `v' must be on stack */ + v->k = VEXP; + v->info = funcparams(ls, 0, v); + break; + + default: return; /* should be follow... */ + } + } +} + + +static void var_or_func (LexState *ls, vardesc *v) { + /* var_or_func -> ['%'] NAME var_or_func_tail */ + if (optional(ls, '%')) { /* upvalue? */ + pushupvalue(ls, str_checkname(ls)); + v->k = VEXP; + v->info = 0; /* closed expression */ + } + else /* variable name */ + singlevar(ls, str_checkname(ls), v, 0); + var_or_func_tail(ls, v); +} + + + +/* +** {====================================================================== +** Rules for Constructors +** ======================================================================= +*/ + +static void recfield (LexState *ls) { + /* recfield -> (NAME | '['exp1']') = exp1 */ + switch (ls->token) { + case NAME: + code_constant(ls, checkname(ls)); + break; + + case '[': + next(ls); + exp1(ls); + check(ls, ']'); + break; + + default: luaX_error(ls, "NAME or `[' expected"); + } + check(ls, '='); + exp1(ls); +} + + +static int recfields (LexState *ls) { + /* recfields -> { ',' recfield } [','] */ + int n = 1; /* one has been read before */ + while (ls->token == ',') { + next(ls); + if (ls->token == ';' || ls->token == '}') + break; + recfield(ls); + n++; + if (n%RFIELDS_PER_FLUSH == 0) + flush_record(ls, RFIELDS_PER_FLUSH); + } + flush_record(ls, n%RFIELDS_PER_FLUSH); + return n; +} + + +static int listfields (LexState *ls) { + /* listfields -> { ',' exp1 } [','] */ + int n = 1; /* one has been read before */ + while (ls->token == ',') { + next(ls); + if (ls->token == ';' || ls->token == '}') + break; + exp1(ls); + n++; + if (n%LFIELDS_PER_FLUSH == 0) + flush_list(ls, n/LFIELDS_PER_FLUSH - 1, LFIELDS_PER_FLUSH); + } + flush_list(ls, n/LFIELDS_PER_FLUSH, n%LFIELDS_PER_FLUSH); + return n; +} + + + +static void constructor_part (LexState *ls, constdesc *cd) { + switch (ls->token) { + case ';': case '}': /* constructor_part -> empty */ + cd->n = 0; + cd->k = ls->token; + return; + + case NAME: { + vardesc v; + exp(ls, &v); + if (ls->token == '=') { + switch (v.k) { + case VGLOBAL: + code_constant(ls, v.info); + break; + case VLOCAL: + code_string(ls, ls->fs->localvar[v.info]); + break; + default: + error_unexpected(ls); + } + next(ls); + exp1(ls); + cd->n = recfields(ls); + cd->k = 1; /* record */ + } + else { + lua_pushvar(ls, &v); + cd->n = listfields(ls); + cd->k = 0; /* list */ + } + break; + } + + case '[': /* constructor_part -> recfield recfields */ + recfield(ls); + cd->n = recfields(ls); + cd->k = 1; /* record */ + break; + + default: /* constructor_part -> exp1 listfields */ + exp1(ls); + cd->n = listfields(ls); + cd->k = 0; /* list */ + break; + } +} + + +static void constructor (LexState *ls) { + /* constructor -> '{' constructor_part [';' constructor_part] '}' */ + int line = ls->linenumber; + int pc = SaveWord(ls); + int nelems; + constdesc cd; + deltastack(ls, 1); + check(ls, '{'); + constructor_part(ls, &cd); + nelems = cd.n; + if (ls->token == ';') { + constdesc other_cd; + next(ls); + constructor_part(ls, &other_cd); + if (cd.k == other_cd.k) /* repeated parts? */ + luaX_error(ls, "invalid constructor syntax"); + nelems += other_cd.n; + } + check_match(ls, '}', '{', line); + fix_opcode(ls, pc, CREATEARRAY, nelems); +} + +/* }====================================================================== */ + + + + +/* +** {====================================================================== +** For parsing expressions, we use a classic stack with priorities. +** Each binary operator is represented by its index in `binop' + FIRSTBIN +** (EQ=2, NE=3, ... '^'=13). The unary NOT is 0 and UNMINUS is 1. +** ======================================================================= +*/ + +#define INDNOT 0 +#define INDMINUS 1 + +/* code of first binary operator */ +#define FIRSTBIN 2 + +/* code for power operator (last operator) +** '^' needs special treatment because it is right associative +*/ +#define POW 13 + +static const int binop [] = {EQ, NE, '>', '<', LE, GE, CONC, + '+', '-', '*', '/', '^', 0}; + +static const int priority [POW+1] = {5, 5, 1, 1, 1, 1, 1, 1, 2, 3, 3, 4, 4, 6}; + +static const OpCode opcodes [POW+1] = {NOTOP, MINUSOP, EQOP, NEQOP, GTOP, + LTOP, LEOP, GEOP, CONCOP, ADDOP, SUBOP, MULTOP, DIVOP, POWOP}; + +#define MAXOPS 20 /* op's stack size (arbitrary limit) */ + +typedef struct stack_op { + int ops[MAXOPS]; + int top; +} stack_op; + + + +static void push (LexState *ls, stack_op *s, int op) { + if (s->top >= MAXOPS) + luaX_error(ls, "expression too complex"); + s->ops[s->top++] = op; +} + + +static void pop_to (LexState *ls, stack_op *s, int prio) { + int op; + while (s->top > 0 && priority[(op=s->ops[s->top-1])] >= prio) { + code_opcode(ls, opcodes[op], optop--; + } +} + +static void simpleexp (LexState *ls, vardesc *v, stack_op *s) { + check_debugline(ls); + switch (ls->token) { + case NUMBER: { /* simpleexp -> NUMBER */ + real r = ls->seminfo.r; + next(ls); + /* dirty trick: check whether it is a -NUMBER not followed by '^' */ + /* (because the priority of '^' is higher than the priority of '-') */ + if (s->top > 0 && s->ops[s->top-1] == INDMINUS && ls->token != '^') { + s->top--; /* remove '-' from stack */ + r = -r; + } + code_number(ls, r); + break; + } + + case STRING: /* simpleexp -> STRING */ + code_string(ls, ls->seminfo.ts); /* must use 'seminfo' before `next' */ + next(ls); + break; + + case NIL: /* simpleexp -> NIL */ + adjuststack(ls, -1); + next(ls); + break; + + case '{': /* simpleexp -> constructor */ + constructor(ls); + break; + + case FUNCTION: /* simpleexp -> FUNCTION body */ + next(ls); + body(ls, 0, ls->linenumber); + break; + + case '(': /* simpleexp -> '(' exp ')' */ + next(ls); + exp(ls, v); + check(ls, ')'); + return; + + case NAME: case '%': + var_or_func(ls, v); + return; + + default: + luaX_error(ls, " expected"); + return; + } + v->k = VEXP; v->info = 0; +} + + +static void prefixexp (LexState *ls, vardesc *v, stack_op *s) { + /* prefixexp -> {NOT | '-'} simpleexp */ + while (ls->token == NOT || ls->token == '-') { + push(ls, s, (ls->token==NOT)?INDNOT:INDMINUS); + next(ls); + } + simpleexp(ls, v, s); +} + + +static void arith_exp (LexState *ls, vardesc *v) { + stack_op s; + int op; + s.top = 0; + prefixexp(ls, v, &s); + while ((op = is_in(ls->token, binop)) >= 0) { + op += FIRSTBIN; + lua_pushvar(ls, v); + /* '^' is right associative, so must 'simulate' a higher priority */ + pop_to(ls, &s, (op == POW)?priority[op]+1:priority[op]); + push(ls, &s, op); + next(ls); + prefixexp(ls, v, &s); + lua_pushvar(ls, v); + } + if (s.top > 0) { + lua_pushvar(ls, v); + pop_to(ls, &s, 0); + } +} + + +static void exp1 (LexState *ls) { + vardesc v; + exp(ls, &v); + lua_pushvar(ls, &v); + if (is_in(ls->token, expfollow) < 0) + luaX_error(ls, "malformed expression"); +} + + +static void exp (LexState *ls, vardesc *v) { + /* exp -> arith_exp {(AND | OR) arith_exp} */ + arith_exp(ls, v); + while (ls->token == AND || ls->token == OR) { + OpCode op = (ls->token == AND) ? ONFJMP : ONTJMP; + int pc; + lua_pushvar(ls, v); + next(ls); + pc = SaveWordPop(ls); + arith_exp(ls, v); + lua_pushvar(ls, v); + fix_jump(ls, pc, op, ls->fs->pc); + } +} + + +/* }==================================================================== */ + + +/* +** {====================================================================== +** Rules for Statements +** ======================================================================= +*/ + + +static void block (LexState *ls) { + /* block -> chunk */ + FuncState *fs = ls->fs; + int nlocalvar = fs->nlocalvar; + chunk(ls); + adjuststack(ls, fs->nlocalvar - nlocalvar); + for (; fs->nlocalvar > nlocalvar; fs->nlocalvar--) + luaI_unregisterlocalvar(ls, fs->lastsetline); +} + + +static int assignment (LexState *ls, vardesc *v, int nvars) { + int left = 0; + checklimit(ls, nvars, MAXVARSLH, "variables in a multiple assignment"); + unloaddot(ls, v); + if (ls->token == ',') { /* assignment -> ',' NAME assignment */ + vardesc nv; + next(ls); + var_or_func(ls, &nv); + if (nv.k == VEXP) + luaX_error(ls, "syntax error"); + left = assignment(ls, &nv, nvars+1); + } + else { /* assignment -> '=' explist1 */ + listdesc d; + if (ls->token != '=') + error_unexpected(ls); + next(ls); + explist1(ls, &d); + adjust_mult_assign(ls, nvars, &d); + } + if (v->k != VINDEXED || left+(nvars-1) == 0) { + /* global/local var or indexed var without values in between */ + storevar(ls, v); + } + else { /* indexed var with values in between*/ + code_setname(ls, v); + code_oparg(ls, SETTABLE, left+(nvars-1), -1); + left += 2; /* table&index are not popped, because they aren't on top */ + } + return left; } @@ -749,6 +1250,31 @@ static void repeatstat (LexState *ls, int line) { } +static int localnamelist (LexState *ls) { + /* localnamelist -> NAME {',' NAME} */ + int i = 1; + store_localvar(ls, str_checkname(ls), 0); + while (ls->token == ',') { + next(ls); + store_localvar(ls, str_checkname(ls), i++); + } + return i; +} + + +static void decinit (LexState *ls, listdesc *d) { + /* decinit -> ['=' explist1] */ + if (ls->token == '=') { + next(ls); + explist1(ls, d); + } + else { + d->n = 0; + d->pc = 0; + } +} + + static void localstat (LexState *ls) { /* stat -> LOCAL localnamelist decinit */ FuncState *fs = ls->fs; @@ -763,6 +1289,21 @@ static void localstat (LexState *ls) { } +static int funcname (LexState *ls, vardesc *v) { + /* funcname -> NAME [':' NAME | '.' NAME] */ + int needself = 0; + singlevar(ls, str_checkname(ls), v, 0); + if (ls->token == ':' || ls->token == '.') { + needself = (ls->token == ':'); + next(ls); + lua_pushvar(ls, v); + code_constant(ls, checkname(ls)); + v->k = VINDEXED; + } + return needself; +} + + static int funcstat (LexState *ls, int line) { /* funcstat -> FUNCTION funcname body */ int needself; @@ -795,6 +1336,26 @@ static void namestat (LexState *ls) { } +static void ifpart (LexState *ls, int line) { + /* ifpart -> cond THEN block [ELSE block | ELSEIF ifpart] */ + int c; + int e; + next(ls); /* skip IF or ELSEIF */ + c = cond(ls); + check(ls, THEN); + block(ls); + e = SaveWord(ls); + if (ls->token == ELSEIF) + ifpart(ls, line); + else { + if (optional(ls, ELSE)) + block(ls); + check_match(ls, END, IF, line); + } + codeIf(ls, c, e); +} + + static int stat (LexState *ls) { int line = ls->linenumber; /* may be needed for error messages */ switch (ls->token) { @@ -838,376 +1399,6 @@ static int stat (LexState *ls) { } } -static int SaveWord (LexState *ls) { - int res = ls->fs->pc; - check_pc(ls, JMPSIZE); - ls->fs->pc += JMPSIZE; /* open space */ - return res; -} - -static int SaveWordPop (LexState *ls) { - deltastack(ls, -1); /* pop condition */ - return SaveWord(ls); -} - -static int cond (LexState *ls) { - /* cond -> exp1 */ - exp1(ls); - return SaveWordPop(ls); -} - -static void block (LexState *ls) { - /* block -> chunk */ - FuncState *fs = ls->fs; - int nlocalvar = fs->nlocalvar; - chunk(ls); - adjuststack(ls, fs->nlocalvar - nlocalvar); - for (; fs->nlocalvar > nlocalvar; fs->nlocalvar--) - luaI_unregisterlocalvar(ls, fs->lastsetline); -} - -static int funcname (LexState *ls, vardesc *v) { - /* funcname -> NAME [':' NAME | '.' NAME] */ - int needself = 0; - singlevar(ls, str_checkname(ls), v, 0); - if (ls->token == ':' || ls->token == '.') { - needself = (ls->token == ':'); - next(ls); - lua_pushvar(ls, v); - code_constant(ls, checkname(ls)); - v->k = VINDEXED; - } - return needself; -} - -static void body (LexState *ls, int needself, int line) { - /* body -> '(' parlist ')' chunk END */ - FuncState newfs; - init_state(ls, &newfs, ls->fs->f->source); - newfs.f->lineDefined = line; - check(ls, '('); - if (needself) - add_localvar(ls, luaS_newfixed(ls->L, "self")); - parlist(ls); - check(ls, ')'); - chunk(ls); - check_match(ls, END, FUNCTION, line); - close_func(ls); - func_onstack(ls, &newfs); -} - - -static void ifpart (LexState *ls, int line) { - /* ifpart -> cond THEN block [ELSE block | ELSEIF ifpart] */ - int c; - int e; - next(ls); /* skip IF or ELSEIF */ - c = cond(ls); - check(ls, THEN); - block(ls); - e = SaveWord(ls); - if (ls->token == ELSEIF) - ifpart(ls, line); - else { - if (optional(ls, ELSE)) - block(ls); - check_match(ls, END, IF, line); - } - codeIf(ls, c, e); -} - - -static void ret (LexState *ls) { - /* ret -> [RETURN explist sc] */ - if (optional(ls, RETURN)) { - listdesc e; - check_debugline(ls); - explist(ls, &e); - if (e.pc > 0) { /* expression is an open function call? */ - Byte *code = ls->fs->f->code; - code[e.pc-2] = TAILCALL; /* instead of a conventional CALL */ - code[e.pc-1] = (Byte)ls->fs->nlocalvar; - } - else - code_oparg(ls, RETCODE, ls->fs->nlocalvar, 0); - ls->fs->stacksize = ls->fs->nlocalvar; /* removes all temp values */ - optional(ls, ';'); - } -} - - -/* -** For parsing expressions, we use a classic stack with priorities. -** Each binary operator is represented by its index in "binop" + FIRSTBIN -** (EQ=2, NE=3, ... '^'=13). The unary NOT is 0 and UNMINUS is 1. -*/ - -#define INDNOT 0 -#define INDMINUS 1 - -/* code of first binary operator */ -#define FIRSTBIN 2 - -/* code for power operator (last operator) -** '^' needs special treatment because it is right associative -*/ -#define POW 13 - -static const int binop [] = {EQ, NE, '>', '<', LE, GE, CONC, - '+', '-', '*', '/', '^', 0}; - -static const int priority [POW+1] = {5, 5, 1, 1, 1, 1, 1, 1, 2, 3, 3, 4, 4, 6}; - -static const OpCode opcodes [POW+1] = {NOTOP, MINUSOP, EQOP, NEQOP, GTOP, - LTOP, LEOP, GEOP, CONCOP, ADDOP, SUBOP, MULTOP, DIVOP, POWOP}; - -#define MAXOPS 20 /* op's stack size (arbitrary limit) */ - -typedef struct stack_op { - int ops[MAXOPS]; - int top; -} stack_op; - - -static void exp1 (LexState *ls) { - vardesc v; - exp0(ls, &v); - lua_pushvar(ls, &v); - if (is_in(ls->token, expfollow) < 0) - luaX_error(ls, "malformed expression"); -} - - -static void exp0 (LexState *ls, vardesc *v) { - /* exp0 -> exp2 {(AND | OR) exp2} */ - exp2(ls, v); - while (ls->token == AND || ls->token == OR) { - int op = (ls->token == AND) ? ONFJMP : ONTJMP; - int pc; - lua_pushvar(ls, v); - next(ls); - pc = SaveWordPop(ls); - exp2(ls, v); - lua_pushvar(ls, v); - fix_jump(ls, pc, op, ls->fs->pc); - } -} - - -static void push (LexState *ls, stack_op *s, int op) { - if (s->top >= MAXOPS) - luaX_error(ls, "expression too complex"); - s->ops[s->top++] = op; -} - - -static void pop_to (LexState *ls, stack_op *s, int prio) { - int op; - while (s->top > 0 && priority[(op=s->ops[s->top-1])] >= prio) { - code_opcode(ls, opcodes[op], optop--; - } -} - -static void simpleexp (LexState *ls, vardesc *v, stack_op *s) { - check_debugline(ls); - switch (ls->token) { - case NUMBER: { /* simpleexp -> NUMBER */ - real r = ls->seminfo.r; - next(ls); - /* dirty trick: check whether it is a -NUMBER not followed by '^' */ - /* (because the priority of '^' is higher than '-'...) */ - if (s->top > 0 && s->ops[s->top-1] == INDMINUS && ls->token != '^') { - s->top--; /* remove '-' from stack */ - r = -r; - } - code_number(ls, r); - break; - } - - case STRING: /* simpleexp -> STRING */ - code_string(ls, ls->seminfo.ts); /* must use 'seminfo' before `next' */ - next(ls); - break; - - case NIL: /* simpleexp -> NIL */ - adjuststack(ls, -1); - next(ls); - break; - - case '{': /* simpleexp -> constructor */ - constructor(ls); - break; - - case FUNCTION: /* simpleexp -> FUNCTION body */ - next(ls); - body(ls, 0, ls->linenumber); - break; - - case '(': /* simpleexp -> '(' exp0 ')' */ - next(ls); - exp0(ls, v); - check(ls, ')'); - return; - - case NAME: case '%': - var_or_func(ls, v); - return; - - default: - luaX_error(ls, " expected"); - return; - } - v->k = VEXP; v->info = 0; -} - - -static void prefixexp (LexState *ls, vardesc *v, stack_op *s) { - /* prefixexp -> {NOT | '-'} simpleexp */ - while (ls->token == NOT || ls->token == '-') { - push(ls, s, (ls->token==NOT)?INDNOT:INDMINUS); - next(ls); - } - simpleexp(ls, v, s); -} - - -static void exp2 (LexState *ls, vardesc *v) { - stack_op s; - int op; - s.top = 0; - prefixexp(ls, v, &s); - while ((op = is_in(ls->token, binop)) >= 0) { - op += FIRSTBIN; - lua_pushvar(ls, v); - /* '^' is right associative, so must 'simulate' a higher priority */ - pop_to(ls, &s, (op == POW)?priority[op]+1:priority[op]); - push(ls, &s, op); - next(ls); - prefixexp(ls, v, &s); - lua_pushvar(ls, v); - } - if (s.top > 0) { - lua_pushvar(ls, v); - pop_to(ls, &s, 0); - } -} - - -static void var_or_func (LexState *ls, vardesc *v) { - /* var_or_func -> ['%'] NAME var_or_func_tail */ - if (optional(ls, '%')) { /* upvalue? */ - pushupvalue(ls, str_checkname(ls)); - v->k = VEXP; - v->info = 0; /* closed expression */ - } - else /* variable name */ - singlevar(ls, str_checkname(ls), v, 0); - var_or_func_tail(ls, v); -} - - -static void var_or_func_tail (LexState *ls, vardesc *v) { - for (;;) { - switch (ls->token) { - case '.': /* var_or_func_tail -> '.' NAME */ - next(ls); - lua_pushvar(ls, v); /* `v' must be on stack */ - v->k = VDOT; - v->info = checkname(ls); - break; - - case '[': /* var_or_func_tail -> '[' exp1 ']' */ - next(ls); - lua_pushvar(ls, v); /* `v' must be on stack */ - exp1(ls); - check(ls, ']'); - v->k = VINDEXED; - break; - - case ':': /* var_or_func_tail -> ':' NAME funcparams */ - next(ls); - lua_pushvar(ls, v); /* `v' must be on stack */ - code_oparg(ls, PUSHSELF, checkname(ls), 1); - v->k = VEXP; - v->info = funcparams(ls, 1); - break; - - case '(': case STRING: case '{': /* var_or_func_tail -> funcparams */ - lua_pushvar(ls, v); /* `v' must be on stack */ - v->k = VEXP; - v->info = funcparams(ls, 0); - break; - - default: return; /* should be follow... */ - } - } -} - -static int funcparams (LexState *ls, int slf) { - FuncState *fs = ls->fs; - int slevel = fs->stacksize - slf - 1; /* where is func in the stack */ - switch (ls->token) { - case '(': { /* funcparams -> '(' explist ')' */ - int line = ls->linenumber; - listdesc e; - next(ls); - explist(ls, &e); - check_match(ls, ')', '(', line); - close_exp(ls, e.pc, MULT_RET); /* close 1 for old semantics */ - break; - } - - case '{': /* funcparams -> constructor */ - constructor(ls); - break; - - case STRING: /* funcparams -> STRING */ - code_string(ls, ls->seminfo.ts); /* must use 'seminfo' before `next' */ - next(ls); - break; - - default: - luaX_error(ls, "function arguments expected"); - break; - } - code_byte(ls, CALL); - code_byte(ls, 0); /* save space for nresult */ - code_byte(ls, (Byte)slevel); - fs->stacksize = slevel; /* call will remove func and params */ - return fs->pc-1; -} - -static void explist (LexState *ls, listdesc *d) { - switch (ls->token) { - case ELSE: case ELSEIF: case END: case UNTIL: - case EOS: case ';': case ')': - d->pc = 0; - d->n = 0; - break; - - default: - explist1(ls, d); - } -} - -static void explist1 (LexState *ls, listdesc *d) { - vardesc v; - exp0(ls, &v); - d->n = 1; - while (ls->token == ',') { - d->n++; - lua_pushvar(ls, &v); - next(ls); - exp0(ls, &v); - } - if (v.k == VEXP) - d->pc = v.info; - else { - lua_pushvar(ls, &v); - d->pc = 0; - } -} static void parlist (LexState *ls) { int nparams = 0; @@ -1244,180 +1435,52 @@ static void parlist (LexState *ls) { code_args(ls, nparams, dots); } -static int localnamelist (LexState *ls) { - /* localnamelist -> NAME {',' NAME} */ - int i = 1; - store_localvar(ls, str_checkname(ls), 0); - while (ls->token == ',') { - next(ls); - store_localvar(ls, str_checkname(ls), i++); - } - return i; -} -static void decinit (LexState *ls, listdesc *d) { - /* decinit -> ['=' explist1] */ - if (ls->token == '=') { - next(ls); - explist1(ls, d); - } - else { - d->n = 0; - d->pc = 0; - } +static void body (LexState *ls, int needself, int line) { + /* body -> '(' parlist ')' chunk END */ + FuncState newfs; + init_state(ls, &newfs, ls->fs->f->source); + newfs.f->lineDefined = line; + check(ls, '('); + if (needself) + add_localvar(ls, luaS_newfixed(ls->L, "self")); + parlist(ls); + check(ls, ')'); + chunk(ls); + check_match(ls, END, FUNCTION, line); + close_func(ls); + func_onstack(ls, &newfs); } -static int assignment (LexState *ls, vardesc *v, int nvars) { - int left = 0; - checklimit(ls, nvars, MAXVARSLH, "variables in a multiple assignment"); - unloaddot(ls, v); - if (ls->token == ',') { /* assignment -> ',' NAME assignment */ - vardesc nv; - next(ls); - var_or_func(ls, &nv); - if (nv.k == VEXP) - luaX_error(ls, "syntax error"); - left = assignment(ls, &nv, nvars+1); - } - else { /* assignment -> '=' explist1 */ - listdesc d; - if (ls->token != '=') - error_unexpected(ls); - next(ls); - explist1(ls, &d); - adjust_mult_assign(ls, nvars, &d); - } - if (v->k != VINDEXED || left+(nvars-1) == 0) { - /* global/local var or indexed var without values in between */ - storevar(ls, v); - } - else { /* indexed var with values in between*/ - code_oparg(ls, SETTABLE, left+(nvars-1), -1); - left += 2; /* table&index are not popped, because they aren't on top */ - } - return left; -} - - -static void constructor (LexState *ls) { - /* constructor -> '{' part [';' part] '}' */ - int line = ls->linenumber; - int pc = SaveWord(ls); - int nelems; - constdesc cd; - deltastack(ls, 1); - check(ls, '{'); - part(ls, &cd); - nelems = cd.n; - if (ls->token == ';') { - constdesc other_cd; - next(ls); - part(ls, &other_cd); - if (cd.k == other_cd.k) /* repeated parts? */ - luaX_error(ls, "invalid constructor syntax"); - nelems += other_cd.n; - } - check_match(ls, '}', '{', line); - fix_opcode(ls, pc, CREATEARRAY, nelems); -} - -static void part (LexState *ls, constdesc *cd) { - switch (ls->token) { - case ';': case '}': /* part -> empty */ - cd->n = 0; - cd->k = ls->token; - return; - - case NAME: { - vardesc v; - exp0(ls, &v); - if (ls->token == '=') { - switch (v.k) { - case VGLOBAL: - code_constant(ls, v.info); - break; - case VLOCAL: - code_string(ls, ls->fs->localvar[v.info]); - break; - default: - error_unexpected(ls); - } - next(ls); - exp1(ls); - cd->n = recfields(ls); - cd->k = 1; /* record */ - } - else { - lua_pushvar(ls, &v); - cd->n = listfields(ls); - cd->k = 0; /* list */ - } - break; +static void ret (LexState *ls) { + /* ret -> [RETURN explist sc] */ + if (optional(ls, RETURN)) { + listdesc e; + check_debugline(ls); + explist(ls, &e); + if (e.pc > 0) { /* expression is an open function call? */ + Byte *code = ls->fs->f->code; + code[e.pc-2] = TAILCALL; /* instead of a conventional CALL */ + code[e.pc-1] = (Byte)ls->fs->nlocalvar; } - - case '[': /* part -> recfield recfields */ - recfield(ls); - cd->n = recfields(ls); - cd->k = 1; /* record */ - break; - - default: /* part -> exp1 listfields */ - exp1(ls); - cd->n = listfields(ls); - cd->k = 0; /* list */ - break; + else + code_oparg(ls, RETCODE, ls->fs->nlocalvar, 0); + ls->fs->stacksize = ls->fs->nlocalvar; /* removes all temp values */ + optional(ls, ';'); } } -static int recfields (LexState *ls) { - /* recfields -> { ',' recfield } [','] */ - int n = 1; /* one has been read before */ - while (ls->token == ',') { - next(ls); - if (ls->token == ';' || ls->token == '}') - break; - recfield(ls); - n++; - if (n%RFIELDS_PER_FLUSH == 0) - flush_record(ls, RFIELDS_PER_FLUSH); +/* }====================================================================== */ + + +static void chunk (LexState *ls) { + /* chunk -> { stat [;] } ret */ + while (stat(ls)) { + LUA_ASSERT(ls->L, ls->fs->stacksize == ls->fs->nlocalvar, + "stack size != # local vars"); + optional(ls, ';'); } - flush_record(ls, n%RFIELDS_PER_FLUSH); - return n; -} - -static int listfields (LexState *ls) { - /* listfields -> { ',' exp1 } [','] */ - int n = 1; /* one has been read before */ - while (ls->token == ',') { - next(ls); - if (ls->token == ';' || ls->token == '}') - break; - exp1(ls); - n++; - if (n%LFIELDS_PER_FLUSH == 0) - flush_list(ls, n/LFIELDS_PER_FLUSH - 1, LFIELDS_PER_FLUSH); - } - flush_list(ls, n/LFIELDS_PER_FLUSH, n%LFIELDS_PER_FLUSH); - return n; -} - -static void recfield (LexState *ls) { - /* recfield -> (NAME | '['exp1']') = exp1 */ - switch (ls->token) { - case NAME: - code_constant(ls, checkname(ls)); - break; - - case '[': - next(ls); - exp1(ls); - check(ls, ']'); - break; - - default: luaX_error(ls, "NAME or `[' expected"); - } - check(ls, '='); - exp1(ls); + ret(ls); /* optional return */ } diff --git a/lvm.c b/lvm.c index 45bc6616..e2da0801 100644 --- a/lvm.c +++ b/lvm.c @@ -1,5 +1,5 @@ /* -** $Id: lvm.c,v 1.75 1999/12/23 18:19:57 roberto Exp roberto $ +** $Id: lvm.c,v 1.76 1999/12/27 17:33:22 roberto Exp roberto $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -12,6 +12,7 @@ #define LUA_REENTRANT #include "lauxlib.h" +#include "ldebug.h" #include "ldo.h" #include "lfunc.h" #include "lgc.h" @@ -33,7 +34,7 @@ /* Extra stack size to run a function: LUA_T_LINE(1), TM calls(2), ... */ -#define EXTRA_STACK 5 +#define EXTRA_STACK 6 @@ -105,7 +106,7 @@ void luaV_gettable (lua_State *L) { if (ttype(table) != LUA_T_ARRAY) { /* not a table, get gettable method */ im = luaT_getimbyObj(L, table, IM_GETTABLE); if (ttype(im) == LUA_T_NIL) - lua_error(L, "indexed expression not a table"); + luaG_indexerror(L, table); } else { /* object is a table... */ int tg = table->value.a->htag; @@ -138,7 +139,7 @@ void luaV_settable (lua_State *L, StkId t) { if (ttype(t) != LUA_T_ARRAY) { /* not a table, get `settable' method */ im = luaT_getimbyObj(L, t, IM_SETTABLE); if (ttype(im) == LUA_T_NIL) - lua_error(L, "indexed expression not a table"); + luaG_indexerror(L, t); } else { /* object is a table... */ im = luaT_getim(L, avalue(t)->htag, IM_SETTABLE); @@ -587,17 +588,28 @@ StkId luaV_execute (lua_State *L, const Closure *cl, const TProtoFunc *tf, case SETLINEW: aux += highbyte(L, *pc++); case SETLINE: aux += *pc++; - L->top = top; - if ((base-1)->ttype != LUA_T_LINE) { - /* open space for LINE value */ - luaD_openstack(L, base); - base->ttype = LUA_T_LINE; - base++; - top++; + if ((base-2)->ttype != LUA_T_LINE) { + /* open space for LINE and NAME values */ + int i = top-base; + while (i--) base[i+2] = base[i]; + base += 2; + top += 2; + (base-1)->ttype = LUA_T_NIL; /* initial value for NAME */ + (base-2)->ttype = LUA_T_LINE; } - (base-1)->value.i = aux; - if (L->linehook) + (base-2)->value.i = aux; + if (L->linehook) { + L->top = top; luaD_lineHook(L, aux); + } + break; + + case SETNAMEW: aux += highbyte(L, *pc++); + case SETNAME: aux += *pc++; + if ((base-2)->ttype == LUA_T_LINE) { /* function has debug info? */ + (base-1)->ttype = -(*pc++); + (base-1)->value.i = aux; + } break; case LONGARGW: aux += highbyte(L, *pc++);