diff options
Diffstat (limited to 'src/lparser.c')
-rw-r--r-- | src/lparser.c | 1910 |
1 files changed, 821 insertions, 1089 deletions
diff --git a/src/lparser.c b/src/lparser.c index b0aa13f5..b792c956 100644 --- a/src/lparser.c +++ b/src/lparser.c @@ -1,5 +1,5 @@ /* -** $Id: lparser.c,v 1.37a 1999/06/17 17:04:03 roberto Exp $ +** $Id: lparser.c,v 1.116 2000/10/27 11:39:52 roberto Exp $ ** LL(1) Parser and code generator for Lua ** See Copyright Notice in lua.h */ @@ -8,1385 +8,1117 @@ #include <stdio.h> #include <string.h> -#include "lauxlib.h" -#include "ldo.h" +#include "lua.h" + +#include "lcode.h" #include "lfunc.h" #include "llex.h" #include "lmem.h" +#include "lobject.h" #include "lopcodes.h" #include "lparser.h" #include "lstate.h" #include "lstring.h" -#include "lua.h" -#include "luadebug.h" -#include "lzio.h" - - - -/* size of a "normal" jump instruction: OpCode + 1 byte */ -#define JMPSIZE 2 - -/* maximum number of local variables */ -#ifndef MAXLOCALS -#define MAXLOCALS 200 /* arbitrary limit (<256) */ -#endif - - -/* maximum number of upvalues */ -#ifndef MAXUPVALUES -#define MAXUPVALUES 32 /* arbitrary limit (<256) */ -#endif - - -/* maximum number of variables in the left side of an assignment */ -#ifndef MAXVARSLH -#define MAXVARSLH 100 /* arbitrary limit (<255) */ -#endif - - -/* maximum number of parameters in a function */ -#ifndef MAXPARAMS -#define MAXPARAMS 100 /* arbitrary limit (<ZEROVARARG) */ -#endif - - -/* -** Variable descriptor: -** must include an "exp" option because LL(1) cannot distinguish -** between variables, upvalues and function calls on first sight. -*/ -typedef enum { - VGLOBAL, /* info is constant index of global name */ - VLOCAL, /* info is stack index */ - VDOT, /* info is constant index of index name */ - VINDEXED, /* no info (table and index are on the stack) */ - VEXP /* info is pc index of "nparam" of a call (or 0 if exp is closed) */ -} varkind; - -typedef struct vardesc { - varkind k; - int info; -} 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" -*/ -typedef struct listdesc { - int n; - int pc; /* 0 if last expression is closed */ -} listdesc; /* ** Constructors descriptor: -** "n" indicates number of elements, and "k" signals whether +** `n' indicates number of elements, and `k' signals whether ** it is a list constructor (k = 0) or a record constructor (k = 1) ** or empty (k = ';' or '}') */ -typedef struct constdesc { +typedef struct Constdesc { int n; int k; -} constdesc; +} Constdesc; + + +typedef struct Breaklabel { + struct Breaklabel *previous; /* chain */ + int breaklist; + int stacklevel; +} Breaklabel; -/* state needed to generate code for a given function */ -typedef struct FuncState { - TProtoFunc *f; /* current function header */ - struct FuncState *prev; /* enclosuring function */ - int pc; /* next position to code */ - int stacksize; /* number of values on activation register */ - int maxstacksize; /* maximum number of values on activation register */ - int nlocalvar; /* number of active local variables */ - int nupvalues; /* number of upvalues */ - int nvars; /* number of entries in f->locvars (-1 if no debug information) */ - int lastsetline; /* line where last SETLINE was issued */ - vardesc upvalues[MAXUPVALUES]; /* upvalues */ - TaggedString *localvar[MAXLOCALS]; /* store local variable names */ -} 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 expr (LexState *ls, expdesc *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 statlist (LexState *ls); -static void var_or_func (LexState *ls, vardesc *v); -static void var_or_func_tail (LexState *ls, vardesc *v); - - - -static void checklimit (LexState *ls, int val, int limit, char *msg) { - if (val > limit) { - char buff[100]; - sprintf(buff, "too many %s (limit=%d)", msg, limit); - luaX_error(ls, buff); - } -} - -static void check_pc (FuncState *fs, int n) { - luaM_growvector(fs->f->code, fs->pc, n, Byte, codeEM, MAX_INT); -} - - -static void code_byte (FuncState *fs, Byte c) { - check_pc(fs, 1); - fs->f->code[fs->pc++] = c; -} -static void deltastack (LexState *ls, int delta) { - FuncState *fs = ls->fs; - fs->stacksize += delta; - if (fs->stacksize > fs->maxstacksize) { - if (fs->stacksize > MAX_BYTE) - luaX_error(ls, "function/expression too complex"); - fs->maxstacksize = fs->stacksize; - } -} - - -static void code_oparg_at (LexState *ls, int pc, OpCode op, - int arg, int delta) { - Byte *code = ls->fs->f->code; - deltastack(ls, delta); - if (arg <= MAX_BYTE) { - code[pc] = (Byte)op; - code[pc+1] = (Byte)arg; - } - else if (arg > MAX_ARG) - luaX_error(ls, "code too long"); - else { /* MAX_BYTE < arg < MAX_ARG */ - if (arg > MAX_WORD) { - code[pc] = (Byte)LONGARG; - code[pc+1] = (Byte)(arg>>16); - pc += 2; - } - code[pc] = (Byte)(op-1); /* opcode for word argument */ - code[pc+1] = (Byte)((arg&0xFFFF)>>8); - code[pc+2] = (Byte)(arg&0xFF); +static void next (LexState *ls) { + ls->lastline = ls->linenumber; + if (ls->lookahead.token != TK_EOS) { /* is there a look-ahead token? */ + ls->t = ls->lookahead; /* use this one */ + ls->lookahead.token = TK_EOS; /* and discharge it */ } + else + ls->t.token = luaX_lex(ls, &ls->t.seminfo); /* read next token */ } -static int codesize (int arg) { - if (arg <= MAX_BYTE) return 2; /* opcode + 1 byte */ - else if (arg <= MAX_WORD) return 3; /* opcode + 1 word (2 bytes) */ - else return 5; /* LONGARG + 1 byte + opcode + 1 word (2 bytes) */ +static void lookahead (LexState *ls) { + LUA_ASSERT(ls->lookahead.token == TK_EOS, "two look-aheads"); + ls->lookahead.token = luaX_lex(ls, &ls->lookahead.seminfo); } -static int fix_opcode (LexState *ls, int pc, OpCode op, int arg) { - int tomove = codesize(arg)-2; - if (tomove > 0) { /* need to open space? */ - FuncState *fs = ls->fs; - TProtoFunc *f = fs->f; - check_pc(fs, tomove); - luaO_memup(f->code+pc+tomove, f->code+pc, fs->pc-pc); - fs->pc += tomove; - } - code_oparg_at(ls, pc, op, arg, 0); - return tomove; +static void error_expected (LexState *ls, int token) { + char buff[100], t[TOKEN_LEN]; + luaX_token2str(token, t); + sprintf(buff, "`%.20s' expected", t); + luaK_error(ls, buff); } -static void code_oparg (LexState *ls, OpCode op, int arg, int delta) { - int size = codesize(arg); - check_pc(ls->fs, size); - code_oparg_at(ls, ls->fs->pc, op, arg, delta); - ls->fs->pc += size; +static void check (LexState *ls, int c) { + if (ls->t.token != c) + error_expected(ls, c); + next(ls); } -static void code_opcode (LexState *ls, OpCode op, int delta) { - deltastack(ls, delta); - code_byte(ls->fs, (Byte)op); +static void check_condition (LexState *ls, int c, const char *msg) { + if (!c) luaK_error(ls, msg); } -static void code_constant (LexState *ls, int c) { - code_oparg(ls, PUSHCONSTANT, c, 1); +static int optional (LexState *ls, int c) { + if (ls->t.token == c) { + next(ls); + return 1; + } + else return 0; } -static int next_constant (FuncState *fs) { - TProtoFunc *f = fs->f; - luaM_growvector(f->consts, f->nconsts, 1, TObject, constantEM, MAX_ARG); - return f->nconsts++; +static void check_match (LexState *ls, int what, int who, int where) { + if (ls->t.token != what) { + if (where == ls->linenumber) + error_expected(ls, what); + else { + char buff[100]; + char t_what[TOKEN_LEN], t_who[TOKEN_LEN]; + luaX_token2str(what, t_what); + luaX_token2str(who, t_who); + sprintf(buff, "`%.20s' expected (to close `%.20s' at line %d)", + t_what, t_who, where); + luaK_error(ls, buff); + } + } + next(ls); } -static int string_constant (FuncState *fs, TaggedString *s) { - TProtoFunc *f = fs->f; - int c = s->constindex; - if (!(c < f->nconsts && - ttype(&f->consts[c]) == LUA_T_STRING && tsvalue(&f->consts[c]) == s)) { - c = next_constant(fs); - ttype(&f->consts[c]) = LUA_T_STRING; - tsvalue(&f->consts[c]) = s; - s->constindex = c; /* hint for next time */ +static int string_constant (FuncState *fs, TString *s) { + Proto *f = fs->f; + int c = s->u.s.constindex; + if (c >= f->nkstr || f->kstr[c] != s) { + luaM_growvector(fs->L, f->kstr, f->nkstr, 1, TString *, + "constant table overflow", MAXARG_U); + c = f->nkstr++; + f->kstr[c] = s; + s->u.s.constindex = c; /* hint for next time */ } return c; } -static void code_string (LexState *ls, TaggedString *s) { - code_constant(ls, string_constant(ls->fs, s)); +static void code_string (LexState *ls, TString *s) { + luaK_kstr(ls, string_constant(ls->fs, s)); } -#define LIM 20 -static int real_constant (FuncState *fs, real r) { - /* check whether 'r' has appeared within the last LIM entries */ - TObject *cnt = fs->f->consts; - int c = fs->f->nconsts; - int lim = c < LIM ? 0 : c-LIM; - while (--c >= lim) { - if (ttype(&cnt[c]) == LUA_T_NUMBER && nvalue(&cnt[c]) == r) - return c; - } - /* not found; create a new entry */ - c = next_constant(fs); - cnt = fs->f->consts; /* 'next_constant' may have reallocated this vector */ - ttype(&cnt[c]) = LUA_T_NUMBER; - nvalue(&cnt[c]) = r; - return c; -} - - -static void code_number (LexState *ls, real f) { - real af = (f<0) ? -f : f; - if (0 <= af && af <= (real)MAX_WORD && (int)af == af) { - /* abs(f) has a short integer value */ - code_oparg(ls, (f<0) ? PUSHNUMBERNEG : PUSHNUMBER, (int)af, 1); - } - else - code_constant(ls, real_constant(ls->fs, f)); +static TString *str_checkname (LexState *ls) { + TString *ts; + check_condition(ls, (ls->t.token == TK_NAME), "<name> expected"); + ts = ls->t.seminfo.ts; + next(ls); + return ts; } -static void flush_record (LexState *ls, int n) { - if (n > 0) - code_oparg(ls, SETMAP, n-1, -2*n); +static int checkname (LexState *ls) { + return string_constant(ls->fs, str_checkname(ls)); } -static void flush_list (LexState *ls, int m, int n) { - if (n > 0) { - code_oparg(ls, SETLIST, m, -n); - code_byte(ls->fs, (Byte)n); - } +static int luaI_registerlocalvar (LexState *ls, TString *varname) { + Proto *f = ls->fs->f; + luaM_growvector(ls->L, f->locvars, f->nlocvars, 1, LocVar, "", MAX_INT); + f->locvars[f->nlocvars].varname = varname; + return f->nlocvars++; } -static void luaI_registerlocalvar (FuncState *fs, TaggedString *varname, - int line) { - if (fs->nvars != -1) { /* debug information? */ - TProtoFunc *f = fs->f; - luaM_growvector(f->locvars, fs->nvars, 1, LocVar, "", MAX_INT); - f->locvars[fs->nvars].varname = varname; - f->locvars[fs->nvars].line = line; - fs->nvars++; - } +static void new_localvar (LexState *ls, TString *name, int n) { + FuncState *fs = ls->fs; + luaX_checklimit(ls, fs->nactloc+n+1, MAXLOCALS, "local variables"); + fs->actloc[fs->nactloc+n] = luaI_registerlocalvar(ls, name); } -static void luaI_unregisterlocalvar (FuncState *fs, int line) { - luaI_registerlocalvar(fs, NULL, line); +static void adjustlocalvars (LexState *ls, int nvars) { + FuncState *fs = ls->fs; + while (nvars--) + fs->f->locvars[fs->actloc[fs->nactloc++]].startpc = fs->pc; } -static void store_localvar (LexState *ls, TaggedString *name, int n) { +static void removelocalvars (LexState *ls, int nvars) { FuncState *fs = ls->fs; - checklimit(ls, fs->nlocalvar+n+1, MAXLOCALS, "local variables"); - fs->localvar[fs->nlocalvar+n] = name; - luaI_registerlocalvar(fs, name, ls->linenumber); + while (nvars--) + fs->f->locvars[fs->actloc[--fs->nactloc]].endpc = fs->pc; } -static void add_localvar (LexState *ls, TaggedString *name) { - store_localvar(ls, name, 0); - ls->fs->nlocalvar++; +static void new_localvarstr (LexState *ls, const char *name, int n) { + new_localvar(ls, luaS_newfixed(ls->L, name), n); } -static void correctvarlines (LexState *ls, int nvars) { - FuncState *fs = ls->fs; - if (fs->nvars != -1) { /* debug information? */ - for (; nvars; nvars--) { /* correct line information */ - fs->f->locvars[fs->nvars-nvars].line = fs->lastsetline; +static int search_local (LexState *ls, TString *n, expdesc *var) { + FuncState *fs; + int level = 0; + for (fs=ls->fs; fs; fs=fs->prev) { + int i; + for (i=fs->nactloc-1; i >= 0; i--) { + if (n == fs->f->locvars[fs->actloc[i]].varname) { + var->k = VLOCAL; + var->u.index = i; + return level; + } } + level++; /* `var' not found; check outer level */ } + var->k = VGLOBAL; /* not found in any level; must be global */ + return -1; } -static int aux_localname (FuncState *fs, TaggedString *n) { - int i; - for (i=fs->nlocalvar-1; i >= 0; i--) - if (n == fs->localvar[i]) return i; /* local var index */ - return -1; /* not found */ -} - - -static void singlevar (LexState *ls, TaggedString *n, vardesc *var, int prev) { - FuncState *fs = prev ? ls->fs->prev : ls->fs; - int i = aux_localname(fs, n); - if (i >= 0) { /* local value? */ - var->k = VLOCAL; - var->info = i; - } - else { - FuncState *level = fs; - while ((level = level->prev) != NULL) /* check shadowing */ - if (aux_localname(level, n) >= 0) - luaX_syntaxerror(ls, "cannot access a variable in outer scope", n->str); - var->k = VGLOBAL; - var->info = string_constant(fs, n); - } +static void singlevar (LexState *ls, TString *n, expdesc *var) { + int level = search_local(ls, n, var); + if (level >= 1) /* neither local (0) nor global (-1)? */ + luaX_syntaxerror(ls, "cannot access a variable in outer scope", n->str); + else if (level == -1) /* global? */ + var->u.index = string_constant(ls->fs, n); } -static int indexupvalue (LexState *ls, TaggedString *n) { +static int indexupvalue (LexState *ls, expdesc *v) { FuncState *fs = ls->fs; - vardesc v; int i; - singlevar(ls, n, &v, 1); for (i=0; i<fs->nupvalues; i++) { - if (fs->upvalues[i].k == v.k && fs->upvalues[i].info == v.info) + if (fs->upvalues[i].k == v->k && fs->upvalues[i].u.index == v->u.index) return i; } /* new one */ - ++(fs->nupvalues); - checklimit(ls, fs->nupvalues, MAXUPVALUES, "upvalues"); - fs->upvalues[i] = v; /* i = fs->nupvalues - 1 */ - return i; -} - - -static void pushupvalue (LexState *ls, TaggedString *n) { - if (ls->fs->prev == NULL) - luaX_syntaxerror(ls, "cannot access upvalue in main", n->str); - if (aux_localname(ls->fs, n) >= 0) - luaX_syntaxerror(ls, "cannot access an upvalue in current scope", n->str); - code_oparg(ls, PUSHUPVALUE, indexupvalue(ls, n), 1); -} - - - -static void check_debugline (LexState *ls) { - if (L->debug && ls->linenumber != ls->fs->lastsetline) { - code_oparg(ls, SETLINE, ls->linenumber, 0); - ls->fs->lastsetline = ls->linenumber; - } -} - - -static void adjuststack (LexState *ls, int n) { - if (n > 0) - code_oparg(ls, POP, n, -n); - else if (n < 0) - code_oparg(ls, PUSHNIL, (-n)-1, -n); + luaX_checklimit(ls, fs->nupvalues+1, MAXUPVALUES, "upvalues"); + fs->upvalues[fs->nupvalues] = *v; + return fs->nupvalues++; } -static void close_exp (LexState *ls, int pc, int nresults) { - if (pc > 0) { /* expression is an open function call? */ - Byte *code = ls->fs->f->code; - code[pc-1] = (Byte)nresults; /* set nresults */ - /* push results, pop params (at code[pc]) and function */ - deltastack(ls, nresults-(code[pc]+1)); +static void pushupvalue (LexState *ls, TString *n) { + FuncState *fs = ls->fs; + expdesc v; + int level = search_local(ls, n, &v); + if (level == -1) { /* global? */ + if (fs->prev == NULL) + luaX_syntaxerror(ls, "cannot access upvalue in main", n->str); + v.u.index = string_constant(fs->prev, n); } -#ifdef DEBUG - code_oparg(ls, CHECKSTACK, ls->fs->stacksize, 0); -#endif + else if (level != 1) + luaX_syntaxerror(ls, + "upvalue must be global or local to immediately outer scope", n->str); + luaK_code1(fs, OP_PUSHUPVALUE, indexupvalue(ls, &v)); } -static void adjust_mult_assign (LexState *ls, int nvars, listdesc *d) { - int diff = d->n - nvars; - if (d->pc == 0) { /* list is closed */ - /* push or pop eventual difference between list lengths */ - adjuststack(ls, diff); - } - else { /* must correct function call */ +static void adjust_mult_assign (LexState *ls, int nvars, int nexps) { + FuncState *fs = ls->fs; + int diff = nexps - nvars; + if (nexps > 0 && luaK_lastisopen(fs)) { /* list ends in a function call */ diff--; /* do not count function call itself */ if (diff <= 0) { /* more variables than values? */ - /* function call must provide extra values */ - close_exp(ls, d->pc, -diff); - } - else { /* more values than variables */ - close_exp(ls, d->pc, 0); /* call should provide no value */ - adjuststack(ls, diff); /* pop eventual extra values */ + luaK_setcallreturns(fs, -diff); /* function call provide extra values */ + diff = 0; /* no more difference */ } + else /* more values than variables */ + luaK_setcallreturns(fs, 0); /* call should provide no value */ } + /* push or pop eventual difference between list lengths */ + luaK_adjuststack(fs, diff); } -static void code_args (LexState *ls, int nparams, int dots) { +static void code_params (LexState *ls, int nparams, int dots) { FuncState *fs = ls->fs; - fs->nlocalvar += nparams; /* "self" may already be there */ - checklimit(ls, fs->nlocalvar, MAXPARAMS, "parameters"); - nparams = fs->nlocalvar; - if (!dots) { - fs->f->code[1] = (Byte)nparams; /* fill-in arg information */ - deltastack(ls, nparams); - } - else { - fs->f->code[1] = (Byte)(nparams+ZEROVARARG); - deltastack(ls, nparams+1); - add_localvar(ls, luaS_new("arg")); + adjustlocalvars(ls, nparams); + luaX_checklimit(ls, fs->nactloc, MAXPARAMS, "parameters"); + fs->f->numparams = fs->nactloc; /* `self' could be there already */ + fs->f->is_vararg = dots; + if (dots) { + new_localvarstr(ls, "arg", 0); + adjustlocalvars(ls, 1); } + luaK_deltastack(fs, fs->nactloc); /* count parameters in the stack */ } -static void unloaddot (LexState *ls, vardesc *v) { - /* dotted variables <a.x> must be stored like regular indexed vars <a["x"]> */ - if (v->k == VDOT) { - code_constant(ls, v->info); - v->k = VINDEXED; - } +static void enterbreak (FuncState *fs, Breaklabel *bl) { + bl->stacklevel = fs->stacklevel; + bl->breaklist = NO_JUMP; + bl->previous = fs->bl; + fs->bl = bl; } -static void lua_pushvar (LexState *ls, vardesc *var) { - switch (var->k) { - case VLOCAL: - code_oparg(ls, PUSHLOCAL, var->info, 1); - break; - case VGLOBAL: - code_oparg(ls, GETGLOBAL, var->info, 1); - break; - case VDOT: - code_oparg(ls, GETDOTTED, var->info, 0); - break; - case VINDEXED: - code_opcode(ls, GETTABLE, -1); - break; - case VEXP: - close_exp(ls, var->info, 1); /* function must return 1 value */ - break; - } - var->k = VEXP; - var->info = 0; /* now this is a closed expression */ -} - - -static void storevar (LexState *ls, vardesc *var) { - switch (var->k) { - case VLOCAL: - code_oparg(ls, SETLOCAL, var->info, -1); - break; - case VGLOBAL: - code_oparg(ls, SETGLOBAL, var->info, -1); - break; - case VINDEXED: - code_opcode(ls, SETTABLEPOP, -3); - break; - default: - LUA_INTERNALERROR("invalid var kind to store"); - } -} - - -static int fix_jump (LexState *ls, int pc, OpCode op, int n) { - /* jump is relative to position following jump instruction */ - return fix_opcode(ls, pc, op, n-(pc+JMPSIZE)); -} - - -static void fix_upjmp (LexState *ls, OpCode op, int pos) { - int delta = ls->fs->pc+JMPSIZE - pos; /* jump is relative */ - code_oparg(ls, op, delta+(codesize(delta)-2), 0); +static void leavebreak (FuncState *fs, Breaklabel *bl) { + fs->bl = bl->previous; + LUA_ASSERT(bl->stacklevel == fs->stacklevel, "wrong levels"); + luaK_patchlist(fs, bl->breaklist, luaK_getlabel(fs)); } -static void codeIf (LexState *ls, int thenAdd, int elseAdd) { - FuncState *fs = ls->fs; - int elseinit = elseAdd+JMPSIZE; - if (fs->pc == elseinit) { /* no else part? */ - fs->pc -= JMPSIZE; - elseinit = fs->pc; - } - else - elseinit += fix_jump(ls, elseAdd, JMP, fs->pc); - fix_jump(ls, thenAdd, IFFJMP, elseinit); -} - - -static void func_onstack (LexState *ls, FuncState *func) { +static void pushclosure (LexState *ls, FuncState *func) { FuncState *fs = ls->fs; + Proto *f = fs->f; int i; - int c = next_constant(fs); - ttype(&fs->f->consts[c]) = LUA_T_PROTO; - fs->f->consts[c].value.tf = func->f; - if (func->nupvalues == 0) - code_constant(ls, c); - else { - for (i=0; i<func->nupvalues; i++) - lua_pushvar(ls, &func->upvalues[i]); - deltastack(ls, 1); /* CLOSURE puts one extra element (before poping) */ - code_oparg(ls, CLOSURE, c, -func->nupvalues); - code_byte(fs, (Byte)func->nupvalues); - } + for (i=0; i<func->nupvalues; i++) + luaK_tostack(ls, &func->upvalues[i], 1); + luaM_growvector(ls->L, f->kproto, f->nkproto, 1, Proto *, + "constant table overflow", MAXARG_A); + f->kproto[f->nkproto++] = func->f; + luaK_code2(fs, OP_CLOSURE, f->nkproto-1, func->nupvalues); } -static void init_state (LexState *ls, FuncState *fs, TaggedString *source) { - TProtoFunc *f = luaF_newproto(); +static void open_func (LexState *ls, FuncState *fs) { + Proto *f = luaF_newproto(ls->L); fs->prev = ls->fs; /* linked list of funcstates */ + fs->ls = ls; + fs->L = ls->L; ls->fs = fs; - fs->stacksize = 0; - fs->maxstacksize = 0; - fs->nlocalvar = 0; + fs->stacklevel = 0; + fs->nactloc = 0; fs->nupvalues = 0; - fs->lastsetline = 0; + fs->bl = NULL; fs->f = f; - f->source = source; + f->source = ls->source; fs->pc = 0; + fs->lasttarget = 0; + fs->lastline = 0; + fs->jlt = NO_JUMP; f->code = NULL; - fs->nvars = (L->debug) ? 0 : -1; /* flag no debug information? */ - code_byte(fs, 0); /* to be filled with maxstacksize */ - code_byte(fs, 0); /* to be filled with arg information */ - /* push function (to avoid GC) */ - tfvalue(L->stack.top) = f; ttype(L->stack.top) = LUA_T_PROTO; - incr_top; + f->maxstacksize = 0; + f->numparams = 0; /* default for main chunk */ + f->is_vararg = 0; /* default for main chunk */ } static void close_func (LexState *ls) { + lua_State *L = ls->L; FuncState *fs = ls->fs; - TProtoFunc *f = fs->f; - code_opcode(ls, ENDCODE, 0); - f->code[0] = (Byte)fs->maxstacksize; - luaM_reallocvector(f->code, fs->pc, Byte); - luaM_reallocvector(f->consts, f->nconsts, TObject); - if (fs->nvars != -1) { /* debug information? */ - luaI_registerlocalvar(fs, NULL, -1); /* flag end of vector */ - luaM_reallocvector(f->locvars, fs->nvars, LocVar); - } + Proto *f = fs->f; + luaK_code0(fs, OP_END); + luaK_getlabel(fs); /* close eventual list of pending jumps */ + luaM_reallocvector(L, f->code, fs->pc, Instruction); + luaM_reallocvector(L, f->kstr, f->nkstr, TString *); + luaM_reallocvector(L, f->knum, f->nknum, Number); + luaM_reallocvector(L, f->kproto, f->nkproto, Proto *); + removelocalvars(ls, fs->nactloc); + luaM_reallocvector(L, f->locvars, f->nlocvars, LocVar); + luaM_reallocvector(L, f->lineinfo, f->nlineinfo+1, int); + f->lineinfo[f->nlineinfo++] = MAX_INT; /* end flag */ + luaF_protook(L, f, fs->pc); /* proto is ok now */ ls->fs = fs->prev; - L->stack.top--; /* pop function */ + LUA_ASSERT(fs->bl == NULL, "wrong list end"); } - -static int expfollow [] = {ELSE, ELSEIF, THEN, IF, WHILE, REPEAT, DO, NAME, - LOCAL, FUNCTION, END, UNTIL, RETURN, ')', ']', '}', ';', EOS, ',', 0}; - - -static int is_in (int tok, int *toks) { - int *t; - for (t=toks; *t; t++) - if (*t == tok) return t-toks; - return -1; -} - - -static void next (LexState *ls) { - ls->token = luaX_lex(ls); -} - - -static void error_expected (LexState *ls, int token) { - char buff[100], t[TOKEN_LEN]; - luaX_token2str(token, t); - sprintf(buff, "`%s' expected", t); - luaX_error(ls, buff); -} - - -static void error_unexpected (LexState *ls) { - luaX_error(ls, "unexpected token"); -} - - -static void error_unmatched (LexState *ls, int what, int who, int where) { - if (where == ls->linenumber) - error_expected(ls, what); - else { - char buff[100]; - char t_what[TOKEN_LEN], t_who[TOKEN_LEN]; - luaX_token2str(what, t_what); - luaX_token2str(who, t_who); - sprintf(buff, "`%s' expected (to close `%s' at line %d)", - t_what, t_who, where); - luaX_error(ls, buff); - } -} - -static void check (LexState *ls, int c) { - if (ls->token != c) - error_expected(ls, c); - next(ls); -} - -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' */ - next(ls); -} - -static int checkname (LexState *ls) { - int sc; - if (ls->token != NAME) - luaX_error(ls, "`NAME' expected"); - sc = string_constant(ls->fs, ls->seminfo.ts); - next(ls); - return sc; -} - - -static TaggedString *str_checkname (LexState *ls) { - int i = checkname(ls); /* this call may realloc `f->consts' */ - return tsvalue(&ls->fs->f->consts[i]); -} - - -static int optional (LexState *ls, int c) { - if (ls->token == c) { - next(ls); - return 1; - } - else return 0; -} - - -TProtoFunc *luaY_parser (ZIO *z) { +Proto *luaY_parser (lua_State *L, ZIO *z) { struct LexState lexstate; struct FuncState funcstate; - luaX_setinput(&lexstate, z); - init_state(&lexstate, &funcstate, luaS_new(zname(z))); + luaX_setinput(L, &lexstate, z, luaS_new(L, zname(z))); + open_func(&lexstate, &funcstate); next(&lexstate); /* read first token */ chunk(&lexstate); - if (lexstate.token != EOS) - luaX_error(&lexstate, "<eof> expected"); + check_condition(&lexstate, (lexstate.t.token == TK_EOS), "<eof> expected"); close_func(&lexstate); + LUA_ASSERT(funcstate.prev == NULL, "wrong list end"); + LUA_ASSERT(funcstate.nupvalues == 0, "no upvalues in main"); return funcstate.f; } /*============================================================*/ -/* GRAMAR RULES */ +/* GRAMMAR RULES */ /*============================================================*/ -static void chunk (LexState *ls) { - /* chunk -> statlist ret */ - statlist(ls); - ret(ls); -} -static void statlist (LexState *ls) { - /* statlist -> { stat [;] } */ - while (stat(ls)) { - LUA_ASSERT(ls->fs->stacksize == ls->fs->nlocalvar, - "stack size != # local vars"); - optional(ls, ';'); +static int explist1 (LexState *ls) { + /* explist1 -> expr { ',' expr } */ + int n = 1; /* at least one expression */ + expdesc v; + expr(ls, &v); + while (ls->t.token == ',') { + luaK_tostack(ls, &v, 1); /* gets only 1 value from previous expression */ + next(ls); /* skip comma */ + expr(ls, &v); + n++; } + luaK_tostack(ls, &v, 0); /* keep open number of values of last expression */ + return n; } -static int stat (LexState *ls) { - int line = ls->linenumber; /* may be needed for error messages */ - FuncState *fs = ls->fs; - switch (ls->token) { - case IF: /* stat -> IF ifpart END */ - ifpart(ls, line); - return 1; - case WHILE: { /* stat -> WHILE cond DO block END */ - TProtoFunc *f = fs->f; - int while_init = fs->pc; - int cond_end, cond_size; +static void funcargs (LexState *ls, int slf) { + FuncState *fs = ls->fs; + int slevel = fs->stacklevel - slf - 1; /* where is func in the stack */ + switch (ls->t.token) { + case '(': { /* funcargs -> '(' [ explist1 ] ')' */ + int line = ls->linenumber; + int nargs = 0; 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(fs, 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); - return 1; + if (ls->t.token != ')') /* arg list not empty? */ + nargs = explist1(ls); + check_match(ls, ')', '(', line); +#ifdef LUA_COMPAT_ARGRET + if (nargs > 0) /* arg list is not empty? */ + luaK_setcallreturns(fs, 1); /* last call returns only 1 value */ +#else + UNUSED(nargs); /* to avoid warnings */ +#endif + break; } - - case DO: { /* stat -> DO block END */ - next(ls); - block(ls); - check_match(ls, END, DO, line); - return 1; + case '{': { /* funcargs -> constructor */ + constructor(ls); + break; } - - case REPEAT: { /* stat -> REPEAT block UNTIL exp1 */ - int repeat_init = fs->pc; + case TK_STRING: { /* funcargs -> STRING */ + code_string(ls, ls->t.seminfo.ts); /* must use `seminfo' before `next' */ next(ls); - block(ls); - check_match(ls, UNTIL, REPEAT, line); - exp1(ls); - fix_upjmp(ls, IFFUPJMP, repeat_init); - deltastack(ls, -1); /* pops condition */ - return 1; + break; } - - case FUNCTION: { /* stat -> 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; + default: { + luaK_error(ls, "function arguments expected"); + break; } + } + fs->stacklevel = slevel; /* call will remove function and arguments */ + luaK_code2(fs, OP_CALL, slevel, MULT_RET); +} - case LOCAL: { /* stat -> LOCAL localnamelist decinit */ - listdesc d; - int nvars; - check_debugline(ls); - next(ls); - nvars = localnamelist(ls); - decinit(ls, &d); - fs->nlocalvar += nvars; - correctvarlines(ls, nvars); /* vars will be alive only after decinit */ - adjust_mult_assign(ls, nvars, &d); - return 1; - } - case NAME: case '%': { /* 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); +static void var_or_func_tail (LexState *ls, expdesc *v) { + for (;;) { + switch (ls->t.token) { + case '.': { /* var_or_func_tail -> '.' NAME */ + next(ls); + luaK_tostack(ls, v, 1); /* `v' must be on stack */ + luaK_kstr(ls, checkname(ls)); + v->k = VINDEXED; + break; + } + case '[': { /* var_or_func_tail -> '[' exp1 ']' */ + next(ls); + luaK_tostack(ls, v, 1); /* `v' must be on stack */ + v->k = VINDEXED; + exp1(ls); + check(ls, ']'); + break; } - else { /* stat -> ['%'] NAME assignment */ - int left = assignment(ls, &v, 1); - adjuststack(ls, left); /* remove eventual 'garbage' left on stack */ + case ':': { /* var_or_func_tail -> ':' NAME funcargs */ + int name; + next(ls); + name = checkname(ls); + luaK_tostack(ls, v, 1); /* `v' must be on stack */ + luaK_code1(ls->fs, OP_PUSHSELF, name); + funcargs(ls, 1); + v->k = VEXP; + v->u.l.t = v->u.l.f = NO_JUMP; + break; } - return 1; + case '(': case TK_STRING: case '{': { /* var_or_func_tail -> funcargs */ + luaK_tostack(ls, v, 1); /* `v' must be on stack */ + funcargs(ls, 0); + v->k = VEXP; + v->u.l.t = v->u.l.f = NO_JUMP; + break; + } + default: return; /* should be follow... */ } + } +} - 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 */ +static void var_or_func (LexState *ls, expdesc *v) { + /* var_or_func -> ['%'] NAME var_or_func_tail */ + if (optional(ls, '%')) { /* upvalue? */ + pushupvalue(ls, str_checkname(ls)); + v->k = VEXP; + v->u.l.t = v->u.l.f = NO_JUMP; } + else /* variable name */ + singlevar(ls, str_checkname(ls), v); + var_or_func_tail(ls, v); } -static int SaveWord (LexState *ls) { - int res = ls->fs->pc; - check_pc(ls->fs, 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 */ +/* +** {====================================================================== +** Rules for Constructors +** ======================================================================= +*/ + + +static void recfield (LexState *ls) { + /* recfield -> (NAME | '['exp1']') = exp1 */ + switch (ls->t.token) { + case TK_NAME: { + luaK_kstr(ls, checkname(ls)); + break; + } + case '[': { + next(ls); + exp1(ls); + check(ls, ']'); + break; + } + default: luaK_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(fs, 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 { ',' recfield } [','] */ + FuncState *fs = ls->fs; + int n = 1; /* at least one element */ + recfield(ls); + while (ls->t.token == ',') { next(ls); - lua_pushvar(ls, v); - code_constant(ls, checkname(ls)); - v->k = VINDEXED; + if (ls->t.token == ';' || ls->t.token == '}') + break; + recfield(ls); + n++; + if (n%RFIELDS_PER_FLUSH == 0) + luaK_code1(fs, OP_SETMAP, RFIELDS_PER_FLUSH); } - 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_new("self")); - parlist(ls); - check(ls, ')'); - chunk(ls); - check_match(ls, END, FUNCTION, line); - close_func(ls); - func_onstack(ls, &newfs); + luaK_code1(fs, OP_SETMAP, n%RFIELDS_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 int listfields (LexState *ls) { + /* listfields -> exp1 { ',' exp1 } [','] */ + FuncState *fs = ls->fs; + int n = 1; /* at least one element */ + exp1(ls); + while (ls->t.token == ',') { + next(ls); + if (ls->t.token == ';' || ls->t.token == '}') + break; + exp1(ls); + n++; + luaX_checklimit(ls, n/LFIELDS_PER_FLUSH, MAXARG_A, + "`item groups' in a list initializer"); + if (n%LFIELDS_PER_FLUSH == 0) + luaK_code2(fs, OP_SETLIST, n/LFIELDS_PER_FLUSH - 1, LFIELDS_PER_FLUSH); } - codeIf(ls, c, e); + luaK_code2(fs, OP_SETLIST, n/LFIELDS_PER_FLUSH, n%LFIELDS_PER_FLUSH); + return n; } -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; + +static void constructor_part (LexState *ls, Constdesc *cd) { + switch (ls->t.token) { + case ';': case '}': { /* constructor_part -> empty */ + cd->n = 0; + cd->k = ls->t.token; + break; + } + case TK_NAME: { /* may be listfields or recfields */ + lookahead(ls); + if (ls->lookahead.token != '=') /* expression? */ + goto case_default; + /* else go through to recfields */ + } + case '[': { /* constructor_part -> recfields */ + cd->n = recfields(ls); + cd->k = 1; /* record */ + break; + } + default: { /* constructor_part -> listfields */ + case_default: + 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, ';'); } } -/* -** 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 int binop [] = {EQ, NE, '>', '<', LE, GE, CONC, - '+', '-', '*', '/', '^', 0}; - -static int priority [POW+1] = {5, 5, 1, 1, 1, 1, 1, 1, 2, 3, 3, 4, 4, 6}; - -static 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, "ill-formed expression"); +static void constructor (LexState *ls) { + /* constructor -> '{' constructor_part [';' constructor_part] '}' */ + FuncState *fs = ls->fs; + int line = ls->linenumber; + int pc = luaK_code1(fs, OP_CREATETABLE, 0); + int nelems; + Constdesc cd; + check(ls, '{'); + constructor_part(ls, &cd); + nelems = cd.n; + if (optional(ls, ';')) { + Constdesc other_cd; + constructor_part(ls, &other_cd); + check_condition(ls, (cd.k != other_cd.k), "invalid constructor syntax"); + nelems += other_cd.n; + } + check_match(ls, '}', '{', line); + luaX_checklimit(ls, nelems, MAXARG_U, "elements in a table constructor"); + SETARG_U(fs->f->code[pc], nelems); /* set initial table size */ } +/* }====================================================================== */ -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; -} +/* +** {====================================================================== +** Expression parsing +** ======================================================================= +*/ -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], op<FIRSTBIN?0:-1); - s->top--; - } -} -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; +static void simpleexp (LexState *ls, expdesc *v) { + FuncState *fs = ls->fs; + switch (ls->t.token) { + case TK_NUMBER: { /* simpleexp -> NUMBER */ + Number r = ls->t.seminfo.r; next(ls); - /* dirty trick: check whether it is a -NUMBER not followed by '^' */ - /* (because the priority of '^' is closer than '-'...) */ - if (s->top > 0 && s->ops[s->top-1] == INDMINUS && ls->token != '^') { - s->top--; /* remove '-' from stack */ - r = -r; - } - code_number(ls, r); + luaK_number(fs, r); break; } - - case STRING: /* simpleexp -> STRING */ - code_string(ls, ls->seminfo.ts); /* must use 'seminfo' before "next" */ + case TK_STRING: { /* simpleexp -> STRING */ + code_string(ls, ls->t.seminfo.ts); /* must use `seminfo' before `next' */ next(ls); break; - - case NIL: /* simpleexp -> NIL */ - adjuststack(ls, -1); + } + case TK_NIL: { /* simpleexp -> NIL */ + luaK_adjuststack(fs, -1); next(ls); break; - - case '{': /* simpleexp -> constructor */ + } + case '{': { /* simpleexp -> constructor */ constructor(ls); break; - - case FUNCTION: /* simpleexp -> FUNCTION body */ + } + case TK_FUNCTION: { /* simpleexp -> FUNCTION body */ next(ls); body(ls, 0, ls->linenumber); break; - - case '(': /* simpleexp -> '(' exp0 ')' */ + } + case '(': { /* simpleexp -> '(' expr ')' */ next(ls); - exp0(ls, v); + expr(ls, v); check(ls, ')'); return; - - case NAME: case '%': + } + case TK_NAME: case '%': { var_or_func(ls, v); return; - - default: - luaX_error(ls, "<expression> expected"); + } + default: { + luaK_error(ls, "<expression> expected"); return; + } } - v->k = VEXP; v->info = 0; + v->k = VEXP; + v->u.l.t = v->u.l.f = NO_JUMP; } -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 exp1 (LexState *ls) { + expdesc v; + expr(ls, &v); + luaK_tostack(ls, &v, 1); } -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 UnOpr getunopr (int op) { + switch (op) { + case TK_NOT: return OPR_NOT; + case '-': return OPR_MINUS; + default: return OPR_NOUNOPR; } } -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 */ +static BinOpr getbinopr (int op) { + switch (op) { + case '+': return OPR_ADD; + case '-': return OPR_SUB; + case '*': return OPR_MULT; + case '/': return OPR_DIV; + case '^': return OPR_POW; + case TK_CONCAT: return OPR_CONCAT; + case TK_NE: return OPR_NE; + case TK_EQ: return OPR_EQ; + case '<': return OPR_LT; + case TK_LE: return OPR_LE; + case '>': return OPR_GT; + case TK_GE: return OPR_GE; + case TK_AND: return OPR_AND; + case TK_OR: return OPR_OR; + default: return OPR_NOBINOPR; } - 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; +static const struct { + char left; /* left priority for each binary operator */ + char right; /* right priority */ +} priority[] = { /* ORDER OPR */ + {5, 5}, {5, 5}, {6, 6}, {6, 6}, /* arithmetic */ + {9, 8}, {4, 3}, /* power and concat (right associative) */ + {2, 2}, {2, 2}, /* equality */ + {2, 2}, {2, 2}, {2, 2}, {2, 2}, /* order */ + {1, 1}, {1, 1} /* logical */ +}; - 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; +#define UNARY_PRIORITY 7 /* priority for unary operators */ - 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... */ - } +/* +** subexpr -> (simplexep | unop subexpr) { binop subexpr } +** where `binop' is any binary operator with a priority higher than `limit' +*/ +static BinOpr subexpr (LexState *ls, expdesc *v, int limit) { + BinOpr op; + UnOpr uop = getunopr(ls->t.token); + if (uop != OPR_NOUNOPR) { + next(ls); + subexpr(ls, v, UNARY_PRIORITY); + luaK_prefix(ls, uop, v); + } + else simpleexp(ls, v); + /* expand while operators have priorities higher than `limit' */ + op = getbinopr(ls->t.token); + while (op != OPR_NOBINOPR && priority[op].left > limit) { + expdesc v2; + BinOpr nextop; + next(ls); + luaK_infix(ls, op, v); + /* read sub-expression with higher priority */ + nextop = subexpr(ls, &v2, priority[op].right); + luaK_posfix(ls, op, v, &v2); + op = nextop; } + return op; /* return first untreated operator */ } -static int funcparams (LexState *ls, int slf) { - FuncState *fs = ls->fs; - int nparams = 1; /* in cases STRING and constructor */ - 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, 1); - nparams = e.n; - break; - } - case '{': /* funcparams -> constructor */ - constructor(ls); - break; +static void expr (LexState *ls, expdesc *v) { + subexpr(ls, v, -1); +} - 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(fs, CALL); - code_byte(fs, 0); /* save space for nresult */ - code_byte(fs, (Byte)(nparams+slf)); - 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); +/* +** {====================================================================== +** Rules for Statements +** ======================================================================= +*/ + + +static int block_follow (int token) { + switch (token) { + case TK_ELSE: case TK_ELSEIF: case TK_END: + case TK_UNTIL: case TK_EOS: + return 1; + default: return 0; } } -static void explist1 (LexState *ls, listdesc *d) { - vardesc v; - exp0(ls, &v); - d->n = 1; - while (ls->token == ',') { - d->n++; - lua_pushvar(ls, &v); + +static void block (LexState *ls) { + /* block -> chunk */ + FuncState *fs = ls->fs; + int nactloc = fs->nactloc; + chunk(ls); + luaK_adjuststack(fs, fs->nactloc - nactloc); /* remove local variables */ + removelocalvars(ls, fs->nactloc - nactloc); +} + + +static int assignment (LexState *ls, expdesc *v, int nvars) { + int left = 0; /* number of values left in the stack after assignment */ + luaX_checklimit(ls, nvars, MAXVARSLH, "variables in a multiple assignment"); + if (ls->t.token == ',') { /* assignment -> ',' NAME assignment */ + expdesc nv; next(ls); - exp0(ls, &v); + var_or_func(ls, &nv); + check_condition(ls, (nv.k != VEXP), "syntax error"); + left = assignment(ls, &nv, nvars+1); + } + else { /* assignment -> '=' explist1 */ + int nexps; + check(ls, '='); + nexps = explist1(ls); + adjust_mult_assign(ls, nvars, nexps); } - if (v.k == VEXP) - d->pc = v.info; - else { - lua_pushvar(ls, &v); - d->pc = 0; + if (v->k != VINDEXED) + luaK_storevar(ls, v); + else { /* there may be garbage between table-index and value */ + luaK_code2(ls->fs, OP_SETTABLE, left+nvars+2, 1); + left += 2; } + 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; +static void cond (LexState *ls, expdesc *v) { + /* cond -> exp */ + expr(ls, v); /* read condition */ + luaK_goiftrue(ls->fs, v, 0); +} - 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; + int while_init = luaK_getlabel(fs); + expdesc v; + Breaklabel bl; + enterbreak(fs, &bl); + next(ls); + cond(ls, &v); + check(ls, TK_DO); + block(ls); + luaK_patchlist(fs, luaK_jump(fs), while_init); + luaK_patchlist(fs, v.u.l.f, luaK_getlabel(fs)); + check_match(ls, TK_END, TK_WHILE, line); + leavebreak(fs, &bl); +} - 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 cond */ + FuncState *fs = ls->fs; + int repeat_init = luaK_getlabel(fs); + expdesc v; + Breaklabel bl; + enterbreak(fs, &bl); + next(ls); + block(ls); + check_match(ls, TK_UNTIL, TK_REPEAT, line); + cond(ls, &v); + luaK_patchlist(fs, v.u.l.f, repeat_init); + leavebreak(fs, &bl); } -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++); + +static void forbody (LexState *ls, int nvar, OpCode prepfor, OpCode loopfor) { + /* forbody -> DO block END */ + FuncState *fs = ls->fs; + int prep = luaK_code1(fs, prepfor, NO_JUMP); + int blockinit = luaK_getlabel(fs); + check(ls, TK_DO); + adjustlocalvars(ls, nvar); /* scope for control variables */ + block(ls); + luaK_patchlist(fs, luaK_code1(fs, loopfor, NO_JUMP), blockinit); + luaK_patchlist(fs, prep, luaK_getlabel(fs)); + removelocalvars(ls, nvar); +} + + +static void fornum (LexState *ls, TString *varname) { + /* fornum -> NAME = exp1,exp1[,exp1] forbody */ + FuncState *fs = ls->fs; + check(ls, '='); + exp1(ls); /* initial value */ + check(ls, ','); + exp1(ls); /* limit */ + if (optional(ls, ',')) + exp1(ls); /* optional step */ + else + luaK_code1(fs, OP_PUSHINT, 1); /* default step */ + new_localvar(ls, varname, 0); + new_localvarstr(ls, "(limit)", 1); + new_localvarstr(ls, "(step)", 2); + forbody(ls, 3, OP_FORPREP, OP_FORLOOP); +} + + +static void forlist (LexState *ls, TString *indexname) { + /* forlist -> NAME,NAME IN exp1 forbody */ + TString *valname; + check(ls, ','); + valname = str_checkname(ls); + /* next test is dirty, but avoids `in' being a reserved word */ + check_condition(ls, + (ls->t.token == TK_NAME && ls->t.seminfo.ts == luaS_new(ls->L, "in")), + "`in' expected"); + next(ls); /* skip `in' */ + exp1(ls); /* table */ + new_localvarstr(ls, "(table)", 0); + new_localvar(ls, indexname, 1); + new_localvar(ls, valname, 2); + forbody(ls, 3, OP_LFORPREP, OP_LFORLOOP); +} + + +static void forstat (LexState *ls, int line) { + /* forstat -> fornum | forlist */ + FuncState *fs = ls->fs; + TString *varname; + Breaklabel bl; + enterbreak(fs, &bl); + next(ls); /* skip `for' */ + varname = str_checkname(ls); /* first variable name */ + switch (ls->t.token) { + case '=': fornum(ls, varname); break; + case ',': forlist(ls, varname); break; + default: luaK_error(ls, "`=' or `,' expected"); } - return i; + check_match(ls, TK_END, TK_FOR, line); + leavebreak(fs, &bl); } -static void decinit (LexState *ls, listdesc *d) { - /* decinit -> ['=' explist1] */ - if (ls->token == '=') { - next(ls); - explist1(ls, d); + +static void test_then_block (LexState *ls, expdesc *v) { + /* test_then_block -> [IF | ELSEIF] cond THEN block */ + next(ls); /* skip IF or ELSEIF */ + cond(ls, v); + check(ls, TK_THEN); + block(ls); /* `then' part */ +} + + +static void ifstat (LexState *ls, int line) { + /* ifstat -> IF cond THEN block {ELSEIF cond THEN block} [ELSE block] END */ + FuncState *fs = ls->fs; + expdesc v; + int escapelist = NO_JUMP; + test_then_block(ls, &v); /* IF cond THEN block */ + while (ls->t.token == TK_ELSEIF) { + luaK_concat(fs, &escapelist, luaK_jump(fs)); + luaK_patchlist(fs, v.u.l.f, luaK_getlabel(fs)); + test_then_block(ls, &v); /* ELSEIF cond THEN block */ } - else { - d->n = 0; - d->pc = 0; + if (ls->t.token == TK_ELSE) { + luaK_concat(fs, &escapelist, luaK_jump(fs)); + luaK_patchlist(fs, v.u.l.f, luaK_getlabel(fs)); + next(ls); /* skip ELSE */ + block(ls); /* `else' part */ } + else + luaK_concat(fs, &escapelist, v.u.l.f); + luaK_patchlist(fs, escapelist, luaK_getlabel(fs)); + check_match(ls, TK_END, TK_IF, line); +} + + +static void localstat (LexState *ls) { + /* stat -> LOCAL NAME {',' NAME} ['=' explist1] */ + int nvars = 0; + int nexps; + do { + next(ls); /* skip LOCAL or ',' */ + new_localvar(ls, str_checkname(ls), nvars++); + } while (ls->t.token == ','); + if (optional(ls, '=')) + nexps = explist1(ls); + else + nexps = 0; + adjust_mult_assign(ls, nvars, nexps); + adjustlocalvars(ls, nvars); } -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 int funcname (LexState *ls, expdesc *v) { + /* funcname -> NAME [':' NAME | '.' NAME] */ + int needself = 0; + singlevar(ls, str_checkname(ls), v); + if (ls->t.token == ':' || ls->t.token == '.') { + needself = (ls->t.token == ':'); 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; - check(ls, '='); - explist1(ls, &d); - adjust_mult_assign(ls, nvars, &d); + luaK_tostack(ls, v, 1); + luaK_kstr(ls, checkname(ls)); + v->k = VINDEXED; } - if (v->k != VINDEXED || left+(nvars-1) == 0) { - /* global/local var or indexed var without values in between */ - storevar(ls, v); + return needself; +} + + +static void funcstat (LexState *ls, int line) { + /* funcstat -> FUNCTION funcname body */ + int needself; + expdesc v; + next(ls); /* skip FUNCTION */ + needself = funcname(ls, &v); + body(ls, needself, line); + luaK_storevar(ls, &v); +} + + +static void namestat (LexState *ls) { + /* stat -> func | ['%'] NAME assignment */ + FuncState *fs = ls->fs; + expdesc v; + var_or_func(ls, &v); + if (v.k == VEXP) { /* stat -> func */ + check_condition(ls, luaK_lastisopen(fs), "syntax error"); /* an upvalue? */ + luaK_setcallreturns(fs, 0); /* call statement uses no results */ } - 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 */ + else { /* stat -> ['%'] NAME assignment */ + int left = assignment(ls, &v, 1); + luaK_adjuststack(fs, left); /* remove eventual garbage left on stack */ } - 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 retstat (LexState *ls) { + /* stat -> RETURN explist */ + FuncState *fs = ls->fs; + next(ls); /* skip RETURN */ + if (!block_follow(ls->t.token)) + explist1(ls); /* optional return values */ + luaK_code1(fs, OP_RETURN, ls->fs->nactloc); + fs->stacklevel = fs->nactloc; /* removes all temp values */ } -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 breakstat (LexState *ls) { + /* stat -> BREAK [NAME] */ + FuncState *fs = ls->fs; + int currentlevel = fs->stacklevel; + Breaklabel *bl = fs->bl; + if (!bl) + luaK_error(ls, "no loop to break"); + next(ls); /* skip BREAK */ + luaK_adjuststack(fs, currentlevel - bl->stacklevel); + luaK_concat(fs, &bl->breaklist, luaK_jump(fs)); + /* correct stack for compiler and symbolic execution */ + luaK_adjuststack(fs, bl->stacklevel - currentlevel); +} - 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; +static int stat (LexState *ls) { + int line = ls->linenumber; /* may be needed for error messages */ + switch (ls->t.token) { + case TK_IF: { /* stat -> ifstat */ + ifstat(ls, line); + return 0; + } + case TK_WHILE: { /* stat -> whilestat */ + whilestat(ls, line); + return 0; + } + case TK_DO: { /* stat -> DO block END */ + next(ls); /* skip DO */ + block(ls); + check_match(ls, TK_END, TK_DO, line); + return 0; + } + case TK_FOR: { /* stat -> forstat */ + forstat(ls, line); + return 0; + } + case TK_REPEAT: { /* stat -> repeatstat */ + repeatstat(ls, line); + return 0; + } + case TK_FUNCTION: { /* stat -> funcstat */ + funcstat(ls, line); + return 0; + } + case TK_LOCAL: { /* stat -> localstat */ + localstat(ls); + return 0; + } + case TK_NAME: case '%': { /* stat -> namestat */ + namestat(ls); + return 0; + } + case TK_RETURN: { /* stat -> retstat */ + retstat(ls); + return 1; /* must be last statement */ + } + case TK_BREAK: { /* stat -> breakstat */ + breakstat(ls); + return 1; /* must be last statement */ + } + default: { + luaK_error(ls, "<statement> expected"); + return 0; /* to avoid warnings */ + } } } -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 parlist (LexState *ls) { + /* parlist -> [ param { ',' param } ] */ + int nparams = 0; + int dots = 0; + if (ls->t.token != ')') { /* is `parlist' not empty? */ + do { + switch (ls->t.token) { + case TK_DOTS: next(ls); dots = 1; break; + case TK_NAME: new_localvar(ls, str_checkname(ls), nparams++); break; + default: luaK_error(ls, "<name> or `...' expected"); + } + } while (!dots && optional(ls, ',')); } - flush_record(ls, n%RFIELDS_PER_FLUSH); - return n; + code_params(ls, nparams, dots); } -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 body (LexState *ls, int needself, int line) { + /* body -> '(' parlist ')' chunk END */ + FuncState new_fs; + open_func(ls, &new_fs); + new_fs.f->lineDefined = line; + check(ls, '('); + if (needself) { + new_localvarstr(ls, "self", 0); + adjustlocalvars(ls, 1); } - flush_list(ls, n/LFIELDS_PER_FLUSH, n%LFIELDS_PER_FLUSH); - return n; + parlist(ls); + check(ls, ')'); + chunk(ls); + check_match(ls, TK_END, TK_FUNCTION, line); + close_func(ls); + pushclosure(ls, &new_fs); } -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 [';'] } */ + int islast = 0; + while (!islast && !block_follow(ls->t.token)) { + islast = stat(ls); + optional(ls, ';'); + LUA_ASSERT(ls->fs->stacklevel == ls->fs->nactloc, + "stack size != # local vars"); } - check(ls, '='); - exp1(ls); } |