diff options
-rw-r--r-- | src/lobject.js | 12 | ||||
-rw-r--r-- | src/ltable.js | 23 | ||||
-rw-r--r-- | tests/ltablib.js | 10 |
3 files changed, 37 insertions, 8 deletions
diff --git a/src/lobject.js b/src/lobject.js index e4ef380..f926e85 100644 --- a/src/lobject.js +++ b/src/lobject.js @@ -13,6 +13,8 @@ const llimit = require('./llimit.js'); const CT = defs.constant_types; const char = defs.char; +const LUA_TPROTO = CT.LUA_NUMTAGS; +const LUA_TDEADKEY = CT.LUA_NUMTAGS+1; class TValue { @@ -108,7 +110,7 @@ class TValue { } ttisdeadkey() { - return this.checktag(CT.LUA_TDEADKEY); + return this.checktag(LUA_TDEADKEY); } l_isfalse() { @@ -150,6 +152,11 @@ class TValue { this.value = x; } + setdeadvalue() { + this.type = LUA_TDEADKEY; + this.value = null; + } + setfrom(tv) { /* in lua C source setobj2t is often used for this */ this.type = tv.type; this.value = tv.value; @@ -175,6 +182,7 @@ class TValue { } const luaO_nilobject = new TValue(CT.LUA_TNIL, null); +Object.freeze(luaO_nilobject); module.exports.luaO_nilobject = luaO_nilobject; class LClosure { @@ -539,6 +547,8 @@ const numarith = function(L, op, v1, v2) { } }; +module.exports.LUA_TPROTO = LUA_TPROTO; +module.exports.LUA_TDEADKEY = LUA_TDEADKEY; module.exports.CClosure = CClosure; module.exports.LClosure = LClosure; module.exports.LocVar = LocVar; diff --git a/src/ltable.js b/src/ltable.js index ce3ba77..0619efe 100644 --- a/src/ltable.js +++ b/src/ltable.js @@ -34,10 +34,17 @@ class Table { constructor(L) { this.id = L.l_G.id_counter++; this.strong = new Map(); + this.dead_hashes = []; this.metatable = null; } } +const clean_dead_keys = function(t) { + for (let i=0; i<t.dead_hashes.length; i++) { + t.strong.delete(t.dead_hashes[i]); + } +}; + const luaH_new = function(L) { return new Table(L); }; @@ -69,6 +76,7 @@ const setgeneric = function(t, hash, key) { if (v) return v.value; + clean_dead_keys(t); let tv = new lobject.TValue(CT.LUA_TNIL, null); t.strong.set(hash, { key: key, @@ -81,7 +89,7 @@ const luaH_setint = function(t, key, value) { assert(typeof key == "number" && (key|0) === key && value instanceof lobject.TValue); let hash = key; /* table_hash known result */ if (value.ttisnil()) { - t.strong.delete(hash); + delete_hash(t, hash); return; } let v = t.strong.get(hash); @@ -89,6 +97,7 @@ const luaH_setint = function(t, key, value) { let tv = v.value; tv.setfrom(value); } else { + clean_dead_keys(t); t.strong.set(hash, { key: new lobject.TValue(CT.LUA_TNUMINT, key), value: new lobject.TValue(value.type, value.value) @@ -102,10 +111,20 @@ const luaH_set = function(t, key) { return setgeneric(t, hash, new lobject.TValue(key.type, key.value)); }; +/* Can't remove from table immediately due to next() */ +const delete_hash = function(t, hash) { + let e = t.strong.get(hash); + if (e) { + e.key.setdeadvalue(); + e.value = new lobject.TValue(CT.LUA_TNIL, null); + t.dead_hashes.push(hash); + } +}; + const luaH_delete = function(t, key) { assert(key instanceof lobject.TValue); let hash = table_hash(key); - t.strong.delete(hash); + return delete_hash(t, hash); }; /* diff --git a/tests/ltablib.js b/tests/ltablib.js index e209db3..43e742b 100644 --- a/tests/ltablib.js +++ b/tests/ltablib.js @@ -14,7 +14,7 @@ const inttable2array = function(t) { let a = []; t.strong.forEach(function (v, k) { - if (typeof k === 'number') + if (v.key.ttisnumber()) a[k - 1] = v.value; }); @@ -73,7 +73,7 @@ test('table.pack', function (t) { t.deepEqual( [...lua.lua_topointer(L, -1).strong.entries()] - .filter(e => typeof e[0] === 'number') // Filter out the 'n' field + .filter(e => e[1].key.ttisnumber()) // Filter out the 'n' field .map(e => e[1].value.value).reverse(), [1, 2, 3], "Correct element(s) on the stack" @@ -148,7 +148,7 @@ test('table.insert', function (t) { t.deepEqual( [...lua.lua_topointer(L, -1).strong.entries()] - .filter(e => typeof e[0] === 'number') + .filter(e => e[1].key.ttisnumber()) .map(e => e[1].value.value).sort(), [1, 2, 3, 4, 5], "Correct element(s) on the stack" @@ -182,7 +182,7 @@ test('table.remove', function (t) { t.deepEqual( [...lua.lua_topointer(L, -1).strong.entries()] - .filter(e => typeof e[0] === 'number') + .filter(e => e[1].key.ttisnumber()) .map(e => e[1].value.value).sort(), [1, 2, 3, 4], "Correct element(s) on the stack" @@ -215,7 +215,7 @@ test('table.move', function (t) { t.deepEqual( [...lua.lua_topointer(L, -1).strong.entries()] - .filter(e => typeof e[0] === 'number') + .filter(e => e[1].key.ttisnumber()) .map(e => e[1].value.value).sort(), [1, 2, 3, 4, 5, 6], "Correct element(s) on the stack" |