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 ``__index`` and
``__call`` metamethods (this may cause unexpected behavior when passing
callable tables to ``ipairs``). The ``__call`` metamethod takes precedence over
an existing ``__index`` metamethod.



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()
      local letter = nil
      return function()
        if letter == nil then
          letter = "a"
        elseif letter == "z" 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

    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)

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
      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"

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.


