From 298d0abff7f292fa4bfbdb40979f41bc8f80f9c2 Mon Sep 17 00:00:00 2001 From: Roberto Ierusalimschy Date: Wed, 29 Dec 1999 14:31:15 -0200 Subject: first version of extra debug information (NAME) --- lparser.c | 1035 ++++++++++++++++++++++++++++++++----------------------------- 1 file changed, 549 insertions(+), 486 deletions(-) (limited to 'lparser.c') diff --git a/lparser.c b/lparser.c index 4229ddd6..e21ad7a1 100644 --- a/lparser.c +++ b/lparser.c @@ -1,5 +1,5 @@ /* -** $Id: lparser.c,v 1.49 1999/12/22 16:58:36 roberto Exp roberto $ +** $Id: lparser.c,v 1.50 1999/12/23 18:19:57 roberto Exp roberto $ ** LL(1) Parser and code generator for Lua ** See Copyright Notice in lua.h */ @@ -63,6 +63,8 @@ typedef enum { typedef struct vardesc { varkind k; int info; + varkind prev_k; /* for debug information (NAMEs) */ + int prev_info; } vardesc; @@ -70,7 +72,7 @@ typedef struct vardesc { ** Expression List descriptor: ** tells number of expressions in the list, ** and, if last expression is open (a function call), -** where is its pc index of "nparam" +** where is its pc index of `nparam' */ typedef struct listdesc { int n; @@ -93,7 +95,7 @@ typedef struct constdesc { /* state needed to generate code for a given function */ typedef struct FuncState { TProtoFunc *f; /* current function header */ - struct FuncState *prev; /* enclosuring function */ + struct FuncState *prev; /* enclosing function */ int pc; /* next position to code */ int stacksize; /* number of values on activation register */ int maxstacksize; /* maximum number of values on activation register */ @@ -107,34 +109,13 @@ typedef struct FuncState { /* -** prototypes for non-terminal functions +** prototypes for recursive non-terminal functions */ -static int assignment (LexState *ls, vardesc *v, int nvars); -static int cond (LexState *ls); -static int funcname (LexState *ls, vardesc *v); -static int funcparams (LexState *ls, int slf); -static int listfields (LexState *ls); -static int localnamelist (LexState *ls); -static int optional (LexState *ls, int c); -static int recfields (LexState *ls); -static int stat (LexState *ls); -static void block (LexState *ls); static void body (LexState *ls, int needself, int line); static void chunk (LexState *ls); static void constructor (LexState *ls); -static void decinit (LexState *ls, listdesc *d); -static void exp0 (LexState *ls, vardesc *v); +static void exp (LexState *ls, vardesc *v); static void exp1 (LexState *ls); -static void exp2 (LexState *ls, vardesc *v); -static void explist (LexState *ls, listdesc *e); -static void explist1 (LexState *ls, listdesc *e); -static void ifpart (LexState *ls, int line); -static void parlist (LexState *ls); -static void part (LexState *ls, constdesc *cd); -static void recfield (LexState *ls); -static void ret (LexState *ls); -static void var_or_func (LexState *ls, vardesc *v); -static void var_or_func_tail (LexState *ls, vardesc *v); @@ -268,7 +249,7 @@ static void code_string (LexState *ls, TaggedString *s) { #define LIM 20 static int real_constant (LexState *ls, real r) { - /* check whether 'r' has appeared within the last LIM entries */ + /* check whether `r' has appeared within the last LIM entries */ TProtoFunc *f = ls->fs->f; TObject *cnt = f->consts; int c = f->nconsts; @@ -279,7 +260,7 @@ static int real_constant (LexState *ls, real r) { } /* not found; create a new entry */ c = next_constant(ls, f); - cnt = f->consts; /* 'next_constant' may reallocate this vector */ + cnt = f->consts; /* `next_constant' may reallocate this vector */ ttype(&cnt[c]) = LUA_T_NUMBER; nvalue(&cnt[c]) = r; return c; @@ -412,6 +393,31 @@ static void check_debugline (LexState *ls) { } +static void code_setname (LexState *ls, const vardesc *v) { + if (ls->L->debug) { + switch (v->prev_k) { + case VGLOBAL: + code_oparg(ls, SETNAME, v->prev_info, 0); + code_byte(ls, -LUA_T_NGLOBAL); + break; + case VLOCAL: { + TaggedString *varname = ls->fs->localvar[v->prev_info]; + code_oparg(ls, SETNAME, string_constant(ls, ls->fs, varname), 0); + code_byte(ls, -LUA_T_NLOCAL); + break; + } + case VDOT: + code_oparg(ls, SETNAME, v->prev_info, 0); + code_byte(ls, -LUA_T_NDOT); + break; + default: /* VINDEXED or VEXP: no debug information */ + code_oparg(ls, SETNAME, 0, 0); + code_byte(ls, -LUA_T_NIL); + } + } +} + + static void adjuststack (LexState *ls, int n) { if (n > 0) code_oparg(ls, POP, n, -n); @@ -468,7 +474,7 @@ static void code_args (LexState *ls, int nparams, int dots) { static void unloaddot (LexState *ls, vardesc *v) { - /* dotted variables must be stored like regular indexed vars */ + /* dotted variables must be stored as regular indexed vars */ if (v->k == VDOT) { code_constant(ls, v->info); v->k = VINDEXED; @@ -486,15 +492,19 @@ static void lua_pushvar (LexState *ls, vardesc *var) { assertglobal(ls, var->info); /* make sure that there is a global */ break; case VDOT: + code_setname(ls, var); code_oparg(ls, GETDOTTED, var->info, 0); break; case VINDEXED: + code_setname(ls, var); code_opcode(ls, GETTABLE, -1); break; case VEXP: close_exp(ls, var->info, 1); /* function must return 1 value */ break; } + var->prev_k = var->k; /* save previous var kind and info */ + var->prev_info = var->info; var->k = VEXP; var->info = 0; /* now this is a closed expression */ } @@ -510,6 +520,7 @@ static void storevar (LexState *ls, const vardesc *var) { assertglobal(ls, var->info); /* make sure that there is a global */ break; case VINDEXED: + code_setname(ls, var); code_opcode(ls, SETTABLEPOP, -3); break; default: @@ -656,7 +667,7 @@ static void check (LexState *ls, int c) { static void check_match (LexState *ls, int what, int who, int where) { if (ls->token != what) error_unmatched(ls, what, who, where); - check_debugline(ls); /* to 'mark' the 'what' */ + check_debugline(ls); /* to `mark' the `what' */ next(ls); } @@ -705,241 +716,298 @@ TProtoFunc *luaY_parser (lua_State *L, ZIO *z) { /*============================================================*/ -static void chunk (LexState *ls) { - /* chunk -> { stat [;] } ret */ - while (stat(ls)) { - LUA_ASSERT(ls->L, ls->fs->stacksize == ls->fs->nlocalvar, - "stack size != # local vars"); - optional(ls, ';'); - } - ret(ls); /* optional return */ -} - -static void whilestat (LexState *ls, int line) { - /* whilestat -> WHILE cond DO block END */ - FuncState *fs = ls->fs; - TProtoFunc *f = fs->f; - int while_init = fs->pc; - int cond_end, cond_size; - next(ls); - cond_end = cond(ls); - check(ls, DO); - block(ls); - check_match(ls, END, WHILE, line); - cond_size = cond_end-while_init; - check_pc(ls, cond_size); - memcpy(f->code+fs->pc, f->code+while_init, cond_size); - luaO_memdown(f->code+while_init, f->code+cond_end, fs->pc-while_init); - while_init += JMPSIZE + fix_jump(ls, while_init, JMP, fs->pc-cond_size); - fix_upjmp(ls, IFTUPJMP, while_init); +static int SaveWord (LexState *ls) { + int res = ls->fs->pc; + check_pc(ls, JMPSIZE); + ls->fs->pc += JMPSIZE; /* open space */ + return res; } -static void repeatstat (LexState *ls, int line) { - /* repeatstat -> REPEAT block UNTIL exp1 */ - FuncState *fs = ls->fs; - int repeat_init = fs->pc; - next(ls); - block(ls); - check_match(ls, UNTIL, REPEAT, line); - exp1(ls); - fix_upjmp(ls, IFFUPJMP, repeat_init); - deltastack(ls, -1); /* pops condition */ +static int SaveWordPop (LexState *ls) { + deltastack(ls, -1); /* pop condition */ + return SaveWord(ls); } -static void localstat (LexState *ls) { - /* stat -> LOCAL localnamelist decinit */ - FuncState *fs = ls->fs; - listdesc d; - int nvars; - check_debugline(ls); - next(ls); - nvars = localnamelist(ls); - decinit(ls, &d); - adjustlocalvars(ls, nvars, fs->lastsetline); - adjust_mult_assign(ls, nvars, &d); +static int cond (LexState *ls) { + /* cond -> exp1 */ + exp1(ls); + return SaveWordPop(ls); } -static int funcstat (LexState *ls, int line) { - /* funcstat -> FUNCTION funcname body */ - int needself; +static void explist1 (LexState *ls, listdesc *d) { vardesc v; - if (ls->fs->prev) /* inside other function? */ - return 0; - check_debugline(ls); - next(ls); - needself = funcname(ls, &v); - body(ls, needself, line); - storevar(ls, &v); - return 1; + exp(ls, &v); + d->n = 1; + while (ls->token == ',') { + d->n++; + lua_pushvar(ls, &v); + next(ls); + exp(ls, &v); + } + if (v.k == VEXP) + d->pc = v.info; + else { + lua_pushvar(ls, &v); + d->pc = 0; + } } -static void namestat (LexState *ls) { - /* stat -> func | ['%'] NAME assignment */ - vardesc v; - check_debugline(ls); - var_or_func(ls, &v); - if (v.k == VEXP) { /* stat -> func */ - if (v.info == 0) /* is just an upper value? */ - luaX_error(ls, "syntax error"); - close_exp(ls, v.info, 0); - } - else { /* stat -> ['%'] NAME assignment */ - int left = assignment(ls, &v, 1); - adjuststack(ls, left); /* remove eventual garbage left on stack */ +static void explist (LexState *ls, listdesc *d) { + switch (ls->token) { + case ELSE: case ELSEIF: case END: case UNTIL: + case EOS: case ';': case ')': + d->pc = 0; + d->n = 0; + break; + + default: + explist1(ls, d); } } -static int stat (LexState *ls) { - int line = ls->linenumber; /* may be needed for error messages */ +static int funcparams (LexState *ls, int slf, vardesc *v) { + FuncState *fs = ls->fs; + int slevel = fs->stacksize - slf - 1; /* where is func in the stack */ switch (ls->token) { - case IF: /* stat -> IF ifpart END */ - ifpart(ls, line); - return 1; + case '(': { /* funcparams -> '(' explist ')' */ + int line = ls->linenumber; + listdesc e; + next(ls); + explist(ls, &e); + check_match(ls, ')', '(', line); + close_exp(ls, e.pc, MULT_RET); /* close 1 for old semantics */ + break; + } - case WHILE: /* stat -> whilestat */ - whilestat(ls, line); - return 1; + case '{': /* funcparams -> constructor */ + constructor(ls); + break; - case DO: { /* stat -> DO block END */ + case STRING: /* funcparams -> STRING */ + code_string(ls, ls->seminfo.ts); /* must use 'seminfo' before `next' */ next(ls); - block(ls); - check_match(ls, END, DO, line); - return 1; - } + break; - case REPEAT: /* stat -> repeatstat */ - repeatstat(ls, line); - return 1; + default: + luaX_error(ls, "function arguments expected"); + break; + } + code_setname(ls, v); + code_byte(ls, CALL); + code_byte(ls, 0); /* save space for nresult */ + code_byte(ls, (Byte)slevel); + fs->stacksize = slevel; /* call will remove func and params */ + return fs->pc-1; +} - case FUNCTION: /* stat -> funcstat */ - return funcstat(ls, line); - case LOCAL: /* stat -> localstat */ - localstat(ls); - return 1; +static void var_or_func_tail (LexState *ls, vardesc *v) { + for (;;) { + switch (ls->token) { + case '.': /* var_or_func_tail -> '.' NAME */ + next(ls); + lua_pushvar(ls, v); /* `v' must be on stack */ + v->k = VDOT; + v->info = checkname(ls); + break; - case NAME: case '%': /* stat -> namestat */ - namestat(ls); - return 1; + case '[': /* var_or_func_tail -> '[' exp1 ']' */ + next(ls); + lua_pushvar(ls, v); /* `v' must be on stack */ + exp1(ls); + check(ls, ']'); + v->k = VINDEXED; + break; - case RETURN: case ';': case ELSE: case ELSEIF: - case END: case UNTIL: case EOS: /* 'stat' follow */ - return 0; + case ':': { /* var_or_func_tail -> ':' NAME funcparams */ + int name; + next(ls); + name = checkname(ls); + lua_pushvar(ls, v); /* `v' must be on stack */ + code_setname(ls, v); + code_oparg(ls, PUSHSELF, name, 1); + v->prev_k = VDOT; /* ':' is syntactic sugar for '.' */ + v->prev_info = name; + v->k = VEXP; + v->info = funcparams(ls, 1, v); + break; + } - default: - error_unexpected(ls); - return 0; /* to avoid warnings */ + case '(': case STRING: case '{': /* var_or_func_tail -> funcparams */ + lua_pushvar(ls, v); /* `v' must be on stack */ + v->k = VEXP; + v->info = funcparams(ls, 0, v); + break; + + default: return; /* should be follow... */ + } } } -static int SaveWord (LexState *ls) { - int res = ls->fs->pc; - check_pc(ls, JMPSIZE); - ls->fs->pc += JMPSIZE; /* open space */ - return res; -} -static int SaveWordPop (LexState *ls) { - deltastack(ls, -1); /* pop condition */ - return SaveWord(ls); +static void var_or_func (LexState *ls, vardesc *v) { + /* var_or_func -> ['%'] NAME var_or_func_tail */ + if (optional(ls, '%')) { /* upvalue? */ + pushupvalue(ls, str_checkname(ls)); + v->k = VEXP; + v->info = 0; /* closed expression */ + } + else /* variable name */ + singlevar(ls, str_checkname(ls), v, 0); + var_or_func_tail(ls, v); } -static int cond (LexState *ls) { - /* cond -> exp1 */ + + +/* +** {====================================================================== +** Rules for Constructors +** ======================================================================= +*/ + +static void recfield (LexState *ls) { + /* recfield -> (NAME | '['exp1']') = exp1 */ + switch (ls->token) { + case NAME: + code_constant(ls, checkname(ls)); + break; + + case '[': + next(ls); + exp1(ls); + check(ls, ']'); + break; + + default: luaX_error(ls, "NAME or `[' expected"); + } + check(ls, '='); exp1(ls); - return SaveWordPop(ls); } -static void block (LexState *ls) { - /* block -> chunk */ - FuncState *fs = ls->fs; - int nlocalvar = fs->nlocalvar; - chunk(ls); - adjuststack(ls, fs->nlocalvar - nlocalvar); - for (; fs->nlocalvar > nlocalvar; fs->nlocalvar--) - luaI_unregisterlocalvar(ls, fs->lastsetline); -} -static int funcname (LexState *ls, vardesc *v) { - /* funcname -> NAME [':' NAME | '.' NAME] */ - int needself = 0; - singlevar(ls, str_checkname(ls), v, 0); - if (ls->token == ':' || ls->token == '.') { - needself = (ls->token == ':'); +static int recfields (LexState *ls) { + /* recfields -> { ',' recfield } [','] */ + int n = 1; /* one has been read before */ + while (ls->token == ',') { next(ls); - lua_pushvar(ls, v); - code_constant(ls, checkname(ls)); - v->k = VINDEXED; + if (ls->token == ';' || ls->token == '}') + break; + recfield(ls); + n++; + if (n%RFIELDS_PER_FLUSH == 0) + flush_record(ls, RFIELDS_PER_FLUSH); } - return needself; + flush_record(ls, n%RFIELDS_PER_FLUSH); + return n; } -static void body (LexState *ls, int needself, int line) { - /* body -> '(' parlist ')' chunk END */ - FuncState newfs; - init_state(ls, &newfs, ls->fs->f->source); - newfs.f->lineDefined = line; - check(ls, '('); - if (needself) - add_localvar(ls, luaS_newfixed(ls->L, "self")); - parlist(ls); - check(ls, ')'); - chunk(ls); - check_match(ls, END, FUNCTION, line); - close_func(ls); - func_onstack(ls, &newfs); + +static int listfields (LexState *ls) { + /* listfields -> { ',' exp1 } [','] */ + int n = 1; /* one has been read before */ + while (ls->token == ',') { + next(ls); + if (ls->token == ';' || ls->token == '}') + break; + exp1(ls); + n++; + if (n%LFIELDS_PER_FLUSH == 0) + flush_list(ls, n/LFIELDS_PER_FLUSH - 1, LFIELDS_PER_FLUSH); + } + flush_list(ls, n/LFIELDS_PER_FLUSH, n%LFIELDS_PER_FLUSH); + return n; } -static void ifpart (LexState *ls, int line) { - /* ifpart -> cond THEN block [ELSE block | ELSEIF ifpart] */ - int c; - int e; - next(ls); /* skip IF or ELSEIF */ - c = cond(ls); - check(ls, THEN); - block(ls); - e = SaveWord(ls); - if (ls->token == ELSEIF) - ifpart(ls, line); - else { - if (optional(ls, ELSE)) - block(ls); - check_match(ls, END, IF, line); + +static void constructor_part (LexState *ls, constdesc *cd) { + switch (ls->token) { + case ';': case '}': /* constructor_part -> empty */ + cd->n = 0; + cd->k = ls->token; + return; + + case NAME: { + vardesc v; + exp(ls, &v); + if (ls->token == '=') { + switch (v.k) { + case VGLOBAL: + code_constant(ls, v.info); + break; + case VLOCAL: + code_string(ls, ls->fs->localvar[v.info]); + break; + default: + error_unexpected(ls); + } + next(ls); + exp1(ls); + cd->n = recfields(ls); + cd->k = 1; /* record */ + } + else { + lua_pushvar(ls, &v); + cd->n = listfields(ls); + cd->k = 0; /* list */ + } + break; + } + + case '[': /* constructor_part -> recfield recfields */ + recfield(ls); + cd->n = recfields(ls); + cd->k = 1; /* record */ + break; + + default: /* constructor_part -> exp1 listfields */ + exp1(ls); + cd->n = listfields(ls); + cd->k = 0; /* list */ + break; } - codeIf(ls, c, e); } -static void ret (LexState *ls) { - /* ret -> [RETURN explist sc] */ - if (optional(ls, RETURN)) { - listdesc e; - check_debugline(ls); - explist(ls, &e); - if (e.pc > 0) { /* expression is an open function call? */ - Byte *code = ls->fs->f->code; - code[e.pc-2] = TAILCALL; /* instead of a conventional CALL */ - code[e.pc-1] = (Byte)ls->fs->nlocalvar; - } - else - code_oparg(ls, RETCODE, ls->fs->nlocalvar, 0); - ls->fs->stacksize = ls->fs->nlocalvar; /* removes all temp values */ - optional(ls, ';'); +static void constructor (LexState *ls) { + /* constructor -> '{' constructor_part [';' constructor_part] '}' */ + int line = ls->linenumber; + int pc = SaveWord(ls); + int nelems; + constdesc cd; + deltastack(ls, 1); + check(ls, '{'); + constructor_part(ls, &cd); + nelems = cd.n; + if (ls->token == ';') { + constdesc other_cd; + next(ls); + constructor_part(ls, &other_cd); + if (cd.k == other_cd.k) /* repeated parts? */ + luaX_error(ls, "invalid constructor syntax"); + nelems += other_cd.n; } + check_match(ls, '}', '{', line); + fix_opcode(ls, pc, CREATEARRAY, nelems); } +/* }====================================================================== */ + + + /* +** {====================================================================== ** For parsing expressions, we use a classic stack with priorities. -** Each binary operator is represented by its index in "binop" + FIRSTBIN +** Each binary operator is represented by its index in `binop' + FIRSTBIN ** (EQ=2, NE=3, ... '^'=13). The unary NOT is 0 and UNMINUS is 1. +** ======================================================================= */ #define INDNOT 0 @@ -969,30 +1037,6 @@ typedef struct stack_op { } stack_op; -static void exp1 (LexState *ls) { - vardesc v; - exp0(ls, &v); - lua_pushvar(ls, &v); - if (is_in(ls->token, expfollow) < 0) - luaX_error(ls, "malformed expression"); -} - - -static void exp0 (LexState *ls, vardesc *v) { - /* exp0 -> exp2 {(AND | OR) exp2} */ - exp2(ls, v); - while (ls->token == AND || ls->token == OR) { - int op = (ls->token == AND) ? ONFJMP : ONTJMP; - int pc; - lua_pushvar(ls, v); - next(ls); - pc = SaveWordPop(ls); - exp2(ls, v); - lua_pushvar(ls, v); - fix_jump(ls, pc, op, ls->fs->pc); - } -} - static void push (LexState *ls, stack_op *s, int op) { if (s->top >= MAXOPS) @@ -1015,8 +1059,8 @@ static void simpleexp (LexState *ls, vardesc *v, stack_op *s) { case NUMBER: { /* simpleexp -> NUMBER */ real r = ls->seminfo.r; next(ls); - /* dirty trick: check whether it is a -NUMBER not followed by '^' */ - /* (because the priority of '^' is higher than '-'...) */ + /* dirty trick: check whether it is a -NUMBER not followed by '^' */ + /* (because the priority of '^' is higher than the priority of '-') */ if (s->top > 0 && s->ops[s->top-1] == INDMINUS && ls->token != '^') { s->top--; /* remove '-' from stack */ r = -r; @@ -1044,9 +1088,9 @@ static void simpleexp (LexState *ls, vardesc *v, stack_op *s) { body(ls, 0, ls->linenumber); break; - case '(': /* simpleexp -> '(' exp0 ')' */ + case '(': /* simpleexp -> '(' exp ')' */ next(ls); - exp0(ls, v); + exp(ls, v); check(ls, ')'); return; @@ -1072,7 +1116,7 @@ static void prefixexp (LexState *ls, vardesc *v, stack_op *s) { } -static void exp2 (LexState *ls, vardesc *v) { +static void arith_exp (LexState *ls, vardesc *v) { stack_op s; int op; s.top = 0; @@ -1094,156 +1138,118 @@ static void exp2 (LexState *ls, vardesc *v) { } -static void var_or_func (LexState *ls, vardesc *v) { - /* var_or_func -> ['%'] NAME var_or_func_tail */ - if (optional(ls, '%')) { /* upvalue? */ - pushupvalue(ls, str_checkname(ls)); - v->k = VEXP; - v->info = 0; /* closed expression */ - } - else /* variable name */ - singlevar(ls, str_checkname(ls), v, 0); - var_or_func_tail(ls, v); +static void exp1 (LexState *ls) { + vardesc v; + exp(ls, &v); + lua_pushvar(ls, &v); + if (is_in(ls->token, expfollow) < 0) + luaX_error(ls, "malformed expression"); } -static void var_or_func_tail (LexState *ls, vardesc *v) { - for (;;) { - switch (ls->token) { - case '.': /* var_or_func_tail -> '.' NAME */ - next(ls); - lua_pushvar(ls, v); /* `v' must be on stack */ - v->k = VDOT; - v->info = checkname(ls); - break; - - case '[': /* var_or_func_tail -> '[' exp1 ']' */ - next(ls); - lua_pushvar(ls, v); /* `v' must be on stack */ - exp1(ls); - check(ls, ']'); - v->k = VINDEXED; - break; - - case ':': /* var_or_func_tail -> ':' NAME funcparams */ - next(ls); - lua_pushvar(ls, v); /* `v' must be on stack */ - code_oparg(ls, PUSHSELF, checkname(ls), 1); - v->k = VEXP; - v->info = funcparams(ls, 1); - break; - - case '(': case STRING: case '{': /* var_or_func_tail -> funcparams */ - lua_pushvar(ls, v); /* `v' must be on stack */ - v->k = VEXP; - v->info = funcparams(ls, 0); - break; - - default: return; /* should be follow... */ - } +static void exp (LexState *ls, vardesc *v) { + /* exp -> arith_exp {(AND | OR) arith_exp} */ + arith_exp(ls, v); + while (ls->token == AND || ls->token == OR) { + OpCode op = (ls->token == AND) ? ONFJMP : ONTJMP; + int pc; + lua_pushvar(ls, v); + next(ls); + pc = SaveWordPop(ls); + arith_exp(ls, v); + lua_pushvar(ls, v); + fix_jump(ls, pc, op, ls->fs->pc); } } -static int funcparams (LexState *ls, int slf) { - FuncState *fs = ls->fs; - int slevel = fs->stacksize - slf - 1; /* where is func in the stack */ - switch (ls->token) { - case '(': { /* funcparams -> '(' explist ')' */ - int line = ls->linenumber; - listdesc e; - next(ls); - explist(ls, &e); - check_match(ls, ')', '(', line); - close_exp(ls, e.pc, MULT_RET); /* close 1 for old semantics */ - break; - } - case '{': /* funcparams -> constructor */ - constructor(ls); - break; +/* }==================================================================== */ - case STRING: /* funcparams -> STRING */ - code_string(ls, ls->seminfo.ts); /* must use 'seminfo' before `next' */ - next(ls); - break; - default: - luaX_error(ls, "function arguments expected"); - break; - } - code_byte(ls, CALL); - code_byte(ls, 0); /* save space for nresult */ - code_byte(ls, (Byte)slevel); - fs->stacksize = slevel; /* call will remove func and params */ - return fs->pc-1; +/* +** {====================================================================== +** Rules for Statements +** ======================================================================= +*/ + + +static void block (LexState *ls) { + /* block -> chunk */ + FuncState *fs = ls->fs; + int nlocalvar = fs->nlocalvar; + chunk(ls); + adjuststack(ls, fs->nlocalvar - nlocalvar); + for (; fs->nlocalvar > nlocalvar; fs->nlocalvar--) + luaI_unregisterlocalvar(ls, fs->lastsetline); } -static void explist (LexState *ls, listdesc *d) { - switch (ls->token) { - case ELSE: case ELSEIF: case END: case UNTIL: - case EOS: case ';': case ')': - d->pc = 0; - d->n = 0; - break; - default: - explist1(ls, d); +static int assignment (LexState *ls, vardesc *v, int nvars) { + int left = 0; + checklimit(ls, nvars, MAXVARSLH, "variables in a multiple assignment"); + unloaddot(ls, v); + if (ls->token == ',') { /* assignment -> ',' NAME assignment */ + vardesc nv; + next(ls); + var_or_func(ls, &nv); + if (nv.k == VEXP) + luaX_error(ls, "syntax error"); + left = assignment(ls, &nv, nvars+1); } -} - -static void explist1 (LexState *ls, listdesc *d) { - vardesc v; - exp0(ls, &v); - d->n = 1; - while (ls->token == ',') { - d->n++; - lua_pushvar(ls, &v); + else { /* assignment -> '=' explist1 */ + listdesc d; + if (ls->token != '=') + error_unexpected(ls); next(ls); - exp0(ls, &v); + explist1(ls, &d); + adjust_mult_assign(ls, nvars, &d); } - if (v.k == VEXP) - d->pc = v.info; - else { - lua_pushvar(ls, &v); - d->pc = 0; + if (v->k != VINDEXED || left+(nvars-1) == 0) { + /* global/local var or indexed var without values in between */ + storevar(ls, v); + } + else { /* indexed var with values in between*/ + code_setname(ls, v); + code_oparg(ls, SETTABLE, left+(nvars-1), -1); + left += 2; /* table&index are not popped, because they aren't on top */ } + return left; } -static void parlist (LexState *ls) { - int nparams = 0; - int dots = 0; - switch (ls->token) { - case DOTS: /* parlist -> DOTS */ - next(ls); - dots = 1; - break; - - case NAME: /* parlist, tailparlist -> NAME [',' tailparlist] */ - init: - store_localvar(ls, str_checkname(ls), nparams++); - if (ls->token == ',') { - next(ls); - switch (ls->token) { - case DOTS: /* tailparlist -> DOTS */ - next(ls); - dots = 1; - break; - - case NAME: /* tailparlist -> NAME [',' tailparlist] */ - goto init; - default: luaX_error(ls, "NAME or `...' expected"); - } - } - break; +static void whilestat (LexState *ls, int line) { + /* whilestat -> WHILE cond DO block END */ + FuncState *fs = ls->fs; + TProtoFunc *f = fs->f; + int while_init = fs->pc; + int cond_end, cond_size; + next(ls); + cond_end = cond(ls); + check(ls, DO); + block(ls); + check_match(ls, END, WHILE, line); + cond_size = cond_end-while_init; + check_pc(ls, cond_size); + memcpy(f->code+fs->pc, f->code+while_init, cond_size); + luaO_memdown(f->code+while_init, f->code+cond_end, fs->pc-while_init); + while_init += JMPSIZE + fix_jump(ls, while_init, JMP, fs->pc-cond_size); + fix_upjmp(ls, IFTUPJMP, while_init); +} - case ')': break; /* parlist -> empty */ - default: luaX_error(ls, "NAME or `...' expected"); - } - code_args(ls, nparams, dots); +static void repeatstat (LexState *ls, int line) { + /* repeatstat -> REPEAT block UNTIL exp1 */ + FuncState *fs = ls->fs; + int repeat_init = fs->pc; + next(ls); + block(ls); + check_match(ls, UNTIL, REPEAT, line); + exp1(ls); + fix_upjmp(ls, IFFUPJMP, repeat_init); + deltastack(ls, -1); /* pops condition */ } + static int localnamelist (LexState *ls) { /* localnamelist -> NAME {',' NAME} */ int i = 1; @@ -1255,6 +1261,7 @@ static int localnamelist (LexState *ls) { return i; } + static void decinit (LexState *ls, listdesc *d) { /* decinit -> ['=' explist1] */ if (ls->token == '=') { @@ -1268,156 +1275,212 @@ static void decinit (LexState *ls, listdesc *d) { } -static int assignment (LexState *ls, vardesc *v, int nvars) { - int left = 0; - checklimit(ls, nvars, MAXVARSLH, "variables in a multiple assignment"); - unloaddot(ls, v); - if (ls->token == ',') { /* assignment -> ',' NAME assignment */ - vardesc nv; +static void localstat (LexState *ls) { + /* stat -> LOCAL localnamelist decinit */ + FuncState *fs = ls->fs; + listdesc d; + int nvars; + check_debugline(ls); + next(ls); + nvars = localnamelist(ls); + decinit(ls, &d); + adjustlocalvars(ls, nvars, fs->lastsetline); + adjust_mult_assign(ls, nvars, &d); +} + + +static int funcname (LexState *ls, vardesc *v) { + /* funcname -> NAME [':' NAME | '.' NAME] */ + int needself = 0; + singlevar(ls, str_checkname(ls), v, 0); + if (ls->token == ':' || ls->token == '.') { + needself = (ls->token == ':'); next(ls); - var_or_func(ls, &nv); - if (nv.k == VEXP) - luaX_error(ls, "syntax error"); - left = assignment(ls, &nv, nvars+1); + lua_pushvar(ls, v); + code_constant(ls, checkname(ls)); + v->k = VINDEXED; } - else { /* assignment -> '=' explist1 */ - listdesc d; - if (ls->token != '=') - error_unexpected(ls); - next(ls); - explist1(ls, &d); - adjust_mult_assign(ls, nvars, &d); + return needself; +} + + +static int funcstat (LexState *ls, int line) { + /* funcstat -> FUNCTION funcname body */ + int needself; + vardesc v; + if (ls->fs->prev) /* inside other function? */ + return 0; + check_debugline(ls); + next(ls); + needself = funcname(ls, &v); + body(ls, needself, line); + storevar(ls, &v); + return 1; +} + + +static void namestat (LexState *ls) { + /* stat -> func | ['%'] NAME assignment */ + vardesc v; + check_debugline(ls); + var_or_func(ls, &v); + if (v.k == VEXP) { /* stat -> func */ + if (v.info == 0) /* is just an upper value? */ + luaX_error(ls, "syntax error"); + close_exp(ls, v.info, 0); } - if (v->k != VINDEXED || left+(nvars-1) == 0) { - /* global/local var or indexed var without values in between */ - storevar(ls, v); + else { /* stat -> ['%'] NAME assignment */ + int left = assignment(ls, &v, 1); + adjuststack(ls, left); /* remove eventual garbage left on stack */ } - else { /* indexed var with values in between*/ - code_oparg(ls, SETTABLE, left+(nvars-1), -1); - left += 2; /* table&index are not popped, because they aren't on top */ +} + + +static void ifpart (LexState *ls, int line) { + /* ifpart -> cond THEN block [ELSE block | ELSEIF ifpart] */ + int c; + int e; + next(ls); /* skip IF or ELSEIF */ + c = cond(ls); + check(ls, THEN); + block(ls); + e = SaveWord(ls); + if (ls->token == ELSEIF) + ifpart(ls, line); + else { + if (optional(ls, ELSE)) + block(ls); + check_match(ls, END, IF, line); } - return left; + codeIf(ls, c, e); } -static void constructor (LexState *ls) { - /* constructor -> '{' part [';' part] '}' */ - int line = ls->linenumber; - int pc = SaveWord(ls); - int nelems; - constdesc cd; - deltastack(ls, 1); - check(ls, '{'); - part(ls, &cd); - nelems = cd.n; - if (ls->token == ';') { - constdesc other_cd; - next(ls); - part(ls, &other_cd); - if (cd.k == other_cd.k) /* repeated parts? */ - luaX_error(ls, "invalid constructor syntax"); - nelems += other_cd.n; +static int stat (LexState *ls) { + int line = ls->linenumber; /* may be needed for error messages */ + switch (ls->token) { + case IF: /* stat -> IF ifpart END */ + ifpart(ls, line); + return 1; + + case WHILE: /* stat -> whilestat */ + whilestat(ls, line); + return 1; + + case DO: { /* stat -> DO block END */ + next(ls); + block(ls); + check_match(ls, END, DO, line); + return 1; + } + + case REPEAT: /* stat -> repeatstat */ + repeatstat(ls, line); + return 1; + + case FUNCTION: /* stat -> funcstat */ + return funcstat(ls, line); + + case LOCAL: /* stat -> localstat */ + localstat(ls); + return 1; + + case NAME: case '%': /* stat -> namestat */ + namestat(ls); + return 1; + + case RETURN: case ';': case ELSE: case ELSEIF: + case END: case UNTIL: case EOS: /* 'stat' follow */ + return 0; + + default: + error_unexpected(ls); + return 0; /* to avoid warnings */ } - check_match(ls, '}', '{', line); - fix_opcode(ls, pc, CREATEARRAY, nelems); } -static void part (LexState *ls, constdesc *cd) { + +static void parlist (LexState *ls) { + int nparams = 0; + int dots = 0; switch (ls->token) { - case ';': case '}': /* part -> empty */ - cd->n = 0; - cd->k = ls->token; - return; + case DOTS: /* parlist -> DOTS */ + next(ls); + dots = 1; + break; - case NAME: { - vardesc v; - exp0(ls, &v); - if (ls->token == '=') { - switch (v.k) { - case VGLOBAL: - code_constant(ls, v.info); - break; - case VLOCAL: - code_string(ls, ls->fs->localvar[v.info]); + case NAME: /* parlist, tailparlist -> NAME [',' tailparlist] */ + init: + store_localvar(ls, str_checkname(ls), nparams++); + if (ls->token == ',') { + next(ls); + switch (ls->token) { + case DOTS: /* tailparlist -> DOTS */ + next(ls); + dots = 1; break; - default: - error_unexpected(ls); + + case NAME: /* tailparlist -> NAME [',' tailparlist] */ + goto init; + + default: luaX_error(ls, "NAME or `...' expected"); } - next(ls); - exp1(ls); - cd->n = recfields(ls); - cd->k = 1; /* record */ - } - else { - lua_pushvar(ls, &v); - cd->n = listfields(ls); - cd->k = 0; /* list */ } break; - } - case '[': /* part -> recfield recfields */ - recfield(ls); - cd->n = recfields(ls); - cd->k = 1; /* record */ - break; + case ')': break; /* parlist -> empty */ - default: /* part -> exp1 listfields */ - exp1(ls); - cd->n = listfields(ls); - cd->k = 0; /* list */ - break; + default: luaX_error(ls, "NAME or `...' expected"); } + code_args(ls, nparams, dots); } -static int recfields (LexState *ls) { - /* recfields -> { ',' recfield } [','] */ - int n = 1; /* one has been read before */ - while (ls->token == ',') { - next(ls); - if (ls->token == ';' || ls->token == '}') - break; - recfield(ls); - n++; - if (n%RFIELDS_PER_FLUSH == 0) - flush_record(ls, RFIELDS_PER_FLUSH); - } - flush_record(ls, n%RFIELDS_PER_FLUSH); - return n; + +static void body (LexState *ls, int needself, int line) { + /* body -> '(' parlist ')' chunk END */ + FuncState newfs; + init_state(ls, &newfs, ls->fs->f->source); + newfs.f->lineDefined = line; + check(ls, '('); + if (needself) + add_localvar(ls, luaS_newfixed(ls->L, "self")); + parlist(ls); + check(ls, ')'); + chunk(ls); + check_match(ls, END, FUNCTION, line); + close_func(ls); + func_onstack(ls, &newfs); } -static int listfields (LexState *ls) { - /* listfields -> { ',' exp1 } [','] */ - int n = 1; /* one has been read before */ - while (ls->token == ',') { - next(ls); - if (ls->token == ';' || ls->token == '}') - break; - exp1(ls); - n++; - if (n%LFIELDS_PER_FLUSH == 0) - flush_list(ls, n/LFIELDS_PER_FLUSH - 1, LFIELDS_PER_FLUSH); + +static void ret (LexState *ls) { + /* ret -> [RETURN explist sc] */ + if (optional(ls, RETURN)) { + listdesc e; + check_debugline(ls); + explist(ls, &e); + if (e.pc > 0) { /* expression is an open function call? */ + Byte *code = ls->fs->f->code; + code[e.pc-2] = TAILCALL; /* instead of a conventional CALL */ + code[e.pc-1] = (Byte)ls->fs->nlocalvar; + } + else + code_oparg(ls, RETCODE, ls->fs->nlocalvar, 0); + ls->fs->stacksize = ls->fs->nlocalvar; /* removes all temp values */ + optional(ls, ';'); } - flush_list(ls, n/LFIELDS_PER_FLUSH, n%LFIELDS_PER_FLUSH); - return n; } -static void recfield (LexState *ls) { - /* recfield -> (NAME | '['exp1']') = exp1 */ - switch (ls->token) { - case NAME: - code_constant(ls, checkname(ls)); - break; +/* }====================================================================== */ - case '[': - next(ls); - exp1(ls); - check(ls, ']'); - break; - default: luaX_error(ls, "NAME or `[' expected"); +static void chunk (LexState *ls) { + /* chunk -> { stat [;] } ret */ + while (stat(ls)) { + LUA_ASSERT(ls->L, ls->fs->stacksize == ls->fs->nlocalvar, + "stack size != # local vars"); + optional(ls, ';'); } - check(ls, '='); - exp1(ls); + ret(ls); /* optional return */ } -- cgit v1.2.3-55-g6feb