aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBenoit Giannangeli <giann008@gmail.com>2017-02-12 17:47:03 +0100
committerBenoit Giannangeli <benoit.giannangeli@boursorama.fr>2017-02-13 08:36:01 +0100
commit9bf2332e3cff054002b2bb94ce045b637298a7db (patch)
treef2801608c6f369b3e318f7b89c1f8db59ae3d95a /src
parent4bf190d1b51c8c2d3f5ab0b6355ecd971b735adc (diff)
downloadfengari-9bf2332e3cff054002b2bb94ce045b637298a7db.tar.gz
fengari-9bf2332e3cff054002b2bb94ce045b637298a7db.tar.bz2
fengari-9bf2332e3cff054002b2bb94ce045b637298a7db.zip
LEN
Diffstat (limited to 'src')
-rw-r--r--src/lobject.js135
-rw-r--r--src/lvm.js42
2 files changed, 123 insertions, 54 deletions
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) */
@@ -850,6 +852,41 @@ const l_isfalse = function(o) {
};
/*
+** 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
** LUAI_MAXCCALLS (which means it is handling a "regular" overflow) but
@@ -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,