aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--luac.outbin190 -> 334 bytes
-rw-r--r--src/lfunc.js17
-rw-r--r--src/lobject.js23
-rw-r--r--src/lstate.js11
-rw-r--r--src/lvm.js128
-rw-r--r--tests/lvm.js22
6 files changed, 178 insertions, 23 deletions
diff --git a/luac.out b/luac.out
index 0b992bf..f693654 100644
--- a/luac.out
+++ b/luac.out
Binary files differ
diff --git a/src/lfunc.js b/src/lfunc.js
index faa0887..929dae8 100644
--- a/src/lfunc.js
+++ b/src/lfunc.js
@@ -21,7 +21,22 @@ class Proto {
}
+class UpVal {
+
+ constructor() {
+ this.v = null;
+ this.u = {
+ open: {
+ next: null,
+ touched: false
+ },
+ value: null
+ };
+ }
+
+}
module.exports = {
- Proto: Proto
+ Proto: Proto,
+ UpVal: UpVal
}; \ No newline at end of file
diff --git a/src/lobject.js b/src/lobject.js
index 876a16f..4cc8c4e 100644
--- a/src/lobject.js
+++ b/src/lobject.js
@@ -3,15 +3,6 @@
const CT = require('./lua.js').constant_types;
-class LClosure {
-
- constructor(n) {
- this.p = null;
- this.nupvalues = n;
- }
-
-}
-
class TValue {
@@ -24,6 +15,20 @@ class TValue {
}
+class LClosure extends TValue {
+
+ constructor(n) {
+ super(CT.LUA_TLCL, null);
+
+ this.p = null;
+ this.nupvalues = n;
+ this.upvals = [];
+
+ this.value = this;
+ }
+
+}
+
class TString extends TValue {
constructor(string) {
diff --git a/src/lstate.js b/src/lstate.js
index 15dedcb..f9dbf8e 100644
--- a/src/lstate.js
+++ b/src/lstate.js
@@ -10,8 +10,13 @@ class CallInfo {
this.base = base;
this.previous = previous;
this.next = next;
- this.savedpc = [];
this.pcOff = 0;
+ this.u = {
+ l: {
+ base: null,
+ savedpc: []
+ }
+ };
}
}
@@ -21,9 +26,9 @@ class lua_State {
constructor(cl) {
this.top = 1;
this.ci = [
- new CallInfo(0, 1, 1, null, null)
+ new CallInfo(cl, 1, 1, null, null)
];
- this.ci[0].savedpc = cl.p.code;
+ this.ci[0].u.l.savedpc = cl.p.code;
this.ciOff = 0;
this.stack = [
cl
diff --git a/src/lvm.js b/src/lvm.js
index 9518721..963d545 100644
--- a/src/lvm.js
+++ b/src/lvm.js
@@ -1,11 +1,16 @@
-/*jshint esversion: 6 */
+ /*jshint esversion: 6 */
"use strict";
const BytecodeParser = require("./lundump.js");
const OC = require('./lopcodes.js');
const CT = require('./lua.js').constant_types;
-const TValue = require('./lobject.js').TValue;
-const Table = require('./lobject.js').Table;
+const lobject = require('./lobject.js');
+const TValue = lobject.TValue;
+const Table = lobject.Table;
+const LClosure = lobject.LClosure;
+const lfunc = require('./lfunc.js');
+const UpVal = lfunc.UpVal;
+const CallInfo = require('./lstate.js').CallInfo;
class LuaVM {
@@ -52,11 +57,11 @@ class LuaVM {
newframe:
for (;;) {
- var cl = L.stack[ci.func];
+ var cl = ci.func;
let k = cl.p.k;
let base = ci.base;
- let i = ci.savedpc[ci.pcOff++];
+ let i = ci.u.l.savedpc[ci.pcOff++];
let ra = this.RA(base, i);
switch (OC.OpCodes[i.opcode]) {
@@ -69,8 +74,8 @@ class LuaVM {
break;
}
case "OP_LOADKX": {
- assert(OC.OpCodes[ci.savedpc[ci.pcOff].opcode] === "OP_EXTRAARG");
- L.stack[ra] = k[ci.savedpc[ci.pcOff++].Ax];
+ 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": {
@@ -92,15 +97,15 @@ class LuaVM {
case "OP_GETTABUP": {
break;
}
- case "OP_GETTABLE": {
- break;
- }
case "OP_SETTABUP": {
break;
}
case "OP_SETUPVAL": {
break;
}
+ case "OP_GETTABLE": {
+ break;
+ }
case "OP_SETTABLE": {
break;
}
@@ -345,6 +350,16 @@ class LuaVM {
break;
}
case "OP_CALL": {
+ let b = i.B;
+ let nresults = i.C - 1;
+
+ if (b !== 0)
+ L.top = ra+b;
+
+ this.precall(ra, L.stack[ra], nresults);
+ ci = L.ci;
+ continue newframe;
+
break;
}
case "OP_TAILCALL": {
@@ -383,6 +398,20 @@ class LuaVM {
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++) { // TODO test
+ if (uv[i].instack)
+ ncl.upvals[i] = this.findupval(base + uv[i].idx);
+ else
+ ncl.upvals[i] = cl.upvals[uv[i].idx];
+ }
break;
}
case "OP_VARARG": {
@@ -395,6 +424,85 @@ class LuaVM {
}
}
+ precall(off, func, nresults) {
+ let L = this.L;
+ let ci;
+
+ switch(func.type) {
+ case CT.LUA_TCCL: // JS function ?
+ throw new Error("LUA_TCCL not implemeted yet")
+ break;
+ case CT.LUA_TLCF: // still JS function ?
+ throw new Error("LUA_TLCF not implemeted yet")
+ break;
+ case CT.LUA_TLCL: {
+ let p = func.p;
+ let n = L.top - off - 1;
+ let fsize = p.maxstacksize;
+ let base;
+
+ if (p.is_vararg) {
+ // base = adjust_varargs(L, p, n);
+ } else {
+ for (; n < p.numparams; n++)
+ L.stack[L.top++] = new TValue(CT.LUA_TNIL, null);
+ base = off + 1;
+ }
+
+ // next_ci
+ if (L.ci.next) {
+ L.ci = L.ci.next;
+ } else {
+ ci = new CallInfo();
+ L.ci.next = ci;
+ ci.previous = L.ci;
+ ci.next = null;
+
+ L.ci = ci;
+ }
+ ci.nresults = nresults;
+ ci.func = func;
+ ci.u.l.base = base;
+ ci.top = base + fsize;
+ L.top = ci.top;
+ ci.u.l.savedpc = p.code;
+ break;
+ }
+ default:
+ // __call
+ }
+ }
+
+ postcall(ci, firstResult, nres) {
+
+ }
+
+ findupval(level) { // TODO test
+ 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;
+ }
+
}
module.exports = {
diff --git a/tests/lvm.js b/tests/lvm.js
index 1dbff2e..1b4d8c3 100644
--- a/tests/lvm.js
+++ b/tests/lvm.js
@@ -157,4 +157,26 @@ test('NEWTABLE', function (t) {
vm.L.stack[0] instanceof Table,
"Program output is correct"
);
+});
+
+
+test('CALL', function (t) {
+ let luaCode = `
+ local f = function (a, b)
+ return a + b
+ end
+
+ local c = f(1, 2)
+
+ return c
+ `, vm;
+
+ t.plan(0);
+
+ t.comment("Running following code: \n" + luaCode);
+
+ // t.doesNotThrow(function () {
+ vm = getVM(luaCode);
+ vm.execute();
+ // }, "Program executed without errors");
}); \ No newline at end of file