From 4b764aa6a84289f04acde43108425c392d2e4806 Mon Sep 17 00:00:00 2001 From: Benoit Giannangeli Date: Wed, 22 Feb 2017 17:24:42 +0100 Subject: Tables are JS Maps, lua_next --- src/lapi.js | 23 +++++++++++++------- src/lobject.js | 13 ++++------- src/lstate.js | 4 ++-- src/ltable.js | 69 +++++++++++++++++++++++++++++++++++++++++++--------------- 4 files changed, 72 insertions(+), 37 deletions(-) (limited to 'src') diff --git a/src/lapi.js b/src/lapi.js index 625608b..e9f15c2 100644 --- a/src/lapi.js +++ b/src/lapi.js @@ -293,7 +293,7 @@ const auxsetstr = function(L, t, k) { }; const lua_setglobal = function(L, name) { - auxsetstr(L, L.l_G.l_registry.value.array[lua.LUA_RIDX_GLOBALS - 1], name); + auxsetstr(L, L.l_G.l_registry.value.get(lua.LUA_RIDX_GLOBALS - 1), name); }; const lua_setmetatable = function(L, objindex) { @@ -390,9 +390,6 @@ const lua_createtable = function(L, narray, nrec) { L.stack[L.top++] = t; assert(L.top <= L.ci.top, "stack overflow"); - - if (narray > 0) - t.value.array = new Array(narray); }; const lua_newtable = function(L) { @@ -447,7 +444,7 @@ const lua_geti = function(L, idx, n) { }; const lua_getglobal = function(L, name) { - return auxgetstr(L, L.l_G.l_registry.value.array[lua.LUA_RIDX_GLOBALS - 1], name); + return auxgetstr(L, L.l_G.l_registry.value.get(lua.LUA_RIDX_GLOBALS - 1), name); }; /* @@ -558,7 +555,7 @@ const lua_load = function(L, data, chunckname) { if (f.nupvalues >= 1) { /* does it have an upvalue? */ /* get global table from registry */ let reg = L.l_G.l_registry; - let gt = reg.value.array[lua.LUA_RIDX_GLOBALS - 1]; + let gt = reg.value.get(lua.LUA_RIDX_GLOBALS - 1); /* set global table as 1st upvalue of 'f' (may be LUA_ENV) */ f.upvals[0].u.value = gt; } @@ -654,7 +651,16 @@ const lua_error = function(L) { }; const lua_next = function(L, idx) { - + let t = index2addr(L, idx); + assert(t.ttistable(), "table expected"); + let more = t.luaH_next(L, L.top - 1); + if (more) { + L.top++; + assert(L.top <= L.ci.top, "stack overflow"); + } else + L.top--; + + return more; }; const lua_concat = function(L, n) { @@ -740,4 +746,5 @@ module.exports.lua_gc = lua_gc; module.exports.lua_getallocf = lua_getallocf; module.exports.lua_getextraspace = lua_getextraspace; module.exports.lua_stringtonumber = lua_stringtonumber; -module.exports.lua_copy = lua_copy; \ No newline at end of file +module.exports.lua_copy = lua_copy; +module.exports.lua_next = lua_next; \ No newline at end of file diff --git a/src/lobject.js b/src/lobject.js index 0a0b615..2ba45ad 100644 --- a/src/lobject.js +++ b/src/lobject.js @@ -113,10 +113,7 @@ const nil = new TValue(CT.LUA_TNIL, null); class Table extends TValue { constructor(array, hash) { - super(CT.LUA_TTABLE, { - array: array !== undefined ? array : [], - hash: new Map(hash) - }); + super(CT.LUA_TTABLE, new Map(hash)); this.metatable = null; } @@ -124,11 +121,9 @@ class Table extends TValue { static keyValue(key) { // Those lua values are used by value, others by reference if (key instanceof TValue - && [CT.LUA_TNUMBER, - CT.LUA_TSTRING, + && [CT.LUA_TSTRING, CT.LUA_TSHRSTR, CT.LUA_TLNGSTR, - CT.LUA_TNUMFLT, CT.LUA_TNUMINT].indexOf(key.type) > -1) { key = key.value; } @@ -140,7 +135,7 @@ class Table extends TValue { key = Table.keyValue(key); if (typeof key === 'number' && key > 0) { - table.value.array[key - 1] = value; // Lua array starts at 1 + table.value.hash.set(key - 1, value); // Lua array starts at 1 } else { table.value.hash.set(key, value); } @@ -151,7 +146,7 @@ class Table extends TValue { let v = nil; if (typeof key === 'number' && key > 0) { - v = table.value.array[key - 1]; // Lua array starts at 1 + v = table.value.hash.get(key - 1); // Lua array starts at 1 } else { v = table.value.hash.get(key); } diff --git a/src/lstate.js b/src/lstate.js index 30e4b15..eec9fae 100644 --- a/src/lstate.js +++ b/src/lstate.js @@ -96,8 +96,8 @@ const stack_init = function(L1, L) { const init_registry = function(L, g) { let registry = new Table(); g.l_registry = registry; - registry.value.array[lua.LUA_RIDX_MAINTHREAD - 1] = L; - registry.value.array[lua.LUA_RIDX_GLOBALS - 1] = new Table(); + registry.value.set(lua.LUA_RIDX_MAINTHREAD - 1, L); + registry.value.set(lua.LUA_RIDX_GLOBALS - 1, new Table()); }; /* diff --git a/src/ltable.js b/src/ltable.js index c1d5430..14139af 100644 --- a/src/ltable.js +++ b/src/ltable.js @@ -4,35 +4,68 @@ const assert = require('assert'); const lobject = require('./lobject.js'); +const lua = require('./lua.js'); +const CT = lua.constant_types; const nil = require('./ldo.js').nil; const Table = lobject.Table; +Table.prototype.ordered_intindexes = function() { + return [...this.value.keys()] + .filter(e => typeof e === 'number' && e % 1 === 0) // Only integer indexes + .sort(); +}; + +Table.prototype.ordered_indexes = function() { + return [...this.value.keys()] + .sort(function(a, b) { + if (typeof a !== "number") return 1; + if (typeof b !== "number") return -1; + return a > b ? 1 : -1 + }) +}; + /* ** Try to find a boundary in table 't'. A 'boundary' is an integer index ** such that t[i] is non-nil and t[i+1] is nil (and 0 if t[1] is nil). */ Table.prototype.luaH_getn = function() { - let array = this.value.array; - let hash = this.value.hash; - - let j = array.length; - if (j > 0 && array[j - 1].ttisnil()) { - /* there is a boundary in the array part: (binary) search for it */ - let i = 0; - while (j - i > 1) { - let m = (i+j)/2; - if (array[m - 1].ttisnil()) j = m; - else i = m; + // TODO: is this costly ? + let indexes = this.ordered_intindexes(); + let len = indexes.length; + + for (let i = 0; i < len; i++) { + let key = indexes[i]; + + if (!this.value.get(key).ttisnil() // t[i] is non-nil + && (i === len - 1 || this.value.get(indexes[i + 1]).ttisinil())) { // t[i+1] is nil or is the last integer indexed element + return indexes[i]; } - return i; } - /* else must find a boundary in hash part */ - else if (hash.size === 0) - return j; - else return hash.get(j); + + return 0; }; -Table.prototype.luaH_next = function(key) { - +Table.prototype.luaH_next = function(L, keyI) { + let keyO = L.stack[keyI]; + let key = Table.keyValue(keyO); + let indexes = this.ordered_indexes(); + let i = indexes.indexOf(key); + + if (i >= 0 && i < indexes.length - 1) { + let nidx = indexes[i+1]; + let tnidx = typeof nidx; + + if (tnidx === 'number' && nidx % 1 === 0) + L.stack[keyI] = new TValue(CT.LUA_TNUMINT, indexes[i + 1]); + else if (tnidx === 'string') + L.stack[keyI] = new TValue(CT.LUA_TLNGSTR, indexes[i + 1]); + else + L.stack[keyI] = indexes[i + 1]; + + L.stack[keyI + 1] = this.map.get(indexes[i]); + return 1; + } + + return 0; }; \ No newline at end of file -- cgit v1.2.3-54-g00ecf