summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md8
-rw-r--r--src/lapi.js15
-rw-r--r--src/lbaselib.js39
-rw-r--r--tests/lbaselib.js36
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