diff options
-rw-r--r-- | luac.out | bin | 0 -> 203 bytes | |||
-rw-r--r-- | sandbox/helloworld.lua | 1 | ||||
-rw-r--r-- | src/lstate.js | 11 | ||||
-rw-r--r-- | src/lvm.js | 27 | ||||
-rw-r--r-- | tests/lvm.js | 66 |
5 files changed, 96 insertions, 9 deletions
diff --git a/luac.out b/luac.out Binary files differnew file mode 100644 index 0000000..1c971ab --- /dev/null +++ b/luac.out diff --git a/sandbox/helloworld.lua b/sandbox/helloworld.lua new file mode 100644 index 0000000..7785fb9 --- /dev/null +++ b/sandbox/helloworld.lua @@ -0,0 +1 @@ +local a = "hello world" diff --git a/src/lstate.js b/src/lstate.js index 9c7eec3..15dedcb 100644 --- a/src/lstate.js +++ b/src/lstate.js @@ -21,14 +21,19 @@ class lua_State { constructor(cl) { this.top = 1; this.ci = [ - new CallInfo(0, 1, 1, null, null); + new CallInfo(0, 1, 1, null, null) ]; this.ci[0].savedpc = cl.p.code; this.ciOff = 0; this.stack = [ - closure + cl ]; this.openupval = []; } -}
\ No newline at end of file +} + +module.exports = { + lua_State: lua_State, + CallInfo: CallInfo +};
\ No newline at end of file @@ -14,7 +14,7 @@ class LuaVM { return base + a; } - RB(base, opcode, base, b) { + RB(base, opcode, b) { return base + b; } @@ -35,18 +35,21 @@ class LuaVM { let ci = L.ci[this.L.ciOff]; newframe: - let cl = ci.func; - let k = cl.p.k; - let base = ci.base; - for (;;) { + var cl = L.stack[ci.func]; + let k = cl.p.k; + let base = ci.base; + let i = ci.savedpc[ci.pcOff++]; - let ra = this.RA(base, i.a); + let ra = this.RA(base, i.A); + console.log(OC.OpCodes[i.opcode]); switch (OC.OpCodes[i.opcode]) { case "OP_MOVE": + L.stack[ra] = RB(base, i.opcode, i.B); break; case "OP_LOADK": + L.stack[ra] = k[i.Bx]; break; case "OP_LOADKX": break; @@ -121,6 +124,18 @@ class LuaVM { case "OP_TAILCALL": break; case "OP_RETURN": + if (i.B >= 2) { + for (let j = 0; j <= i.B-2; j++) { + L.stack[L.ciOff + j] = L.stack[ra + j]; + } + } + L.ci = ci.previous; + + if (L.ci === null) return; + + if (i.B !== 0) L.top = ci.top; + + continue newframe; break; case "OP_FORLOOP": break; diff --git a/tests/lvm.js b/tests/lvm.js new file mode 100644 index 0000000..6ee348d --- /dev/null +++ b/tests/lvm.js @@ -0,0 +1,66 @@ +"use strict"; + +const test = require('tape'); +const fs = require('fs'); +const child_process = require('child_process'); +const beautify = require('js-beautify').js_beautify; +const tmp = require('tmp'); +const DataView = require('buffer-dataview'); + +const BytecodeParser = require("../src/lundump.js"); +const lua_State = require("../src/lstate.js").lua_State; +const LuaVM = require("../src/lvm.js").LuaVM; + +const toByteCode = function (luaCode) { + var luaFile = tmp.fileSync(), + bclist; + + fs.writeSync(luaFile.fd, luaCode); + + child_process.execSync(`luac-5.3 -o ${luaFile.name}.bc ${luaFile.name}`); + child_process.execSync(`luac-5.3 -l ${luaFile.name} > ${luaFile.name}.bc.txt`); + + bclist = fs.readFileSync(`${luaFile.name}.bc.txt`, 'utf8'); + + console.log(bclist); + + return { + dataView: new DataView(fs.readFileSync(`${luaFile.name}.bc`)), + bclist: bclist + }; +}; + +const getVM = function (luaCode) { + var bc = toByteCode(luaCode), + dv = bc.dataView, + bcl = bc.bclist; + + let p = new BytecodeParser(dv); + let cl = p.luaU_undump(); + + let L = new lua_State(cl); + + return new LuaVM(L); +}; + +test('LOADK, RETURN', function (t) { + let luaCode = ` + local a = "hello world" + return a + `, vm; + + t.plan(2); + + t.comment("Running following code: \n" + luaCode); + + t.doesNotThrow(function () { + vm = getVM(luaCode); + vm.execute(); + }, "Program executed without errors"); + + t.strictEqual( + vm.L.stack[0].value, + "hello world", + "Program output is correct" + ); +});
\ No newline at end of file |