Beispiel #1
0
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);
}
Beispiel #2
0
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);
}
Beispiel #3
0
void luaK_posfix (FuncState *fs, BinOpr op,
                  expdesc *e1, expdesc *e2, int line) {
  switch (op) {
    case OPR_AND: {
      lua_assert(e1->t == NO_JUMP);  /* list must be closed */
      luaK_dischargevars(fs, e2);
      luaK_concat(fs, &e2->f, e1->f);
      *e1 = *e2;
      break;
    }
    case OPR_OR: {
      lua_assert(e1->f == NO_JUMP);  /* list must be closed */
      luaK_dischargevars(fs, e2);
      luaK_concat(fs, &e2->t, e1->t);
      *e1 = *e2;
      break;
    }
    case OPR_CONCAT: {
      luaK_exp2val(fs, e2);
      if (e2->k == VRELOCABLE && GET_OPCODE(getcode(fs, e2)) == OP_CONCAT) {
        lua_assert(e1->u.info == GETARG_B(getcode(fs, e2))-1);
        freeexp(fs, e1);
        SETARG_B(getcode(fs, e2), e1->u.info);
        e1->k = VRELOCABLE; e1->u.info = e2->u.info;
      }
      else {
        luaK_exp2nextreg(fs, e2);  /* operand must be on the 'stack' */
        codearith(fs, OP_CONCAT, e1, e2, line);
      }
      break;
    }
    case OPR_ADD: case OPR_SUB: case OPR_MUL: case OPR_DIV:
    case OPR_IDIV: case OPR_MOD: case OPR_POW:
    case OPR_BAND: case OPR_BOR: case OPR_BXOR:
    case OPR_SHL: case OPR_SHR: {
      codearith(fs, cast(OpCode, (op - OPR_ADD) + OP_ADD), e1, e2, line);
      break;
    }
    case OPR_EQ: case OPR_LT: case OPR_LE: {
      codecomp(fs, cast(OpCode, op - OPR_EQ + OP_EQ), 1, e1, e2);
      break;
    }
    case OPR_NE: case OPR_GT: case OPR_GE: {
      codecomp(fs, cast(OpCode, op - OPR_NE + OP_EQ), 0, e1, e2);
      break;
    }
    default: lua_assert(0);
  }
}
Beispiel #4
0
void luaK_tostack (LexState *ls, expdesc *v, int onlyone) {
  FuncState *fs = ls->fs;
  if (!discharge(fs, v)) {  /* `v' is an expression? */
    OpCode previous = GET_OPCODE(fs->f->code[fs->pc-1]);
    if (!ISJUMP(previous) && v->u.l.f == NO_JUMP && v->u.l.t == NO_JUMP) {
      /* expression has no jumps */
      if (onlyone)
        luaK_setcallreturns(fs, 1);  /* call must return 1 value */
    }
    else {  /* expression has jumps */
      int final;  /* position after whole expression */
      int j = NO_JUMP;  /*  eventual  jump over values */
      int p_nil = NO_JUMP;  /* position of an eventual PUSHNIL */
      int p_1 = NO_JUMP;  /* position of an eventual PUSHINT */
      if (ISJUMP(previous) || need_value(fs, v->u.l.f, OP_JMPONF)
                           || need_value(fs, v->u.l.t, OP_JMPONT)) {
        /* expression needs values */
        if (ISJUMP(previous))
          luaK_concat(fs, &v->u.l.t, fs->pc-1);  /* put `previous' in t. list */
        else {
          j = code_label(fs, OP_JMP, NO_JUMP);  /* to jump over both pushes */
          /* correct stack for compiler and symbolic execution */
          luaK_adjuststack(fs, 1);
        }
        p_nil = code_label(fs, OP_PUSHNILJMP, 0);
        p_1 = code_label(fs, OP_PUSHINT, 1);
        luaK_patchlist(fs, j, luaK_getlabel(fs));
      }
      final = luaK_getlabel(fs);
      luaK_patchlistaux(fs, v->u.l.f, p_nil, OP_JMPONF, final);
      luaK_patchlistaux(fs, v->u.l.t, p_1, OP_JMPONT, final);
      v->u.l.f = v->u.l.t = NO_JUMP;
    }
Beispiel #5
0
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));
}
Beispiel #6
0
static void luaK_testgo (FuncState *fs, expdesc *v, int invert, OpCode jump) {
  int prevpos;  /* position of last instruction */
  Instruction *previous;
  int *golist, *exitlist;
  if (!invert) {
    golist = &v->u.l.f;    /* go if false */
    exitlist = &v->u.l.t;  /* exit if true */
  }
  else {
    golist = &v->u.l.t;    /* go if true */
    exitlist = &v->u.l.f;  /* exit if false */
  }
  discharge1(fs, v);
  prevpos = fs->pc-1;
  previous = &fs->f->code[prevpos];
  LUA_ASSERT(*previous==previous_instruction(fs), "no jump allowed here");
  if (!ISJUMP(GET_OPCODE(*previous)))
    prevpos = luaK_code1(fs, jump, NO_JUMP);
  else {  /* last instruction is already a jump */
    if (invert)
      SET_OPCODE(*previous, invertjump(GET_OPCODE(*previous)));
  }
  luaK_concat(fs, exitlist, prevpos);  /* insert last jump in `exitlist' */
  luaK_patchlist(fs, *golist, luaK_getlabel(fs));
  *golist = NO_JUMP;
}
Beispiel #7
0
int luaK_jump (FuncState *fs) {
  int j = luaK_code1(fs, OP_JMP, NO_JUMP);
  if (j == fs->lasttarget) {  /* possible jumps to this jump? */
    luaK_concat(fs, &j, fs->jlt);  /* keep them on hold */
    fs->jlt = NO_JUMP;
  }
  return j;
}
Beispiel #8
0
int FuncState::luaK_jump (/*FuncState *fs*/) {
	int jpc = this->jpc;  /* save list of jumps to here */
	int j;
	this->jpc = NO_JUMP;
	j = luaK_codeAsBx(OP_JMP, 0, NO_JUMP);
	luaK_concat(&j, jpc);  /* keep them on hold */
	return j;
}
Beispiel #9
0
/*
** Create a jump instruction and return its position, so its destination
** can be fixed later (with 'fixjump'). If there are jumps to
** this position (kept in 'jpc'), link them all together so that
** 'patchlistaux' will fix all them directly to the final destination.
*/
int luaK_jump (FuncState *fs) {
  int jpc = fs->jpc;  /* save list of jumps to here */
  int j;
  fs->jpc = NO_JUMP;  /* no more jumps to here */
  j = luaK_codeAsBx(fs, OP_JMP, 0, NO_JUMP);
  luaK_concat(fs, &j, jpc);  /* keep them on hold */
  return j;
}
Beispiel #10
0
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));
}
Beispiel #11
0
/*
** 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);
  }
Beispiel #12
0
/*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);
	}
Beispiel #13
0
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;
}
Beispiel #14
0
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));
}
Beispiel #15
0
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 */
}
Beispiel #16
0
void luaK_goiffalse (FuncState *fs, expdesc *e) {
  int pc;  /* pc of last jump */
  luaK_dischargevars(fs, e);
  switch (e->k) {
    case VJMP: {
      pc = e->u.info;
      break;
    }
    case VNIL: case VFALSE: {
      pc = NO_JUMP;  /* always false; do nothing */
      break;
    }
    default: {
      pc = jumponcond(fs, e, 1);
      break;
    }
  }
  luaK_concat(fs, &e->t, pc);  /* insert last jump in `t' list */
  luaK_patchtohere(fs, e->f);
  e->f = NO_JUMP;
}
Beispiel #17
0
void luaK_goiftrue (FuncState *fs, expdesc *e) {
  int pc;  /* pc of last jump */
  luaK_dischargevars(fs, e);
  switch (e->k) {
    case VJMP: {
      invertjump(fs, e);
      pc = e->u.info;
      break;
    }
    case VTRUE: {
      pc = NO_JUMP;  /* always true; do nothing */
      break;
    }
    default: {
      pc = jumponcond(fs, e, 0);
      break;
    }
  }
  luaK_concat(fs, &e->f, pc);  /* insert last jump in `f' list */
  luaK_patchtohere(fs, e->t);
  e->t = NO_JUMP;
}
Beispiel #18
0
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));
}
Beispiel #19
0
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));
}
Beispiel #20
0
/*
** Add elements in 'list' to list of pending jumps to "here"
** (current position)
*/
void luaK_patchtohere (FuncState *fs, int list) {
  luaK_getlabel(fs);  /* mark "here" as a jump target */
  luaK_concat(fs, &fs->jpc, list);
}
Beispiel #21
0
void FuncState::luaK_patchtohere (/*FuncState *fs,*/ int list) {
	luaK_getlabel();
	luaK_concat(&jpc, list);
}
Beispiel #22
0
void luaK_patchtohere (FuncState *fs, int list) {
  luaK_getlabel(fs);
  luaK_concat(fs, &fs->jpc, list);
}
Beispiel #23
0
void ICACHE_FLASH_ATTR luaK_patchtohere (FuncState *fs, int list) {
  luaK_getlabel(fs);
  luaK_concat(fs, &fs->jpc, list);
}
Beispiel #24
0
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);
}
Beispiel #25
0
void luaK_patchlist (FuncState *fs, int list, int target) {
  if (target == fs->lasttarget)  /* same target that list `jlt'? */
    luaK_concat(fs, &fs->jlt, list);  /* delay fixing */
  else
    luaK_patchlistaux(fs, list, target, OP_END, 0);
}