seqlua
view README @ 14:03ed3361f332
Added TODO: avoid closure creation with seqlua_aux_call in seqlua.c
| author | jbe | 
|---|---|
| date | Wed Aug 20 06:08:03 2014 +0200 (2014-08-20) | 
| parents | 2ef6eb7d17d2 | 
| children | a95fbd16473f | 
 line source
     1 seqlua: Extended sequences and iterators in Lua
     2 ===============================================
     4 This is an experimental package to extend Lua in the following manner:
     6 * allow ipairs(...) to accept tables as well as functions or iterator triplets,
     7 * provide a function iterator(...) that returns single functions unmodified,
     8   but converts
     9     * iterator triplets into closures, and
    10     * tables into a function closure that iterates over the elements,
    11 * provide the auxiliary C functions and macros to simplify iterating over both
    12   tables and iterator functions with the same statement.
    14 This library completely ignores the ``__ipairs`` metamethod (as it is
    15 deprecated since Lua 5.3.0-alpha). It respects, however, any ``__call``
    16 metamethods (this may cause unexpected behavior when passing callable tables
    17 to ``ipairs``).
    21 Lua part of the library
    22 -----------------------
    24 The new ``ipairs(...)`` function works as follows:
    26     require "seqlua"
    28     t = {"a", "b", "c"}
    30     for i, v in ipairs(t) do
    31       print(i, v)
    32     end
    33     -- prints:
    34     --  1   a
    35     --  2   b
    36     --  3   c
    38     function alphabet(from, to)
    39       local letter = nil
    40       return function()
    41         if letter == nil then
    42           letter = from
    43         elseif letter == to then
    44           return nil
    45         else
    46           letter = string.char(string.byte(letter) + 1)
    47         end
    48         return letter
    49       end
    50     end
    52     f = alphabet("a", "z")
    54     for i, v in ipairs(f) do
    55       print(i, v)
    56     end
    57     -- prints:
    58     --  1   a
    59     --  2   b
    60     --  3   c
    61     --  ...
    62     --  25  y
    63     --  26  z
    65     c = setmetatable(
    66       { iter = alphabet("a", "f") },
    67       { __call = function(t) return t.iter() end }
    68     )
    70     for i, v in ipairs(c) do
    71       print(i, v)
    72     end
    73     -- prints:
    74     --  1   a
    75     --  2   b
    76     --  3   c
    77     --  4   d
    78     --  5   e
    79     --  6   f
    81     g = coroutine.wrap(function()
    82       coroutine.yield("Alice")
    83       coroutine.yield("Bob")
    84       for i = 1, 3 do
    85         coroutine.yield("Person #" .. tostring(i))
    86       end
    87     end)
    89     for i, v in ipairs(g) do
    90       print(i, v)
    91     end
    92     -- prints:
    93     --  1   Alice
    94     --  2   Bob
    95     --  3   Person #1
    96     --  4   Person #2
    97     --  5   Person #3
    99     set = {apple = true, banana = true}
   100     for i, k, v in ipairs(pairs(set)) do
   101       print(i, k, v)
   102     end
   103     -- prints:
   104     --  1   banana  true
   105     --  2   apple   true
   106     -- (order of "apple" and "banana" may vary)
   108 The function ``iterator(...)`` may be used to convert any table, any function,
   109 or any iterator triplet into a single function (possibly creating a closure):
   111     require "seqlua"
   113     function filter_strings(...)
   114       nextvalue = iterator(...)
   115       return function()
   116         local value
   117         repeat
   118           value = nextvalue()
   119         until value == nil or type(value) == "string"
   120         return value
   121       end
   122     end
   124     for i, v in ipairs(filter_strings{"Hello", true, "World"}) do
   125       print(i, v)
   126     end
   127     -- prints:
   128     --  1   Hello
   129     --  2   World
   131     tbl = {apple = true, banana = true, [1] = "array entry"}
   132     for v in filter_strings(pairs(tbl)) do
   133       print(v)
   134     end
   135     -- prints:
   136     --   banana
   137     --   apple
   138     -- (order may vary)
   142 C part of the library
   143 ---------------------
   145 In ``seqlualib.h``, the following macro is defined:
   147     #define seqlua_iterloop(L, iter, idx) \
   148       for ( \
   149         seqlua_iterinit((L), (iter), (idx)); \
   150         seqlua_iternext(iter); \
   151         lua_pop((L), 1) \
   152       )
   154 This macro allows iteration over either tables or iterator functions (but not
   155 iterator triplets) as the following example function demonstrates:
   157     int printcsv(lua_State *L) {
   158       seqlua_Iterator iter;
   159       seqlua_iterloop(L, &iter, 1) {
   160         if (seqlua_itercount(&iter) > 1) fputs(",", stdout);
   161         fputs(luaL_tolstring(L, -1, NULL), stdout);
   162         lua_pop(L, 1);  // pops value that luaL_tolstring pushed onto stack
   163       }
   164       fputs("\n", stdout);
   165       return 0;
   166     }
   168     printcsv{"a", "b", "c"}
   169     -- prints: a,b,c
   171     printcsv(assert(io.open("testfile")):lines())
   172     -- prints: line1,line2,... of "testfile"
   174 NOTE: ``seqlua_iterinit`` will store one extra element on the stack during
   175 iteration. When ``seqlua_iternext`` returns 0, this extra element is popped
   176 from the stack automatically.
   178 Additionally, ``seqlualib`` includes a function ``seqlua_iterclosure(L, idx)``,
   179 which converts a table at a given stack index into a function closure (stored
   180 on the same stack index) that iterates over the elements of the table. If the
   181 value at the given stack index is already a function, it leaves the value
   182 unchanged. If the value is convertible to a function using ``__call,`` then the
   183 value is replaced by a closure calling the ``__call`` metamethod.
