seqlua
changeset 23:29792283522f
Removed iterator(...) function; ipairs doesn't accept iterator triplets anymore
author | jbe |
---|---|
date | Thu Aug 21 20:01:52 2014 +0200 (2014-08-21) |
parents | 50c6388d4963 |
children | 28d472cc7a9b |
files | README seqlua.c seqlua_c_example.c seqlua_c_example_test.lua seqlua_ipairs_example.lua seqlualib.c |
line diff
1.1 --- a/README Thu Aug 21 13:04:45 2014 +0200 1.2 +++ b/README Thu Aug 21 20:01:52 2014 +0200 1.3 @@ -3,12 +3,8 @@ 1.4 1.5 This is an experimental package to extend Lua in the following manner: 1.6 1.7 -* allow ipairs(...) to accept tables as well as functions or iterator triplets, 1.8 -* provide a function iterator(...) that returns single functions unmodified, 1.9 - but converts 1.10 - * iterator triplets into closures, and 1.11 - * tables into a function closure that iterates over the elements, 1.12 -* provide the auxiliary C functions and macros to simplify iterating over both 1.13 +* allow ipairs(...) to accept tables as well as functions 1.14 +* provide auxiliary C functions and macros to simplify iterating over both 1.15 tables and iterator functions with the same statement. 1.16 1.17 This library completely ignores the ``__ipairs`` metamethod (as it is 1.18 @@ -50,9 +46,7 @@ 1.19 end 1.20 end 1.21 1.22 - f = alphabet("a", "z") 1.23 - 1.24 - for i, v in ipairs(f) do 1.25 + for i, v in ipairs(alphabet()) do 1.26 print(i, v) 1.27 end 1.28 -- prints: 1.29 @@ -63,50 +57,33 @@ 1.30 -- 25 y 1.31 -- 26 z 1.32 1.33 - set = {apple = true, banana = true} 1.34 - for i, k, v in ipairs(pairs(set)) do 1.35 - print(i, k, v) 1.36 + function filter(f, seq) 1.37 + return coroutine.wrap(function() 1.38 + for i, v in ipairs(seq) do f(v) end 1.39 + end) 1.40 end 1.41 - -- prints: 1.42 - -- 1 banana true 1.43 - -- 2 apple true 1.44 - -- (order of "apple" and "banana" may vary) 1.45 - 1.46 -More examples for invoking the ``ipairs(...)`` function can be found in the 1.47 -file ``seqlua_ipairs_example.lua``. 1.48 1.49 -The function ``iterator(...)`` may be used to convert any table, any function, 1.50 -or any iterator triplet into a single function (possibly creating a closure): 1.51 - 1.52 - require "seqlua" 1.53 - 1.54 - function filter_strings(...) 1.55 - nextvalue = iterator(...) 1.56 - return function() 1.57 - local value 1.58 - repeat 1.59 - value = nextvalue() 1.60 - until value == nil or type(value) == "string" 1.61 - return value 1.62 + function filterfunc(v) 1.63 + local type_v = type(v) 1.64 + if type_v == "string" then 1.65 + coroutine.yield(v) 1.66 + elseif type_v == "number" then 1.67 + for i = 1, v do 1.68 + coroutine.yield(true) 1.69 + end 1.70 end 1.71 end 1.72 1.73 - for i, v in ipairs(filter_strings{"Hello", true, "World"}) do 1.74 - print(i, v) 1.75 - end 1.76 - -- prints: 1.77 - -- 1 Hello 1.78 - -- 2 World 1.79 - 1.80 - tbl = {apple = true, banana = true, [1] = "array entry"} 1.81 - for v in filter_strings(pairs(tbl)) do 1.82 + for v in filter(filterfunc, {"a", "b", 3, "c"}) do 1.83 print(v) 1.84 end 1.85 -- prints: 1.86 - -- banana 1.87 - -- apple 1.88 - -- (order may vary) 1.89 - 1.90 + -- a 1.91 + -- b 1.92 + -- true 1.93 + -- true 1.94 + -- true 1.95 + -- c 1.96 1.97 1.98 C part of the library 1.99 @@ -121,8 +98,8 @@ 1.100 lua_pop((L), 1) \ 1.101 ) 1.102 1.103 -This macro allows iteration over either tables or iterator functions (but not 1.104 -iterator triplets) as the following example function demonstrates: 1.105 +This macro allows iteration over either tables or iterator functions as the 1.106 +following example function demonstrates: 1.107 1.108 int printcsv(lua_State *L) { 1.109 seqlua_Iterator iter; 1.110 @@ -141,20 +118,4 @@ 1.111 printcsv(assert(io.open("testfile")):lines()) 1.112 -- prints: line1,line2,... of "testfile" 1.113 1.114 -Additionally, ``seqlualib`` includes a function ``seqlua_iterclosure(L, idx)``, 1.115 -which converts a table at a given stack index into a function closure (stored 1.116 -on the same stack index) that iterates over the elements of the table. If the 1.117 -value at the given stack index is already a function (or if it is callable 1.118 -through a ``__call`` metamethod), then ``seqlua_iterclosure(L, idx)`` leaves 1.119 -the value at ``idx`` unchanged. 1.120 1.121 - 1.122 -TODO 1.123 ----- 1.124 - 1.125 -Accepting iterator triplets doesn't work, because even if a single function 1.126 -is passed to ipairs, that function still might expect to get the previous 1.127 -iteration value as second argument. Therefore, accepting iterator triplets 1.128 -as argument to ipairs should be removed. 1.129 - 1.130 -
2.1 --- a/seqlua.c Thu Aug 21 13:04:45 2014 +0200 2.2 +++ b/seqlua.c Thu Aug 21 20:01:52 2014 +0200 2.3 @@ -33,41 +33,13 @@ 2.4 } 2.5 } 2.6 2.7 -static int seqlua_ipairsaux_triplet(lua_State *L) { 2.8 - lua_Integer i = lua_tointeger(L, lua_upvalueindex(4)) + 1; 2.9 - lua_settop(L, 0); 2.10 - lua_pushinteger(L, i); 2.11 - lua_replace(L, lua_upvalueindex(4)); 2.12 - lua_pushinteger(L, i); 2.13 - lua_pushvalue(L, lua_upvalueindex(1)); 2.14 - lua_pushvalue(L, lua_upvalueindex(2)); 2.15 - lua_pushvalue(L, lua_upvalueindex(3)); 2.16 - lua_call(L, 2, LUA_MULTRET); 2.17 - if (lua_isnoneornil(L, 2)) { 2.18 - lua_settop(L, 0); 2.19 - lua_pushnil(L); 2.20 - return 1; 2.21 - } else { 2.22 - lua_pushvalue(L, 2); 2.23 - lua_replace(L, lua_upvalueindex(3)); 2.24 - return lua_gettop(L); 2.25 - } 2.26 -} 2.27 - 2.28 static int seqlua_ipairs(lua_State *L) { 2.29 luaL_checkany(L, 1); // provides better error message 2.30 - if (lua_type(L, 1) == LUA_TFUNCTION) { 2.31 - seqlua_ipairs_function: 2.32 - if (!lua_isnoneornil(L, 2) || !lua_isnoneornil(L, 3)) { 2.33 - lua_settop(L, 3); 2.34 - lua_pushinteger(L, 0); 2.35 - lua_pushcclosure(L, seqlua_ipairsaux_triplet, 4); 2.36 - return 1; 2.37 - } 2.38 + if ( 2.39 + lua_type(L, 1) == LUA_TFUNCTION || 2.40 + (luaL_getmetafield(L, 1, "__call") && (lua_pop(L, 1), 1)) 2.41 + ) { 2.42 lua_pushcfunction(L, seqlua_ipairsaux_func); 2.43 - } else if (luaL_getmetafield(L, 1, "__call")) { 2.44 - lua_pop(L, 1); 2.45 - goto seqlua_ipairs_function; 2.46 } else if (luaL_getmetafield(L, 1, "__index")) { 2.47 lua_pushcfunction(L, seqlua_ipairsaux_meta); 2.48 } else { 2.49 @@ -79,70 +51,8 @@ 2.50 return 3; 2.51 } 2.52 2.53 -static int seqlua_iteratoraux_raw(lua_State *L) { 2.54 - lua_Integer i = lua_tointeger(L, lua_upvalueindex(2)) + 1; 2.55 - lua_rawgeti(L, lua_upvalueindex(1), i); 2.56 - if (lua_isnil(L, -1)) return 1; 2.57 - lua_pushinteger(L, i); 2.58 - lua_replace(L, lua_upvalueindex(2)); 2.59 - return 1; 2.60 -} 2.61 - 2.62 -static int seqlua_iteratoraux_meta(lua_State *L) { 2.63 - lua_Integer i = lua_tointeger(L, lua_upvalueindex(2)) + 1; 2.64 - lua_pushinteger(L, i); 2.65 - lua_gettable(L, lua_upvalueindex(1)); 2.66 - if (lua_isnil(L, -1)) return 1; 2.67 - lua_pushinteger(L, i); 2.68 - lua_replace(L, lua_upvalueindex(2)); 2.69 - return 1; 2.70 -} 2.71 - 2.72 -static int seqlua_iteratoraux_triplet(lua_State *L) { 2.73 - lua_settop(L, 0); 2.74 - lua_pushvalue(L, lua_upvalueindex(1)); 2.75 - lua_pushvalue(L, lua_upvalueindex(2)); 2.76 - lua_pushvalue(L, lua_upvalueindex(3)); 2.77 - lua_call(L, 2, LUA_MULTRET); 2.78 - if (lua_isnoneornil(L, 1)) { 2.79 - lua_settop(L, 1); 2.80 - return 1; 2.81 - } 2.82 - lua_pushvalue(L, 1); 2.83 - lua_replace(L, lua_upvalueindex(3)); 2.84 - return lua_gettop(L); 2.85 -} 2.86 - 2.87 -int seqlua_iterator(lua_State *L) { 2.88 - luaL_checkany(L, 1); // provides better error message 2.89 - lua_settop(L, 3); 2.90 - if (lua_type(L, 1) == LUA_TFUNCTION) { 2.91 - seqlua_iterator_function: 2.92 - if (lua_isnil(L, 2) && lua_isnil(L, 3)) { 2.93 - lua_settop(L, 1); 2.94 - } else { 2.95 - lua_pushcclosure(L, seqlua_iteratoraux_triplet, 3); 2.96 - } 2.97 - } else if (luaL_getmetafield(L, 1, "__call")) { 2.98 - lua_pop(L, 1); 2.99 - goto seqlua_iterator_function; 2.100 - } else if (luaL_getmetafield(L, 1, "__index")) { 2.101 - lua_pushvalue(L, 1); 2.102 - lua_pushinteger(L, 0); 2.103 - lua_pushcclosure(L, seqlua_iteratoraux_meta, 2); 2.104 - } else { 2.105 - luaL_checktype(L, 1, LUA_TTABLE); 2.106 - lua_pushvalue(L, 1); 2.107 - lua_pushinteger(L, 0); 2.108 - lua_pushcclosure(L, seqlua_iteratoraux_raw, 2); 2.109 - } 2.110 - return 1; 2.111 -} 2.112 - 2.113 int luaopen_seqlua(lua_State *L) { 2.114 lua_pushcfunction(L, seqlua_ipairs); 2.115 lua_setglobal(L, "ipairs"); 2.116 - lua_pushcfunction(L, seqlua_iterator); 2.117 - lua_setglobal(L, "iterator"); 2.118 return 1; 2.119 }
3.1 --- a/seqlua_c_example.c Thu Aug 21 13:04:45 2014 +0200 3.2 +++ b/seqlua_c_example.c Thu Aug 21 20:01:52 2014 +0200 3.3 @@ -14,23 +14,8 @@ 3.4 return 0; 3.5 } 3.6 3.7 -static int seqlua_c_example_printthree(lua_State *L) { 3.8 - int i; 3.9 - seqlua_iterclosure(L, 1); 3.10 - for (i=0; i<3; i++) { 3.11 - lua_pushvalue(L, 1); 3.12 - lua_call(L, 0, 1); 3.13 - fputs(luaL_tolstring(L, -1, NULL), stdout); 3.14 - lua_pop(L, 1); // pop value that luaL_tolstring pushed onto stack 3.15 - fputs("\n", stdout); 3.16 - } 3.17 - return 0; 3.18 -} 3.19 - 3.20 int luaopen_seqlua_c_example(lua_State *L) { 3.21 lua_pushcfunction(L, seqlua_c_example_printcsv); 3.22 lua_setglobal(L, "printcsv"); 3.23 - lua_pushcfunction(L, seqlua_c_example_printthree); 3.24 - lua_setglobal(L, "printthree"); 3.25 return 0; 3.26 }
4.1 --- a/seqlua_c_example_test.lua Thu Aug 21 13:04:45 2014 +0200 4.2 +++ b/seqlua_c_example_test.lua Thu Aug 21 20:01:52 2014 +0200 4.3 @@ -22,15 +22,3 @@ 4.4 -- prints: 4.5 -- a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z 4.6 4.7 -printthree(alphabet()) 4.8 --- prints: 4.9 --- a 4.10 --- b 4.11 --- c 4.12 - 4.13 -printthree(setmetatable({v="x"}, {__call=function(t) return t.v end})) 4.14 --- prints: 4.15 --- x 4.16 --- x 4.17 --- x 4.18 -
5.1 --- a/seqlua_ipairs_example.lua Thu Aug 21 13:04:45 2014 +0200 5.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 5.3 @@ -1,110 +0,0 @@ 5.4 -require "seqlua" 5.5 - 5.6 -t = {"a", "b", "c"} 5.7 - 5.8 -for i, v in ipairs(t) do 5.9 - print(i, v) 5.10 -end 5.11 --- prints: 5.12 --- 1 a 5.13 --- 2 b 5.14 --- 3 c 5.15 - 5.16 -function alphabet(from, to) 5.17 - local letter = nil 5.18 - return function() 5.19 - if letter == nil then 5.20 - letter = from 5.21 - elseif letter == to then 5.22 - return nil 5.23 - else 5.24 - letter = string.char(string.byte(letter) + 1) 5.25 - end 5.26 - return letter 5.27 - end 5.28 -end 5.29 - 5.30 -f = alphabet("a", "z") 5.31 - 5.32 -for i, v in ipairs(f) do 5.33 - print(i, v) 5.34 -end 5.35 --- prints: 5.36 --- 1 a 5.37 --- 2 b 5.38 --- 3 c 5.39 --- ... 5.40 --- 25 y 5.41 --- 26 z 5.42 - 5.43 -c = setmetatable( 5.44 - { iter = alphabet("a", "f") }, 5.45 - { __call = function(t) return t.iter() end } 5.46 -) 5.47 - 5.48 -for i, v in ipairs(c) do 5.49 - print(i, v) 5.50 -end 5.51 --- prints: 5.52 --- 1 a 5.53 --- 2 b 5.54 --- 3 c 5.55 --- 4 d 5.56 --- 5 e 5.57 --- 6 f 5.58 - 5.59 -g = coroutine.wrap(function() 5.60 - coroutine.yield("Alice") 5.61 - coroutine.yield("Bob") 5.62 - for i = 1, 3 do 5.63 - coroutine.yield("Person #" .. tostring(i)) 5.64 - end 5.65 -end) 5.66 - 5.67 -for i, v in ipairs(g) do 5.68 - print(i, v) 5.69 -end 5.70 --- prints: 5.71 --- 1 Alice 5.72 --- 2 Bob 5.73 --- 3 Person #1 5.74 --- 4 Person #2 5.75 --- 5 Person #3 5.76 - 5.77 -function filter(f, iter, iter_s, iter_i) 5.78 - return coroutine.wrap(function() 5.79 - for i, v in ipairs(iter, iter_s, iter_i) do f(v) end 5.80 - end) 5.81 -end 5.82 - 5.83 -function filterfunc(v) 5.84 - local type_v = type(v) 5.85 - if type_v == "string" then 5.86 - coroutine.yield(v) 5.87 - elseif type_v == "number" then 5.88 - for i = 1, v do 5.89 - coroutine.yield(true) 5.90 - end 5.91 - end 5.92 -end 5.93 - 5.94 -for v in filter(filterfunc, {"a", "b", 3, "c"}) do 5.95 - print(v) 5.96 -end 5.97 --- prints: 5.98 --- a 5.99 --- b 5.100 --- true 5.101 --- true 5.102 --- true 5.103 --- c 5.104 - 5.105 -set = {apple = true, banana = true} 5.106 -for i, k, v in ipairs(pairs(set)) do 5.107 - print(i, k, v) 5.108 -end 5.109 --- prints: 5.110 --- 1 banana true 5.111 --- 2 apple true 5.112 --- (order of "apple" and "banana" may vary) 5.113 -
6.1 --- a/seqlualib.c Thu Aug 21 13:04:45 2014 +0200 6.2 +++ b/seqlualib.c Thu Aug 21 20:01:52 2014 +0200 6.3 @@ -10,13 +10,12 @@ 6.4 luaL_checkany(L, idx); // provides better error message 6.5 iter->L = L; 6.6 iter->idx = idx; 6.7 - if (lua_type(L, idx) == LUA_TFUNCTION) { 6.8 + if ( 6.9 + lua_type(L, idx) == LUA_TFUNCTION || 6.10 + (luaL_getmetafield(L, idx, "__call") && (lua_pop(L, 1), 1)) 6.11 + ) { 6.12 iter->itertype = SEQLUA_ITERTYPE_FUNC; 6.13 - } else if (luaL_getmetafield(L, idx, "__call")) { 6.14 - lua_pop(L, 1); 6.15 - iter->itertype = SEQLUA_ITERTYPE_FUNC; 6.16 - } else if (luaL_getmetafield(L, idx, "__index")) { 6.17 - lua_pop(L, 1); 6.18 + } else if (luaL_getmetafield(L, idx, "__index") && (lua_pop(L, 1), 1)) { 6.19 iter->itertype = SEQLUA_ITERTYPE_META; 6.20 } else { 6.21 luaL_checktype(L, idx, LUA_TTABLE); 6.22 @@ -48,43 +47,3 @@ 6.23 return 1; 6.24 } 6.25 6.26 -static int seqlua_iterclosureaux_raw(lua_State *L) { 6.27 - lua_Integer i = lua_tointeger(L, lua_upvalueindex(2)) + 1; 6.28 - lua_rawgeti(L, lua_upvalueindex(1), i); 6.29 - if (lua_isnil(L, -1)) return 1; 6.30 - lua_pushinteger(L, i); 6.31 - lua_replace(L, lua_upvalueindex(2)); 6.32 - return 1; 6.33 -} 6.34 - 6.35 -static int seqlua_iterclosureaux_meta(lua_State *L) { 6.36 - lua_Integer i = lua_tointeger(L, lua_upvalueindex(2)) + 1; 6.37 - lua_pushinteger(L, i); 6.38 - lua_gettable(L, lua_upvalueindex(1)); 6.39 - if (lua_isnil(L, -1)) return 1; 6.40 - lua_pushinteger(L, i); 6.41 - lua_replace(L, lua_upvalueindex(2)); 6.42 - return 1; 6.43 -} 6.44 - 6.45 -void seqlua_iterclosure(lua_State *L, int idx) { 6.46 - luaL_checkany(L, idx); // provides better error message 6.47 - if (lua_type(L, idx) == LUA_TFUNCTION) { 6.48 - // do nothing 6.49 - } else if (luaL_getmetafield(L, idx, "__call")) { 6.50 - lua_pop(L, 1); 6.51 - } else if (luaL_getmetafield(L, idx, "__index")) { 6.52 - lua_pop(L, 1); 6.53 - lua_pushvalue(L, idx); 6.54 - lua_pushinteger(L, 0); 6.55 - lua_pushcclosure(L, seqlua_iterclosureaux_meta, 2); 6.56 - lua_replace(L, idx); 6.57 - } else { 6.58 - luaL_checktype(L, idx, LUA_TTABLE); 6.59 - lua_pushvalue(L, idx); 6.60 - lua_pushinteger(L, 0); 6.61 - lua_pushcclosure(L, seqlua_iterclosureaux_raw, 2); 6.62 - lua_replace(L, idx); 6.63 - } 6.64 -} 6.65 -