diff options
-rw-r--r-- | luac.out | bin | 334 -> 334 bytes | |||
-rw-r--r-- | src/lstate.js | 9 | ||||
-rw-r--r-- | src/lvm.js | 113 | ||||
-rw-r--r-- | tests/lvm.js | 23 |
4 files changed, 76 insertions, 69 deletions
Binary files differ diff --git a/src/lstate.js b/src/lstate.js index f9dbf8e..bf49b42 100644 --- a/src/lstate.js +++ b/src/lstate.js @@ -7,13 +7,12 @@ class CallInfo { constructor(func, top, base, previous, next) { this.func = func; this.top = top; - this.base = base; this.previous = previous; this.next = next; this.pcOff = 0; this.u = { l: { - base: null, + base: base, savedpc: [] } }; @@ -25,10 +24,8 @@ class lua_State { constructor(cl) { this.top = 1; - this.ci = [ - new CallInfo(cl, 1, 1, null, null) - ]; - this.ci[0].u.l.savedpc = cl.p.code; + this.ci = new CallInfo(cl, 1, 1, null, null); + this.ci.u.l.savedpc = cl.p.code; this.ciOff = 0; this.stack = [ cl @@ -1,4 +1,4 @@ - /*jshint esversion: 6 */ +/*jshint esversion: 6 */ "use strict"; const BytecodeParser = require("./lundump.js"); @@ -31,11 +31,11 @@ class LuaVM { } RKB(base, k, i) { - return OC.ISK(b) ? k[OC.INDEXK(b)] : base + i.B; + return OC.ISK(i.B) ? k[OC.INDEXK(i.B)] : this.L.stack[base + i.B]; } RKC(base, k, i) { - return OC.ISK(c) ? k[OC.INDEXK(c)] : base + i.C; + return OC.ISK(i.C) ? k[OC.INDEXK(i.C)] : this.L.stack[base + i.C]; } static tonumber(v) { @@ -53,13 +53,13 @@ class LuaVM { execute() { let L = this.L; - let ci = L.ci[this.L.ciOff]; newframe: for (;;) { + let ci = L.ci; var cl = ci.func; let k = cl.p.k; - let base = ci.base; + let base = ci.u.l.base let i = ci.u.l.savedpc[ci.pcOff++]; let ra = this.RA(base, i); @@ -117,47 +117,47 @@ class LuaVM { break; } case "OP_ADD": { - let op1 = k[i.B]; - let op2 = k[i.C]; + 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.type === CT.LUA_TNUMINT && op2.type === CT.LUA_TNUMINT) { - L.stack[ra] = new TValue(CT.LUA_TNUMINT, k[i.B].value + k[i.C].value); + L.stack[ra] = new TValue(CT.LUA_TNUMINT, op1.value + op2.value); } else if (numberop1 !== false && numberop2 !== false) { - L.stack[ra] = new TValue(CT.LUA_TNUMFLT, k[i.B].value + k[i.C].value); + L.stack[ra] = new TValue(CT.LUA_TNUMFLT, op1.value + op2.value); } else { // Metamethod - throw new Error(`Can't perform binary operation on ${k[i.B].value} and ${k[i.C].value}`); + throw new Error(`Can't perform binary operation on ${op1.value} and ${op2.value}`); } break; } case "OP_SUB": { - let op1 = k[i.B]; - let op2 = k[i.C]; + 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.type === CT.LUA_TNUMINT && op2.type === CT.LUA_TNUMINT) { - L.stack[ra] = new TValue(CT.LUA_TNUMINT, k[i.B].value - k[i.C].value); + L.stack[ra] = new TValue(CT.LUA_TNUMINT, op1.value - op2.value); } else if (numberop1 !== false && numberop2 !== false) { - L.stack[ra] = new TValue(CT.LUA_TNUMFLT, k[i.B].value - k[i.C].value); + L.stack[ra] = new TValue(CT.LUA_TNUMFLT, op1.value - op2.value); } else { // Metamethod - throw new Error(`Can't perform binary operation on ${k[i.B].value} and ${k[i.C].value}`); + throw new Error(`Can't perform binary operation on ${op1.value} and ${k[i.C].value}`); } break; } case "OP_MUL": { - let op1 = k[i.B]; - let op2 = k[i.C]; + 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.type === CT.LUA_TNUMINT && op2.type === CT.LUA_TNUMINT) { - L.stack[ra] = new TValue(CT.LUA_TNUMINT, k[i.B].value * k[i.C].value); + L.stack[ra] = new TValue(CT.LUA_TNUMINT, op1.value * op2.value); } else if (numberop1 !== false && numberop2 !== false) { - L.stack[ra] = new TValue(CT.LUA_TNUMFLT, k[i.B].value * k[i.C].value); + 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}`); @@ -165,15 +165,15 @@ class LuaVM { break; } case "OP_MOD": { - let op1 = k[i.B]; - let op2 = k[i.C]; + 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.type === CT.LUA_TNUMINT && op2.type === CT.LUA_TNUMINT) { - L.stack[ra] = new TValue(CT.LUA_TNUMINT, k[i.B].value % k[i.C].value); + L.stack[ra] = new TValue(CT.LUA_TNUMINT, op1.value % op2.value); } else if (numberop1 !== false && numberop2 !== false) { - L.stack[ra] = new TValue(CT.LUA_TNUMFLT, k[i.B].value % k[i.C].value); + 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}`); @@ -181,13 +181,13 @@ class LuaVM { break; } case "OP_POW": { - let op1 = k[i.B]; - let op2 = k[i.C]; + 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(k[i.B].value, k[i.C].value)); + 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}`); @@ -195,13 +195,13 @@ class LuaVM { break; } case "OP_DIV": { - let op1 = k[i.B]; - let op2 = k[i.C]; + 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 / k[i.C].value); + 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}`); @@ -209,15 +209,15 @@ class LuaVM { break; } case "OP_IDIV": { - let op1 = k[i.B]; - let op2 = k[i.C]; + 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.type === CT.LUA_TNUMINT && op2.type === CT.LUA_TNUMINT) { - L.stack[ra] = new TValue(CT.LUA_TNUMINT, Math.floor(k[i.B].value / k[i.C].value)); + L.stack[ra] = new TValue(CT.LUA_TNUMINT, Math.floor(op1.value / op2.value)); } else if (numberop1 !== false && numberop2 !== false) { - L.stack[ra] = new TValue(CT.LUA_TNUMFLT, Math.floor(k[i.B].value / k[i.C].value)); + L.stack[ra] = new TValue(CT.LUA_TNUMFLT, Math.floor(op1.value / op2.value)); } else { // Metamethod throw new Error(`Can't perform binary operation on ${k[i.B].value} and ${k[i.C].value}`); @@ -225,13 +225,13 @@ class LuaVM { break; } case "OP_BAND": { - let op1 = k[i.B]; - let op2 = k[i.C]; + 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.type === CT.LUA_TNUMINT && op2.type === CT.LUA_TNUMINT) { - L.stack[ra] = new TValue(CT.LUA_TNUMINT, k[i.B].value & k[i.C].value); + L.stack[ra] = new TValue(CT.LUA_TNUMINT, op1.value & op2.value); } else { // Metamethod throw new Error(`Can't perform binary operation on ${k[i.B].value} and ${k[i.C].value}`); @@ -239,13 +239,13 @@ class LuaVM { break; } case "OP_BOR": { - let op1 = k[i.B]; - let op2 = k[i.C]; + 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.type === CT.LUA_TNUMINT && op2.type === CT.LUA_TNUMINT) { - L.stack[ra] = new TValue(CT.LUA_TNUMINT, k[i.B].value | k[i.C].value); + L.stack[ra] = new TValue(CT.LUA_TNUMINT, op1.value | op2.value); } else { // Metamethod throw new Error(`Can't perform binary operation on ${k[i.B].value} and ${k[i.C].value}`); @@ -253,13 +253,13 @@ class LuaVM { break; } case "OP_BXOR": { - let op1 = k[i.B]; - let op2 = k[i.C]; + 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.type === CT.LUA_TNUMINT && op2.type === CT.LUA_TNUMINT) { - L.stack[ra] = new TValue(CT.LUA_TNUMINT, k[i.B].value ^ k[i.C].value); + L.stack[ra] = new TValue(CT.LUA_TNUMINT, op1.value ^ op2.value); } else { // Metamethod throw new Error(`Can't perform binary operation on ${k[i.B].value} and ${k[i.C].value}`); @@ -267,13 +267,13 @@ class LuaVM { break; } case "OP_SHL": { - let op1 = k[i.B]; - let op2 = k[i.C]; + 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.type === CT.LUA_TNUMINT && op2.type === CT.LUA_TNUMINT) { - L.stack[ra] = new TValue(CT.LUA_TNUMINT, k[i.B].value << k[i.C].value); + L.stack[ra] = new TValue(CT.LUA_TNUMINT, op1.value << op2.value); } else { // Metamethod throw new Error(`Can't perform binary operation on ${k[i.B].value} and ${k[i.C].value}`); @@ -281,13 +281,13 @@ class LuaVM { break; } case "OP_SHR": { - let op1 = k[i.B]; - let op2 = k[i.C]; + 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.type === CT.LUA_TNUMINT && op2.type === CT.LUA_TNUMINT) { - L.stack[ra] = new TValue(CT.LUA_TNUMINT, k[i.B].value >> k[i.C].value); + L.stack[ra] = new TValue(CT.LUA_TNUMINT, op1.value >> op2.value); } else { // Metamethod throw new Error(`Can't perform binary operation on ${k[i.B].value} and ${k[i.C].value}`); @@ -299,12 +299,12 @@ class LuaVM { let numberop = LuaVM.tonumber(op); if (op.type === CT.LUA_TNUMINT) { - L.stack[ra] = new TValue(CT.LUA_TNUMINT, -L.stack[this.RB(base, i)].value); + L.stack[ra] = new TValue(CT.LUA_TNUMINT, -op.value); } else if (numberop !== false) { - L.stack[ra] = new TValue(CT.LUA_TNUMFLT, -L.stack[this.RB(base, i)].value); + L.stack[ra] = new TValue(CT.LUA_TNUMFLT, -op.value); } else { // Metamethod - throw new Error(`Can't perform unary operation on ${k[i.B].value} and ${k[i.C].value}`); + throw new Error(`Can't perform unary operation on ${op.value}`); } break; } @@ -313,10 +313,10 @@ class LuaVM { let numberop = LuaVM.tonumber(op); if (op.type === CT.LUA_TNUMINT) { - L.stack[ra] = new TValue(CT.LUA_TNUMINT, ~L.stack[this.RB(base, i)].value); + L.stack[ra] = new TValue(CT.LUA_TNUMINT, ~op.value); } else { // Metamethod - throw new Error(`Can't perform unary operation on ${k[i.B].value} and ${k[i.C].value}`); + throw new Error(`Can't perform unary operation on ${op.value}`); } break; } @@ -367,14 +367,16 @@ class LuaVM { } case "OP_RETURN": { if (i.B >= 2) { + // TODO moveresults, ldo.c:334 for (let j = 0; j <= i.B-2; j++) { L.stack[L.ciOff + j] = L.stack[ra + j]; + L.top++; } } + L.ciOff--; L.ci = ci.previous; // TODO what to return when end of program ? - console.log(L.stack); if (L.ci === null) return; if (i.B !== 0) L.top = ci.top; @@ -445,7 +447,7 @@ class LuaVM { // base = adjust_varargs(L, p, n); } else { for (; n < p.numparams; n++) - L.stack[L.top++] = new TValue(CT.LUA_TNIL, null); + L.stack[L.top++] = new TValue(CT.LUA_TNIL, null); // complete missing arguments base = off + 1; } @@ -459,6 +461,7 @@ class LuaVM { ci.next = null; L.ci = ci; + L.ciOff++; } ci.nresults = nresults; ci.func = func; diff --git a/tests/lvm.js b/tests/lvm.js index 1b4d8c3..54c40ae 100644 --- a/tests/lvm.js +++ b/tests/lvm.js @@ -1,3 +1,4 @@ +/*jshint esversion: 6 */ "use strict"; const test = require('tape'); @@ -60,7 +61,7 @@ test('LOADK, RETURN', function (t) { }, "Program executed without errors"); t.strictEqual( - vm.L.stack[0].value, + vm.L.stack[vm.L.top - 1].value, "hello world", "Program output is correct" ); @@ -84,7 +85,7 @@ test('MOV', function (t) { }, "Program executed without errors"); t.strictEqual( - vm.L.stack[0].value, + vm.L.stack[vm.L.top - 1].value, "hello world", "Program output is correct" ); @@ -107,7 +108,7 @@ test('Binary op', function (t) { }, "Program executed without errors"); t.deepEqual( - vm.L.stack.slice(0, 12).map(function (e) { return e.value; }), + vm.L.stack.slice(vm.L.top - 12 - 1, vm.L.top - 1).map(function (e) { return e.value; }), [15, -5, 50, 0.5, 5, 9765625.0, 0, 0, 15, 15, 5120, 0], "Program output is correct" ); @@ -131,7 +132,7 @@ test('Unary op, LOADBOOL', function (t) { }, "Program executed without errors"); t.deepEqual( - vm.L.stack.slice(0, 3).map(function (e) { return e.value; }), + vm.L.stack.slice(vm.L.top - 3 - 1, vm.L.top - 1).map(function (e) { return e.value; }), [-5, true, -6], "Program output is correct" ); @@ -154,7 +155,7 @@ test('NEWTABLE', function (t) { }, "Program executed without errors"); t.ok( - vm.L.stack[0] instanceof Table, + vm.L.stack[vm.L.top - 1] instanceof Table, "Program output is correct" ); }); @@ -171,12 +172,18 @@ test('CALL', function (t) { return c `, vm; - t.plan(0); + t.plan(2); t.comment("Running following code: \n" + luaCode); - // t.doesNotThrow(function () { + t.doesNotThrow(function () { vm = getVM(luaCode); vm.execute(); - // }, "Program executed without errors"); + }, "Program executed without errors"); + + t.strictEqual( + vm.L.stack[vm.L.top - 1].value, + 3, + "Program output is correct" + ); });
\ No newline at end of file |