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
|