seqlua
diff seqlualib.c @ 30:367fc70acc15
Respect the __ipairs and __len metamethods
| author | jbe |
|---|---|
| date | Sat Aug 23 23:13:17 2014 +0200 (2014-08-23) |
| parents | 29792283522f |
| children | 4fc9090ada1d |
line diff
1.1 --- a/seqlualib.c Fri Aug 22 12:27:25 2014 +0200 1.2 +++ b/seqlualib.c Sat Aug 23 23:13:17 2014 +0200 1.3 @@ -2,25 +2,37 @@ 1.4 #include <lauxlib.h> 1.5 #include "seqlualib.h" 1.6 1.7 -#define SEQLUA_ITERTYPE_FUNC 1 1.8 -#define SEQLUA_ITERTYPE_META 2 1.9 -#define SEQLUA_ITERTYPE_RAW 3 1.10 +#define SEQLUA_ITERTYPE_IPAIRS 1 1.11 +#define SEQLUA_ITERTYPE_CALL 2 1.12 +#define SEQLUA_ITERTYPE_INDEX 3 1.13 +#define SEQLUA_ITERTYPE_RAW 4 1.14 1.15 void seqlua_iterinit(lua_State *L, seqlua_Iterator *iter, int idx) { 1.16 - luaL_checkany(L, idx); // provides better error message 1.17 + if (luaL_getmetafield(L, idx, "__ipairs")) { 1.18 + lua_pushvalue(L, idx); 1.19 + lua_call(L, 1, 3); 1.20 + iter->itertype = SEQLUA_ITERTYPE_IPAIRS; 1.21 + } else { 1.22 + if (lua_type(L, idx) == LUA_TFUNCTION) { 1.23 + iter->itertype = SEQLUA_ITERTYPE_CALL; 1.24 + } else if ( 1.25 + luaL_getmetafield(L, idx, "__index") || 1.26 + luaL_getmetafield(L, idx, "__len") 1.27 + ) { 1.28 + lua_pop(L, 1); 1.29 + iter->itertype = SEQLUA_ITERTYPE_INDEX; 1.30 + iter->len = luaL_len(L, idx); 1.31 + } else { 1.32 + luaL_checktype(L, idx, LUA_TTABLE); 1.33 + iter->itertype = SEQLUA_ITERTYPE_RAW; 1.34 + } 1.35 + // always occupy 3 stack indicies 1.36 + lua_pushnil(L); 1.37 + lua_pushnil(L); 1.38 + lua_pushnil(L); 1.39 + iter->idx = idx; 1.40 + } 1.41 iter->L = L; 1.42 - iter->idx = idx; 1.43 - if ( 1.44 - lua_type(L, idx) == LUA_TFUNCTION || 1.45 - (luaL_getmetafield(L, idx, "__call") && (lua_pop(L, 1), 1)) 1.46 - ) { 1.47 - iter->itertype = SEQLUA_ITERTYPE_FUNC; 1.48 - } else if (luaL_getmetafield(L, idx, "__index") && (lua_pop(L, 1), 1)) { 1.49 - iter->itertype = SEQLUA_ITERTYPE_META; 1.50 - } else { 1.51 - luaL_checktype(L, idx, LUA_TTABLE); 1.52 - iter->itertype = SEQLUA_ITERTYPE_RAW; 1.53 - } 1.54 iter->i = 0; 1.55 } 1.56 1.57 @@ -28,20 +40,35 @@ 1.58 lua_State *L = iter->L; 1.59 lua_Integer i = ++iter->i; 1.60 switch (iter->itertype) { 1.61 - case SEQLUA_ITERTYPE_FUNC: 1.62 + case SEQLUA_ITERTYPE_IPAIRS: 1.63 + lua_pushvalue(L, -3); 1.64 + lua_pushvalue(L, -3); 1.65 + lua_pushvalue(L, -3); 1.66 + lua_call(L, 2, 2); 1.67 + if (lua_isnil(L, -2)) { 1.68 + lua_pop(L, 5); 1.69 + return 0; 1.70 + } 1.71 + lua_remove(L, -3); 1.72 + return 1; 1.73 + case SEQLUA_ITERTYPE_CALL: 1.74 lua_pushvalue(L, iter->idx); 1.75 lua_call(L, 0, 1); 1.76 break; 1.77 - case SEQLUA_ITERTYPE_META: 1.78 + case SEQLUA_ITERTYPE_INDEX: 1.79 + if (i > iter->len) { 1.80 + lua_pop(L, 3); 1.81 + return 0; 1.82 + } 1.83 lua_pushinteger(L, i); 1.84 lua_gettable(L, iter->idx); 1.85 - break; 1.86 + return 1; 1.87 case SEQLUA_ITERTYPE_RAW: 1.88 lua_rawgeti(L, iter->idx, i); 1.89 break; 1.90 } 1.91 if (lua_isnil(L, -1)) { 1.92 - lua_pop(L, 1); 1.93 + lua_pop(L, 4); 1.94 return 0; 1.95 } 1.96 return 1;