# HG changeset patch # User jbe # Date 1408644112 -7200 # Node ID 29792283522fad56068fef162aba11319e449859 # Parent 50c6388d49634647f5953e45b6d364dcc6b6c249 Removed iterator(...) function; ipairs doesn't accept iterator triplets anymore diff -r 50c6388d4963 -r 29792283522f README --- a/README Thu Aug 21 13:04:45 2014 +0200 +++ b/README Thu Aug 21 20:01:52 2014 +0200 @@ -3,12 +3,8 @@ This is an experimental package to extend Lua in the following manner: -* allow ipairs(...) to accept tables as well as functions or iterator triplets, -* provide a function iterator(...) that returns single functions unmodified, - but converts - * iterator triplets into closures, and - * tables into a function closure that iterates over the elements, -* provide the auxiliary C functions and macros to simplify iterating over both +* allow ipairs(...) to accept tables as well as functions +* provide auxiliary C functions and macros to simplify iterating over both tables and iterator functions with the same statement. This library completely ignores the ``__ipairs`` metamethod (as it is @@ -50,9 +46,7 @@ end end - f = alphabet("a", "z") - - for i, v in ipairs(f) do + for i, v in ipairs(alphabet()) do print(i, v) end -- prints: @@ -63,50 +57,33 @@ -- 25 y -- 26 z - set = {apple = true, banana = true} - for i, k, v in ipairs(pairs(set)) do - print(i, k, v) + function filter(f, seq) + return coroutine.wrap(function() + for i, v in ipairs(seq) do f(v) end + end) end - -- prints: - -- 1 banana true - -- 2 apple true - -- (order of "apple" and "banana" may vary) - -More examples for invoking the ``ipairs(...)`` function can be found in the -file ``seqlua_ipairs_example.lua``. -The function ``iterator(...)`` may be used to convert any table, any function, -or any iterator triplet into a single function (possibly creating a closure): - - require "seqlua" - - function filter_strings(...) - nextvalue = iterator(...) - return function() - local value - repeat - value = nextvalue() - until value == nil or type(value) == "string" - return value + function filterfunc(v) + local type_v = type(v) + if type_v == "string" then + coroutine.yield(v) + elseif type_v == "number" then + for i = 1, v do + coroutine.yield(true) + end end end - for i, v in ipairs(filter_strings{"Hello", true, "World"}) do - print(i, v) - end - -- prints: - -- 1 Hello - -- 2 World - - tbl = {apple = true, banana = true, [1] = "array entry"} - for v in filter_strings(pairs(tbl)) do + for v in filter(filterfunc, {"a", "b", 3, "c"}) do print(v) end -- prints: - -- banana - -- apple - -- (order may vary) - + -- a + -- b + -- true + -- true + -- true + -- c C part of the library @@ -121,8 +98,8 @@ lua_pop((L), 1) \ ) -This macro allows iteration over either tables or iterator functions (but not -iterator triplets) as the following example function demonstrates: +This macro allows iteration over either tables or iterator functions as the +following example function demonstrates: int printcsv(lua_State *L) { seqlua_Iterator iter; @@ -141,20 +118,4 @@ printcsv(assert(io.open("testfile")):lines()) -- prints: line1,line2,... of "testfile" -Additionally, ``seqlualib`` includes a function ``seqlua_iterclosure(L, idx)``, -which converts a table at a given stack index into a function closure (stored -on the same stack index) that iterates over the elements of the table. If the -value at the given stack index is already a function (or if it is callable -through a ``__call`` metamethod), then ``seqlua_iterclosure(L, idx)`` leaves -the value at ``idx`` unchanged. - -TODO ----- - -Accepting iterator triplets doesn't work, because even if a single function -is passed to ipairs, that function still might expect to get the previous -iteration value as second argument. Therefore, accepting iterator triplets -as argument to ipairs should be removed. - - diff -r 50c6388d4963 -r 29792283522f seqlua.c --- a/seqlua.c Thu Aug 21 13:04:45 2014 +0200 +++ b/seqlua.c Thu Aug 21 20:01:52 2014 +0200 @@ -33,41 +33,13 @@ } } -static int seqlua_ipairsaux_triplet(lua_State *L) { - lua_Integer i = lua_tointeger(L, lua_upvalueindex(4)) + 1; - lua_settop(L, 0); - lua_pushinteger(L, i); - lua_replace(L, lua_upvalueindex(4)); - lua_pushinteger(L, i); - lua_pushvalue(L, lua_upvalueindex(1)); - lua_pushvalue(L, lua_upvalueindex(2)); - lua_pushvalue(L, lua_upvalueindex(3)); - lua_call(L, 2, LUA_MULTRET); - if (lua_isnoneornil(L, 2)) { - lua_settop(L, 0); - lua_pushnil(L); - return 1; - } else { - lua_pushvalue(L, 2); - lua_replace(L, lua_upvalueindex(3)); - return lua_gettop(L); - } -} - static int seqlua_ipairs(lua_State *L) { luaL_checkany(L, 1); // provides better error message - if (lua_type(L, 1) == LUA_TFUNCTION) { - seqlua_ipairs_function: - if (!lua_isnoneornil(L, 2) || !lua_isnoneornil(L, 3)) { - lua_settop(L, 3); - lua_pushinteger(L, 0); - lua_pushcclosure(L, seqlua_ipairsaux_triplet, 4); - return 1; - } + if ( + lua_type(L, 1) == LUA_TFUNCTION || + (luaL_getmetafield(L, 1, "__call") && (lua_pop(L, 1), 1)) + ) { lua_pushcfunction(L, seqlua_ipairsaux_func); - } else if (luaL_getmetafield(L, 1, "__call")) { - lua_pop(L, 1); - goto seqlua_ipairs_function; } else if (luaL_getmetafield(L, 1, "__index")) { lua_pushcfunction(L, seqlua_ipairsaux_meta); } else { @@ -79,70 +51,8 @@ return 3; } -static int seqlua_iteratoraux_raw(lua_State *L) { - lua_Integer i = lua_tointeger(L, lua_upvalueindex(2)) + 1; - lua_rawgeti(L, lua_upvalueindex(1), i); - if (lua_isnil(L, -1)) return 1; - lua_pushinteger(L, i); - lua_replace(L, lua_upvalueindex(2)); - return 1; -} - -static int seqlua_iteratoraux_meta(lua_State *L) { - lua_Integer i = lua_tointeger(L, lua_upvalueindex(2)) + 1; - lua_pushinteger(L, i); - lua_gettable(L, lua_upvalueindex(1)); - if (lua_isnil(L, -1)) return 1; - lua_pushinteger(L, i); - lua_replace(L, lua_upvalueindex(2)); - return 1; -} - -static int seqlua_iteratoraux_triplet(lua_State *L) { - lua_settop(L, 0); - lua_pushvalue(L, lua_upvalueindex(1)); - lua_pushvalue(L, lua_upvalueindex(2)); - lua_pushvalue(L, lua_upvalueindex(3)); - lua_call(L, 2, LUA_MULTRET); - if (lua_isnoneornil(L, 1)) { - lua_settop(L, 1); - return 1; - } - lua_pushvalue(L, 1); - lua_replace(L, lua_upvalueindex(3)); - return lua_gettop(L); -} - -int seqlua_iterator(lua_State *L) { - luaL_checkany(L, 1); // provides better error message - lua_settop(L, 3); - if (lua_type(L, 1) == LUA_TFUNCTION) { - seqlua_iterator_function: - if (lua_isnil(L, 2) && lua_isnil(L, 3)) { - lua_settop(L, 1); - } else { - lua_pushcclosure(L, seqlua_iteratoraux_triplet, 3); - } - } else if (luaL_getmetafield(L, 1, "__call")) { - lua_pop(L, 1); - goto seqlua_iterator_function; - } else if (luaL_getmetafield(L, 1, "__index")) { - lua_pushvalue(L, 1); - lua_pushinteger(L, 0); - lua_pushcclosure(L, seqlua_iteratoraux_meta, 2); - } else { - luaL_checktype(L, 1, LUA_TTABLE); - lua_pushvalue(L, 1); - lua_pushinteger(L, 0); - lua_pushcclosure(L, seqlua_iteratoraux_raw, 2); - } - return 1; -} - int luaopen_seqlua(lua_State *L) { lua_pushcfunction(L, seqlua_ipairs); lua_setglobal(L, "ipairs"); - lua_pushcfunction(L, seqlua_iterator); - lua_setglobal(L, "iterator"); return 1; } diff -r 50c6388d4963 -r 29792283522f seqlua_c_example.c --- a/seqlua_c_example.c Thu Aug 21 13:04:45 2014 +0200 +++ b/seqlua_c_example.c Thu Aug 21 20:01:52 2014 +0200 @@ -14,23 +14,8 @@ return 0; } -static int seqlua_c_example_printthree(lua_State *L) { - int i; - seqlua_iterclosure(L, 1); - for (i=0; i<3; i++) { - lua_pushvalue(L, 1); - lua_call(L, 0, 1); - fputs(luaL_tolstring(L, -1, NULL), stdout); - lua_pop(L, 1); // pop value that luaL_tolstring pushed onto stack - fputs("\n", stdout); - } - return 0; -} - int luaopen_seqlua_c_example(lua_State *L) { lua_pushcfunction(L, seqlua_c_example_printcsv); lua_setglobal(L, "printcsv"); - lua_pushcfunction(L, seqlua_c_example_printthree); - lua_setglobal(L, "printthree"); return 0; } diff -r 50c6388d4963 -r 29792283522f seqlua_c_example_test.lua --- a/seqlua_c_example_test.lua Thu Aug 21 13:04:45 2014 +0200 +++ b/seqlua_c_example_test.lua Thu Aug 21 20:01:52 2014 +0200 @@ -22,15 +22,3 @@ -- prints: -- 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 -printthree(alphabet()) --- prints: --- a --- b --- c - -printthree(setmetatable({v="x"}, {__call=function(t) return t.v end})) --- prints: --- x --- x --- x - diff -r 50c6388d4963 -r 29792283522f seqlua_ipairs_example.lua --- a/seqlua_ipairs_example.lua Thu Aug 21 13:04:45 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,110 +0,0 @@ -require "seqlua" - -t = {"a", "b", "c"} - -for i, v in ipairs(t) do - print(i, v) -end --- prints: --- 1 a --- 2 b --- 3 c - -function alphabet(from, to) - local letter = nil - return function() - if letter == nil then - letter = from - elseif letter == to then - return nil - else - letter = string.char(string.byte(letter) + 1) - end - return letter - end -end - -f = alphabet("a", "z") - -for i, v in ipairs(f) do - print(i, v) -end --- prints: --- 1 a --- 2 b --- 3 c --- ... --- 25 y --- 26 z - -c = setmetatable( - { iter = alphabet("a", "f") }, - { __call = function(t) return t.iter() end } -) - -for i, v in ipairs(c) do - print(i, v) -end --- prints: --- 1 a --- 2 b --- 3 c --- 4 d --- 5 e --- 6 f - -g = coroutine.wrap(function() - coroutine.yield("Alice") - coroutine.yield("Bob") - for i = 1, 3 do - coroutine.yield("Person #" .. tostring(i)) - end -end) - -for i, v in ipairs(g) do - print(i, v) -end --- prints: --- 1 Alice --- 2 Bob --- 3 Person #1 --- 4 Person #2 --- 5 Person #3 - -function filter(f, iter, iter_s, iter_i) - return coroutine.wrap(function() - for i, v in ipairs(iter, iter_s, iter_i) do f(v) end - end) -end - -function filterfunc(v) - local type_v = type(v) - if type_v == "string" then - coroutine.yield(v) - elseif type_v == "number" then - for i = 1, v do - coroutine.yield(true) - end - end -end - -for v in filter(filterfunc, {"a", "b", 3, "c"}) do - print(v) -end --- prints: --- a --- b --- true --- true --- true --- c - -set = {apple = true, banana = true} -for i, k, v in ipairs(pairs(set)) do - print(i, k, v) -end --- prints: --- 1 banana true --- 2 apple true --- (order of "apple" and "banana" may vary) - diff -r 50c6388d4963 -r 29792283522f seqlualib.c --- a/seqlualib.c Thu Aug 21 13:04:45 2014 +0200 +++ b/seqlualib.c Thu Aug 21 20:01:52 2014 +0200 @@ -10,13 +10,12 @@ luaL_checkany(L, idx); // provides better error message iter->L = L; iter->idx = idx; - if (lua_type(L, idx) == LUA_TFUNCTION) { + if ( + lua_type(L, idx) == LUA_TFUNCTION || + (luaL_getmetafield(L, idx, "__call") && (lua_pop(L, 1), 1)) + ) { iter->itertype = SEQLUA_ITERTYPE_FUNC; - } else if (luaL_getmetafield(L, idx, "__call")) { - lua_pop(L, 1); - iter->itertype = SEQLUA_ITERTYPE_FUNC; - } else if (luaL_getmetafield(L, idx, "__index")) { - lua_pop(L, 1); + } else if (luaL_getmetafield(L, idx, "__index") && (lua_pop(L, 1), 1)) { iter->itertype = SEQLUA_ITERTYPE_META; } else { luaL_checktype(L, idx, LUA_TTABLE); @@ -48,43 +47,3 @@ return 1; } -static int seqlua_iterclosureaux_raw(lua_State *L) { - lua_Integer i = lua_tointeger(L, lua_upvalueindex(2)) + 1; - lua_rawgeti(L, lua_upvalueindex(1), i); - if (lua_isnil(L, -1)) return 1; - lua_pushinteger(L, i); - lua_replace(L, lua_upvalueindex(2)); - return 1; -} - -static int seqlua_iterclosureaux_meta(lua_State *L) { - lua_Integer i = lua_tointeger(L, lua_upvalueindex(2)) + 1; - lua_pushinteger(L, i); - lua_gettable(L, lua_upvalueindex(1)); - if (lua_isnil(L, -1)) return 1; - lua_pushinteger(L, i); - lua_replace(L, lua_upvalueindex(2)); - return 1; -} - -void seqlua_iterclosure(lua_State *L, int idx) { - luaL_checkany(L, idx); // provides better error message - if (lua_type(L, idx) == LUA_TFUNCTION) { - // do nothing - } else if (luaL_getmetafield(L, idx, "__call")) { - lua_pop(L, 1); - } else if (luaL_getmetafield(L, idx, "__index")) { - lua_pop(L, 1); - lua_pushvalue(L, idx); - lua_pushinteger(L, 0); - lua_pushcclosure(L, seqlua_iterclosureaux_meta, 2); - lua_replace(L, idx); - } else { - luaL_checktype(L, idx, LUA_TTABLE); - lua_pushvalue(L, idx); - lua_pushinteger(L, 0); - lua_pushcclosure(L, seqlua_iterclosureaux_raw, 2); - lua_replace(L, idx); - } -} -