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 | 1035 ++++++++++++++++++++++++++++------------------------ lvm.c | 38 +- 6 files changed, 658 insertions(+), 520 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,241 +716,298 @@ 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, ';'); - } - ret(ls); /* optional return */ -} - -static void whilestat (LexState *ls, int line) { - /* whilestat -> WHILE cond DO block END */ - FuncState *fs = ls->fs; - TProtoFunc *f = fs->f; - int while_init = fs->pc; - int cond_end, cond_size; - next(ls); - cond_end = cond(ls); - check(ls, DO); - block(ls); - check_match(ls, END, WHILE, line); - cond_size = cond_end-while_init; - check_pc(ls, cond_size); - memcpy(f->code+fs->pc, f->code+while_init, cond_size); - luaO_memdown(f->code+while_init, f->code+cond_end, fs->pc-while_init); - while_init += JMPSIZE + fix_jump(ls, while_init, JMP, fs->pc-cond_size); - fix_upjmp(ls, IFTUPJMP, while_init); +static int SaveWord (LexState *ls) { + int res = ls->fs->pc; + check_pc(ls, JMPSIZE); + ls->fs->pc += JMPSIZE; /* open space */ + return res; } -static void repeatstat (LexState *ls, int line) { - /* repeatstat -> REPEAT block UNTIL exp1 */ - FuncState *fs = ls->fs; - int repeat_init = fs->pc; - next(ls); - block(ls); - check_match(ls, UNTIL, REPEAT, line); - exp1(ls); - fix_upjmp(ls, IFFUPJMP, repeat_init); - deltastack(ls, -1); /* pops condition */ +static int SaveWordPop (LexState *ls) { + deltastack(ls, -1); /* pop condition */ + return SaveWord(ls); } -static void localstat (LexState *ls) { - /* stat -> LOCAL localnamelist decinit */ - FuncState *fs = ls->fs; - listdesc d; - int nvars; - check_debugline(ls); - next(ls); - nvars = localnamelist(ls); - decinit(ls, &d); - adjustlocalvars(ls, nvars, fs->lastsetline); - adjust_mult_assign(ls, nvars, &d); +static int cond (LexState *ls) { + /* cond -> exp1 */ + exp1(ls); + return SaveWordPop(ls); } -static int funcstat (LexState *ls, int line) { - /* funcstat -> FUNCTION funcname body */ - int needself; +static void explist1 (LexState *ls, listdesc *d) { vardesc v; - if (ls->fs->prev) /* inside other function? */ - return 0; - check_debugline(ls); - next(ls); - needself = funcname(ls, &v); - body(ls, needself, line); - storevar(ls, &v); - return 1; + exp(ls, &v); + d->n = 1; + while (ls->token == ',') { + d->n++; + lua_pushvar(ls, &v); + next(ls); + exp(ls, &v); + } + if (v.k == VEXP) + d->pc = v.info; + else { + lua_pushvar(ls, &v); + d->pc = 0; + } } -static void namestat (LexState *ls) { - /* stat -> func | ['%'] NAME assignment */ - vardesc v; - check_debugline(ls); - var_or_func(ls, &v); - if (v.k == VEXP) { /* stat -> func */ - if (v.info == 0) /* is just an upper value? */ - luaX_error(ls, "syntax error"); - close_exp(ls, v.info, 0); - } - else { /* stat -> ['%'] NAME assignment */ - int left = assignment(ls, &v, 1); - adjuststack(ls, left); /* remove eventual garbage left on stack */ +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 stat (LexState *ls) { - int line = ls->linenumber; /* may be needed for error messages */ +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 IF: /* stat -> IF ifpart END */ - ifpart(ls, line); - return 1; + 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 WHILE: /* stat -> whilestat */ - whilestat(ls, line); - return 1; + case '{': /* funcparams -> constructor */ + constructor(ls); + break; - case DO: { /* stat -> DO block END */ + case STRING: /* funcparams -> STRING */ + code_string(ls, ls->seminfo.ts); /* must use 'seminfo' before `next' */ next(ls); - block(ls); - check_match(ls, END, DO, line); - return 1; - } + break; - case REPEAT: /* stat -> repeatstat */ - repeatstat(ls, line); - return 1; + 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; +} - case FUNCTION: /* stat -> funcstat */ - return funcstat(ls, line); - case LOCAL: /* stat -> localstat */ - localstat(ls); - return 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 NAME: case '%': /* stat -> namestat */ - namestat(ls); - return 1; + 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 RETURN: case ';': case ELSE: case ELSEIF: - case END: case UNTIL: case EOS: /* 'stat' follow */ - return 0; + 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; + } - default: - error_unexpected(ls); - return 0; /* to avoid warnings */ + 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 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 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 int cond (LexState *ls) { - /* cond -> exp1 */ + + +/* +** {====================================================================== +** 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); - 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 == ':'); +static int recfields (LexState *ls) { + /* recfields -> { ',' recfield } [','] */ + int n = 1; /* one has been read before */ + while (ls->token == ',') { next(ls); - lua_pushvar(ls, v); - code_constant(ls, checkname(ls)); - v->k = VINDEXED; + if (ls->token == ';' || ls->token == '}') + break; + recfield(ls); + n++; + if (n%RFIELDS_PER_FLUSH == 0) + flush_record(ls, RFIELDS_PER_FLUSH); } - return needself; + flush_record(ls, n%RFIELDS_PER_FLUSH); + return n; } -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 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 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); + +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; } - 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, ';'); +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 +** 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 @@ -969,30 +1037,6 @@ typedef struct stack_op { } 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) @@ -1015,8 +1059,8 @@ static void simpleexp (LexState *ls, vardesc *v, stack_op *s) { 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 '-'...) */ + /* 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; @@ -1044,9 +1088,9 @@ static void simpleexp (LexState *ls, vardesc *v, stack_op *s) { body(ls, 0, ls->linenumber); break; - case '(': /* simpleexp -> '(' exp0 ')' */ + case '(': /* simpleexp -> '(' exp ')' */ next(ls); - exp0(ls, v); + exp(ls, v); check(ls, ')'); return; @@ -1072,7 +1116,7 @@ static void prefixexp (LexState *ls, vardesc *v, stack_op *s) { } -static void exp2 (LexState *ls, vardesc *v) { +static void arith_exp (LexState *ls, vardesc *v) { stack_op s; int op; s.top = 0; @@ -1094,156 +1138,118 @@ static void exp2 (LexState *ls, vardesc *v) { } -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 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 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 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); } } -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; +/* +** {====================================================================== +** 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 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 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); } -} - -static void explist1 (LexState *ls, listdesc *d) { - vardesc v; - exp0(ls, &v); - d->n = 1; - while (ls->token == ',') { - d->n++; - lua_pushvar(ls, &v); + else { /* assignment -> '=' explist1 */ + listdesc d; + if (ls->token != '=') + error_unexpected(ls); next(ls); - exp0(ls, &v); + explist1(ls, &d); + adjust_mult_assign(ls, nvars, &d); } - if (v.k == VEXP) - d->pc = v.info; - else { - lua_pushvar(ls, &v); - d->pc = 0; + 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; } -static void parlist (LexState *ls) { - int nparams = 0; - int dots = 0; - switch (ls->token) { - case DOTS: /* parlist -> DOTS */ - next(ls); - dots = 1; - break; - - case NAME: /* parlist, tailparlist -> NAME [',' tailparlist] */ - init: - store_localvar(ls, str_checkname(ls), nparams++); - if (ls->token == ',') { - next(ls); - switch (ls->token) { - case DOTS: /* tailparlist -> DOTS */ - next(ls); - dots = 1; - break; - - case NAME: /* tailparlist -> NAME [',' tailparlist] */ - goto init; - default: luaX_error(ls, "NAME or `...' expected"); - } - } - break; +static void whilestat (LexState *ls, int line) { + /* whilestat -> WHILE cond DO block END */ + FuncState *fs = ls->fs; + TProtoFunc *f = fs->f; + int while_init = fs->pc; + int cond_end, cond_size; + next(ls); + cond_end = cond(ls); + check(ls, DO); + block(ls); + check_match(ls, END, WHILE, line); + cond_size = cond_end-while_init; + check_pc(ls, cond_size); + memcpy(f->code+fs->pc, f->code+while_init, cond_size); + luaO_memdown(f->code+while_init, f->code+cond_end, fs->pc-while_init); + while_init += JMPSIZE + fix_jump(ls, while_init, JMP, fs->pc-cond_size); + fix_upjmp(ls, IFTUPJMP, while_init); +} - case ')': break; /* parlist -> empty */ - default: luaX_error(ls, "NAME or `...' expected"); - } - code_args(ls, nparams, dots); +static void repeatstat (LexState *ls, int line) { + /* repeatstat -> REPEAT block UNTIL exp1 */ + FuncState *fs = ls->fs; + int repeat_init = fs->pc; + next(ls); + block(ls); + check_match(ls, UNTIL, REPEAT, line); + exp1(ls); + fix_upjmp(ls, IFFUPJMP, repeat_init); + deltastack(ls, -1); /* pops condition */ } + static int localnamelist (LexState *ls) { /* localnamelist -> NAME {',' NAME} */ int i = 1; @@ -1255,6 +1261,7 @@ static int localnamelist (LexState *ls) { return i; } + static void decinit (LexState *ls, listdesc *d) { /* decinit -> ['=' explist1] */ if (ls->token == '=') { @@ -1268,156 +1275,212 @@ static void decinit (LexState *ls, listdesc *d) { } -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; +static void localstat (LexState *ls) { + /* stat -> LOCAL localnamelist decinit */ + FuncState *fs = ls->fs; + listdesc d; + int nvars; + check_debugline(ls); + next(ls); + nvars = localnamelist(ls); + decinit(ls, &d); + adjustlocalvars(ls, nvars, fs->lastsetline); + adjust_mult_assign(ls, nvars, &d); +} + + +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); - var_or_func(ls, &nv); - if (nv.k == VEXP) - luaX_error(ls, "syntax error"); - left = assignment(ls, &nv, nvars+1); + lua_pushvar(ls, v); + code_constant(ls, checkname(ls)); + v->k = VINDEXED; } - else { /* assignment -> '=' explist1 */ - listdesc d; - if (ls->token != '=') - error_unexpected(ls); - next(ls); - explist1(ls, &d); - adjust_mult_assign(ls, nvars, &d); + return needself; +} + + +static int funcstat (LexState *ls, int line) { + /* funcstat -> FUNCTION funcname body */ + int needself; + vardesc v; + if (ls->fs->prev) /* inside other function? */ + return 0; + check_debugline(ls); + next(ls); + needself = funcname(ls, &v); + body(ls, needself, line); + storevar(ls, &v); + return 1; +} + + +static void namestat (LexState *ls) { + /* stat -> func | ['%'] NAME assignment */ + vardesc v; + check_debugline(ls); + var_or_func(ls, &v); + if (v.k == VEXP) { /* stat -> func */ + if (v.info == 0) /* is just an upper value? */ + luaX_error(ls, "syntax error"); + close_exp(ls, v.info, 0); } - if (v->k != VINDEXED || left+(nvars-1) == 0) { - /* global/local var or indexed var without values in between */ - storevar(ls, v); + else { /* stat -> ['%'] NAME assignment */ + int left = assignment(ls, &v, 1); + adjuststack(ls, left); /* remove eventual garbage left on stack */ } - 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 */ +} + + +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); } - return left; + codeIf(ls, c, e); } -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; +static int stat (LexState *ls) { + int line = ls->linenumber; /* may be needed for error messages */ + switch (ls->token) { + case IF: /* stat -> IF ifpart END */ + ifpart(ls, line); + return 1; + + case WHILE: /* stat -> whilestat */ + whilestat(ls, line); + return 1; + + case DO: { /* stat -> DO block END */ + next(ls); + block(ls); + check_match(ls, END, DO, line); + return 1; + } + + case REPEAT: /* stat -> repeatstat */ + repeatstat(ls, line); + return 1; + + case FUNCTION: /* stat -> funcstat */ + return funcstat(ls, line); + + case LOCAL: /* stat -> localstat */ + localstat(ls); + return 1; + + case NAME: case '%': /* stat -> namestat */ + namestat(ls); + return 1; + + case RETURN: case ';': case ELSE: case ELSEIF: + case END: case UNTIL: case EOS: /* 'stat' follow */ + return 0; + + default: + error_unexpected(ls); + return 0; /* to avoid warnings */ } - check_match(ls, '}', '{', line); - fix_opcode(ls, pc, CREATEARRAY, nelems); } -static void part (LexState *ls, constdesc *cd) { + +static void parlist (LexState *ls) { + int nparams = 0; + int dots = 0; switch (ls->token) { - case ';': case '}': /* part -> empty */ - cd->n = 0; - cd->k = ls->token; - return; + case DOTS: /* parlist -> DOTS */ + next(ls); + dots = 1; + break; - 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]); + case NAME: /* parlist, tailparlist -> NAME [',' tailparlist] */ + init: + store_localvar(ls, str_checkname(ls), nparams++); + if (ls->token == ',') { + next(ls); + switch (ls->token) { + case DOTS: /* tailparlist -> DOTS */ + next(ls); + dots = 1; break; - default: - error_unexpected(ls); + + case NAME: /* tailparlist -> NAME [',' tailparlist] */ + goto init; + + default: luaX_error(ls, "NAME or `...' expected"); } - 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 '[': /* part -> recfield recfields */ - recfield(ls); - cd->n = recfields(ls); - cd->k = 1; /* record */ - break; + case ')': break; /* parlist -> empty */ - default: /* part -> exp1 listfields */ - exp1(ls); - cd->n = listfields(ls); - cd->k = 0; /* list */ - break; + default: luaX_error(ls, "NAME or `...' expected"); } + code_args(ls, nparams, dots); } -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 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 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); + +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, ';'); } - 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"); +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, ';'); } - 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++);