| 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@30
 | 
     6 * allow ``ipairs(seq)`` to accept tables as well as functions (i.e function
 | 
| 
jbe@30
 | 
     7   iterators),
 | 
| 
jbe@25
 | 
     8 * add a new function ``string.concat(separator, seq)`` to concat either table
 | 
| 
jbe@25
 | 
     9   entries or function return values,
 | 
| 
jbe@23
 | 
    10 * provide auxiliary C functions and macros to simplify iterating over both
 | 
| 
jbe@0
 | 
    11   tables and iterator functions with the same statement.
 | 
| 
jbe@0
 | 
    12 
 | 
| 
jbe@30
 | 
    13 In all cases, existing ``__index``, ``__len``, or ``__ipairs`` metamethods are
 | 
| 
jbe@30
 | 
    14 respected. The ``__ipairs`` metamethod takes precedence.
 | 
| 
jbe@0
 | 
    15 
 | 
| 
jbe@0
 | 
    16 
 | 
| 
jbe@0
 | 
    17 Lua part of the library
 | 
| 
jbe@0
 | 
    18 -----------------------
 | 
| 
jbe@0
 | 
    19 
 | 
| 
jbe@30
 | 
    20 The modified ``ipairs(seq)`` and the new ``string.concat(sep, seq)`` functions
 | 
| 
jbe@30
 | 
    21 accept either a table or a function as ``seq``. This is demonstrated in the
 | 
| 
jbe@30
 | 
    22 following examples:
 | 
| 
jbe@0
 | 
    23 
 | 
| 
jbe@0
 | 
    24     require "seqlua"
 | 
| 
jbe@0
 | 
    25 
 | 
| 
jbe@0
 | 
    26     t = {"a", "b", "c"}
 | 
| 
jbe@0
 | 
    27 
 | 
| 
jbe@0
 | 
    28     for i, v in ipairs(t) do
 | 
| 
jbe@0
 | 
    29       print(i, v)
 | 
| 
jbe@0
 | 
    30     end
 | 
| 
jbe@0
 | 
    31     -- prints:
 | 
| 
jbe@0
 | 
    32     --  1   a
 | 
| 
jbe@0
 | 
    33     --  2   b
 | 
| 
jbe@0
 | 
    34     --  3   c
 | 
| 
jbe@0
 | 
    35 
 | 
| 
jbe@25
 | 
    36     print(string.concat(",", t))
 | 
| 
jbe@25
 | 
    37     -- prints: a,b,c
 | 
| 
jbe@25
 | 
    38 
 | 
| 
jbe@19
 | 
    39     function alphabet()
 | 
| 
jbe@0
 | 
    40       local letter = nil
 | 
| 
jbe@0
 | 
    41       return function()
 | 
| 
jbe@0
 | 
    42         if letter == nil then
 | 
| 
jbe@19
 | 
    43           letter = "a"
 | 
| 
jbe@19
 | 
    44         elseif letter == "z" then
 | 
| 
jbe@0
 | 
    45           return nil
 | 
| 
jbe@0
 | 
    46         else
 | 
| 
jbe@0
 | 
    47           letter = string.char(string.byte(letter) + 1)
 | 
| 
jbe@0
 | 
    48         end
 | 
| 
jbe@0
 | 
    49         return letter
 | 
| 
jbe@0
 | 
    50       end
 | 
| 
jbe@0
 | 
    51     end
 | 
| 
jbe@0
 | 
    52 
 | 
| 
jbe@23
 | 
    53     for i, v in ipairs(alphabet()) do
 | 
| 
jbe@0
 | 
    54       print(i, v)
 | 
| 
jbe@0
 | 
    55     end
 | 
| 
jbe@0
 | 
    56     -- prints:
 | 
| 
jbe@0
 | 
    57     --  1   a
 | 
| 
jbe@0
 | 
    58     --  2   b
 | 
| 
jbe@0
 | 
    59     --  3   c
 | 
| 
jbe@0
 | 
    60     --  ...
 | 
| 
jbe@0
 | 
    61     --  25  y
 | 
| 
jbe@0
 | 
    62     --  26  z
 | 
| 
jbe@0
 | 
    63 
 | 
| 
jbe@25
 | 
    64     print(string.concat(",", alphabet()))
 | 
| 
jbe@25
 | 
    65     -- prints: a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z
 | 
| 
jbe@25
 | 
    66 
 | 
| 
jbe@26
 | 
    67     function filter(f)
 | 
| 
jbe@26
 | 
    68       return function(seq)
 | 
| 
jbe@26
 | 
    69         return coroutine.wrap(function()
 | 
| 
jbe@26
 | 
    70           for i, v in ipairs(seq) do f(v) end
 | 
| 
jbe@26
 | 
    71         end)
 | 
| 
jbe@26
 | 
    72       end
 | 
| 
jbe@0
 | 
    73     end
 | 
| 
jbe@19
 | 
    74 
 | 
| 
jbe@29
 | 
    75     alpha_beta_x = filter(function(v)
 | 
| 
jbe@28
 | 
    76       if v == "a" then
 | 
| 
jbe@28
 | 
    77         coroutine.yield("alpha")
 | 
| 
jbe@28
 | 
    78       elseif v == "b" then
 | 
| 
jbe@28
 | 
    79         coroutine.yield("beta")
 | 
| 
jbe@28
 | 
    80       elseif type(v) == "number" then
 | 
| 
jbe@23
 | 
    81         for i = 1, v do
 | 
| 
jbe@28
 | 
    82           coroutine.yield("X")
 | 
| 
jbe@23
 | 
    83         end
 | 
| 
jbe@0
 | 
    84       end
 | 
| 
jbe@26
 | 
    85     end)
 | 
| 
jbe@0
 | 
    86 
 | 
| 
jbe@29
 | 
    87     print((","):concat(alpha_beta_x{"a", 3, "b", "c", "d"}))
 | 
| 
jbe@28
 | 
    88     -- prints: alpha,X,X,X,beta
 | 
| 
jbe@25
 | 
    89 
 | 
| 
jbe@29
 | 
    90     print((","):concat(alpha_beta_x(alphabet())))
 | 
| 
jbe@28
 | 
    91     -- prints: alpha,beta
 | 
| 
jbe@27
 | 
    92 
 | 
| 
jbe@0
 | 
    93 
 | 
| 
jbe@0
 | 
    94 C part of the library
 | 
| 
jbe@0
 | 
    95 ---------------------
 | 
| 
jbe@0
 | 
    96 
 | 
| 
jbe@0
 | 
    97 In ``seqlualib.h``, the following macro is defined:
 | 
| 
jbe@0
 | 
    98 
 | 
| 
jbe@0
 | 
    99     #define seqlua_iterloop(L, iter, idx) \
 | 
| 
jbe@0
 | 
   100       for ( \
 | 
| 
jbe@0
 | 
   101         seqlua_iterinit((L), (iter), (idx)); \
 | 
| 
jbe@0
 | 
   102         seqlua_iternext(iter); \
 | 
| 
jbe@25
 | 
   103       )
 | 
| 
jbe@25
 | 
   104 
 | 
| 
jbe@25
 | 
   105 and
 | 
| 
jbe@25
 | 
   106 
 | 
| 
jbe@25
 | 
   107     #define seqlua_iterloopauto(L, iter, idx) \
 | 
| 
jbe@25
 | 
   108       for ( \
 | 
| 
jbe@25
 | 
   109         seqlua_iterinit((L), (iter), (idx)); \
 | 
| 
jbe@25
 | 
   110         seqlua_iternext(iter); \
 | 
| 
jbe@0
 | 
   111         lua_pop((L), 1) \
 | 
| 
jbe@0
 | 
   112       )
 | 
| 
jbe@0
 | 
   113 
 | 
| 
jbe@23
 | 
   114 This macro allows iteration over either tables or iterator functions as the
 | 
| 
jbe@23
 | 
   115 following example function demonstrates:
 | 
| 
jbe@0
 | 
   116 
 | 
| 
jbe@0
 | 
   117     int printcsv(lua_State *L) {
 | 
| 
jbe@0
 | 
   118       seqlua_Iterator iter;
 | 
| 
jbe@0
 | 
   119       seqlua_iterloop(L, &iter, 1) {
 | 
| 
jbe@0
 | 
   120         if (seqlua_itercount(&iter) > 1) fputs(",", stdout);
 | 
| 
jbe@0
 | 
   121         fputs(luaL_tolstring(L, -1, NULL), stdout);
 | 
| 
jbe@25
 | 
   122         // two values need to be popped (the value pushed by
 | 
| 
jbe@25
 | 
   123         // seqlua_iternext and the value pushed by luaL_tolstring)
 | 
| 
jbe@25
 | 
   124         lua_pop(L, 2);
 | 
| 
jbe@0
 | 
   125       }
 | 
| 
jbe@0
 | 
   126       fputs("\n", stdout);
 | 
| 
jbe@0
 | 
   127       return 0;
 | 
| 
jbe@0
 | 
   128     }
 | 
| 
jbe@0
 | 
   129 
 | 
| 
jbe@11
 | 
   130     printcsv{"a", "b", "c"}
 | 
| 
jbe@11
 | 
   131     -- prints: a,b,c
 | 
| 
jbe@11
 | 
   132 
 | 
| 
jbe@11
 | 
   133     printcsv(assert(io.open("testfile")):lines())
 | 
| 
jbe@11
 | 
   134     -- prints: line1,line2,... of "testfile"
 | 
| 
jbe@0
 | 
   135 
 | 
| 
jbe@31
 | 
   136 NOTE: During iteration using ``seqlua_iterloop``, ``seqlua_iterloopauto``, or
 | 
| 
jbe@31
 | 
   137 ``seqlua_iterinit``, three extra elements are stored on the stack (additionally
 | 
| 
jbe@31
 | 
   138 to the value). These extra elements are removed automatically when the loop ends
 | 
| 
jbe@31
 | 
   139 (i.e. when ``seqlua_iternext`` returns zero). The value pushed onto the stack
 | 
| 
jbe@31
 | 
   140 for every iteration step has to be removed manually from the stack, unless
 | 
| 
jbe@31
 | 
   141 ``seqlua_iterloopauto`` is used.
 | 
| 
jbe@0
 | 
   142 
 | 
| 
jbe@31
 | 
   143 
 |