jbe@0: seqlua: Extended sequences and iterators in Lua jbe@0: =============================================== jbe@0: jbe@0: This is an experimental package to extend Lua in the following manner: jbe@0: jbe@23: * allow ipairs(...) to accept tables as well as functions jbe@23: * provide auxiliary C functions and macros to simplify iterating over both jbe@0: tables and iterator functions with the same statement. jbe@0: jbe@0: This library completely ignores the ``__ipairs`` metamethod (as it is jbe@18: deprecated since Lua 5.3.0-alpha). It respects, however, any ``__index`` and jbe@18: ``__call`` metamethods (this may cause unexpected behavior when passing jbe@18: callable tables to ``ipairs``). The ``__call`` metamethod takes precedence over jbe@18: an existing ``__index`` metamethod. jbe@0: jbe@0: jbe@0: jbe@0: Lua part of the library jbe@0: ----------------------- jbe@0: jbe@0: The new ``ipairs(...)`` function works as follows: jbe@0: jbe@0: require "seqlua" jbe@0: jbe@0: t = {"a", "b", "c"} jbe@0: jbe@0: for i, v in ipairs(t) do jbe@0: print(i, v) jbe@0: end jbe@0: -- prints: jbe@0: -- 1 a jbe@0: -- 2 b jbe@0: -- 3 c jbe@0: jbe@19: function alphabet() jbe@0: local letter = nil jbe@0: return function() jbe@0: if letter == nil then jbe@19: letter = "a" jbe@19: elseif letter == "z" then jbe@0: return nil jbe@0: else jbe@0: letter = string.char(string.byte(letter) + 1) jbe@0: end jbe@0: return letter jbe@0: end jbe@0: end jbe@0: jbe@23: for i, v in ipairs(alphabet()) do jbe@0: print(i, v) jbe@0: end jbe@0: -- prints: jbe@0: -- 1 a jbe@0: -- 2 b jbe@0: -- 3 c jbe@0: -- ... jbe@0: -- 25 y jbe@0: -- 26 z jbe@0: jbe@23: function filter(f, seq) jbe@23: return coroutine.wrap(function() jbe@23: for i, v in ipairs(seq) do f(v) end jbe@23: end) jbe@0: end jbe@19: jbe@23: function filterfunc(v) jbe@23: local type_v = type(v) jbe@23: if type_v == "string" then jbe@23: coroutine.yield(v) jbe@23: elseif type_v == "number" then jbe@23: for i = 1, v do jbe@23: coroutine.yield(true) jbe@23: end jbe@0: end jbe@0: end jbe@0: jbe@23: for v in filter(filterfunc, {"a", "b", 3, "c"}) do jbe@0: print(v) jbe@0: end jbe@0: -- prints: jbe@23: -- a jbe@23: -- b jbe@23: -- true jbe@23: -- true jbe@23: -- true jbe@23: -- c jbe@0: jbe@0: jbe@0: C part of the library jbe@0: --------------------- jbe@0: jbe@0: In ``seqlualib.h``, the following macro is defined: jbe@0: jbe@0: #define seqlua_iterloop(L, iter, idx) \ jbe@0: for ( \ jbe@0: seqlua_iterinit((L), (iter), (idx)); \ jbe@0: seqlua_iternext(iter); \ jbe@0: lua_pop((L), 1) \ jbe@0: ) jbe@0: jbe@23: This macro allows iteration over either tables or iterator functions as the jbe@23: following example function demonstrates: jbe@0: jbe@0: int printcsv(lua_State *L) { jbe@0: seqlua_Iterator iter; jbe@0: seqlua_iterloop(L, &iter, 1) { jbe@0: if (seqlua_itercount(&iter) > 1) fputs(",", stdout); jbe@0: fputs(luaL_tolstring(L, -1, NULL), stdout); jbe@1: lua_pop(L, 1); // pops value that luaL_tolstring pushed onto stack jbe@0: } jbe@0: fputs("\n", stdout); jbe@0: return 0; jbe@0: } jbe@0: jbe@11: printcsv{"a", "b", "c"} jbe@11: -- prints: a,b,c jbe@11: jbe@11: printcsv(assert(io.open("testfile")):lines()) jbe@11: -- prints: line1,line2,... of "testfile" jbe@0: jbe@0: