/// <summary> /// Equivalent to luaK_prefix. </summary> internal void kPrefix(int op, Expdesc e) { Expdesc e2 = new Expdesc(Expdesc.VKNUM, 0); switch (op) { case Syntax.OPR_MINUS: if (e.kind() == Expdesc.VK) { kExp2anyreg(e); } codearith(Lua.OP_UNM, e, e2); break; case Syntax.OPR_NOT: codenot(e); break; case Syntax.OPR_LEN: kExp2anyreg(e); codearith(Lua.OP_LEN, e, e2); break; default: throw new System.ArgumentException(); } }
internal void setargc(Expdesc e, int c) { int at = e.info_Renamed; int[] code = f.code_Renamed; code[at] = Lua.SETARG_C(code[at], c); }
private void freeexp(Expdesc e) { if (e.kind() == Expdesc.VNONRELOC) { freereg(e.info_Renamed); } }
/// <summary> /// Equivalent to <code>luaK_goiffalse</code>. </summary> internal void kGoiffalse(Expdesc e) { int lj; // pc of last jump kDischargevars(e); switch (e.k) { case Expdesc.VNIL: case Expdesc.VFALSE: lj = NO_JUMP; // always false; do nothing break; case Expdesc.VTRUE: lj = kJump(); // always jump break; case Expdesc.VJMP: lj = e.info_Renamed; break; default: lj = jumponcond(e, true); break; } e.t = kConcat(e.t, lj); // insert last jump in `t' list kPatchtohere(e.f); e.f = NO_JUMP; }
internal void setargb(Expdesc e, int b) { int at = e.info_Renamed; int[] code = f.code_Renamed; code[at] = Lua.SETARG_B(code[at], b); }
internal void setarga(Expdesc e, int a) { int at = e.info_Renamed; int[] code = f.code_Renamed; code[at] = Lua.SETARG_A(code[at], a); }
/// <summary> /// Equivalent to <code>luaK_goiftrue</code>. </summary> internal void kGoiftrue(Expdesc e) { int lj; // pc of last jump kDischargevars(e); switch (e.k) { case Expdesc.VK: case Expdesc.VKNUM: case Expdesc.VTRUE: lj = NO_JUMP; // always true; do nothing break; case Expdesc.VFALSE: lj = kJump(); // always jump break; case Expdesc.VJMP: invertjump(e); lj = e.info_Renamed; break; default: lj = jumponcond(e, false); break; } e.f = kConcat(e.f, lj); // insert last jump in `f' list kPatchtohere(e.t); e.t = NO_JUMP; }
/// <summary> /// Equivalent to luaK_exp2nextreg. </summary> internal void kExp2nextreg(Expdesc e) { kDischargevars(e); freeexp(e); kReserveregs(1); exp2reg(e, freereg_Renamed - 1); }
/// <summary> /// Equivalent to luaK_dischargevars. </summary> internal void kDischargevars(Expdesc e) { switch (e.kind()) { case Expdesc.VLOCAL: e.Kind = Expdesc.VNONRELOC; break; case Expdesc.VUPVAL: e.reloc(kCodeABC(Lua.OP_GETUPVAL, 0, e.info_Renamed, 0)); break; case Expdesc.VGLOBAL: e.reloc(kCodeABx(Lua.OP_GETGLOBAL, 0, e.info_Renamed)); break; case Expdesc.VINDEXED: freereg(e.aux()); freereg(e.info()); e.reloc(kCodeABC(Lua.OP_GETTABLE, 0, e.info_Renamed, e.aux_Renamed)); break; case Expdesc.VVARARG: case Expdesc.VCALL: kSetoneret(e); break; default: break; // there is one value available (somewhere) } }
private void discharge2anyreg(Expdesc e) { if (e.k != Expdesc.VNONRELOC) { kReserveregs(1); discharge2reg(e, freereg_Renamed - 1); } }
private void invertjump(Expdesc e) { int at = getjumpcontrol(e.info_Renamed); int[] code = f.code_Renamed; int instr = code[at]; //# assert testTMode(Lua.OPCODE(instr)) && Lua.OPCODE(instr) != Lua.OP_TESTSET && Lua.OPCODE(instr) != Lua.OP_TEST code[at] = Lua.SETARG_A(instr, (Lua.ARGA(instr) == 0 ? 1 : 0)); }
/// <summary> /// Equivalent to <code>luaK_exp2val</code>. </summary> internal void kExp2val(Expdesc e) { if (e.hasjumps()) { kExp2anyreg(e); } else { kDischargevars(e); } }
/// <summary> /// Equivalent to luaK_setoneret. </summary> internal void kSetoneret(Expdesc e) { if (e.kind() == Expdesc.VCALL) // expression is an open function call? { e.nonreloc(Lua.ARGA(getcode(e))); } else if (e.kind() == Expdesc.VVARARG) { setargb(e, 2); e.Kind = Expdesc.VRELOCABLE; } }
internal void kSelf(Expdesc e, Expdesc key) { kExp2anyreg(e); freeexp(e); int func = freereg_Renamed; kReserveregs(2); kCodeABC(Lua.OP_SELF, func, e.info_Renamed, kExp2RK(key)); freeexp(key); e.info_Renamed = func; e.k = Expdesc.VNONRELOC; }
/// <summary> /// Equivalent to luaK_setreturns. </summary> internal void kSetreturns(Expdesc e, int nresults) { if (e.kind() == Expdesc.VCALL) // expression is an open function call? { setargc(e, nresults + 1); } else if (e.kind() == Expdesc.VVARARG) { setargb(e, nresults + 1); setarga(e, freereg_Renamed); kReserveregs(1); } }
private void codearith(int op, Expdesc e1, Expdesc e2) { if (constfolding(op, e1, e2)) { return; } else { int o1 = kExp2RK(e1); int o2 = (op != Lua.OP_UNM && op != Lua.OP_LEN) ? kExp2RK(e2) : 0; freeexp(e2); freeexp(e1); e1.info_Renamed = kCodeABC(op, 0, o1, o2); e1.k = Expdesc.VRELOCABLE; } }
private int jumponcond(Expdesc e, bool cond) { if (e.k == Expdesc.VRELOCABLE) { int ie = getcode(e); if (Lua.OPCODE(ie) == Lua.OP_NOT) { pc--; // remove previous OP_NOT return(condjump(Lua.OP_TEST, Lua.ARGB(ie), 0, cond ? 0 : 1)); } /* else go through */ } discharge2anyreg(e); freeexp(e); return(condjump(Lua.OP_TESTSET, Lua.NO_REG, e.info_Renamed, cond ? 1 : 0)); }
internal void codecomp(int op, bool cond, Expdesc e1, Expdesc e2) { int o1 = kExp2RK(e1); int o2 = kExp2RK(e2); freeexp(e2); freeexp(e1); if ((!cond) && op != Lua.OP_EQ) { /* exchange args to replace by `<' or `<=' */ int temp = o1; // o1 <==> o2 o1 = o2; o2 = temp; cond = true; } e1.info_Renamed = condjump(op, (cond ? 1 : 0), o1, o2); e1.k = Expdesc.VJMP; }
/// <summary> /// Equivalent to luaK_exp2anyreg. </summary> internal int kExp2anyreg(Expdesc e) { kDischargevars(e); if (e.k == Expdesc.VNONRELOC) { if (!e.hasjumps()) { return(e.info_Renamed); } if (e.info_Renamed >= nactvar) // reg is not a local? { exp2reg(e, e.info_Renamed); // put value on it return(e.info_Renamed); } } kExp2nextreg(e); // default return(e.info_Renamed); }
private void discharge2reg(Expdesc e, int reg) { kDischargevars(e); switch (e.k) { case Expdesc.VNIL: kNil(reg, 1); break; case Expdesc.VFALSE: case Expdesc.VTRUE: kCodeABC(Lua.OP_LOADBOOL, reg, (e.k == Expdesc.VTRUE ? 1 : 0), 0); break; case Expdesc.VK: kCodeABx(Lua.OP_LOADK, reg, e.info_Renamed); break; case Expdesc.VKNUM: kCodeABx(Lua.OP_LOADK, reg, kNumberK(e.nval_Renamed)); break; case Expdesc.VRELOCABLE: setarga(e, reg); break; case Expdesc.VNONRELOC: if (reg != e.info_Renamed) { kCodeABC(Lua.OP_MOVE, reg, e.info_Renamed, 0); } break; case Expdesc.VVOID: case Expdesc.VJMP: return; default: //# assert false break; } e.nonreloc(reg); }
private void codenot(Expdesc e) { kDischargevars(e); switch (e.k) { case Expdesc.VNIL: case Expdesc.VFALSE: e.k = Expdesc.VTRUE; break; case Expdesc.VK: case Expdesc.VKNUM: case Expdesc.VTRUE: e.k = Expdesc.VFALSE; break; case Expdesc.VJMP: invertjump(e); break; case Expdesc.VRELOCABLE: case Expdesc.VNONRELOC: discharge2anyreg(e); freeexp(e); e.info_Renamed = kCodeABC(Lua.OP_NOT, 0, e.info_Renamed, 0); e.k = Expdesc.VRELOCABLE; break; default: //# assert false break; } /* interchange true and false lists */ { int temp = e.f; e.f = e.t; e.t = temp; } removevalues(e.f); removevalues(e.t); }
/// <summary> /// Equivalent to <code>luaK_storevar</code>. </summary> internal void kStorevar(Expdesc @var, Expdesc ex) { switch (@var.k) { case Expdesc.VLOCAL: { freeexp(ex); exp2reg(ex, @var.info_Renamed); return; } case Expdesc.VUPVAL: { int e = kExp2anyreg(ex); kCodeABC(Lua.OP_SETUPVAL, e, @var.info_Renamed, 0); break; } case Expdesc.VGLOBAL: { int e = kExp2anyreg(ex); kCodeABx(Lua.OP_SETGLOBAL, e, @var.info_Renamed); break; } case Expdesc.VINDEXED: { int e = kExp2RK(ex); kCodeABC(Lua.OP_SETTABLE, @var.info_Renamed, @var.aux_Renamed, e); break; } default: { /* invalid var kind to store */ //# assert false break; } } freeexp(ex); }
/// <summary> /// Equivalent to <code>luaK_exp2RK</code>. </summary> internal int kExp2RK(Expdesc e) { kExp2val(e); switch (e.k) { case Expdesc.VKNUM: case Expdesc.VTRUE: case Expdesc.VFALSE: case Expdesc.VNIL: if (nk <= Lua.MAXINDEXRK) // constant fit in RK operand? { e.info_Renamed = (e.k == Expdesc.VNIL) ? nilK() : (e.k == Expdesc.VKNUM) ? kNumberK(e.nval_Renamed) : boolK(e.k == Expdesc.VTRUE); e.k = Expdesc.VK; return(e.info_Renamed | Lua.BITRK); } else { break; } case Expdesc.VK: if (e.info_Renamed <= Lua.MAXINDEXRK) // constant fit in argC? { return(e.info_Renamed | Lua.BITRK); } else { break; } default: break; } /* not a constant in the right range: put it in a register */ return(kExp2anyreg(e)); }
/// <summary> /// Equivalent to luaK_infix. </summary> internal void kInfix(int op, Expdesc v) { switch (op) { case Syntax.OPR_AND: kGoiftrue(v); break; case Syntax.OPR_OR: kGoiffalse(v); break; case Syntax.OPR_CONCAT: kExp2nextreg(v); // operand must be on the `stack' break; default: if (!isnumeral(v)) { kExp2RK(v); } break; } }
private void exp2reg(Expdesc e, int reg) { discharge2reg(e, reg); if (e.k == Expdesc.VJMP) { e.t = kConcat(e.t, e.info_Renamed); // put this jump in `t' list } if (e.hasjumps()) { 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 == Expdesc.VJMP) ? NO_JUMP : kJump(); p_f = code_label(reg, 0, 1); p_t = code_label(reg, 1, 0); kPatchtohere(fj); } int finalpos = kGetlabel(); // position after whole expression patchlistaux(e.f, finalpos, reg, p_f); patchlistaux(e.t, finalpos, reg, p_t); } e.init(Expdesc.VNONRELOC, reg); }
/// <summary> /// Equivalent to luaK_setmultret (in lcode.h). </summary> internal void kSetmultret(Expdesc e) { kSetreturns(e, Lua.MULTRET); }
/// <summary> /// Equivalent to luaK_posfix. </summary> internal void kPosfix(int op, Expdesc e1, Expdesc e2) { switch (op) { case Syntax.OPR_AND: /* list must be closed */ //# assert e1.t == NO_JUMP kDischargevars(e2); e2.f = kConcat(e2.f, e1.f); e1.init(e2); break; case Syntax.OPR_OR: /* list must be closed */ //# assert e1.f == NO_JUMP kDischargevars(e2); e2.t = kConcat(e2.t, e1.t); e1.init(e2); break; case Syntax.OPR_CONCAT: kExp2val(e2); if (e2.k == Expdesc.VRELOCABLE && Lua.OPCODE(getcode(e2)) == Lua.OP_CONCAT) { //# assert e1.info == Lua.ARGB(getcode(e2))-1 freeexp(e1); setcode(e2, Lua.SETARG_B(getcode(e2), e1.info_Renamed)); e1.k = e2.k; e1.info_Renamed = e2.info_Renamed; } else { kExp2nextreg(e2); // operand must be on the 'stack' codearith(Lua.OP_CONCAT, e1, e2); } break; case Syntax.OPR_ADD: codearith(Lua.OP_ADD, e1, e2); break; case Syntax.OPR_SUB: codearith(Lua.OP_SUB, e1, e2); break; case Syntax.OPR_MUL: codearith(Lua.OP_MUL, e1, e2); break; case Syntax.OPR_DIV: codearith(Lua.OP_DIV, e1, e2); break; case Syntax.OPR_MOD: codearith(Lua.OP_MOD, e1, e2); break; case Syntax.OPR_POW: codearith(Lua.OP_POW, e1, e2); break; case Syntax.OPR_EQ: codecomp(Lua.OP_EQ, true, e1, e2); break; case Syntax.OPR_NE: codecomp(Lua.OP_EQ, false, e1, e2); break; case Syntax.OPR_LT: codecomp(Lua.OP_LT, true, e1, e2); break; case Syntax.OPR_LE: codecomp(Lua.OP_LE, true, e1, e2); break; case Syntax.OPR_GT: codecomp(Lua.OP_LT, false, e1, e2); break; case Syntax.OPR_GE: codecomp(Lua.OP_LE, false, e1, e2); break; default: //# assert false break; } }
internal void setcode(Expdesc e, int code) { f.code_Renamed[e.info_Renamed] = code; }
internal int getcode(Expdesc e) { return(f.code_Renamed[e.info_Renamed]); }
private bool constfolding(int op, Expdesc e1, Expdesc e2) { double r; if (!isnumeral(e1) || !isnumeral(e2)) { return(false); } double v1 = e1.nval_Renamed; double v2 = e2.nval_Renamed; switch (op) { case Lua.OP_ADD: r = v1 + v2; break; case Lua.OP_SUB: r = v1 - v2; break; case Lua.OP_MUL: r = v1 * v2; break; case Lua.OP_DIV: if (v2 == 0.0) { return(false); // do not attempt to divide by 0 } r = v1 / v2; break; case Lua.OP_MOD: if (v2 == 0.0) { return(false); // do not attempt to divide by 0 } r = v1 % v2; break; case Lua.OP_POW: r = Lua.iNumpow(v1, v2); break; case Lua.OP_UNM: r = -v1; break; case Lua.OP_LEN: // no constant folding for 'len' return(false); default: //# assert false r = 0.0; break; } if (double.IsNaN(r)) { return(false); // do not attempt to produce NaN } e1.nval_Renamed = r; return(true); }