seqlua: Extended sequences and iterators in Lua
===============================================

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
  tables and iterator functions with the same statement.

This library completely ignores the ``__ipairs`` metamethod (as it is
deprecated since Lua 5.3.0-alpha). It respects, however, any ``__call``
metamethods (this may cause unexpected behavior when passing callable tables
to ``ipairs``).



Lua part of the library
-----------------------

The new ``ipairs(...)`` function works as follows:

    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

    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)

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
      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
      print(v)
    end
    -- prints:
    --   banana
    --   apple
    -- (order may vary)



C part of the library
---------------------

In ``seqlualib.h``, the following macro is defined:

    #define seqlua_iterloop(L, iter, idx) \
      for ( \
        seqlua_iterinit((L), (iter), (idx)); \
        seqlua_iternext(iter); \
        lua_pop((L), 1) \
      )

This macro allows iteration over either tables or iterator functions (but not
iterator triplets) as the following example function demonstrates:

    int printcsv(lua_State *L) {
      seqlua_Iterator iter;
      seqlua_iterloop(L, &iter, 1) {
        if (seqlua_itercount(&iter) > 1) fputs(",", stdout);
        fputs(luaL_tolstring(L, -1, NULL), stdout);
        lua_pop(L, 1);  // pops value that luaL_tolstring pushed onto stack
      }
      fputs("\n", stdout);
      return 0;
    }

    printcsv{"a", "b", "c"}
    -- prints: a,b,c

    printcsv(assert(io.open("testfile")):lines())
    -- prints: line1,line2,... of "testfile"

NOTE: ``seqlua_iterinit`` will store one extra element on the stack during
iteration. When ``seqlua_iternext`` returns 0, this extra element is popped
from the stack automatically.

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, it leaves the value
unchanged. If the value is convertible to a function using ``__call,`` then the
value is replaced by a closure calling the ``__call`` metamethod.


