From dbe2a3bf2ef8c053e6c596c99e29eb27b6118f1b Mon Sep 17 00:00:00 2001 From: Benoit Giannangeli Date: Wed, 22 Feb 2017 08:23:37 +0100 Subject: ipairs --- README.md | 8 ++++---- src/lapi.js | 15 +++++++++++++++ src/lbaselib.js | 39 +++++++++++++++++++++++++++++++++++++++ tests/lbaselib.js | 36 ++++++++++++++++++++++++++++++++++++ 4 files changed, 94 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index e145ed7..f9111f6 100644 --- a/README.md +++ b/README.md @@ -212,16 +212,16 @@ - [x] pcall - [x] xpcall - [x] collectgarbage (unavailable) + - [x] ipairs - [ ] assert - - [ ] dofile - - [ ] ipairs - - [ ] loadfile - - [ ] load - [ ] next - [ ] pairs - [ ] rawlen - [ ] select - [ ] tonumber + - [ ] dofile + - [ ] loadfile + - [ ] load - [ ] ... - [ ] Debug (errors) - [ ] DOM API binding diff --git a/src/lapi.js b/src/lapi.js index c091150..e149619 100644 --- a/src/lapi.js +++ b/src/lapi.js @@ -426,6 +426,20 @@ const lua_getfield = function(L, idx, k) { return auxgetstr(L, index2addr(L, idx), k); }; +const lua_geti = function(L, idx, n) { + let t = index2addr(L, idx); + let slot = t.__index(t, n); + if (!slot.ttisnil()) { + L.stack[L.top++] = slot; + assert(L.top <= L.ci.top, "stack overflow"); + } else { + L.stack[L.top++] = new TValue(CT.LUA_TNUMINT, n); + assert(L.top <= L.ci.top, "stack overflow"); + lvm.gettable(L, t, L.stack[L.top - 1], L.top - 1); + } + return L.stack[L.top - 1].ttnov(); +}; + const lua_getglobal = function(L, name) { return auxgetstr(L, L.l_G.l_registry.value.array[lua.LUA_RIDX_GLOBALS - 1], name); }; @@ -651,6 +665,7 @@ module.exports.lua_createtable = lua_createtable; module.exports.lua_newtable = lua_newtable; module.exports.lua_settable = lua_settable; module.exports.lua_gettable = lua_gettable; +module.exports.lua_geti = lua_geti; module.exports.lua_absindex = lua_absindex; module.exports.index2addr = index2addr; module.exports.lua_rawget = lua_rawget; diff --git a/src/lbaselib.js b/src/lbaselib.js index b3dcd12..d0e094f 100644 --- a/src/lbaselib.js +++ b/src/lbaselib.js @@ -89,6 +89,44 @@ const luaB_type = function(L) { return 1; }; +const pairsmeta = function(L, method, iszero, iter) { + lauxlib.luaL_checkany(L, 1); + if (lauxlib.luaL_getmetafield(L, 1, method).ttisnil()) { /* no metamethod? */ + lapi.lua_pushcfunction(L, iter); /* will return generator, */ + lapi.lua_pushvalue(L, 1); /* state, */ + if (iszero) lapi.lua_pushinteger(L, 0); /* and initial value */ + else lapi.lua_pushnil(L); + } else { + lapi.lua_pushvalue(L, 1); /* argument 'self' to metamethod */ + lapi.lua_call(L, 1, 3); /* get 3 values from metamethod */ + } + return 3; +}; + +/* +** Traversal function for 'ipairs' +*/ +const ipairsaux = function(L) { + let i = lauxlib.luaL_checkinteger(L, 2) + 1; + lapi.lua_pushinteger(L, i); + return lapi.lua_geti(L, 1, i) === CT.LUA_TNIL ? 1 : 2; +}; + +/* +** 'ipairs' function. Returns 'ipairsaux', given "table", 0. +** (The given "table" may not be a table.) +*/ +const luaB_ipairs = function(L) { + // Lua 5.2 + // return pairsmeta(L, "__ipairs", 1, ipairsaux); + + lauxlib.luaL_checkany(L, 1); + lapi.lua_pushcfunction(L, ipairsaux); /* iteration function */ + lapi.lua_pushvalue(L, 1); /* state */ + lapi.lua_pushinteger(L, 0); /* initial value */ + return 3; +}; + const luaB_error = function(L) { let level = lauxlib.luaL_optinteger(L, 2, 1); lapi.lua_settop(L, 1); @@ -144,6 +182,7 @@ const base_funcs = { "print": luaB_print, "tostring": luaB_tostring, "getmetatable": luaB_getmetatable, + "ipairs": luaB_ipairs, "setmetatable": luaB_setmetatable, "rawequal": luaB_rawequal, "rawset": luaB_rawset, diff --git a/tests/lbaselib.js b/tests/lbaselib.js index 85563da..53191eb 100644 --- a/tests/lbaselib.js +++ b/tests/lbaselib.js @@ -365,4 +365,40 @@ test('xpcall', function (t) { lapi.lua_tostring(L, -1).endsWith("you fucked up"), "msgh was called and modified the error" ) +}); + + +test('ipairs', function (t) { + let luaCode = ` + local t = {1, 2, 3, 4, 5, ['yo'] = 'lo'} + + local sum = 0 + for i, v in ipairs(t) do + sum = sum + v + end + + return sum + `, 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-pcall"); + + lapi.lua_call(L, 0, -1); + + }, "JS Lua program ran without error"); + + t.strictEqual( + lapi.lua_tointeger(L, -1), + 15, + "Correct element(s) on the stack" + ) }); \ No newline at end of file -- cgit v1.2.3-70-g09d2