From fc911817a8401d0696407e91501f0ef65f05b711 Mon Sep 17 00:00:00 2001 From: Benoit Giannangeli Date: Wed, 22 Feb 2017 17:32:28 +0100 Subject: use luaL_argerror/error instead of throwing --- src/lauxlib.js | 19 ++++++++----------- src/lbaselib.js | 12 ++++++++++++ src/lobject.js | 11 ++++++----- src/ltable.js | 15 ++++++++++----- tests/lbaselib.js | 47 ++++++++++++++++++++++++++++++++++++++++++++--- 5 files changed, 80 insertions(+), 24 deletions(-) diff --git a/src/lauxlib.js b/src/lauxlib.js index 4e32437..29b223f 100644 --- a/src/lauxlib.js +++ b/src/lauxlib.js @@ -95,11 +95,8 @@ const typeerror = function(L, arg, tname) { else typearg = luaL_typename(L, arg); - throw new Error(`${tname} expected, got ${typearg}`); - - // TODO: - // let msg = lua_pushstring(L, `${tname} expected, got ${typearg}`); - // return luaL_argerror(L, arg, msg); + let msg = lua_pushstring(L, `${tname} expected, got ${typearg}`); + return luaL_argerror(L, arg, msg); }; const luaL_where = function(L, level) { @@ -141,12 +138,12 @@ const luaL_typename = function(L, i) { }; const luaL_argcheck = function(L, cond, arg, extramsg) { - if (!cond) throw new Error(extramsg); // TODO: luaL_argerror + if (!cond) luaL_argerror(L, arg, extramsg); }; const luaL_checkany = function(L, arg) { if (lapi.lua_type(L, arg) === CT.LUA_TNONE) - throw new Error("value expected"); // TODO: luaL_argerror(L, arg, "value expected"); + luaL_argerror(L, arg, "value expected"); }; const luaL_checktype = function(L, arg, t) { @@ -170,7 +167,7 @@ const luaL_optstring = luaL_optlstring; const interror = function(L, arg) { if (lapi.lua_isnumber(L, arg)) - throw new Error("number has no integer representation"); + luaL_argerror(L, arg, "number has no integer representation"); else tag_error(L, arg, CT.LUA_TNUMBER); }; @@ -216,7 +213,7 @@ const luaL_callmeta = function(L, obj, event) { const luaL_tolstring = function(L, idx) { if (luaL_callmeta(L, idx, "__tostring")) { if (!lapi.lua_isstring(L, -1)) - throw new Error("'__tostring' must return a string"); // TODO: luaL_error + luaL_error(L, "'__tostring' must return a string"); } else { switch(lapi.lua_type(L, idx)) { case CT.LUA_TNUMBER: @@ -307,9 +304,9 @@ const luaL_setfuncs = function(L, l, nup) { const luaL_checkstack = function(L, space, msg) { if (!lapi.lua_checkstack(L, space)) { if (msg) - throw new Error(L, `stack overflow (${msg})`); + luaL_error(L, `stack overflow (${msg})`); else - throw new Error(L, 'stack overflow'); // TODO: luaL_error + luaL_error(L, 'stack overflow'); } }; diff --git a/src/lbaselib.js b/src/lbaselib.js index 2eacaaf..f405a7d 100644 --- a/src/lbaselib.js +++ b/src/lbaselib.js @@ -110,6 +110,17 @@ const pairsmeta = function(L, method, iszero, iter) { return 3; }; +const luaB_next = function(L) { + lauxlib.luaL_checktype(L, 1, CT.LUA_TTABLE); + lapi.lua_settop(L, 2); /* create a 2nd argument if there isn't one */ + if (lapi.lua_next(L, 1)) + return 2; + else { + lapi.lua_pushnil(L); + return 1; + } +}; + /* ** Traversal function for 'ipairs' */ @@ -244,6 +255,7 @@ const base_funcs = { "tostring": luaB_tostring, "tonumber": luaB_tonumber, "getmetatable": luaB_getmetatable, + "next": luaB_next, "ipairs": luaB_ipairs, "select": luaB_select, "setmetatable": luaB_setmetatable, diff --git a/src/lobject.js b/src/lobject.js index 2ba45ad..4e4b701 100644 --- a/src/lobject.js +++ b/src/lobject.js @@ -121,7 +121,8 @@ class Table extends TValue { static keyValue(key) { // Those lua values are used by value, others by reference if (key instanceof TValue - && [CT.LUA_TSTRING, + && [CT.LUA_TNIL, + CT.LUA_TSTRING, CT.LUA_TSHRSTR, CT.LUA_TLNGSTR, CT.LUA_TNUMINT].indexOf(key.type) > -1) { @@ -135,9 +136,9 @@ class Table extends TValue { key = Table.keyValue(key); if (typeof key === 'number' && key > 0) { - table.value.hash.set(key - 1, value); // Lua array starts at 1 + table.value.set(key - 1, value); // Lua array starts at 1 } else { - table.value.hash.set(key, value); + table.value.set(key, value); } } @@ -146,9 +147,9 @@ class Table extends TValue { let v = nil; if (typeof key === 'number' && key > 0) { - v = table.value.hash.get(key - 1); // Lua array starts at 1 + v = table.value.get(key - 1); // Lua array starts at 1 } else { - v = table.value.hash.get(key); + v = table.value.get(key); } return v ? v : nil; diff --git a/src/ltable.js b/src/ltable.js index 14139af..7611b4c 100644 --- a/src/ltable.js +++ b/src/ltable.js @@ -8,6 +8,7 @@ const lua = require('./lua.js'); const CT = lua.constant_types; const nil = require('./ldo.js').nil; const Table = lobject.Table; +const TValue = lobject.TValue; Table.prototype.ordered_intindexes = function() { @@ -37,9 +38,9 @@ Table.prototype.luaH_getn = function() { 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]; + if (!this.__index(this, key).ttisnil() // t[i] is non-nil + && (i === len - 1 || this.__index(this, indexes[i + 1]).ttisnil())) { // t[i+1] is nil or is the last integer indexed element + return indexes[i] + 1; } } @@ -50,9 +51,13 @@ Table.prototype.luaH_next = function(L, keyI) { let keyO = L.stack[keyI]; let key = Table.keyValue(keyO); let indexes = this.ordered_indexes(); + + if (indexes.length === 0) return 0; + let i = indexes.indexOf(key); - if (i >= 0 && i < indexes.length - 1) { + if ((i >= 0 || key === null) && i < indexes.length - 1) { + if (key === null) i = -1; let nidx = indexes[i+1]; let tnidx = typeof nidx; @@ -63,7 +68,7 @@ Table.prototype.luaH_next = function(L, keyI) { else L.stack[keyI] = indexes[i + 1]; - L.stack[keyI + 1] = this.map.get(indexes[i]); + L.stack[keyI + 1] = this.value.get(indexes[i + 1]); return 1; } diff --git a/tests/lbaselib.js b/tests/lbaselib.js index d71e3ab..d2f0e0e 100644 --- a/tests/lbaselib.js +++ b/tests/lbaselib.js @@ -426,19 +426,19 @@ test('select', function (t) { }, "JS Lua program ran without error"); t.deepEqual( - lapi.lua_topointer(L, -3).map(e => e.value), + [...lapi.lua_topointer(L, -3).entries()].map(e => e[1].value), [3], "Correct element(s) on the stack" ); t.deepEqual( - lapi.lua_topointer(L, -2).map(e => e.value), + [...lapi.lua_topointer(L, -2).entries()].map(e => e[1].value).sort(), [2, 3], "Correct element(s) on the stack" ); t.deepEqual( - lapi.lua_topointer(L, -1).map(e => e.value), + [...lapi.lua_topointer(L, -1).entries()].map(e => e[1].value).sort(), [2, 3], "Correct element(s) on the stack" ); @@ -552,4 +552,45 @@ test('rawlen', function (t) { 5, "Correct element(s) on the stack" ); +}); + + +test('next', function (t) { + let luaCode = ` + local total = 0 + local t = { + 1, + two = 2, + 3, + four = 4 + } + + for k,v in next, t, nil do + total = total + v + end + + return total + `, L; + + t.plan(2); + + t.doesNotThrow(function () { + + let bc = toByteCode(luaCode).dataView; + + L = lauxlib.luaL_newstate(); + + linit.luaL_openlibs(L); + + lapi.lua_load(L, bc, "test-next"); + + lapi.lua_call(L, 0, -1); + + }, "JS Lua program ran without error"); + + t.strictEqual( + lapi.lua_tonumber(L, -1), + 10, + "Correct element(s) on the stack" + ); }); \ No newline at end of file -- cgit v1.2.3-70-g09d2