seqlua

view seqlua.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"
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 static int seqlua_ipairsaux_raw(lua_State *L) {
7 lua_Integer i;
8 luaL_checktype(L, 1, LUA_TTABLE);
9 i = luaL_checkinteger(L, 2) + 1;
10 lua_pushinteger(L, i);
11 lua_rawgeti(L, 1, i); // TODO: Lua 5.3 returns type
12 return lua_isnil(L, -1) ? 1 : 2;
13 }
15 static int seqlua_ipairsaux_index(lua_State *L) {
16 lua_Integer i = luaL_checkinteger(L, 2) + 1;
17 lua_pushinteger(L, i);
18 lua_pushinteger(L, i);
19 lua_gettable(L, 1); // TODO: Lua 5.3 returns type
20 return lua_isnil(L, -1) ? 1 : 2;
21 }
23 static int seqlua_ipairsaux_call(lua_State *L) {
24 lua_pushinteger(L, luaL_checkinteger(L, 2) + 1);
25 lua_insert(L, 1); // integer on stack index 1
26 lua_settop(L, 2); // function on stack index 2
27 lua_call(L, 0, LUA_MULTRET);
28 if (lua_isnoneornil(L, 2)) {
29 lua_settop(L, 0);
30 lua_pushnil(L);
31 return 1;
32 } else {
33 return lua_gettop(L);
34 }
35 }
37 static int seqlua_ipairs(lua_State *L) {
38 const char *method;
39 int generated = 0;
40 seqlua_ipairs_repeat:
41 if (luaL_getmetafield(L, 1, "__ipairs")) {
42 lua_pushvalue(L, 1);
43 lua_call(L, 1, 3);
44 if (lua_type(L, -3) == LUA_TSTRING) {
45 const char *method = lua_tostring(L, -3);
46 if (!strcmp(method, "raw")) {
47 lua_pushcfunction(L, seqlua_ipairsaux_raw);
48 } else if (!strcmp(method, "index")) {
49 lua_pushcfunction(L, seqlua_ipairsaux_index);
50 } else if (!strcmp(method, "call")) {
51 lua_pushcfunction(L, seqlua_ipairsaux_call);
52 } else {
53 luaL_error(L, "Unexpected string returned by __ipairs metamethod");
54 }
55 lua_pushvalue(L, -3);
56 lua_pushinteger(L, 0);
57 }
58 } else {
59 int t = lua_type(L, 1);
60 if (t == LUA_TFUNCTION) {
61 if (generated) goto seqlua_ipairs_call;
62 method = lua_tostring(L, 2);
63 if (method) {
64 if (!strcmp(method, "call")) {
65 seqlua_ipairs_call:
66 lua_pushcfunction(L, seqlua_ipairsaux_call);
67 goto seqlua_ipairs_finish;
68 } else if (!strcmp(method, "generator")) {
69 lua_settop(L, 1);
70 lua_call(L, 0, 1);
71 generated = 1;
72 goto seqlua_ipairs_repeat;
73 }
74 }
75 } else if (luaL_getmetafield(L, 1, "__index")) {
76 lua_pushcfunction(L, seqlua_ipairsaux_index);
77 goto seqlua_ipairs_finish;
78 }
79 luaL_checktype(L, 1, LUA_TTABLE);
80 lua_pushcfunction(L, seqlua_ipairsaux_raw);
81 seqlua_ipairs_finish:
82 lua_pushvalue(L, 1);
83 lua_pushinteger(L, 0);
84 }
85 return 3;
86 }
88 static int seqlua_concat(lua_State *L) {
89 const char *sep;
90 size_t seplen;
91 luaL_Buffer buf;
92 seqlua_Iterator iter;
93 sep = luaL_checklstring(L, 1, &seplen);
94 luaL_checkany(L, 2);
95 lua_settop(L, 3);
96 luaL_buffinit(L, &buf);
97 seqlua_iterloop(L, &iter, SEQLUA_MODE_CALL, 2) {
98 lua_replace(L, 3);
99 if (seqlua_itercount(&iter) > 1) luaL_addlstring(&buf, sep, seplen);
100 luaL_tolstring(L, 3, NULL);
101 luaL_addvalue(&buf);
102 }
103 luaL_pushresult(&buf);
104 return 1;
105 }
107 int luaopen_seqlua(lua_State *L) {
108 lua_pushcfunction(L, seqlua_ipairs);
109 lua_setglobal(L, "ipairs");
110 lua_getglobal(L, "string");
111 lua_pushcfunction(L, seqlua_concat);
112 lua_setfield(L, -2, "concat");
113 return 0;
114 }

Impressum / About Us