From 238009cd056acc3277b38eb6520c1afee019bb26 Mon Sep 17 00:00:00 2001 From: Benoit Giannangeli Date: Tue, 14 Feb 2017 12:56:44 +0100 Subject: __newindex --- src/ltm.js | 3 ++ src/lvm.js | 2 +- tests/ltm.js | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 95 insertions(+), 1 deletion(-) diff --git a/src/ltm.js b/src/ltm.js index fc0d0ec..c712160 100644 --- a/src/ltm.js +++ b/src/ltm.js @@ -1,6 +1,8 @@ /*jshint esversion: 6 */ "use strict"; +const assert = require('assert'); + const lobject = require('./lobject.js'); const TValue = lobject.TValue; const Table = lobject.Table; @@ -56,6 +58,7 @@ const luaT_callTM = function(L, f, p1, p2, p3, hasres) { ldo.luaD_callnoyield(L, func, hasres); if (hasres) { + assert(typeof result === "number"); L.stack[result] = L.stack[--L.top]; } }; diff --git a/src/lvm.js b/src/lvm.js index b0b5d53..cd9548e 100644 --- a/src/lvm.js +++ b/src/lvm.js @@ -1006,7 +1006,7 @@ const luaV_finishset = function(L, t, key, val, slot, recur) { } if (tm.ttisfunction()) { - ltm.luaT_callTM(L, tm, t, key, val, 1); + ltm.luaT_callTM(L, tm, t, key, val, 0); return; } diff --git a/tests/ltm.js b/tests/ltm.js index 5644ae8..e7085cd 100644 --- a/tests/ltm.js +++ b/tests/ltm.js @@ -164,4 +164,95 @@ test('__index function in metatable', function (t) { "__index", "Program output is correct" ); +}); + + +test('__newindex function in metatable', function (t) { + let luaCode = ` + local mt = { + __newindex = function (table, key, value) + return "__newindex" + end + } + + local t = {} + + -- setmetatable(t, mt) + + t.yo = "hello" + + return t.yo + `, L; + + t.plan(8); + + t.comment("Running following code: \n" + luaCode); + + t.doesNotThrow(function () { + L = getState(luaCode); + }, "Bytecode parsed without errors"); + + + // main (8 instructions at 0x7faadcf00ac0) + // 0+ params, 3 slots, 1 upvalue, 2 locals, 3 constants, 1 function + // 1 [1] NEWTABLE 0 0 1 + // 2 [4] CLOSURE 1 0 ; 0x7faadcf00d10 + // 3 [4] SETTABLE 0 -1 1 ; "__newindex" - + // 4 [7] NEWTABLE 1 0 0 + // 5 [11] SETTABLE 1 -2 -3 ; "yo" "hello" <=== We stop here + // 6 [13] GETTABLE 2 1 -2 ; "yo" + // 7 [13] RETURN 2 2 + // 8 [13] RETURN 0 1 + // + // function (3 instructions at 0x7faadcf00d10) + // 3 params, 4 slots, 0 upvalues, 3 locals, 1 constant, 0 functions + // 1 [3] LOADK 3 -1 ; "__newindex" + // 2 [3] RETURN 3 2 + // 3 [4] RETURN 0 1 + + t.strictEqual( + OC.OpCodes[L.stack[0].p.code[4].opcode], + "OP_SETTABLE", + "Correct opcode marked as breakpoint" + ); + + t.comment("We set a breakpoint just before 'return t.yo'") + L.stack[0].p.code[4].breakpoint = true; // Stop just before 'return t.yo' + + t.doesNotThrow(function () { + VM.luaV_execute(L); + }, "First part of the program executed without errors"); + + t.strictEqual( + OC.OpCodes[L.ci.u.l.savedpc[L.ci.pcOff - 1].opcode], + "OP_SETTABLE", + "Stopped at correct opcode" + ); + + t.comment("We unset the breakpoint and correct pcOff"); + L.ci.pcOff--; + L.stack[0].p.code[4].breakpoint = false; + + t.ok( + L.stack[2].ttistable() && !L.stack[2].value.hash.get("__newindex"), + "t is on stack at 2" + ); + + t.ok( + L.stack[1].ttistable() && L.stack[1].value.hash.get("__newindex"), + "mt is on stack at 1" + ); + + t.comment("We manually set t's metatable to mt"); + L.stack[2].metatable = L.stack[1]; + + t.doesNotThrow(function () { + VM.luaV_execute(L); + }, "Second part of the program executed without errors"); + + t.strictEqual( + L.stack[L.top - 1].value, + null, + "Program output is correct" + ); }); \ No newline at end of file -- cgit v1.2.3-70-g09d2