aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/lfunc.js42
-rw-r--r--src/lvm.js1501
2 files changed, 776 insertions, 767 deletions
diff --git a/src/lfunc.js b/src/lfunc.js
index e9ec377..77eb853 100644
--- a/src/lfunc.js
+++ b/src/lfunc.js
@@ -49,7 +49,47 @@ class UpVal {
}
+const findupval = function(L, level) {
+ let pp = L.openupval;
+
+ while(pp !== null && pp.v >= level) {
+ let p = pp;
+
+ if (p.v === level)
+ return p;
+
+ pp = p.u.open.next;
+ }
+
+ let uv = new UpVal();
+ uv.refcount = 0;
+ uv.u.open.next = pp;
+ uv.u.open.touched = true;
+
+ pp = uv;
+
+ uv.v = level;
+
+ // Thread with upvalue list business ? lfunc.c:75
+
+ return uv;
+}
+
+const luaF_close = function(L, level) {
+ while (L.openupval !== null && L.openupval.v >= level) {
+ let uv = L.openupval;
+ assert(uv.isopen());
+ L.openupval = uv.u.open.next; /* remove from 'open' list */
+ if (uv.refcount > 0) {
+ uv.value = L.stack[uv.v];
+ uv.v = null;
+ }
+ }
+}
+
module.exports = {
Proto: Proto,
- UpVal: UpVal
+ UpVal: UpVal,
+ findupval: findupval,
+ luaF_close: luaF_close
}; \ No newline at end of file
diff --git a/src/lvm.js b/src/lvm.js
index 479dcfe..6523482 100644
--- a/src/lvm.js
+++ b/src/lvm.js
@@ -19,846 +19,815 @@ const CallInfo = lstate.CallInfo;
const llimit = require('./llimit.js');
const ldo = require('./ldo.js');
-class LuaVM {
-
- constructor(L) {
- this.L = L;
- }
+const RA = function(L, base, i) {
+ return base + i.A;
+}
- RA(base, i) {
- return base + i.A;
- }
+const RB = function(L, base, i) {
+ return base + i.B;
+}
- RB(base, i) {
- return base + i.B;
- }
+const RC = function(L, base, i) {
+ return base + i.C;
+}
- RC(base, i) {
- return base + i.C;
- }
+const RKB = function(L, base, k, i) {
+ return OC.ISK(i.B) ? k[OC.INDEXK(i.B)] : L.stack[base + i.B];
+}
- RKB(base, k, i) {
- return OC.ISK(i.B) ? k[OC.INDEXK(i.B)] : this.L.stack[base + i.B];
- }
+const RKC = function(L, base, k, i) {
+ return OC.ISK(i.C) ? k[OC.INDEXK(i.C)] : L.stack[base + i.C];
+}
- RKC(base, k, i) {
- return OC.ISK(i.C) ? k[OC.INDEXK(i.C)] : this.L.stack[base + i.C];
- }
+const luaV_execute = function(L) {
+ let ci = L.ci;
+ ci.callstatus |= lstate.CIST_FRESH;
+ newframe:
+ for (;;) {
+ ci = L.ci;
+ var cl = ci.func;
+ let k = cl.p.k;
+ let base = ci.u.l.base
+
+ let i = ci.u.l.savedpc[ci.pcOff++];
+ let ra = RA(L, base, i);
+
+ switch (OC.OpCodes[i.opcode]) {
+ case "OP_MOVE": {
+ L.stack[ra] = L.stack[RB(L, base, i)];
+ break;
+ }
+ case "OP_LOADK": {
+ L.stack[ra] = k[i.Bx];
+ break;
+ }
+ case "OP_LOADKX": {
+ assert(OC.OpCodes[ci.u.l.savedpc[ci.pcOff].opcode] === "OP_EXTRAARG");
+ L.stack[ra] = k[ci.u.l.savedpc[ci.pcOff++].Ax];
+ break;
+ }
+ case "OP_LOADBOOL": {
+ L.stack[ra] = new TValue(CT.LUA_TBOOLEAN, i.B !== 0);
- execute() {
- let L = this.L;
-
- let ci = L.ci;
- ci.callstatus |= lstate.CIST_FRESH;
- newframe:
- for (;;) {
- ci = L.ci;
- var cl = ci.func;
- let k = cl.p.k;
- let base = ci.u.l.base
-
- let i = ci.u.l.savedpc[ci.pcOff++];
- let ra = this.RA(base, i);
-
- switch (OC.OpCodes[i.opcode]) {
- case "OP_MOVE": {
- L.stack[ra] = L.stack[this.RB(base, i)];
- break;
- }
- case "OP_LOADK": {
- L.stack[ra] = k[i.Bx];
- break;
- }
- case "OP_LOADKX": {
- assert(OC.OpCodes[ci.u.l.savedpc[ci.pcOff].opcode] === "OP_EXTRAARG");
- L.stack[ra] = k[ci.u.l.savedpc[ci.pcOff++].Ax];
- break;
- }
- case "OP_LOADBOOL": {
- L.stack[ra] = new TValue(CT.LUA_TBOOLEAN, i.B !== 0);
+ if (i.C !== 0)
+ ci.pcOff++; /* skip next instruction (if C) */
- if (i.C !== 0)
- ci.pcOff++; /* skip next instruction (if C) */
+ break;
+ }
+ case "OP_LOADNIL": {
+ for (let j = 0; j <= i.B; j++)
+ L.stack[ra + j] = ldo.nil;
+ break;
+ }
+ case "OP_GETUPVAL": {
+ L.stack[ra] = cl.upvals[i.B].val(L);
+ break;
+ }
+ case "OP_SETUPVAL": {
+ cl.upvals[i.B].setval(L, ra);
+ break;
+ }
+ case "OP_GETTABUP": {
+ let table = cl.upvals[i.B].val(L);
+ let key = RKC(L, base, k, i);
+
+ // if (!table.ttistable() || !table.metatable.__index(table, key)) {
+ // // __index
+ // } else {
+ L.stack[ra] = table.metatable.__index(table, key);
+ // }
+ break;
+ }
+ case "OP_SETTABUP": {
+ let table = cl.upvals[i.A].val(L);
+ let key = RKB(L, base, k, i);
+ let v = RKC(L, base, k, i);
+
+ // if (!table.ttistable() || !table.metatable.__index(table, key)) {
+ // // __index
+ // } else {
+ table.metatable.__newindex(table, key, v);
+ // }
+
+ break;
+ }
+ case "OP_GETTABLE": {
+ let table = RKB(L, base, k, i);
+ let key = RKC(L, base, k, i);
+
+ // if (!table.ttistable() || !table.metatable.__index(table, key)) {
+ // // __index
+ // } else {
+ L.stack[ra] = table.metatable.__index(table, key);
+ // }
+ break;
+ }
+ case "OP_SETTABLE": {
+ let table = L.stack[ra];
+ let key = RKB(L, base, k, i);
+ let v = RKC(L, base, k, i);
+
+ // if (!table.ttistable() || !table.metatable.__index(table, key)) {
+ // // __index
+ // } else {
+ table.metatable.__newindex(table, key, v);
+ // }
+
+ break;
+ }
+ case "OP_NEWTABLE": {
+ L.stack[ra] = new Table();
+ break;
+ }
+ case "OP_SELF": {
+ let table = L.stack[RB(L, base, i)];
+ let key = RKC(L, base, k, i);
- break;
- }
- case "OP_LOADNIL": {
- for (let j = 0; j <= i.B; j++)
- L.stack[ra + j] = ldo.nil;
- break;
- }
- case "OP_GETUPVAL": {
- L.stack[ra] = cl.upvals[i.B].val(L);
- break;
- }
- case "OP_SETUPVAL": {
- cl.upvals[i.B].setval(L, ra);
- break;
- }
- case "OP_GETTABUP": {
- let table = cl.upvals[i.B].val(L);
- let key = this.RKC(base, k, i);
-
- // if (!table.ttistable() || !table.metatable.__index(table, key)) {
- // // __index
- // } else {
- L.stack[ra] = table.metatable.__index(table, key);
- // }
- break;
- }
- case "OP_SETTABUP": {
- let table = cl.upvals[i.A].val(L);
- let key = this.RKB(base, k, i);
- let v = this.RKC(base, k, i);
-
- // if (!table.ttistable() || !table.metatable.__index(table, key)) {
- // // __index
- // } else {
- table.metatable.__newindex(table, key, v);
- // }
-
- break;
- }
- case "OP_GETTABLE": {
- let table = this.RKB(base, k, i);
- let key = this.RKC(base, k, i);
-
- // if (!table.ttistable() || !table.metatable.__index(table, key)) {
- // // __index
- // } else {
- L.stack[ra] = table.metatable.__index(table, key);
- // }
- break;
- }
- case "OP_SETTABLE": {
- let table = L.stack[ra];
- let key = this.RKB(base, k, i);
- let v = this.RKC(base, k, i);
-
- // if (!table.ttistable() || !table.metatable.__index(table, key)) {
- // // __index
- // } else {
- table.metatable.__newindex(table, key, v);
- // }
-
- break;
- }
- case "OP_NEWTABLE": {
- L.stack[ra] = new Table();
- break;
- }
- case "OP_SELF": {
- let table = L.stack[this.RB(base, i)];
- let key = this.RKC(base, k, i);
+ L.stack[ra + 1] = table;
- L.stack[ra + 1] = table;
+ // if (!table.ttistable() || !table.metatable.__index(table, key)) {
+ // // __index
+ // } else {
+ L.stack[ra] = table.metatable.__index(table, key);
+ // }
- // if (!table.ttistable() || !table.metatable.__index(table, key)) {
- // // __index
- // } else {
- L.stack[ra] = table.metatable.__index(table, key);
- // }
+ break;
+ }
+ case "OP_ADD": {
+ let op1 = RKB(L, base, k, i);
+ let op2 = RKC(L, base, k, i);
+ let numberop1 = tonumber(op1);
+ let numberop2 = tonumber(op2);
+
+ if (op1.ttisinteger() && op2.ttisinteger()) {
+ L.stack[ra] = new TValue(CT.LUA_TNUMINT, (op1.value + op2.value)|0);
+ } else if (numberop1 !== false && numberop2 !== false) {
+ L.stack[ra] = new TValue(CT.LUA_TNUMFLT, op1.value + op2.value);
+ } else {
+ // Metamethod
+ throw new Error(`Can't perform binary operation on ${op1.value} and ${op2.value}`);
+ }
+ break;
+ }
+ case "OP_SUB": {
+ let op1 = RKB(L, base, k, i);
+ let op2 = RKC(L, base, k, i);
+ let numberop1 = tonumber(op1);
+ let numberop2 = tonumber(op2);
+
+ if (op1.ttisinteger() && op2.ttisinteger()) {
+ L.stack[ra] = new TValue(CT.LUA_TNUMINT, (op1.value - op2.value)|0);
+ } else if (numberop1 !== false && numberop2 !== false) {
+ L.stack[ra] = new TValue(CT.LUA_TNUMFLT, op1.value - op2.value);
+ } else {
+ // Metamethod
+ throw new Error(`Can't perform binary operation on ${op1.value} and ${k[i.C].value}`);
+ }
+ break;
+ }
+ case "OP_MUL": {
+ let op1 = RKB(L, base, k, i);
+ let op2 = RKC(L, base, k, i);
+ let numberop1 = tonumber(op1);
+ let numberop2 = tonumber(op2);
+
+ if (op1.ttisinteger() && op2.ttisinteger()) {
+ L.stack[ra] = new TValue(CT.LUA_TNUMINT, (op1.value * op2.value)|0);
+ } else if (numberop1 !== false && numberop2 !== false) {
+ L.stack[ra] = new TValue(CT.LUA_TNUMFLT, k[i.B].value * op2.value);
+ } else {
+ // Metamethod
+ throw new Error(`Can't perform binary operation on ${k[i.B].value} and ${k[i.C].value}`);
+ }
+ break;
+ }
+ case "OP_MOD": {
+ let op1 = RKB(L, base, k, i);
+ let op2 = RKC(L, base, k, i);
+ let numberop1 = tonumber(op1);
+ let numberop2 = tonumber(op2);
+
+ if (op1.ttisinteger() && op2.ttisinteger()) {
+ L.stack[ra] = new TValue(CT.LUA_TNUMINT, (op1.value % op2.value)|0);
+ } else if (numberop1 !== false && numberop2 !== false) {
+ L.stack[ra] = new TValue(CT.LUA_TNUMFLT, k[i.B].value % op2.value);
+ } else {
+ // Metamethod
+ throw new Error(`Can't perform binary operation on ${k[i.B].value} and ${k[i.C].value}`);
+ }
+ break;
+ }
+ case "OP_POW": {
+ let op1 = RKB(L, base, k, i);
+ let op2 = RKC(L, base, k, i);
+ let numberop1 = tonumber(op1);
+ let numberop2 = tonumber(op2);
+
+ if (numberop1 !== false && numberop2 !== false) {
+ L.stack[ra] = new TValue(CT.LUA_TNUMFLT, Math.pow(op1.value, op2.value));
+ } else {
+ // Metamethod
+ throw new Error(`Can't perform binary operation on ${k[i.B].value} and ${k[i.C].value}`);
+ }
+ break;
+ }
+ case "OP_DIV": {
+ let op1 = RKB(L, base, k, i);
+ let op2 = RKC(L, base, k, i);
+ let numberop1 = tonumber(op1);
+ let numberop2 = tonumber(op2);
+
+ if (numberop1 !== false && numberop2 !== false) {
+ L.stack[ra] = new TValue(CT.LUA_TNUMFLT, k[i.B].value / op2.value);
+ } else {
+ // Metamethod
+ throw new Error(`Can't perform binary operation on ${k[i.B].value} and ${k[i.C].value}`);
+ }
+ break;
+ }
+ case "OP_IDIV": {
+ let op1 = RKB(L, base, k, i);
+ let op2 = RKC(L, base, k, i);
+ let numberop1 = tonumber(op1);
+ let numberop2 = tonumber(op2);
+
+ if (op1.ttisinteger() && op2.ttisinteger()) {
+ L.stack[ra] = new TValue(CT.LUA_TNUMINT, (op1.value / op2.value)|0);
+ } else if (numberop1 !== false && numberop2 !== false) {
+ L.stack[ra] = new TValue(CT.LUA_TNUMFLT, (op1.value / op2.value)|0);
+ } else {
+ // Metamethod
+ throw new Error(`Can't perform binary operation on ${k[i.B].value} and ${k[i.C].value}`);
+ }
+ break;
+ }
+ case "OP_BAND": {
+ let op1 = RKB(L, base, k, i);
+ let op2 = RKC(L, base, k, i);
+ let numberop1 = tonumber(op1);
+ let numberop2 = tonumber(op2);
+
+ if (op1.ttisinteger() && op2.ttisinteger()) {
+ L.stack[ra] = new TValue(CT.LUA_TNUMINT, (op1.value & op2.value)|0);
+ } else {
+ // Metamethod
+ throw new Error(`Can't perform binary operation on ${k[i.B].value} and ${k[i.C].value}`);
+ }
+ break;
+ }
+ case "OP_BOR": {
+ let op1 = RKB(L, base, k, i);
+ let op2 = RKC(L, base, k, i);
+ let numberop1 = tonumber(op1);
+ let numberop2 = tonumber(op2);
+
+ if (op1.ttisinteger() && op2.ttisinteger()) {
+ L.stack[ra] = new TValue(CT.LUA_TNUMINT, (op1.value | op2.value)|0);
+ } else {
+ // Metamethod
+ throw new Error(`Can't perform binary operation on ${k[i.B].value} and ${k[i.C].value}`);
+ }
+ break;
+ }
+ case "OP_BXOR": {
+ let op1 = RKB(L, base, k, i);
+ let op2 = RKC(L, base, k, i);
+ let numberop1 = tonumber(op1);
+ let numberop2 = tonumber(op2);
+
+ if (op1.ttisinteger() && op2.ttisinteger()) {
+ L.stack[ra] = new TValue(CT.LUA_TNUMINT, (op1.value ^ op2.value)|0);
+ } else {
+ // Metamethod
+ throw new Error(`Can't perform binary operation on ${k[i.B].value} and ${k[i.C].value}`);
+ }
+ break;
+ }
+ case "OP_SHL": {
+ let op1 = RKB(L, base, k, i);
+ let op2 = RKC(L, base, k, i);
+ let numberop1 = tonumber(op1);
+ let numberop2 = tonumber(op2);
+
+ if (op1.ttisinteger() && op2.ttisinteger()) {
+ L.stack[ra] = new TValue(CT.LUA_TNUMINT, (op1.value << op2.value)|0);
+ } else {
+ // Metamethod
+ throw new Error(`Can't perform binary operation on ${k[i.B].value} and ${k[i.C].value}`);
+ }
+ break;
+ }
+ case "OP_SHR": {
+ let op1 = RKB(L, base, k, i);
+ let op2 = RKC(L, base, k, i);
+ let numberop1 = tonumber(op1);
+ let numberop2 = tonumber(op2);
+
+ if (op1.ttisinteger() && op2.ttisinteger()) {
+ L.stack[ra] = new TValue(CT.LUA_TNUMINT, (op1.value >> op2.value)|0);
+ } else {
+ // Metamethod
+ throw new Error(`Can't perform binary operation on ${k[i.B].value} and ${k[i.C].value}`);
+ }
+ break;
+ }
+ case "OP_UNM": {
+ let op = L.stack[RB(L, base, i)];
+ let numberop = tonumber(op);
+
+ if (op.ttisinteger()) {
+ L.stack[ra] = new TValue(CT.LUA_TNUMINT, -op.value);
+ } else if (numberop !== false) {
+ L.stack[ra] = new TValue(CT.LUA_TNUMFLT, -op.value);
+ } else {
+ // Metamethod
+ throw new Error(`Can't perform unary operation on ${op.value}`);
+ }
+ break;
+ }
+ case "OP_BNOT": {
+ let op = L.stack[RB(L, base, i)];
+ let numberop = tonumber(op);
- break;
- }
- case "OP_ADD": {
- let op1 = this.RKB(base, k, i);
- let op2 = this.RKC(base, k, i);
- let numberop1 = LuaVM.tonumber(op1);
- let numberop2 = LuaVM.tonumber(op2);
-
- if (op1.ttisinteger() && op2.ttisinteger()) {
- L.stack[ra] = new TValue(CT.LUA_TNUMINT, (op1.value + op2.value)|0);
- } else if (numberop1 !== false && numberop2 !== false) {
- L.stack[ra] = new TValue(CT.LUA_TNUMFLT, op1.value + op2.value);
- } else {
- // Metamethod
- throw new Error(`Can't perform binary operation on ${op1.value} and ${op2.value}`);
- }
- break;
- }
- case "OP_SUB": {
- let op1 = this.RKB(base, k, i);
- let op2 = this.RKC(base, k, i);
- let numberop1 = LuaVM.tonumber(op1);
- let numberop2 = LuaVM.tonumber(op2);
-
- if (op1.ttisinteger() && op2.ttisinteger()) {
- L.stack[ra] = new TValue(CT.LUA_TNUMINT, (op1.value - op2.value)|0);
- } else if (numberop1 !== false && numberop2 !== false) {
- L.stack[ra] = new TValue(CT.LUA_TNUMFLT, op1.value - op2.value);
- } else {
- // Metamethod
- throw new Error(`Can't perform binary operation on ${op1.value} and ${k[i.C].value}`);
- }
- break;
- }
- case "OP_MUL": {
- let op1 = this.RKB(base, k, i);
- let op2 = this.RKC(base, k, i);
- let numberop1 = LuaVM.tonumber(op1);
- let numberop2 = LuaVM.tonumber(op2);
-
- if (op1.ttisinteger() && op2.ttisinteger()) {
- L.stack[ra] = new TValue(CT.LUA_TNUMINT, (op1.value * op2.value)|0);
- } else if (numberop1 !== false && numberop2 !== false) {
- L.stack[ra] = new TValue(CT.LUA_TNUMFLT, k[i.B].value * op2.value);
- } else {
- // Metamethod
- throw new Error(`Can't perform binary operation on ${k[i.B].value} and ${k[i.C].value}`);
- }
- break;
- }
- case "OP_MOD": {
- let op1 = this.RKB(base, k, i);
- let op2 = this.RKC(base, k, i);
- let numberop1 = LuaVM.tonumber(op1);
- let numberop2 = LuaVM.tonumber(op2);
-
- if (op1.ttisinteger() && op2.ttisinteger()) {
- L.stack[ra] = new TValue(CT.LUA_TNUMINT, (op1.value % op2.value)|0);
- } else if (numberop1 !== false && numberop2 !== false) {
- L.stack[ra] = new TValue(CT.LUA_TNUMFLT, k[i.B].value % op2.value);
- } else {
- // Metamethod
- throw new Error(`Can't perform binary operation on ${k[i.B].value} and ${k[i.C].value}`);
- }
- break;
- }
- case "OP_POW": {
- let op1 = this.RKB(base, k, i);
- let op2 = this.RKC(base, k, i);
- let numberop1 = LuaVM.tonumber(op1);
- let numberop2 = LuaVM.tonumber(op2);
-
- if (numberop1 !== false && numberop2 !== false) {
- L.stack[ra] = new TValue(CT.LUA_TNUMFLT, Math.pow(op1.value, op2.value));
- } else {
- // Metamethod
- throw new Error(`Can't perform binary operation on ${k[i.B].value} and ${k[i.C].value}`);
- }
- break;
- }
- case "OP_DIV": {
- let op1 = this.RKB(base, k, i);
- let op2 = this.RKC(base, k, i);
- let numberop1 = LuaVM.tonumber(op1);
- let numberop2 = LuaVM.tonumber(op2);
-
- if (numberop1 !== false && numberop2 !== false) {
- L.stack[ra] = new TValue(CT.LUA_TNUMFLT, k[i.B].value / op2.value);
- } else {
- // Metamethod
- throw new Error(`Can't perform binary operation on ${k[i.B].value} and ${k[i.C].value}`);
- }
- break;
- }
- case "OP_IDIV": {
- let op1 = this.RKB(base, k, i);
- let op2 = this.RKC(base, k, i);
- let numberop1 = LuaVM.tonumber(op1);
- let numberop2 = LuaVM.tonumber(op2);
-
- if (op1.ttisinteger() && op2.ttisinteger()) {
- L.stack[ra] = new TValue(CT.LUA_TNUMINT, (op1.value / op2.value)|0);
- } else if (numberop1 !== false && numberop2 !== false) {
- L.stack[ra] = new TValue(CT.LUA_TNUMFLT, (op1.value / op2.value)|0);
- } else {
- // Metamethod
- throw new Error(`Can't perform binary operation on ${k[i.B].value} and ${k[i.C].value}`);
- }
- break;
- }
- case "OP_BAND": {
- let op1 = this.RKB(base, k, i);
- let op2 = this.RKC(base, k, i);
- let numberop1 = LuaVM.tonumber(op1);
- let numberop2 = LuaVM.tonumber(op2);
-
- if (op1.ttisinteger() && op2.ttisinteger()) {
- L.stack[ra] = new TValue(CT.LUA_TNUMINT, (op1.value & op2.value)|0);
- } else {
- // Metamethod
- throw new Error(`Can't perform binary operation on ${k[i.B].value} and ${k[i.C].value}`);
- }
- break;
- }
- case "OP_BOR": {
- let op1 = this.RKB(base, k, i);
- let op2 = this.RKC(base, k, i);
- let numberop1 = LuaVM.tonumber(op1);
- let numberop2 = LuaVM.tonumber(op2);
-
- if (op1.ttisinteger() && op2.ttisinteger()) {
- L.stack[ra] = new TValue(CT.LUA_TNUMINT, (op1.value | op2.value)|0);
- } else {
- // Metamethod
- throw new Error(`Can't perform binary operation on ${k[i.B].value} and ${k[i.C].value}`);
- }
- break;
- }
- case "OP_BXOR": {
- let op1 = this.RKB(base, k, i);
- let op2 = this.RKC(base, k, i);
- let numberop1 = LuaVM.tonumber(op1);
- let numberop2 = LuaVM.tonumber(op2);
-
- if (op1.ttisinteger() && op2.ttisinteger()) {
- L.stack[ra] = new TValue(CT.LUA_TNUMINT, (op1.value ^ op2.value)|0);
- } else {
- // Metamethod
- throw new Error(`Can't perform binary operation on ${k[i.B].value} and ${k[i.C].value}`);
- }
- break;
- }
- case "OP_SHL": {
- let op1 = this.RKB(base, k, i);
- let op2 = this.RKC(base, k, i);
- let numberop1 = LuaVM.tonumber(op1);
- let numberop2 = LuaVM.tonumber(op2);
-
- if (op1.ttisinteger() && op2.ttisinteger()) {
- L.stack[ra] = new TValue(CT.LUA_TNUMINT, (op1.value << op2.value)|0);
- } else {
- // Metamethod
- throw new Error(`Can't perform binary operation on ${k[i.B].value} and ${k[i.C].value}`);
- }
- break;
- }
- case "OP_SHR": {
- let op1 = this.RKB(base, k, i);
- let op2 = this.RKC(base, k, i);
- let numberop1 = LuaVM.tonumber(op1);
- let numberop2 = LuaVM.tonumber(op2);
-
- if (op1.ttisinteger() && op2.ttisinteger()) {
- L.stack[ra] = new TValue(CT.LUA_TNUMINT, (op1.value >> op2.value)|0);
- } else {
- // Metamethod
- throw new Error(`Can't perform binary operation on ${k[i.B].value} and ${k[i.C].value}`);
- }
- break;
- }
- case "OP_UNM": {
- let op = L.stack[this.RB(base, i)];
- let numberop = LuaVM.tonumber(op);
-
- if (op.ttisinteger()) {
- L.stack[ra] = new TValue(CT.LUA_TNUMINT, -op.value);
- } else if (numberop !== false) {
- L.stack[ra] = new TValue(CT.LUA_TNUMFLT, -op.value);
- } else {
- // Metamethod
- throw new Error(`Can't perform unary operation on ${op.value}`);
- }
- break;
- }
- case "OP_BNOT": {
- let op = L.stack[this.RB(base, i)];
- let numberop = LuaVM.tonumber(op);
-
- if (op.ttisinteger()) {
- L.stack[ra] = new TValue(CT.LUA_TNUMINT, ~op.value);
- } else {
- // Metamethod
- throw new Error(`Can't perform unary operation on ${op.value}`);
- }
- break;
- }
- case "OP_NOT": {
- let op = L.stack[this.RB(base, i)];
- L.stack[ra] = new TValue(CT.LUA_TBOOLEAN, LuaVM.l_isfalse(op));
- break;
- }
- case "OP_LEN": {
- break;
- }
- case "OP_CONCAT": {
- break;
+ if (op.ttisinteger()) {
+ L.stack[ra] = new TValue(CT.LUA_TNUMINT, ~op.value);
+ } else {
+ // Metamethod
+ throw new Error(`Can't perform unary operation on ${op.value}`);
}
- case "OP_JMP": {
- this.dojump(ci, i, 0);
- break;
- }
- case "OP_EQ": {
- if (LuaVM.luaV_equalobj(this.RKB(base, k, i), this.RKC(base, k, i)) !== i.A)
- ci.pcOff++;
- else
- this.donextjump(ci);
- base = ci.u.l.base;
- break;
- }
- case "OP_LT": {
- if (LuaVM.luaV_lessthan(this.RKB(base, k, i), this.RKC(base, k, i)) !== i.A)
- ci.pcOff++;
- else
- this.donextjump(ci);
- base = ci.u.l.base;
- break;
- }
- case "OP_LE": {
- if (LuaVM.luaV_lessequal(this.RKB(base, k, i), this.RKC(base, k, i)) !== i.A)
- ci.pcOff++;
- else
- this.donextjump(ci);
- base = ci.u.l.base;
- break;
- }
- case "OP_TEST": {
- if (i.C ? LuaVM.l_isfalse(L.stack[ra]) : !LuaVM.l_isfalse(L.stack[ra]))
- ci.pcOff++;
- else
- this.donextjump(ci);
- break;
- }
- case "OP_TESTSET": {
- let rb = L.stack[this.RB(base, i)];
- if (i.C ? LuaVM.l_isfalse(rb) : !LuaVM.l_isfalse(rb))
- ci.pcOff++;
- else {
- L.stack[ra] = rb;
- this.donextjump(ci);
- }
- break;
- }
- case "OP_CALL": {
- let b = i.B;
- let nresults = i.C - 1;
-
- if (b !== 0)
- L.top = ra+b;
-
- if (ldo.precall(L, ra, L.stack[ra], nresults)) {
- if (nresults >= 0)
- L.top = ci.top;
- base = ci.u.l.base;
- } else {
- ci = L.ci;
- continue newframe;
- }
+ break;
+ }
+ case "OP_NOT": {
+ let op = L.stack[RB(L, base, i)];
+ L.stack[ra] = new TValue(CT.LUA_TBOOLEAN, l_isfalse(op));
+ break;
+ }
+ case "OP_LEN": {
+ break;
+ }
+ case "OP_CONCAT": {
+ break;
+ }
+ case "OP_JMP": {
+ dojump(L, ci, i, 0);
+ break;
+ }
+ case "OP_EQ": {
+ if (luaV_equalobj(RKB(L, base, k, i), RKC(L, base, k, i)) !== i.A)
+ ci.pcOff++;
+ else
+ donextjump(L, ci);
+ base = ci.u.l.base;
+ break;
+ }
+ case "OP_LT": {
+ if (luaV_lessthan(RKB(L, base, k, i), RKC(L, base, k, i)) !== i.A)
+ ci.pcOff++;
+ else
+ donextjump(L, ci);
+ base = ci.u.l.base;
+ break;
+ }
+ case "OP_LE": {
+ if (luaV_lessequal(RKB(L, base, k, i), RKC(L, base, k, i)) !== i.A)
+ ci.pcOff++;
+ else
+ donextjump(L, ci);
+ base = ci.u.l.base;
+ break;
+ }
+ case "OP_TEST": {
+ if (i.C ? l_isfalse(L.stack[ra]) : !l_isfalse(L.stack[ra]))
+ ci.pcOff++;
+ else
+ donextjump(L, ci);
+ break;
+ }
+ case "OP_TESTSET": {
+ let rb = L.stack[RB(L, base, i)];
+ if (i.C ? l_isfalse(rb) : !l_isfalse(rb))
+ ci.pcOff++;
+ else {
+ L.stack[ra] = rb;
+ donextjump(L, ci);
+ }
+ break;
+ }
+ case "OP_CALL": {
+ let b = i.B;
+ let nresults = i.C - 1;
- break;
- }
- case "OP_TAILCALL": {
- if (i.B !== 0) L.top = ra + i.B;
- if (ldo.precall(L, ra, L.stack[ra], LUA_MULTRET)) { // JS function
- base = ci.u.l.base;
- } else {
- /* tail call: put called frame (n) in place of caller one (o) */
- let nci = L.ci;
- let oci = nci.previous;
- let nfunc = nci.func;
- let nfuncOff = nci.funcOff;
- let ofunc = oci.func;
- let ofuncOff = oci.funcOff;
- let lim = nci.u.l.base + nfunc.p.numparams;
- if (cl.p.p.length > 0) this.closeupvals(oci.u.l.base);
- for (let aux = 0; nfuncOff + aux < lim; aux++)
- L.stack[ofuncOff + aux] = L.stack[nfuncOff + aux];
- oci.func = nci.func;
- oci.u.l.base = ofuncOff + (nci.u.l.base - nfuncOff);
- L.top = ofuncOff + (L.top - nfuncOff);
- oci.top = L.top;
- oci.u.l.savedpc = nci.u.l.savedpc;
- oci.pcOff = nci.pcOff;
- oci.callstatus |= lstate.CIST_TAIL;
- L.ci = oci;
- ci = L.ci;
- L.ciOff--;
-
- assert(L.top === oci.u.l.base + L.stack[ofuncOff].p.maxstacksize);
-
- continue newframe;
- }
- break;
+ if (b !== 0)
+ L.top = ra+b;
+
+ if (ldo.precall(L, ra, L.stack[ra], nresults)) {
+ if (nresults >= 0)
+ L.top = ci.top;
+ base = ci.u.l.base;
+ } else {
+ ci = L.ci;
+ continue newframe;
}
- case "OP_RETURN": {
- if (cl.p.p.length > 0) this.closeupvals(base);
- let b = ldo.postcall(L, ci, ra, (i.B !== 0 ? i.B - 1 : L.top - ra));
- if (ci.callstatus & lstate.CIST_FRESH)
- return; /* external invocation: return */
-
+ break;
+ }
+ case "OP_TAILCALL": {
+ if (i.B !== 0) L.top = ra + i.B;
+ if (ldo.precall(L, ra, L.stack[ra], LUA_MULTRET)) { // JS function
+ base = ci.u.l.base;
+ } else {
+ /* tail call: put called frame (n) in place of caller one (o) */
+ let nci = L.ci;
+ let oci = nci.previous;
+ let nfunc = nci.func;
+ let nfuncOff = nci.funcOff;
+ let ofunc = oci.func;
+ let ofuncOff = oci.funcOff;
+ let lim = nci.u.l.base + nfunc.p.numparams;
+ if (cl.p.p.length > 0) lfunc.luaF_close(L, oci.u.l.base);
+ for (let aux = 0; nfuncOff + aux < lim; aux++)
+ L.stack[ofuncOff + aux] = L.stack[nfuncOff + aux];
+ oci.func = nci.func;
+ oci.u.l.base = ofuncOff + (nci.u.l.base - nfuncOff);
+ L.top = ofuncOff + (L.top - nfuncOff);
+ oci.top = L.top;
+ oci.u.l.savedpc = nci.u.l.savedpc;
+ oci.pcOff = nci.pcOff;
+ oci.callstatus |= lstate.CIST_TAIL;
+ L.ci = oci;
ci = L.ci;
- if (b) L.top = ci.top;
+ L.ciOff--;
+
+ assert(L.top === oci.u.l.base + L.stack[ofuncOff].p.maxstacksize);
continue newframe;
- break;
}
- case "OP_FORLOOP": {
- if (L.stack[ra].ttisinteger()) { /* integer loop? */
- let step = L.stack[ra + 2].value;
- let idx = L.stack[ra].value + step;
- let limit = L.stack[ra + 1].value;
-
- if (0 < step ? idx <= limit : limit <= idx) {
- ci.pcOff += i.sBx;
- L.stack[ra].value = idx;
- L.stack[ra + 3] = new TValue(CT.LUA_TNUMINT, idx); // TODO: if tvalue already there, just update it
- }
- } else { /* floating loop */
- let step = L.stack[ra + 2].value;
- let idx = L.stack[ra].value + step;
- let limit = L.stack[ra + 1].value;
-
- // TODO: luai_numlt, luai_numle
- if (0 < step ? idx <= limit : limit <= idx) {
- ci.pcOff += i.sBx;
- L.stack[ra].value = idx;
- L.stack[ra + 3] = new TValue(CT.LUA_TNUMFLT, idx); // TODO: if tvalue already there, just update it
- }
- }
- break;
- }
- case "OP_FORPREP": {
- let init = L.stack[ra];
- let plimit = L.stack[ra + 1];
- let pstep = L.stack[ra + 2];
- let forlimit = LuaVM.forlimit(plimit, pstep.value);
-
- if (init.ttisinteger() && pstep.ttisinteger() && forlimit.casted) { /* all values are integer */
- let initv = forlimit.stopnow ? 0 : init.value;
- plimit.value = forlimit.ilimit;
- init.value = initv - pstep.value;
- } else { /* try making all values floats */
- let ninit = LuaVM.tonumber(init);
- let nlimit = LuaVM.tonumber(plimit);
- let nstep = LuaVM.tonumber(pstep);
-
- if (nlimit === false)
- throw new Error("'for' limit must be a number");
-
- plimit.type = CT.LUA_TNUMFLT;
- plimit.value = nlimit.value;
-
- if (nstep === false)
- throw new Error("'for' step must be a number");
-
- pstep.type = CT.LUA_TNUMFLT;
- pstep.value = nstep.value;
-
- if (ninit === false)
- throw new Error("'for' initial value must be a number");
-
- init.type = CT.LUA_TNUMFLT;
- init.value = ninit.value - nstep.value;
+ break;
+ }
+ case "OP_RETURN": {
+ if (cl.p.p.length > 0) lfunc.luaF_close(L, base);
+ let b = ldo.postcall(L, ci, ra, (i.B !== 0 ? i.B - 1 : L.top - ra));
+
+ if (ci.callstatus & lstate.CIST_FRESH)
+ return; /* external invocation: return */
+
+ ci = L.ci;
+ if (b) L.top = ci.top;
+
+ continue newframe;
+ break;
+ }
+ case "OP_FORLOOP": {
+ if (L.stack[ra].ttisinteger()) { /* integer loop? */
+ let step = L.stack[ra + 2].value;
+ let idx = L.stack[ra].value + step;
+ let limit = L.stack[ra + 1].value;
+
+ if (0 < step ? idx <= limit : limit <= idx) {
+ ci.pcOff += i.sBx;
+ L.stack[ra].value = idx;
+ L.stack[ra + 3] = new TValue(CT.LUA_TNUMINT, idx); // TODO: if tvalue already there, just update it
}
-
- ci.pcOff += i.sBx;
- break;
- }
- case "OP_TFORCALL": {
- break;
- }
- case "OP_TFORLOOP": {
- if (!L.stack[ra + 1].ttisnil()) { /* continue loop? */
- L.stack[ra] = L.stack[ra + 1]; /* save control variable */
- ci.cpOff += i.sBx; /* jump back */
+ } else { /* floating loop */
+ let step = L.stack[ra + 2].value;
+ let idx = L.stack[ra].value + step;
+ let limit = L.stack[ra + 1].value;
+
+ // TODO: luai_numlt, luai_numle
+ if (0 < step ? idx <= limit : limit <= idx) {
+ ci.pcOff += i.sBx;
+ L.stack[ra].value = idx;
+ L.stack[ra + 3] = new TValue(CT.LUA_TNUMFLT, idx); // TODO: if tvalue already there, just update it
}
- break;
}
- case "OP_SETLIST": {
- let n = i.B;
- let c = i.C;
+ break;
+ }
+ case "OP_FORPREP": {
+ let init = L.stack[ra];
+ let plimit = L.stack[ra + 1];
+ let pstep = L.stack[ra + 2];
+ let forlim = forlimit(plimit, pstep.value);
- if (n === 0) n = L.top - ra - 1;
+ if (init.ttisinteger() && pstep.ttisinteger() && forlim.casted) { /* all values are integer */
+ let initv = forlim.stopnow ? 0 : init.value;
+ plimit.value = forlim.ilimit;
+ init.value = initv - pstep.value;
+ } else { /* try making all values floats */
+ let ninit = tonumber(init);
+ let nlimit = tonumber(plimit);
+ let nstep = tonumber(pstep);
- if (c === 0) {
- assert(OC.OpCodes[ci.u.l.savedpc[ci.pcOff].opcode] === "OP_EXTRAARG");
- c = ci.u.l.savedpc[ci.pcOff++].Ax;
- }
+ if (nlimit === false)
+ throw new Error("'for' limit must be a number");
- let table = L.stack[ra].value;
- let last = ((c - 1) * OC.LFIELDS_PER_FLUSH) + n;
+ plimit.type = CT.LUA_TNUMFLT;
+ plimit.value = nlimit.value;
- for (; n > 0; n--) {
- table.array[last--] = L.stack[ra + n];
- }
+ if (nstep === false)
+ throw new Error("'for' step must be a number");
- L.top = ci.top; /* correct top (in case of previous open call) */
- break;
- }
- case "OP_CLOSURE": {
- let p = cl.p.p[i.Bx];
- let nup = p.upvalues.length;
- let uv = p.upvalues;
- let ncl = new LClosure(nup);
- ncl.p = p;
-
- L.stack[ra] = ncl;
-
- for (let i = 0; i < nup; i++) {
- if (uv[i].instack)
- ncl.upvals[i] = this.findupval(base + uv[i].idx);
- else
- ncl.upvals[i] = cl.upvals[uv[i].idx];
- ncl.upvals[i].refcount++;
- }
- break;
- }
- case "OP_VARARG": {
- let b = i.B - 1;
- let n = base - ci.funcOff - cl.p.numparams - 1;
- let j;
-
- if (n < 0) /* less arguments than parameters? */
- n = 0; /* no vararg arguments */
-
- if (b < 0) {
- b = n; /* get all var. arguments */
- base = ci.u.l.base;
- ra = this.RA(base, i); /* previous call may change the stack */
+ pstep.type = CT.LUA_TNUMFLT;
+ pstep.value = nstep.value;
- L.top = ra + n;
- }
-
- for (j = 0; j < b && j < n; j++)
- L.stack[ra + j] = L.stack[base - n + j];
+ if (ninit === false)
+ throw new Error("'for' initial value must be a number");
- for (; j < b; j++) /* complete required results with nil */
- L.stack[ra + j] = ldo.nil;
- break;
+ init.type = CT.LUA_TNUMFLT;
+ init.value = ninit.value - nstep.value;
}
- case "OP_EXTRAARG": {
- break;
+
+ ci.pcOff += i.sBx;
+ break;
+ }
+ case "OP_TFORCALL": {
+ break;
+ }
+ case "OP_TFORLOOP": {
+ if (!L.stack[ra + 1].ttisnil()) { /* continue loop? */
+ L.stack[ra] = L.stack[ra + 1]; /* save control variable */
+ ci.cpOff += i.sBx; /* jump back */
}
+ break;
}
- }
- }
+ case "OP_SETLIST": {
+ let n = i.B;
+ let c = i.C;
+
+ if (n === 0) n = L.top - ra - 1;
- findupval(level) {
- let L = this.L;
- let pp = L.openupval;
-
- while(pp !== null && pp.v >= level) {
- let p = pp;
+ if (c === 0) {
+ assert(OC.OpCodes[ci.u.l.savedpc[ci.pcOff].opcode] === "OP_EXTRAARG");
+ c = ci.u.l.savedpc[ci.pcOff++].Ax;
+ }
- if (p.v === level)
- return p;
+ let table = L.stack[ra].value;
+ let last = ((c - 1) * OC.LFIELDS_PER_FLUSH) + n;
- pp = p.u.open.next;
- }
+ for (; n > 0; n--) {
+ table.array[last--] = L.stack[ra + n];
+ }
- let uv = new UpVal();
- uv.refcount = 0;
- uv.u.open.next = pp;
- uv.u.open.touched = true;
+ L.top = ci.top; /* correct top (in case of previous open call) */
+ break;
+ }
+ case "OP_CLOSURE": {
+ let p = cl.p.p[i.Bx];
+ let nup = p.upvalues.length;
+ let uv = p.upvalues;
+ let ncl = new LClosure(nup);
+ ncl.p = p;
+
+ L.stack[ra] = ncl;
+
+ for (let i = 0; i < nup; i++) {
+ if (uv[i].instack)
+ ncl.upvals[i] = lfunc.findupval(L, base + uv[i].idx);
+ else
+ ncl.upvals[i] = cl.upvals[uv[i].idx];
+ ncl.upvals[i].refcount++;
+ }
+ break;
+ }
+ case "OP_VARARG": {
+ let b = i.B - 1;
+ let n = base - ci.funcOff - cl.p.numparams - 1;
+ let j;
- pp = uv;
+ if (n < 0) /* less arguments than parameters? */
+ n = 0; /* no vararg arguments */
- uv.v = level;
+ if (b < 0) {
+ b = n; /* get all var. arguments */
+ base = ci.u.l.base;
+ ra = RA(L, base, i); /* previous call may change the stack */
- // Thread with upvalue list business ? lfunc.c:75
+ L.top = ra + n;
+ }
- return uv;
- }
+ for (j = 0; j < b && j < n; j++)
+ L.stack[ra + j] = L.stack[base - n + j];
- closeupvals(level) {
- let L = this.L;
- while (L.openupval !== null && L.openupval.v >= level) {
- let uv = L.openupval;
- assert(uv.isopen());
- L.openupval = uv.u.open.next; /* remove from 'open' list */
- if (uv.refcount > 0) {
- uv.value = L.stack[uv.v];
- uv.v = null;
+ for (; j < b; j++) /* complete required results with nil */
+ L.stack[ra + j] = ldo.nil;
+ break;
+ }
+ case "OP_EXTRAARG": {
+ break;
}
}
}
+}
- dojump(ci, i, e) {
- let a = i.A;
- if (a != 0) closeupvals(ci.u.l.base + a - 1);
- ci.pcOff += i.sBx + e;
- }
+const dojump = function(L, ci, i, e) {
+ let a = i.A;
+ if (a != 0) lfunc.luaF_close(L, ci.u.l.base + a - 1);
+ ci.pcOff += i.sBx + e;
+}
- donextjump(ci) {
- this.dojump(ci, ci.u.l.savedpc[ci.pcOff], 1);
- }
+const donextjump = function(L, ci) {
+ dojump(L, ci, ci.u.l.savedpc[ci.pcOff], 1);
+}
- static luaV_lessequal(l, r) {
- if (l.ttisnumber() && r.ttisnumber())
- return LuaVM.LEnum(l, r);
- else if (l.ttisstring() && r.ttisstring())
- return LuaVM.l_strcmp(l, r) <= 0;
- // TODO: metatable
- // else if (l.metatable.__le || r.metatable.__le) {
- // let res = l.metatable.__le ? l.metatable.__le(l, r) : r.metatable.__le(l, r);
- // if (res >= 0)
- // return res;
- // } else {
- // L.ci.callstatus |= lstate.CIST_LEQ;
- // let res = l.metatable.__lt ? l.metatable.__lt(r, l) : r.metatable.__lt(r, l);
- // L.ci.callstatus ^= lstate.CIST_LEQ;
- // if (res < 0)
- // throw new Error("attempt to compare ...");
- // return !res;
- // }
- }
+const luaV_lessequal = function(l, r) {
+ if (l.ttisnumber() && r.ttisnumber())
+ return LEnum(l, r);
+ else if (l.ttisstring() && r.ttisstring())
+ return l_strcmp(l, r) <= 0;
+ // TODO: metatable
+ // else if (l.metatable.__le || r.metatable.__le) {
+ // let res = l.metatable.__le ? l.metatable.__le(l, r) : r.metatable.__le(l, r);
+ // if (res >= 0)
+ // return res;
+ // } else {
+ // L.ci.callstatus |= lstate.CIST_LEQ;
+ // let res = l.metatable.__lt ? l.metatable.__lt(r, l) : r.metatable.__lt(r, l);
+ // L.ci.callstatus ^= lstate.CIST_LEQ;
+ // if (res < 0)
+ // throw new Error("attempt to compare ...");
+ // return !res;
+ // }
+}
- static luaV_lessthan(l, r) {
- if (l.ttisnumber() && r.ttisnumber())
- return LuaVM.LTnum(l, r);
- else if (l.ttisstring() && r.ttisstring())
- return LuaVM.l_strcmp(l, r) < 0;
- // TODO: metatable
- // else if (l.metatable.__lt || r.metatable.__lt) {
- // let res = l.metatable.__lt ? l.metatable.__lt(l, r) : r.metatable.__lt(l, r);
- // if (res < 0)
- // throw new Error("attempt to compare ...")
- // return res;
- // }
- }
+const luaV_lessthan = function(l, r) {
+ if (l.ttisnumber() && r.ttisnumber())
+ return LTnum(l, r);
+ else if (l.ttisstring() && r.ttisstring())
+ return l_strcmp(l, r) < 0;
+ // TODO: metatable
+ // else if (l.metatable.__lt || r.metatable.__lt) {
+ // let res = l.metatable.__lt ? l.metatable.__lt(l, r) : r.metatable.__lt(l, r);
+ // if (res < 0)
+ // throw new Error("attempt to compare ...")
+ // return res;
+ // }
+}
- static luaV_equalobj(t1, t2) {
- if (t1.ttype() !== t2.ttype()) { /* not the same variant? */
- if (t1.ttnov() !== t2.ttnov() || t1.ttnov() !== CT.LUA_NUMBER)
- return 0; /* only numbers can be equal with different variants */
- else { /* two numbers with different variants */
- /* compare them as integers */
- return Math.floor(t1.value) === Math.floor(t2.value) // TODO: tointeger
- }
+const luaV_equalobj = function(t1, t2) {
+ if (t1.ttype() !== t2.ttype()) { /* not the same variant? */
+ if (t1.ttnov() !== t2.ttnov() || t1.ttnov() !== CT.LUA_NUMBER)
+ return 0; /* only numbers can be equal with different variants */
+ else { /* two numbers with different variants */
+ /* compare them as integers */
+ return Math.floor(t1.value) === Math.floor(t2.value) // TODO: tointeger
}
+ }
- /* values have same type and same variant */
- switch(t1.ttype()) {
- case CT.LUA_TNIL:
- return 1;
- case CT.LUA_TNUMINT:
- case CT.LUA_TNUMFLT:
- case CT.LUA_TBOOLEAN:
- case CT.LUA_TLIGHTUSERDATA:
- case CT.LUA_TLCF:
- case CT.LUA_TSHRSTR:
- case CT.LUA_TLNGSTR:
- return t1.value === t2.value ? 1 : 0;
- case CT.LUA_TUSERDATA:
- case CT.LUA_TTABLE:
- if (t1 === t2) return 1;
- // TODO: __eq
- default:
- return t1.value === t2.value ? 1 : 0;
- }
+ /* values have same type and same variant */
+ switch(t1.ttype()) {
+ case CT.LUA_TNIL:
+ return 1;
+ case CT.LUA_TNUMINT:
+ case CT.LUA_TNUMFLT:
+ case CT.LUA_TBOOLEAN:
+ case CT.LUA_TLIGHTUSERDATA:
+ case CT.LUA_TLCF:
+ case CT.LUA_TSHRSTR:
+ case CT.LUA_TLNGSTR:
+ return t1.value === t2.value ? 1 : 0;
+ case CT.LUA_TUSERDATA:
+ case CT.LUA_TTABLE:
+ if (t1 === t2) return 1;
+ // TODO: __eq
+ default:
+ return t1.value === t2.value ? 1 : 0;
}
+}
- static forlimit(obj, step) {
- let stopnow = false;
- let ilimit = LuaVM.luaV_tointeger(obj, step < 0 ? 2 : 1);
- if (ilimit === false) {
- let n = LuaVM.tonumber(obj);
- if (n === false)
- return false;
-
- if (0 < n) {
- ilimit = llimit.LUA_MAXINTEGER;
- if (step < 0) stopnow = true;
- } else {
- ilimit = llimit.LUA_MININTEGER;
- if (step >= 0) stopnow = true;
- }
+const forlimit = function(obj, step) {
+ let stopnow = false;
+ let ilimit = luaV_tointeger(obj, step < 0 ? 2 : 1);
+ if (ilimit === false) {
+ let n = tonumber(obj);
+ if (n === false)
+ return false;
+
+ if (0 < n) {
+ ilimit = llimit.LUA_MAXINTEGER;
+ if (step < 0) stopnow = true;
+ } else {
+ ilimit = llimit.LUA_MININTEGER;
+ if (step >= 0) stopnow = true;
}
+ }
- return {
- casted: true,
- stopnow: stopnow,
- ilimit: ilimit
- }
+ return {
+ casted: true,
+ stopnow: stopnow,
+ ilimit: ilimit
}
+}
- /*
- ** try to convert a value to an integer, rounding according to 'mode':
- ** mode == 0: accepts only integral values
- ** mode == 1: takes the floor of the number
- ** mode == 2: takes the ceil of the number
- */
- static luaV_tointeger(obj, mode) {
- if (obj.ttisfloat()) {
- let n = obj.value;
- let f = n|0;
-
- if (n !== f) { /* not an integral value? */
- if (mode === 0)
- return false; /* fails if mode demands integral value */
- else if (mode > 1) /* needs ceil? */
- f += 1; /* convert floor to ceil (remember: n != f) */
- }
-
- return f|0;
- } else if (obj.ttisinteger()) {
- return obj.value|0;
- } else if (obj.ttisstring()) {
- return LuaVM.luaV_tointeger(parseFloat(obj.value), mode); // TODO: luaO_str2num
+/*
+** try to convert a value to an integer, rounding according to 'mode':
+** mode == 0: accepts only integral values
+** mode == 1: takes the floor of the number
+** mode == 2: takes the ceil of the number
+*/
+const luaV_tointeger = function(obj, mode) {
+ if (obj.ttisfloat()) {
+ let n = obj.value;
+ let f = n|0;
+
+ if (n !== f) { /* not an integral value? */
+ if (mode === 0)
+ return false; /* fails if mode demands integral value */
+ else if (mode > 1) /* needs ceil? */
+ f += 1; /* convert floor to ceil (remember: n != f) */
}
- return false;
+ return f|0;
+ } else if (obj.ttisinteger()) {
+ return obj.value|0;
+ } else if (obj.ttisstring()) {
+ return luaV_tointeger(parseFloat(obj.value), mode); // TODO: luaO_str2num
}
- static tonumber(v) {
- if (v.type === CT.LUA_TNUMFLT)
- return new TValue(v.type, v.value);
+ return false;
+}
- if (v.type === CT.LUA_TNUMINT)
- return new TValue(CT.LUA_TNUMFLT, v.value);
+const tonumber = function(v) {
+ if (v.type === CT.LUA_TNUMFLT)
+ return new TValue(v.type, v.value);
- if (v.type === CT.LUA_TSHRSTR || v.type === CT.LUA_TLNGSTR)
- return new TValue(CT.LUA_TNUMFLT, parseFloat(v.value)); // TODO: luaO_str2num
+ if (v.type === CT.LUA_TNUMINT)
+ return new TValue(CT.LUA_TNUMFLT, v.value);
- return false;
- }
+ if (v.type === CT.LUA_TSHRSTR || v.type === CT.LUA_TLNGSTR)
+ return new TValue(CT.LUA_TNUMFLT, parseFloat(v.value)); // TODO: luaO_str2num
- static LTnum(l, r) {
- if (l.ttisinteger()) {
- if (r.ttisinteger())
- return l.value < r.value ? 1 : 0;
- else
- return LuaVM.LTintfloat(r.value, l.value);
- } else {
- if (r.ttisfloat())
- return l.value < r.value ? 1 : 0;
- else if (isNan(l.value))
- return 0;
- else
- return !LuaVM.LEintfloat(r.value, l.value);
- }
- }
+ return false;
+}
- static LEnum(l, r) {
- if (l.ttisinteger()) {
- if (r.ttisinteger())
- return l.value <= r.value ? 1 : 0;
- else
- return LuaVM.LEintfloat(l.value, r.value);
- } else {
- if (r.ttisfloat())
- return l.value <= r.value ? 1 : 0;
- else if (isNan(l.value))
- return false;
- else
- return !LuaVM.LTintfloat(r.value, l.value);
- }
+const LTnum = function(l, r) {
+ if (l.ttisinteger()) {
+ if (r.ttisinteger())
+ return l.value < r.value ? 1 : 0;
+ else
+ return LTintfloat(r.value, l.value);
+ } else {
+ if (r.ttisfloat())
+ return l.value < r.value ? 1 : 0;
+ else if (isNan(l.value))
+ return 0;
+ else
+ return !LEintfloat(r.value, l.value);
}
+}
- static LEintfloat(l, r) {
- // TODO: LEintfloat
- return l <= r ? 1 : 0;
+const LEnum = function(l, r) {
+ if (l.ttisinteger()) {
+ if (r.ttisinteger())
+ return l.value <= r.value ? 1 : 0;
+ else
+ return LEintfloat(l.value, r.value);
+ } else {
+ if (r.ttisfloat())
+ return l.value <= r.value ? 1 : 0;
+ else if (isNan(l.value))
+ return false;
+ else
+ return !LTintfloat(r.value, l.value);
}
+}
- static LTintfloat(l, r) {
- // TODO: LTintfloat
- return l < r ? 1 : 0;
- }
+const LEintfloat = function(l, r) {
+ // TODO: LEintfloat
+ return l <= r ? 1 : 0;
+}
- static l_strcmp(ls, rs) {
- // TODO: lvm.c:248 static int l_strcmp (const TString *ls, const TString *rs)
- return ls.value === rs.value ? 0 : (ls.value < rs.value ? -1 : 1);
- }
+const LTintfloat = function(l, r) {
+ // TODO: LTintfloat
+ return l < r ? 1 : 0;
+}
- static l_isfalse(o) {
- return o.ttisnil() || (o.ttisboolean() && o.value === false)
- }
+const l_strcmp = function(ls, rs) {
+ // TODO: lvm.c:248 static int l_strcmp (const TString *ls, const TString *rs)
+ return ls.value === rs.value ? 0 : (ls.value < rs.value ? -1 : 1);
+}
+const l_isfalse = function(o) {
+ return o.ttisnil() || (o.ttisboolean() && o.value === false)
}
module.exports = {
- LuaVM: LuaVM
+ RA: RA,
+ RB: RB,
+ RC: RC,
+ RKB: RKB,
+ RKC: RKC,
+ luaV_execute: luaV_execute,
+ dojump: dojump,
+ donextjump: donextjump,
+ luaV_lessequal: luaV_lessequal,
+ luaV_lessthan: luaV_lessthan,
+ luaV_equalobj: luaV_equalobj,
+ forlimit: forlimit,
+ luaV_tointeger: luaV_tointeger,
+ tonumber: tonumber,
+ LTnum: LTnum,
+ LEnum: LEnum,
+ LEintfloat: LEintfloat,
+ LTintfloat: LTintfloat,
+ l_strcmp: l_strcmp,
+ l_isfalse: l_isfalse
}; \ No newline at end of file