jbe@0: #include jbe@0: #include jbe@0: #include "seqlualib.h" jbe@0: jbe@15: #define SEQLUA_ITERTYPE_FUNC 1 jbe@15: #define SEQLUA_ITERTYPE_META 2 jbe@15: #define SEQLUA_ITERTYPE_RAW 3 jbe@0: jbe@0: void seqlua_iterinit(lua_State *L, seqlua_Iterator *iter, int idx) { jbe@0: luaL_checkany(L, idx); // provides better error message jbe@0: iter->L = L; jbe@15: iter->idx = idx; jbe@15: if (lua_type(L, idx) == LUA_TFUNCTION) { jbe@0: iter->itertype = SEQLUA_ITERTYPE_FUNC; jbe@15: } else if (luaL_getmetafield(L, idx, "__call")) { jbe@15: lua_pop(L, 1); jbe@15: iter->itertype = SEQLUA_ITERTYPE_FUNC; jbe@15: } else if (luaL_getmetafield(L, idx, "__index")) { jbe@15: lua_pop(L, 1); jbe@15: iter->itertype = SEQLUA_ITERTYPE_META; jbe@0: } else { jbe@15: luaL_checktype(L, idx, LUA_TTABLE); jbe@15: iter->itertype = SEQLUA_ITERTYPE_RAW; jbe@0: } jbe@0: iter->i = 0; jbe@0: } jbe@0: jbe@0: int seqlua_iternext(seqlua_Iterator *iter) { jbe@0: lua_State *L = iter->L; jbe@0: lua_Integer i = ++iter->i; jbe@0: switch (iter->itertype) { jbe@0: case SEQLUA_ITERTYPE_FUNC: jbe@8: lua_pushvalue(L, iter->idx); jbe@0: lua_call(L, 0, 1); jbe@0: break; jbe@0: case SEQLUA_ITERTYPE_META: jbe@0: lua_pushinteger(L, i); jbe@8: lua_gettable(L, iter->idx); jbe@0: break; jbe@0: case SEQLUA_ITERTYPE_RAW: jbe@8: lua_rawgeti(L, iter->idx, i); jbe@8: break; jbe@0: } jbe@0: if (lua_isnil(L, -1)) { jbe@15: lua_pop(L, 1); jbe@0: return 0; jbe@0: } jbe@0: return 1; jbe@0: } jbe@0: jbe@0: static int seqlua_iterclosureaux_raw(lua_State *L) { jbe@0: lua_Integer i = lua_tointeger(L, lua_upvalueindex(2)) + 1; jbe@0: lua_rawgeti(L, lua_upvalueindex(1), i); jbe@0: if (lua_isnil(L, -1)) return 1; jbe@0: lua_pushinteger(L, i); jbe@0: lua_replace(L, lua_upvalueindex(2)); jbe@0: return 1; jbe@0: } jbe@0: jbe@0: static int seqlua_iterclosureaux_meta(lua_State *L) { jbe@0: lua_Integer i = lua_tointeger(L, lua_upvalueindex(2)) + 1; jbe@0: lua_pushinteger(L, i); jbe@0: lua_gettable(L, lua_upvalueindex(1)); jbe@0: if (lua_isnil(L, -1)) return 1; jbe@0: lua_pushinteger(L, i); jbe@0: lua_replace(L, lua_upvalueindex(2)); jbe@0: return 1; jbe@0: } jbe@0: jbe@0: void seqlua_iterclosure(lua_State *L, int idx) { jbe@8: luaL_checkany(L, idx); // provides better error message jbe@0: if (lua_type(L, idx) == LUA_TFUNCTION) { jbe@0: // do nothing jbe@0: } else if (luaL_getmetafield(L, idx, "__call")) { jbe@15: lua_pop(L, 1); jbe@0: } else if (luaL_getmetafield(L, idx, "__index")) { jbe@0: lua_pop(L, 1); jbe@0: lua_pushvalue(L, idx); jbe@0: lua_pushinteger(L, 0); jbe@17: lua_pushcclosure(L, seqlua_iterclosureaux_meta, 2); jbe@0: lua_replace(L, idx); jbe@0: } else { jbe@0: luaL_checktype(L, idx, LUA_TTABLE); jbe@0: lua_pushvalue(L, idx); jbe@0: lua_pushinteger(L, 0); jbe@17: lua_pushcclosure(L, seqlua_iterclosureaux_raw, 2); jbe@0: lua_replace(L, idx); jbe@0: } jbe@0: } jbe@0: