luaa: add support for meta __ipairs

Signed-off-by: Julien Danjou <julien@danjou.info>
This commit is contained in:
Julien Danjou 2008-11-06 17:33:58 +01:00
parent a5cb98162d
commit 4c5a6b1df2
1 changed files with 63 additions and 5 deletions

68
luaa.c
View File

@ -356,23 +356,62 @@ luaAe_pairs(lua_State *L)
return luaA_generic_pairs(L);
}
static int
luaA_ipairs_aux(lua_State *L)
{
int i = luaL_checkint(L, 2) + 1;
luaL_checktype(L, 1, LUA_TTABLE);
lua_pushinteger(L, i);
lua_rawgeti(L, 1, i);
return (lua_isnil(L, -1)) ? 0 : 2;
}
/** Overload standard ipairs function to use __ipairs field of metatables.
* \param L The Lua VM state.
* \return The number of elements pushed on stack.
*/
static int
luaAe_ipairs(lua_State *L)
{
if(luaL_getmetafield(L, 1, "__ipairs"))
{
lua_insert(L, 1);
lua_call(L, lua_gettop(L) - 1, LUA_MULTRET);
return lua_gettop(L);
}
luaL_checktype(L, 1, LUA_TTABLE);
lua_pushvalue(L, lua_upvalueindex(1));
lua_pushvalue(L, 1);
lua_pushinteger(L, 0); /* and initial value */
return 3;
}
/** Replace various standards Lua functions with our own.
* \param L The Lua VM state.
*/
static void
luaA_fixups(lua_State *L)
{
/* replace string.len */
lua_getglobal(L, "string");
lua_pushcfunction(L, luaA_mbstrlen);
lua_setfield(L, -2, "len");
lua_pop(L, 1);
/* replace next */
lua_pushliteral(L, "next");
lua_pushcfunction(L, luaAe_next);
lua_settable(L, LUA_GLOBALSINDEX);
/* replace pairs */
lua_pushliteral(L, "pairs");
lua_pushcfunction(L, luaAe_next);
lua_pushcclosure(L, luaAe_pairs, 1); /* pairs get next as upvalue */
lua_settable(L, LUA_GLOBALSINDEX);
/* replace ipairs */
lua_pushliteral(L, "ipairs");
lua_pushcfunction(L, luaA_ipairs_aux);
lua_pushcclosure(L, luaAe_ipairs, 1);
lua_settable(L, LUA_GLOBALSINDEX);
}
/** __next function for wtable objects.
@ -389,6 +428,21 @@ luaA_wtable_next(lua_State *L)
return 1;
}
/** __ipairs function for wtable objects.
* \param L The Lua VM state.
* \return The number of elements pushed on stack.
*/
static int
luaA_wtable_ipairs(lua_State *L)
{
/* push ipairs_aux */
lua_pushvalue(L, lua_upvalueindex(2));
/* push content table */
lua_pushvalue(L, lua_upvalueindex(1));
lua_pushinteger(L, 0); /* and initial value */
return 3;
}
/** Index function of wtable objects.
* \param L The Lua VM state.
* \return The number of elements pushed on stack.
@ -463,15 +517,19 @@ luaA_table2wtable(lua_State *L)
lua_newtable(L); /* create *real* content table */
lua_newtable(L); /* metatable */
lua_pushvalue(L, -2); /* copy content table */
lua_pushcclosure(L, luaA_wtable_next, 1); /* __next has the content table as upvalue */
lua_pushcfunction(L, luaA_ipairs_aux); /* push ipairs aux */
lua_pushcclosure(L, luaA_wtable_ipairs, 2);
lua_pushvalue(L, -3); /* copy content table */
lua_pushcclosure(L, luaA_wtable_index, 1); /* __index has the content table as upvalue */
lua_pushcclosure(L, luaA_wtable_next, 1); /* __next has the content table as upvalue */
lua_pushvalue(L, -4); /* copy content table */
lua_pushcclosure(L, luaA_wtable_index, 1); /* __index has the content table as upvalue */
lua_pushvalue(L, -5); /* copy content table */
lua_pushcclosure(L, luaA_wtable_newindex, 1); /* __newindex has the content table as upvalue */
/* set metatable field with just pushed closure */
lua_setfield(L, -4, "__newindex");
lua_setfield(L, -3, "__index");
lua_setfield(L, -2, "__next");
lua_setfield(L, -5, "__newindex");
lua_setfield(L, -4, "__index");
lua_setfield(L, -3, "__next");
lua_setfield(L, -2, "__ipairs");
/* set metatable impossible to touch */
lua_pushliteral(L, "wtable");
lua_setfield(L, -2, "__metatable");