From b618b835c74a8637e00ba1f4adf6b8884d360d43 Mon Sep 17 00:00:00 2001 From: Benoit Giannangeli Date: Fri, 3 Feb 2017 15:59:29 +0100 Subject: Table, metatable --- luac.out | Bin 241 -> 190 bytes src/lobject.js | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- src/lvm.js | 2 ++ tests/lvm.js | 23 +++++++++++++++++++++ 4 files changed, 88 insertions(+), 1 deletion(-) diff --git a/luac.out b/luac.out index 85aec6d..0b992bf 100644 Binary files a/luac.out and b/luac.out differ diff --git a/src/lobject.js b/src/lobject.js index 7efbef5..876a16f 100644 --- a/src/lobject.js +++ b/src/lobject.js @@ -18,11 +18,73 @@ class TValue { constructor(type, value) { this.type = type; this.value = value; + this.metatable = null; } } + +class TString extends TValue { + + constructor(string) { + super(CT.LUA_TSTRING, string); + } + +} + + +class Table extends TValue { + + constructor(array, hash) { + super(CT.LUA_TTABLE, { + array: array !== undefined ? array : [], + hash: new Map(hash) + }); + + this.usermetatable = null; + + this.metatable = { + __newindex: function (table, key) { + if (key instanceof TValue) { + // Those lua values are used by value, tables and functions by reference + if ([CT.TNUMBER, CT.TSTRING, CT.TSHRSTR, CT.TLNGSTR, CT.TNUMFLT, CT.TNUMINT].indexOf(key.type) > -1) { + key = key.value; + } + } + + if (typeof key === 'number') { + table.value.array[key] = value; + } else { + table.value.hash.set(key, value); + } + }, + + __index: function (table, key, value) { + if (key instanceof TValue) { + // Those lua values are used by value, tables and functions by reference + if ([CT.TNUMBER, CT.TSTRING, CT.TSHRSTR, CT.TLNGSTR, CT.TNUMFLT, CT.TNUMINT].indexOf(key.type) > -1) { + key = key.value; + } + } + + if (typeof key === 'number') { + return table.value.array[key]; + } else { + return table.value.hash.get(key); + } + }, + + __len: function (table) { + return t.value.array.length; + } + }; + } + +} + + module.exports = { LClosure: LClosure, - TValue: TValue + TValue: TValue, + Table: Table }; \ No newline at end of file diff --git a/src/lvm.js b/src/lvm.js index 3d6f43a..9518721 100644 --- a/src/lvm.js +++ b/src/lvm.js @@ -5,6 +5,7 @@ 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; class LuaVM { @@ -104,6 +105,7 @@ class LuaVM { break; } case "OP_NEWTABLE": { + L.stack[ra] = new Table(); break; } case "OP_SELF": { diff --git a/tests/lvm.js b/tests/lvm.js index 6a4ed9f..1dbff2e 100644 --- a/tests/lvm.js +++ b/tests/lvm.js @@ -10,6 +10,7 @@ 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 Table = require("../src/lobject.js").Table; const toByteCode = function (luaCode) { var luaFile = tmp.fileSync(), @@ -134,4 +135,26 @@ test('Unary op, LOADBOOL', function (t) { [-5, true, -6], "Program output is correct" ); +}); + + +test('NEWTABLE', function (t) { + let luaCode = ` + local a = {} + 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.ok( + vm.L.stack[0] instanceof Table, + "Program output is correct" + ); }); \ No newline at end of file -- cgit v1.2.3-54-g00ecf