| rev | 
   line source | 
| 
jbe@0
 | 
     1 seqlua: Extended sequences and iterators in Lua
 | 
| 
jbe@0
 | 
     2 ===============================================
 | 
| 
jbe@0
 | 
     3 
 | 
| 
jbe@0
 | 
     4 This is an experimental package to extend Lua in the following manner:
 | 
| 
jbe@0
 | 
     5 
 | 
| 
jbe@23
 | 
     6 * allow ipairs(...) to accept tables as well as functions
 | 
| 
jbe@23
 | 
     7 * provide auxiliary C functions and macros to simplify iterating over both
 | 
| 
jbe@0
 | 
     8   tables and iterator functions with the same statement.
 | 
| 
jbe@0
 | 
     9 
 | 
| 
jbe@0
 | 
    10 This library completely ignores the ``__ipairs`` metamethod (as it is
 | 
| 
jbe@18
 | 
    11 deprecated since Lua 5.3.0-alpha). It respects, however, any ``__index`` and
 | 
| 
jbe@18
 | 
    12 ``__call`` metamethods (this may cause unexpected behavior when passing
 | 
| 
jbe@18
 | 
    13 callable tables to ``ipairs``). The ``__call`` metamethod takes precedence over
 | 
| 
jbe@18
 | 
    14 an existing ``__index`` metamethod.
 | 
| 
jbe@0
 | 
    15 
 | 
| 
jbe@0
 | 
    16 
 | 
| 
jbe@0
 | 
    17 
 | 
| 
jbe@0
 | 
    18 Lua part of the library
 | 
| 
jbe@0
 | 
    19 -----------------------
 | 
| 
jbe@0
 | 
    20 
 | 
| 
jbe@0
 | 
    21 The new ``ipairs(...)`` function works as follows:
 | 
| 
jbe@0
 | 
    22 
 | 
| 
jbe@0
 | 
    23     require "seqlua"
 | 
| 
jbe@0
 | 
    24 
 | 
| 
jbe@0
 | 
    25     t = {"a", "b", "c"}
 | 
| 
jbe@0
 | 
    26 
 | 
| 
jbe@0
 | 
    27     for i, v in ipairs(t) do
 | 
| 
jbe@0
 | 
    28       print(i, v)
 | 
| 
jbe@0
 | 
    29     end
 | 
| 
jbe@0
 | 
    30     -- prints:
 | 
| 
jbe@0
 | 
    31     --  1   a
 | 
| 
jbe@0
 | 
    32     --  2   b
 | 
| 
jbe@0
 | 
    33     --  3   c
 | 
| 
jbe@0
 | 
    34 
 | 
| 
jbe@19
 | 
    35     function alphabet()
 | 
| 
jbe@0
 | 
    36       local letter = nil
 | 
| 
jbe@0
 | 
    37       return function()
 | 
| 
jbe@0
 | 
    38         if letter == nil then
 | 
| 
jbe@19
 | 
    39           letter = "a"
 | 
| 
jbe@19
 | 
    40         elseif letter == "z" then
 | 
| 
jbe@0
 | 
    41           return nil
 | 
| 
jbe@0
 | 
    42         else
 | 
| 
jbe@0
 | 
    43           letter = string.char(string.byte(letter) + 1)
 | 
| 
jbe@0
 | 
    44         end
 | 
| 
jbe@0
 | 
    45         return letter
 | 
| 
jbe@0
 | 
    46       end
 | 
| 
jbe@0
 | 
    47     end
 | 
| 
jbe@0
 | 
    48 
 | 
| 
jbe@23
 | 
    49     for i, v in ipairs(alphabet()) do
 | 
| 
jbe@0
 | 
    50       print(i, v)
 | 
| 
jbe@0
 | 
    51     end
 | 
| 
jbe@0
 | 
    52     -- prints:
 | 
| 
jbe@0
 | 
    53     --  1   a
 | 
| 
jbe@0
 | 
    54     --  2   b
 | 
| 
jbe@0
 | 
    55     --  3   c
 | 
| 
jbe@0
 | 
    56     --  ...
 | 
| 
jbe@0
 | 
    57     --  25  y
 | 
| 
jbe@0
 | 
    58     --  26  z
 | 
| 
jbe@0
 | 
    59 
 | 
| 
jbe@23
 | 
    60     function filter(f, seq)
 | 
| 
jbe@23
 | 
    61       return coroutine.wrap(function()
 | 
| 
jbe@23
 | 
    62         for i, v in ipairs(seq) do f(v) end
 | 
| 
jbe@23
 | 
    63       end)
 | 
| 
jbe@0
 | 
    64     end
 | 
| 
jbe@19
 | 
    65 
 | 
| 
jbe@23
 | 
    66     function filterfunc(v)
 | 
| 
jbe@23
 | 
    67       local type_v = type(v)
 | 
| 
jbe@23
 | 
    68       if type_v == "string" then
 | 
| 
jbe@23
 | 
    69         coroutine.yield(v)
 | 
| 
jbe@23
 | 
    70       elseif type_v == "number" then
 | 
| 
jbe@23
 | 
    71         for i = 1, v do
 | 
| 
jbe@23
 | 
    72           coroutine.yield(true)
 | 
| 
jbe@23
 | 
    73         end
 | 
| 
jbe@0
 | 
    74       end
 | 
| 
jbe@0
 | 
    75     end
 | 
| 
jbe@0
 | 
    76 
 | 
| 
jbe@23
 | 
    77     for v in filter(filterfunc, {"a", "b", 3, "c"}) do
 | 
| 
jbe@0
 | 
    78       print(v)
 | 
| 
jbe@0
 | 
    79     end
 | 
| 
jbe@0
 | 
    80     -- prints:
 | 
| 
jbe@23
 | 
    81     --  a
 | 
| 
jbe@23
 | 
    82     --  b
 | 
| 
jbe@23
 | 
    83     --  true
 | 
| 
jbe@23
 | 
    84     --  true
 | 
| 
jbe@23
 | 
    85     --  true
 | 
| 
jbe@23
 | 
    86     --  c
 | 
| 
jbe@0
 | 
    87 
 | 
| 
jbe@0
 | 
    88 
 | 
| 
jbe@0
 | 
    89 C part of the library
 | 
| 
jbe@0
 | 
    90 ---------------------
 | 
| 
jbe@0
 | 
    91 
 | 
| 
jbe@0
 | 
    92 In ``seqlualib.h``, the following macro is defined:
 | 
| 
jbe@0
 | 
    93 
 | 
| 
jbe@0
 | 
    94     #define seqlua_iterloop(L, iter, idx) \
 | 
| 
jbe@0
 | 
    95       for ( \
 | 
| 
jbe@0
 | 
    96         seqlua_iterinit((L), (iter), (idx)); \
 | 
| 
jbe@0
 | 
    97         seqlua_iternext(iter); \
 | 
| 
jbe@0
 | 
    98         lua_pop((L), 1) \
 | 
| 
jbe@0
 | 
    99       )
 | 
| 
jbe@0
 | 
   100 
 | 
| 
jbe@23
 | 
   101 This macro allows iteration over either tables or iterator functions as the
 | 
| 
jbe@23
 | 
   102 following example function demonstrates:
 | 
| 
jbe@0
 | 
   103 
 | 
| 
jbe@0
 | 
   104     int printcsv(lua_State *L) {
 | 
| 
jbe@0
 | 
   105       seqlua_Iterator iter;
 | 
| 
jbe@0
 | 
   106       seqlua_iterloop(L, &iter, 1) {
 | 
| 
jbe@0
 | 
   107         if (seqlua_itercount(&iter) > 1) fputs(",", stdout);
 | 
| 
jbe@0
 | 
   108         fputs(luaL_tolstring(L, -1, NULL), stdout);
 | 
| 
jbe@1
 | 
   109         lua_pop(L, 1);  // pops value that luaL_tolstring pushed onto stack
 | 
| 
jbe@0
 | 
   110       }
 | 
| 
jbe@0
 | 
   111       fputs("\n", stdout);
 | 
| 
jbe@0
 | 
   112       return 0;
 | 
| 
jbe@0
 | 
   113     }
 | 
| 
jbe@0
 | 
   114 
 | 
| 
jbe@11
 | 
   115     printcsv{"a", "b", "c"}
 | 
| 
jbe@11
 | 
   116     -- prints: a,b,c
 | 
| 
jbe@11
 | 
   117 
 | 
| 
jbe@11
 | 
   118     printcsv(assert(io.open("testfile")):lines())
 | 
| 
jbe@11
 | 
   119     -- prints: line1,line2,... of "testfile"
 | 
| 
jbe@0
 | 
   120 
 | 
| 
jbe@0
 | 
   121 
 |