static void ifstat(LexState* ls, int line) { /* ifstat -> IF cond THEN block {ELSEIF cond THEN block} [ELSE block] END */ FuncState* fs = ls->fs; int flist; int escapelist = NO_JUMP; flist = test_then_block(ls); /* IF cond THEN block */ while (ls->t.token == TK_ELSEIF) { luaK_concat(fs, &escapelist, luaK_jump(fs)); luaK_patchtohere(fs, flist); flist = test_then_block(ls); /* ELSEIF cond THEN block */ } if (ls->t.token == TK_ELSE) { luaK_concat(fs, &escapelist, luaK_jump(fs)); luaK_patchtohere(fs, flist); luaX_next(ls); /* skip ELSE (after patch, for correct line info) */ block(ls); /* `else' part */ } else luaK_concat(fs, &escapelist, flist); luaK_patchtohere(fs, escapelist); check_match(ls, TK_END, TK_IF, line); }
static void selectstat (LexState *ls, int line) { /* selectstat -> CASE val1 OF val2 THEN block [OF valx THEN block [ELSE THEN block]] ESAC */ FuncState *fs = ls->fs; BlockCnt bl; int escapelist = NO_JUMP; expdesc v; luaX_next(ls); /* skip `case' */ enterblock(fs, &bl, 0); /* block to control variable scope */ expr(ls, &v); checknext(ls, TK_OF); casestat(ls, &v); while (ls->t.token == TK_OF) { luaK_concat(fs, &escapelist, luaK_jump(fs)); luaK_patchtohere(fs, v.f); luaX_next(ls); /* skip OF */ casestat(ls, &v); /* OF val THEN block */ } if (ls->t.token == TK_ELSE) { luaK_concat(fs, &escapelist, luaK_jump(fs)); luaK_patchtohere(fs, v.f); luaX_next(ls); /* skip ELSE */ block(ls); /* default part */ } else { luaK_concat(fs, &escapelist, v.f); } luaK_patchtohere(fs, escapelist); check_match(ls, TK_ESAC, TK_CASE, line); leaveblock(fs); }
static void forbody (LexState *ls, int base, int line, int nvars, int isnum) { /* forbody -> DO block */ BlockCnt bl; FuncState *fs = GetCurrentFuncState( ls ); adjustlocalvars(ls, 3); /* control variables */ checknext(ls, TK_DO); int prep = isnum ? luaK_codeAsBx(fs, OP_FORPREP, base, NO_JUMP) : luaK_jump(fs); enterblock(fs, &bl, 0); /* scope for declared variables */ adjustlocalvars(ls, nvars); luaK_reserveregs(fs, nvars); block(ls); leaveblock(fs); /* end of scope for declared variables */ luaK_patchtohere(fs, prep); int endfor = (isnum) ? luaK_codeAsBx(fs, OP_FORLOOP, base, NO_JUMP) : luaK_codeABC(fs, OP_TFORLOOP, base, 0, nvars); luaK_fixline(fs, line); /* pretend that `OP_FOR' starts the loop */ luaK_patchlist(fs, (isnum ? endfor : luaK_jump(fs)), prep + 1); }
static void repeatstat(LexState* ls, int line) { /* repeatstat -> REPEAT block UNTIL cond */ int condexit; FuncState* fs = ls->fs; int repeat_init = luaK_getlabel(fs); BlockCnt bl1, bl2; enterblock(fs, &bl1, 1); /* loop block */ enterblock(fs, &bl2, 0); /* scope block */ luaX_next(ls); /* skip REPEAT */ chunk(ls); luaK_patchtohere(fs, bl1.continuelist); check_match(ls, TK_UNTIL, TK_REPEAT, line); condexit = cond(ls); /* read condition (inside scope block) */ if (!bl2.upval) /* no upvalues? */ { leaveblock(fs); /* finish scope */ luaK_patchlist(ls->fs, condexit, repeat_init); /* close the loop */ } else /* complete semantics when there are upvalues */ { breakstat(ls); /* if condition then break */ luaK_patchtohere(ls->fs, condexit); /* else... */ leaveblock(fs); /* finish scope... */ luaK_patchlist(ls->fs, luaK_jump(fs), repeat_init); /* and repeat */ } leaveblock(fs); /* finish loop */ }
static void continuestat (LexState *ls) { /* stat -> CONTINUE [loop number] */ FuncState *fs = ls->fs; BlockCnt *bl = fs->bl; BlockCnt *nextbl = NULL; int upval = 0, wasupval = 0; int levels = 1; next(ls); /* skip CONTINUE */ if (testnext(ls, TK_NUMBER)) { if (ls->t.seminfo.r != floor(ls->t.seminfo.r)) luaX_syntaxerror(ls, "loop block number must be integer"); levels = (int) ls->t.seminfo.r; if (levels < 1 || levels > LUA_MAXBREAKLEVEL) luaX_syntaxerror(ls, "loop block number out of range"); } while (levels-- > 0) { wasupval = upval; while (bl && !bl->isbreakable) { upval |= bl->upval; bl = bl->previous; } if (bl && levels > 0) { nextbl = bl; bl = bl->previous; } } if (!bl) luaX_syntaxerror(ls, "no loop to continue"); if (wasupval) luaK_codeABC(fs, OP_CLOSE, nextbl->nactvar, 0, 0); luaK_concat(fs, &bl->continuelist, luaK_jump(fs)); }
static void leaveblock(FuncState *fs) { BlockCnt *bl = fs->bl; LexState *ls = fs->ls; if (bl->previous && bl->upval) { /* create a 'jump to here' to close upvalues */ int j = luaK_jump(fs); luaK_patchclose(fs, j, bl->nactvar); luaK_patchtohere(fs, j); } if (bl->isloop) breaklabel(ls); /* close pending breaks */ fs->bl = bl->previous; removevars(fs, bl->nactvar); lua_assert(bl->nactvar == fs->nactvar); fs->freereg = fs->nactvar; /* free registers */ ls->dyd->label.n = bl->firstlabel; /* remove local labels */ if (bl->previous) /* inner block? */ movegotosout(fs, bl); /* update pending gotos to outer block */ else if (bl->firstgoto < ls->dyd->gt.n) /* pending gotos in outer block? */ undefgoto(ls, &ls->dyd->gt.arr[bl->firstgoto]); /* error */ }
static void breakstat (LexState *ls) { FuncState *fs = ls->fs; BlockCnt *bl = fs->bl; int upval = 0; while (bl && !bl->isbreakable) { upval |= bl->upval; bl = bl->previous; } if (!bl) luaX_syntaxerror(ls, "no loop to break"); if (upval) luaK_codeABC(fs, OP_CLOSE, bl->nactvar, 0, 0); luaK_concat(fs, &bl->breaklist, luaK_jump(fs)); }
static void forbody (LexState *ls, int base, int line, int nvars, int isnum) { BlockCnt bl; FuncState *fs = ls->fs; int prep, endfor; adjustlocalvars(ls, nvars); /* scope for all variables */ check(ls, TK_DO); enterblock(fs, &bl, 1); /* loop block */ prep = luaK_getlabel(fs); block(ls); luaK_patchtohere(fs, prep-1); endfor = (isnum) ? luaK_codeAsBx(fs, OP_FORLOOP, base, NO_JUMP) : luaK_codeABC(fs, OP_TFORLOOP, base, 0, nvars - 3); luaK_fixline(fs, line); /* pretend that `OP_FOR' starts the loop */ luaK_patchlist(fs, (isnum) ? endfor : luaK_jump(fs), prep); leaveblock(fs); }
static void whilestat (LexState *ls, int line) { /* whilestat -> WHILE cond DO block END */ FuncState *fs = ls->fs; int whileinit; int condexit; BlockCnt bl; luaX_next(ls); /* skip WHILE */ whileinit = luaK_getlabel(fs); condexit = cond(ls); enterblock(fs, &bl, 1); checknext(ls, TK_DO); block(ls); luaK_patchlist(fs, luaK_jump(fs), whileinit); check_match(ls, TK_END, TK_WHILE, line); leaveblock(fs); luaK_patchtohere(fs, condexit); /* false conditions finish the loop */ }
/* ** Ensures final expression result (including results from its jump ** lists) is in register 'reg'. ** If expression has jumps, need to patch these jumps either to ** its final position or to "load" instructions (for those tests ** that do not produce values). */ static void exp2reg (FuncState *fs, expdesc *e, int reg) { discharge2reg(fs, e, reg); if (e->k == VJMP) /* expression itself is a test? */ luaK_concat(fs, &e->t, e->u.info); /* put this jump in 't' list */ if (hasjumps(e)) { int final; /* position after whole expression */ int p_f = NO_JUMP; /* position of an eventual LOAD false */ int p_t = NO_JUMP; /* position of an eventual LOAD true */ if (need_value(fs, e->t) || need_value(fs, e->f)) { int fj = (e->k == VJMP) ? NO_JUMP : luaK_jump(fs); p_f = code_loadbool(fs, reg, 0, 1); p_t = code_loadbool(fs, reg, 1, 0); luaK_patchtohere(fs, fj); } final = luaK_getlabel(fs); patchlistaux(fs, e->f, final, reg, p_f); patchlistaux(fs, e->t, final, reg, p_t); }
static void breakstat (LexState *ls) { FuncState *fs = ls->fs; BlockCnt *bl = fs->bl; int upval = 0; while (bl && bl->isbreakable != 1) { if (bl->isbreakable == 2) luaK_codeABC(fs, OP_EXITTRY, 0, 0, 0); else if (bl->isbreakable == 3) luaX_syntaxerror(ls, "can't break in 'finally' clause"); upval |= bl->upval; bl = bl->previous; } if (!bl) luaX_syntaxerror(ls, "no loop to break"); if (upval) luaK_codeABC(fs, OP_CLOSE, bl->nactvar, 0, 0); luaK_concat(fs, &bl->breaklist, luaK_jump(fs)); }
/*static*/ void FuncState::exp2reg (/*FuncState *fs,*/ expdesc *e, int reg) { discharge2reg(e, reg); if (e->k == VJMP) luaK_concat(&e->t, e->u.info); /* put this jump in 't' list */ if (hasjumps(e)) { int final; /* position after whole expression */ int p_f = NO_JUMP; /* position of an eventual LOAD false */ int p_t = NO_JUMP; /* position of an eventual LOAD true */ if (need_value(e->t) || need_value(e->f)) { int fj = (e->k == VJMP) ? NO_JUMP : luaK_jump(); p_f = code_label(reg, 0, 1); p_t = code_label(reg, 1, 0); luaK_patchtohere(fj); } final = luaK_getlabel(); patchlistaux(e->f, final, reg, p_f); patchlistaux(e->t, final, reg, p_t); }
static void exp2reg (FuncState *fs, expdesc *e, int reg) { discharge2reg(fs, e, reg); if (e->k == VJMP) luaK_concat(fs, &e->t, e->u.info); /* put this jump in `t' list */ if (hasjumps(e)) { if (e->k != VJMP) luaK_goiftrue(fs, e); int fj = (e->k == VJMP) ? NO_JUMP : luaK_jump(fs); int p_f = code_label(fs, reg, 0, 1); luaK_patchtohere(fs, fj); int p_t = code_label(fs, reg, 1, 0); patchlistaux(fs, e->f, p_f); patchlistaux(fs, e->t, p_t); } e->f = e->t = NO_JUMP; e->u.info = reg; e->k = VNONRELOC; }
static void whilestat (LexState *ls, int line) { /* whilestat -> WHILE cond DO block END */ Instruction codeexp[MAXEXPWHILE + EXTRAEXP]; int lineexp; int i; int sizeexp; FuncState *fs = ls->fs; int whileinit, blockinit, expinit; expdesc v; BlockCnt bl; next(ls); /* skip WHILE */ whileinit = luaK_jump(fs); /* jump to condition (which will be moved) */ expinit = luaK_getlabel(fs); expr(ls, &v); /* parse condition */ if (v.k == VK) v.k = VTRUE; /* `trues' are all equal here */ lineexp = ls->linenumber; luaK_goiffalse(fs, &v); luaK_concat(fs, &v.f, fs->jpc); fs->jpc = NO_JUMP; sizeexp = fs->pc - expinit; /* size of expression code */ if (sizeexp > MAXEXPWHILE) luaX_syntaxerror(ls, "`while' condition too complex"); for (i = 0; i < sizeexp; i++) /* save `exp' code */ codeexp[i] = fs->f->code[expinit + i]; fs->pc = expinit; /* remove `exp' code */ enterblock(fs, &bl, 1); check(ls, TK_DO); blockinit = luaK_getlabel(fs); block(ls); luaK_patchtohere(fs, whileinit); /* initial jump jumps to here */ luaK_patchtohere(fs, bl.continuelist); /* move `exp' back to code */ if (v.t != NO_JUMP) v.t += fs->pc - expinit; if (v.f != NO_JUMP) v.f += fs->pc - expinit; for (i=0; i<sizeexp; i++) luaK_code(fs, codeexp[i], lineexp); check_match(ls, TK_END, TK_WHILE, line); leaveblock(fs); luaK_patchlist(fs, v.t, blockinit); /* true conditions go back to loop */ luaK_patchtohere(fs, v.f); /* false conditions finish the loop */ }
/*static*/ void FuncState::leaveblock (/*FuncState *fs*/) { //BlockCnt *bl = fs->bl; //LexState *ls = fs->ls; if (bl->previous && bl->upval) { /* create a 'jump to here' to close upvalues */ int j = luaK_jump(); luaK_patchclose(j, bl->nactvar); luaK_patchtohere(j); } if (bl->isloop) ls->breaklabel(); /* close pending breaks */ bl = bl->previous; removevars(bl->nactvar); lua_assert(bl->nactvar == nactvar); free_reg = nactvar; /* free registers */ ls->dyd->label.n = bl->firstlabel; /* remove local labels */ if (bl->previous) /* inner block? */ movegotosout(bl); /* update pending gotos to outer block */ else if (bl->firstgoto < ls->dyd->gt.n) /* pending gotos in outer block? */ ls->undefgoto(&ls->dyd->gt.arr[bl->firstgoto]); /* error */ }
static void fornum (LexState *ls, TString *varname, int line) { /* fornum -> NAME = exp1,exp1[,exp1] DO body */ FuncState *fs = ls->fs; int base = fs->freereg; new_localvar(ls, varname, 0); new_localvarstr(ls, "(for limit)", 1); new_localvarstr(ls, "(for step)", 2); check(ls, '='); exp1(ls); /* initial value */ check(ls, ','); exp1(ls); /* limit */ if (testnext(ls, ',')) exp1(ls); /* optional step */ else { /* default step = 1 */ luaK_codeABx(fs, OP_LOADK, fs->freereg, luaK_numberK(fs, 1)); luaK_reserveregs(fs, 1); } luaK_codeABC(fs, OP_SUB, fs->freereg - 3, fs->freereg - 3, fs->freereg - 1); luaK_jump(fs); forbody(ls, base, line, 3, 1); }
static void repeatstat (LexState *ls, int line) { /* repeatstat -> REPEAT block UNTIL cond */ int condexit; FuncState *fs = ls->fs; int repeat_init = luaK_getlabel(fs); BlockCnt bl1, bl2; enterblock(fs, &bl1, 1); /* loop block */ enterblock(fs, &bl2, 0); /* scope block */ luaX_next(ls); /* skip REPEAT */ chunk(ls); check_match(ls, TK_UNTIL, TK_REPEAT, line); #if LUA_EXT_CONTINUE if (bl2.continuelist != NO_JUMP) { int oldprohibition = fs->prohibitedloc; luaK_patchtohere(fs, bl2.continuelist); fs->prohibitedloc = bl2.continuepos; condexit = cond(ls); /* read condition (inside scope block) */ fs->prohibitedloc = oldprohibition; bl2.continuelist = NO_JUMP; } else { condexit = cond(ls); /* read condition (inside scope block) */ } #else condexit = cond(ls); /* read condition (inside scope block) */ #endif /* LUA_EXT_CONTINUE */ if (!bl2.upval) { /* no upvalues? */ leaveblock(fs); /* finish scope */ luaK_patchlist(ls->fs, condexit, repeat_init); /* close the loop */ } else { /* complete semantics when there are upvalues */ breakstat(ls); /* if condition then break */ luaK_patchtohere(ls->fs, condexit); /* else... */ leaveblock(fs); /* finish scope... */ luaK_patchlist(ls->fs, luaK_jump(fs), repeat_init); /* and repeat */ } leaveblock(fs); /* finish loop */ }
static void breakstat (LexState *ls) { FuncState *fs = GetCurrentFuncState( ls ); BlockCnt *bl = (BlockCnt*)fs->blockList.GetFirst(); int upval = 0; while (bl && !bl->isbreakable) { upval |= bl->upval; bl = (BlockCnt*)bl->next; } if (!bl) { luaX_syntaxerror(ls, "no loop to break"); } if (upval) { luaK_codeABC(fs, OP_CLOSE, bl->nactvar, 0, 0); } luaK_concat(fs, &bl->breaklist, luaK_jump(fs)); }
static void continuestat (LexState *ls) { FuncState *fs = ls->fs; BlockCnt *bl = fs->bl; int continuepos = fs->nactvar; { BlockCnt *b2 = bl; if (b2) { b2 = b2->previous; while (b2 && !b2->isbreakable) { continuepos = bl->nactvar; bl = b2; b2 = b2->previous; } } if (!b2) luaX_syntaxerror(ls, "no loop to continue"); /* b2 is a loop block, bl is the scope block just above it, continuepos is the nactvar of the scope above that */ } if (bl->continuelist == NO_JUMP) bl->continuepos = continuepos; luaK_concat(fs, &bl->continuelist, luaK_jump(fs)); }
static int ICACHE_FLASH_ATTR condjump (FuncState *fs, OpCode op, int A, int B, int C) { luaK_codeABC(fs, op, A, B, C); return luaK_jump(fs); }
/* ** Code a "conditional jump", that is, a test or comparison opcode ** followed by a jump. Return jump position. */ static int condjump (FuncState *fs, OpCode op, int A, int B, int C) { luaK_codeABC(fs, op, A, B, C); return luaK_jump(fs); }
/*static*/ int FuncState::condjump (/*FuncState *fs,*/ OpCode op, int A, int B, int C) { luaK_codeABC(op, A, B, C); return luaK_jump(); }
void FuncState::luaK_jumpto(int t) { luaK_patchlist(luaK_jump(), t); }
static void trystat (LexState *ls, int line) { /* trystat -> TRY block CATCH err DO block END */ FuncState *fs = ls->fs; BlockCnt bl; int base, pc, escapelist = NO_JUMP; luaX_next(ls); enterblock(fs, &bl, 2); /* try block */ base = fs->freereg; new_localvarliteral(ls, "(error obj)", 0); adjustlocalvars(ls, 1); /* error object */ luaK_reserveregs(fs, 1); pc = luaK_codeAsBx(fs, OP_TRY, base, NO_JUMP); chunk(ls); if (ls->t.token == TK_CATCH) { TString *varname; int errobj; luaK_codeABC(fs, OP_EXITTRY, 0, 0, 0); luaK_concat(fs, &escapelist, luaK_jump(fs)); SET_OPCODE(fs->f->code[pc], OP_TRYCATCH); /* change it to TRYCATCH */ luaK_patchtohere(fs, pc); bl.isbreakable = 0; // local err luaX_next(ls); /* skip `catch' */ varname = str_checkname(ls); /* first variable name */ // do checknext(ls, TK_DO); errobj = fs->freereg; new_localvar(ls, varname, 0); adjustlocalvars(ls, 1); luaK_reserveregs(fs, 1); luaK_codeABC(fs, OP_MOVE, errobj, base, 0); block(ls); } else if (ls->t.token == TK_FINALLY) { luaK_codeABC(fs, OP_EXITTRY, 0, 0, 0); luaK_concat(fs, &escapelist, luaK_jump(fs)); SET_OPCODE(fs->f->code[pc], OP_TRYFIN); /* change it to TRYFIN */ luaK_patchtohere(fs, pc); bl.isbreakable = 3; luaX_next(ls); /* skip 'finally' */ block(ls); luaK_codeABC(fs, OP_RETFIN, base, 0, 0); /* OP_ENDFIN jump to the return point */ } else { luaK_codeABC(fs, OP_EXITTRY, 0, 0, 0); luaK_concat(fs, &escapelist, pc); } leaveblock(fs); luaK_patchtohere(fs, escapelist); check_match(ls, TK_END, TK_TRY, line); }