From 9bf2332e3cff054002b2bb94ce045b637298a7db Mon Sep 17 00:00:00 2001 From: Benoit Giannangeli Date: Sun, 12 Feb 2017 17:47:03 +0100 Subject: LEN --- src/lobject.js | 135 +++++++++++++++++++++++++++++++++++---------------------- src/lvm.js | 42 +++++++++++++++++- 2 files changed, 123 insertions(+), 54 deletions(-) (limited to 'src') diff --git a/src/lobject.js b/src/lobject.js index 713a734..7b39668 100644 --- a/src/lobject.js +++ b/src/lobject.js @@ -106,6 +106,86 @@ class TValue { 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) + }); + + this.metatable = null; + } + + 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_TSHRSTR, + CT.LUA_TLNGSTR, + CT.LUA_TNUMFLT, + CT.LUA_TNUMINT].indexOf(key.type) > -1) { + key = key.value; + } + + return key; + } + + __newindex(table, key, value) { + key = Table.keyValue(key); + + if (typeof key === 'number' && key > 0) { + table.value.array[key - 1] = value; // Lua array starts at 1 + } else { + table.value.hash.set(key, value); + } + } + + __index(table, key) { + key = Table.keyValue(key); + + let v = nil; + if (typeof key === 'number' && key > 0) { + v = table.value.array[key - 1]; // Lua array starts at 1 + } else { + v = table.value.hash.get(key); + } + + return v ? v : nil; + } + + __len(table) { + return this.luaH_getn(); + } + + /* + ** 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). + */ + luaH_getn() { + 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; + } + return i; + } + /* else must find a boundary in hash part */ + else if (hash.size === 0) + return j; + else return j; // TODO: unbound_search(t, j) => but why ? + } + +} + class LClosure extends TValue { constructor(n) { @@ -150,59 +230,10 @@ class Userdata extends TValue { } -class Table extends TValue { - - constructor(array, hash) { - super(CT.LUA_TTABLE, { - array: array !== undefined ? array : [], - hash: new Map(hash) - }); - - this.metatable = null; - } - - __newindex(table, key, value) { - if (key instanceof TValue) { - // Those lua values are used by value, tables and functions by reference - if ([CT.LUA_TNUMBER, CT.LUA_TSTRING, CT.LUA_TSHRSTR, CT.LUA_TLNGSTR, CT.LUA_TNUMFLT, CT.LUA_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(table, key) { - if (key instanceof TValue) { - // Those lua values are used by value, tables and functions by reference - if ([CT.LUA_TNUMBER, CT.LUA_TSTRING, CT.LUA_TSHRSTR, CT.LUA_TLNGSTR, CT.LUA_TNUMFLT, CT.LUA_TNUMINT].indexOf(key.type) > -1) { - key = key.value; - } - } - - let v = nil; - if (typeof key === 'number') { - v = table.value.array[key]; - } else { - v = table.value.hash.get(key); - } - - return v ? v : nil; - } - - __len(table) { - return t.value.array.length; - } - -} - - module.exports = { LClosure: LClosure, TValue: TValue, - Table: Table + Table: Table, + TString: TString, + Userdata: Userdata }; \ No newline at end of file diff --git a/src/lvm.js b/src/lvm.js index c2cef1b..17a9033 100644 --- a/src/lvm.js +++ b/src/lvm.js @@ -376,6 +376,8 @@ const luaV_execute = function(L) { break; } case "OP_LEN": { + luaV_objlen(L, ra, L.stack[RB(L, base, i)]); + base = ci.u.l.base; break; } case "OP_CONCAT": { @@ -585,11 +587,11 @@ const luaV_execute = function(L) { c = ci.u.l.savedpc[ci.pcOff++].Ax; } - let table = L.stack[ra].value; + let table = L.stack[ra]; let last = ((c - 1) * OC.LFIELDS_PER_FLUSH) + n; for (; n > 0; n--) { - table.array[last--] = L.stack[ra + n]; + table.__newindex(table, last--, L.stack[ra + n]); } L.top = ci.top; /* correct top (in case of previous open call) */ @@ -849,6 +851,41 @@ const l_isfalse = function(o) { return o.ttisnil() || (o.ttisboolean() && o.value === false) }; +/* +** Main operation 'ra' = #rb'. +*/ +const luaV_objlen = function(L, ra, rb) { + let tm; + switch(rb.ttype()) { + case CT.LUA_TTABLE: { + tm = rb.value.metatable; + if (tm) break; + L.stack[ra] = rb.luaH_getn(); + return; + } + case CT.LUA_TSHRSTR: + case CT.LUA_TLNGSTR: + L.stack[ra] = rb.value.length; // TODO: 8-byte clean string + return; + default: { + tm = ltm.luaT_gettmbyobj(L, rb, TMS.TM_LEN); + if (tm.ttisnil()) + throw new Error("attempt to get length"); // TODO: luaG_typeerror + break; + } + } + + ltm.luaT_callTM(L, tm, rb, rb, ra, 1); +}; + +/* +** Main operation for concatenation: concat 'total' values in the stack, +** from 'L->top - total' up to 'L->top - 1'. +*/ +const luaV_concat = function(L, total) { + assert(total >= 2); +} + /* ** Check appropriate error for stack overflow ("regular" overflow or ** overflow while handling stack overflow). If 'nCalls' is larger than @@ -907,6 +944,7 @@ module.exports = { LTintfloat: LTintfloat, l_strcmp: l_strcmp, l_isfalse: l_isfalse, + luaV_objlen: luaV_objlen, stackerror: stackerror, luaD_call: luaD_call, luaD_callnoyield: luaD_callnoyield, -- cgit v1.2.3-70-g09d2