void prefix(int /* UnOpr */ op, expdesc e, int line) { expdesc e2 = new expdesc(); e2.init(LexState.VKNUM, 0); switch (op) { case LexState.OPR_MINUS: { if (e.isnumeral()) /* minus constant? */ e.u.setNval(e.u.nval().neg()); /* fold it */ else { this.exp2anyreg(e); this.codearith(OP_UNM, e, e2, line); } break; } case LexState.OPR_NOT: this.codenot(e); break; case LexState.OPR_LEN: { this.exp2anyreg(e); /* cannot operate on constants */ this.codearith(OP_LEN, e, e2, line); break; } default: _assert(false); } }
int exp2RK(expdesc e) { this.exp2val(e); switch (e.k) { case LexState.VTRUE: case LexState.VFALSE: case LexState.VNIL: { if (this.nk <= MAXINDEXRK) { /* constant fit in RK operand? */ e.u.info = (e.k == LexState.VNIL) ? this.nilK() : this.boolK((e.k == LexState.VTRUE)); e.k = LexState.VK; return RKASK(e.u.info); } else break; } case LexState.VKNUM: { e.u.info = this.numberK(e.u.nval()); e.k = LexState.VK; /* go through */ } case LexState.VK: { if (e.u.info <= MAXINDEXRK) /* constant fit in argC? */ return RKASK(e.u.info); else break; } default: break; } /* not a constant in the right range: put it in a register */ return this.exp2anyreg(e); }
void setoneret(expdesc e) { if (e.k == LexState.VCALL) { /* expression is an open function call? */ e.k = LexState.VNONRELOC; e.u.info = GETARG_A(this.getcode(e)); } else if (e.k == LexState.VVARARG) { SETARG_B(this.getcodePtr(e), 2); e.k = LexState.VRELOCABLE; /* can relocate its simple result */ } }
void indexed(expdesc t, expdesc k) { t.u.ind_t = (short) t.u.info; t.u.ind_idx = (short) this.exp2RK(k); LuaC._assert(t.k == LexState.VUPVAL || vkisinreg(t.k)); t.u.ind_vt = (short) ((t.k == LexState.VUPVAL) ? LexState.VUPVAL : LexState.VLOCAL); t.k = LexState.VINDEXED; }
void infix(int /* BinOpr */ op, expdesc v) { switch (op) { case LexState.OPR_AND: { this.goiftrue(v); break; } case LexState.OPR_OR: { this.goiffalse(v); break; } case LexState.OPR_CONCAT: { this.exp2nextreg(v); /* operand must be on the `stack' */ break; } case LexState.OPR_ADD: case LexState.OPR_SUB: case LexState.OPR_MUL: case LexState.OPR_DIV: case LexState.OPR_MOD: case LexState.OPR_POW: { if (!v.isnumeral()) this.exp2RK(v); break; } default: { this.exp2RK(v); break; } } }
void codenot(expdesc e) { this.dischargevars(e); switch (e.k) { case LexState.VNIL: case LexState.VFALSE: { e.k = LexState.VTRUE; break; } case LexState.VK: case LexState.VKNUM: case LexState.VTRUE: { e.k = LexState.VFALSE; break; } case LexState.VJMP: { this.invertjump(e); break; } case LexState.VRELOCABLE: case LexState.VNONRELOC: { this.discharge2anyreg(e); this.freeexp(e); e.u.info = this.codeABC(OP_NOT, 0, e.u.info, 0); e.k = LexState.VRELOCABLE; break; } default: { _assert(false); /* cannot happen */ break; } } /* interchange true and false lists */ { int temp = e.f.i; e.f.i = e.t.i; e.t.i = temp; } this.removevalues(e.f.i); this.removevalues(e.t.i); }
boolean constfolding(int op, expdesc e1, expdesc e2) { LuaValue v1, v2, r; if (!e1.isnumeral() || !e2.isnumeral()) return false; if ((op == OP_DIV || op == OP_MOD) && e2.u.nval().eq_b(LuaValue.ZERO)) return false; /* do not attempt to divide by 0 */ v1 = e1.u.nval(); v2 = e2.u.nval(); switch (op) { case OP_ADD: r = v1.add(v2); break; case OP_SUB: r = v1.sub(v2); break; case OP_MUL: r = v1.mul(v2); break; case OP_DIV: r = v1.div(v2); break; case OP_MOD: r = v1.mod(v2); break; case OP_POW: r = v1.pow(v2); break; case OP_UNM: r = v1.neg(); break; case OP_LEN: // r = v1.len(); // break; return false; /* no constant folding for 'len' */ default: _assert(false); r = null; break; } if (Double.isNaN(r.todouble())) return false; /* do not attempt to produce NaN */ e1.u.setNval(r); return true; }
void self(expdesc e, expdesc key) { int func; this.exp2anyreg(e); this.freeexp(e); func = this.freereg; this.reserveregs(2); this.codeABC(OP_SELF, func, e.u.info, this.exp2RK(key)); this.freeexp(key); e.u.info = func; e.k = LexState.VNONRELOC; }
void exp2reg(expdesc e, int reg) { this.discharge2reg(e, reg); if (e.k == LexState.VJMP) this.concat(e.t, e.u.info); /* put this jump in `t' list */ if (e.hasjumps()) { int _final; /* position after whole expression */ int p_f = LexState.NO_JUMP; /* position of an eventual LOAD false */ int p_t = LexState.NO_JUMP; /* position of an eventual LOAD true */ if (this.need_value(e.t.i) || this.need_value(e.f.i)) { int fj = (e.k == LexState.VJMP) ? LexState.NO_JUMP : this.jump(); p_f = this.code_label(reg, 0, 1); p_t = this.code_label(reg, 1, 0); this.patchtohere(fj); } _final = this.getlabel(); this.patchlistaux(e.f.i, _final, reg, p_f); this.patchlistaux(e.t.i, _final, reg, p_t); } e.f.i = e.t.i = LexState.NO_JUMP; e.u.info = reg; e.k = LexState.VNONRELOC; }
static int singlevaraux(FuncState fs, LuaString n, expdesc var, int base) { if (fs == null) /* no more levels? */ return LexState.VVOID; /* default is global */ int v = fs.searchvar(n); /* look up at current level */ if (v >= 0) { var.init(LexState.VLOCAL, v); if (base == 0) fs.markupval(v); /* local will be used as an upval */ return LexState.VLOCAL; } else { /* not found at current level; try upvalues */ int idx = fs.searchupvalue(n); /* try existing upvalues */ if (idx < 0) { /* not found? */ if (singlevaraux(fs.prev, n, var, 0) == LexState.VVOID) /* try upper levels */ return LexState.VVOID; /* not found; is a global */ /* else was LOCAL or UPVAL */ idx = fs.newupvalue(n, var); /* will be a new upvalue */ } var.init(LexState.VUPVAL, idx); return LexState.VUPVAL; } }
int exp2anyreg(expdesc e) { this.dischargevars(e); if (e.k == LexState.VNONRELOC) { if (!e.hasjumps()) return e.u.info; /* exp is already in a register */ if (e.u.info >= this.nactvar) { /* reg. is not a local? */ this.exp2reg(e, e.u.info); /* put value on it */ return e.u.info; } } this.exp2nextreg(e); /* default */ return e.u.info; }
void dischargevars(expdesc e) { switch (e.k) { case LexState.VLOCAL: { e.k = LexState.VNONRELOC; break; } case LexState.VUPVAL: { e.u.info = this.codeABC(OP_GETUPVAL, 0, e.u.info, 0); e.k = LexState.VRELOCABLE; break; } case LexState.VINDEXED: { int op = OP_GETTABUP; /* assume 't' is in an upvalue */ this.freereg(e.u.ind_idx); if (e.u.ind_vt == LexState.VLOCAL) { /* 't' is in a register? */ this.freereg(e.u.ind_t); op = OP_GETTABLE; } e.u.info = this.codeABC(op, 0, e.u.ind_t, e.u.ind_idx); e.k = LexState.VRELOCABLE; break; } case LexState.VVARARG: case LexState.VCALL: { this.setoneret(e); break; } default: break; /* there is one value available (somewhere) */ } }
void codecomp(int /* OpCode */ op, int cond, expdesc e1, expdesc e2) { int o1 = this.exp2RK(e1); int o2 = this.exp2RK(e2); this.freeexp(e2); this.freeexp(e1); if (cond == 0 && op != OP_EQ) { int temp; /* exchange args to replace by `<' or `<=' */ temp = o1; o1 = o2; o2 = temp; /* o1 <==> o2 */ cond = 1; } e1.u.info = this.condjump(op, cond, o1, o2); e1.k = LexState.VJMP; }
void codearith(int op, expdesc e1, expdesc e2, int line) { if (constfolding(op, e1, e2)) return; else { int o2 = (op != OP_UNM && op != OP_LEN) ? this.exp2RK(e2) : 0; int o1 = this.exp2RK(e1); if (o1 > o2) { this.freeexp(e1); this.freeexp(e2); } else { this.freeexp(e2); this.freeexp(e1); } e1.u.info = this.codeABC(op, 0, o1, o2); e1.k = LexState.VRELOCABLE; fixline(line); } }
void discharge2reg(expdesc e, int reg) { this.dischargevars(e); switch (e.k) { case LexState.VNIL: { this.nil(reg, 1); break; } case LexState.VFALSE: case LexState.VTRUE: { this.codeABC(OP_LOADBOOL, reg, (e.k == LexState.VTRUE ? 1 : 0), 0); break; } case LexState.VK: { this.codeABx(OP_LOADK, reg, e.u.info); break; } case LexState.VKNUM: { this.codeABx(OP_LOADK, reg, this.numberK(e.u.nval())); break; } case LexState.VRELOCABLE: { InstructionPtr pc = this.getcodePtr(e); SETARG_A(pc, reg); break; } case LexState.VNONRELOC: { if (reg != e.u.info) this.codeABC(OP_MOVE, reg, e.u.info, 0); break; } default: { _assert(e.k == LexState.VVOID || e.k == LexState.VJMP); return; /* nothing to do... */ } } e.u.info = reg; e.k = LexState.VNONRELOC; }
void posfix(int op, expdesc e1, expdesc e2, int line) { switch (op) { case LexState.OPR_AND: { _assert(e1.t.i == LexState.NO_JUMP); /* list must be closed */ this.dischargevars(e2); this.concat(e2.f, e1.f.i); // *e1 = *e2; e1.setvalue(e2); break; } case LexState.OPR_OR: { _assert(e1.f.i == LexState.NO_JUMP); /* list must be closed */ this.dischargevars(e2); this.concat(e2.t, e1.t.i); // *e1 = *e2; e1.setvalue(e2); break; } case LexState.OPR_CONCAT: { this.exp2val(e2); if (e2.k == LexState.VRELOCABLE && GET_OPCODE(this.getcode(e2)) == OP_CONCAT) { _assert(e1.u.info == GETARG_B(this.getcode(e2)) - 1); this.freeexp(e1); SETARG_B(this.getcodePtr(e2), e1.u.info); e1.k = LexState.VRELOCABLE; e1.u.info = e2.u.info; } else { this.exp2nextreg(e2); /* operand must be on the 'stack' */ this.codearith(OP_CONCAT, e1, e2, line); } break; } case LexState.OPR_ADD: this.codearith(OP_ADD, e1, e2, line); break; case LexState.OPR_SUB: this.codearith(OP_SUB, e1, e2, line); break; case LexState.OPR_MUL: this.codearith(OP_MUL, e1, e2, line); break; case LexState.OPR_DIV: this.codearith(OP_DIV, e1, e2, line); break; case LexState.OPR_MOD: this.codearith(OP_MOD, e1, e2, line); break; case LexState.OPR_POW: this.codearith(OP_POW, e1, e2, line); break; case LexState.OPR_EQ: this.codecomp(OP_EQ, 1, e1, e2); break; case LexState.OPR_NE: this.codecomp(OP_EQ, 0, e1, e2); break; case LexState.OPR_LT: this.codecomp(OP_LT, 1, e1, e2); break; case LexState.OPR_LE: this.codecomp(OP_LE, 1, e1, e2); break; case LexState.OPR_GT: this.codecomp(OP_LT, 0, e1, e2); break; case LexState.OPR_GE: this.codecomp(OP_LE, 0, e1, e2); break; default: _assert(false); } }
void exp2anyregup(expdesc e) { if (e.k != LexState.VUPVAL || e.hasjumps()) exp2anyreg(e); }
void exp2val(expdesc e) { if (e.hasjumps()) this.exp2anyreg(e); else this.dischargevars(e); }