seqlua
view seqlualib.c @ 52:3362ec36cb09
Do not automatically assume that functions passed to ipairs are iterators
but require ipairs(func, mode) to have an explicit mode set to "call" or "generator"
but require ipairs(func, mode) to have an explicit mode set to "call" or "generator"
author | jbe |
---|---|
date | Tue Aug 26 21:10:03 2014 +0200 (2014-08-26) |
parents | 332216604f83 |
children | 92ce3958aca7 |
line source
1 #include <lua.h>
2 #include <lauxlib.h>
3 #include "seqlualib.h"
4 #include <string.h>
6 #define SEQLUA_ITERTYPE_IPAIRS 1
7 #define SEQLUA_ITERTYPE_CALL 2
8 #define SEQLUA_ITERTYPE_INDEX 3
9 #define SEQLUA_ITERTYPE_RAW 4
11 void seqlua_iterinit(lua_State *L, seqlua_Iterator *iter, int mode, int idx) {
12 int generated = 0;
13 seqlua_iterinit_repeat:
14 if (luaL_getmetafield(L, idx, "__ipairs")) {
15 if (!generated) lua_pushvalue(L, idx);
16 lua_call(L, 1, 3);
17 if (lua_type(L, -3) == LUA_TSTRING) {
18 const char *method = lua_tostring(L, -3);
19 if (!strcmp(method, "raw")) {
20 iter->itertype = SEQLUA_ITERTYPE_RAW;
21 } else if (!strcmp(method, "index")) {
22 iter->itertype = SEQLUA_ITERTYPE_INDEX;
23 } else if (!strcmp(method, "call")) {
24 iter->itertype = SEQLUA_ITERTYPE_CALL;
25 } else {
26 luaL_error(L, "Unexpected string returned by __ipairs metamethod");
27 }
28 iter->idx = lua_gettop(L) - 1;
29 } else {
30 iter->itertype = SEQLUA_ITERTYPE_IPAIRS;
31 }
32 } else {
33 if (lua_type(L, idx) == LUA_TFUNCTION) {
34 if (generated || mode == SEQLUA_MODE_CALL) {
35 iter->itertype = SEQLUA_ITERTYPE_CALL;
36 goto seqlua_iterinit_finish;
37 } else if (mode == SEQLUA_MODE_GENERATOR) {
38 lua_pushvalue(L, idx);
39 lua_call(L, 0, 1);
40 idx = lua_gettop(L);
41 goto seqlua_iterinit_repeat;
42 }
43 } else if (luaL_getmetafield(L, idx, "__index")) {
44 lua_pop(L, 1);
45 iter->itertype = SEQLUA_ITERTYPE_INDEX;
46 goto seqlua_iterinit_finish;
47 }
48 luaL_checktype(L, idx, LUA_TTABLE);
49 iter->itertype = SEQLUA_ITERTYPE_RAW;
50 seqlua_iterinit_finish:
51 // always occupy 3 stack indicies
52 if (!generated) lua_pushnil(L);
53 lua_pushnil(L);
54 lua_pushnil(L);
55 iter->idx = idx;
56 }
57 iter->L = L;
58 iter->i = 0;
59 }
61 int seqlua_iternext(seqlua_Iterator *iter) {
62 lua_State *L = iter->L;
63 lua_Integer i = ++iter->i;
64 switch (iter->itertype) {
65 case SEQLUA_ITERTYPE_IPAIRS:
66 lua_pushvalue(L, -3);
67 lua_pushvalue(L, -3);
68 lua_pushvalue(L, -3);
69 lua_call(L, 2, 2);
70 if (lua_isnil(L, -2)) {
71 lua_pop(L, 5);
72 return 0;
73 }
74 lua_remove(L, -3);
75 return 1;
76 case SEQLUA_ITERTYPE_CALL:
77 lua_pushvalue(L, iter->idx);
78 lua_call(L, 0, 1);
79 break;
80 case SEQLUA_ITERTYPE_INDEX:
81 lua_pushinteger(L, i);
82 lua_gettable(L, iter->idx);
83 break;
84 case SEQLUA_ITERTYPE_RAW:
85 lua_rawgeti(L, iter->idx, i);
86 break;
87 }
88 if (lua_isnil(L, -1)) {
89 lua_pop(L, 4);
90 return 0;
91 }
92 return 1;
93 }