Browse Source

first version of extra debug information (NAME)

Roberto Ierusalimschy 25 years ago
parent
commit
298d0abff7
6 changed files with 658 additions and 520 deletions
  1. 58 8
      ldebug.c
  2. 3 2
      ldo.c
  3. 19 10
      lobject.h
  4. 4 1
      lopcodes.h
  5. 549 486
      lparser.c
  6. 25 13
      lvm.c

+ 58 - 8
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");
+}

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

+ 19 - 10
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;
 
 

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

+ 549 - 486
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 <a.x> must be stored like regular indexed vars <a["x"]> */
+  /* dotted variables <a.x> must be stored as regular indexed vars <a["x"]> */
   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 */
 }
 

+ 25 - 13
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++);