seqlua

view README @ 36:4f82d3b3dbd9

Removed wrong spaces in example output in README
author jbe
date Sun Aug 24 22:32:57 2014 +0200 (2014-08-24)
parents 332216604f83
children adf671e3458c
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(seq)`` to accept tables as well as functions (i.e function
7 iterators),
8 * add a new function ``string.concat(separator, seq)`` to concat either
9 table entries or function return values,
10 * provide auxiliary C functions and macros to simplify iterating over both
11 tables and iterator functions with the same statement.
13 Existing ``__ipairs`` or ``__index`` (but not ``__len``) metamethods are
14 respected by both the Lua functions and the C functions and macros. The
15 ``__ipairs`` metamethod takes precedence over ``__index``, while the
16 ``__len`` metamethod is never used.
20 Lua part of the library
21 -----------------------
23 The modified ``ipairs(seq)`` and the new ``string.concat(sep, seq)`` functions
24 accept either a table or a function as ``seq``. This is demonstrated in the
25 following examples:
27 require "seqlua"
29 t = {"a", "b", "c"}
31 for i, v in ipairs(t) do
32 print(i, v)
33 end
34 -- prints:
35 -- 1 a
36 -- 2 b
37 -- 3 c
39 print(string.concat(",", t))
40 -- prints: a,b,c
42 function alphabet()
43 local letter = nil
44 return function()
45 if letter == nil then
46 letter = "a"
47 elseif letter == "z" then
48 return nil
49 else
50 letter = string.char(string.byte(letter) + 1)
51 end
52 return letter
53 end
54 end
56 for i, v in ipairs(alphabet()) do
57 print(i, v)
58 end
59 -- prints:
60 -- 1 a
61 -- 2 b
62 -- 3 c
63 -- ...
64 -- 25 y
65 -- 26 z
67 print(string.concat(",", alphabet()))
68 -- 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
70 function filter(f)
71 return function(seq)
72 return coroutine.wrap(function()
73 for i, v in ipairs(seq) do f(v) end
74 end)
75 end
76 end
78 alpha_beta_x = filter(function(v)
79 if v == "a" then
80 coroutine.yield("alpha")
81 elseif v == "b" then
82 coroutine.yield("beta")
83 elseif type(v) == "number" then
84 for i = 1, v do
85 coroutine.yield("X")
86 end
87 end
88 end)
90 print((","):concat(alpha_beta_x{"a", 3, "b", "c", "d"}))
91 -- prints: alpha,X,X,X,beta
93 print((","):concat(alpha_beta_x(alphabet())))
94 -- prints: alpha,beta
97 C part of the library
98 ---------------------
100 In ``seqlualib.h``, the following macro is defined:
102 #define seqlua_iterloop(L, iter, idx) \
103 for ( \
104 seqlua_iterinit((L), (iter), (idx)); \
105 seqlua_iternext(iter); \
106 )
108 and
110 #define seqlua_iterloopauto(L, iter, idx) \
111 for ( \
112 seqlua_iterinit((L), (iter), (idx)); \
113 seqlua_iternext(iter); \
114 lua_pop((L), 1) \
115 )
117 This macro allows iteration over either tables or iterator functions as the
118 following example function demonstrates:
120 int printcsv(lua_State *L) {
121 seqlua_Iterator iter;
122 seqlua_iterloop(L, &iter, 1) {
123 if (seqlua_itercount(&iter) > 1) fputs(",", stdout);
124 fputs(luaL_tolstring(L, -1, NULL), stdout);
125 // two values need to be popped (the value pushed by
126 // seqlua_iternext and the value pushed by luaL_tolstring)
127 lua_pop(L, 2);
128 }
129 fputs("\n", stdout);
130 return 0;
131 }
133 printcsv{"a", "b", "c"}
134 -- prints: a,b,c
136 printcsv(assert(io.open("testfile")):lines())
137 -- prints: line1,line2,... of "testfile"
139 NOTE: During iteration using ``seqlua_iterloop``, ``seqlua_iterloopauto``, or
140 ``seqlua_iterinit``, three extra elements are stored on the stack (additionally
141 to the value). These extra elements are removed automatically when the loop ends
142 (i.e. when ``seqlua_iternext`` returns zero). The value pushed onto the stack
143 for every iteration step has to be removed manually from the stack, unless
144 ``seqlua_iterloopauto`` is used.
147 Respected metamethods
148 ---------------------
150 Regarding the behavior of the Lua functions and the C functions and macros
151 provided by this extension, an existing ``__index`` metamethod will be
152 respected automatically. An existing ``__ipairs`` metamethod, however, takes
153 precedence.
155 If the ``__ipairs`` field of a value's metatable is set, then it must always
156 refer to a function. When starting iteration over a value with such a
157 metamethod being set, then this function is called with ``self`` (i.e. the
158 value itself) passed as first argument. The return values of the ``__ipairs``
159 metamethod may take one of the following 4 forms:
161 * ``return function_or_callable, static_argument, startindex`` causes the three
162 arguments to be returned by ``ipairs`` without further modification. Using
163 the C macros and functions for iteration, the behavior is according to the
164 generic loop statement in Lua:
165 ``for i, v in function_or_callable, static_argument, startindex do ... end``
166 * ``return "raw", table`` will result in iteration over the table ``table``
167 using ``lua_rawgeti``
168 * ``return "index", table_or_userdata`` will result in iteration over the table
169 or userdata while respecting any ``__index`` metamethod of the table or
170 userdata value
171 * ``return "call", function_or_callable`` will use the callable value as
172 (function) iterator where the function is expected to return a single value
173 without any index (the index is inserted automatically when using the
174 ``ipairs`` function for iteration)
176 These possiblities are demonstrated by the following example code:
178 require "seqlua"
180 do
181 local function ipairsaux(t, i)
182 i = i + 1
183 if i <= 3 then
184 return i, t[i]
185 end
186 end
187 custom = setmetatable(
188 {"one", "two", "three", "four", "five"},
189 {
190 __ipairs = function(self)
191 return ipairsaux, self, 0
192 end
193 }
194 )
195 end
196 print(string.concat(",", custom))
197 -- prints: one,two,three
198 -- (note that "four" and "five" are not printed)
200 tbl = {"alpha", "beta"}
202 proxy1 = setmetatable({}, {__index = tbl})
203 for i, v in ipairs(proxy1) do print(i, v) end
204 -- prints:
205 -- 1 alpha
206 -- 2 beta
208 proxy2 = setmetatable({}, {
209 __ipairs = function(self)
210 return "index", proxy1
211 end
212 })
213 for i, v in ipairs(proxy2) do print(i, v) end
214 -- prints:
215 -- 1 alpha
216 -- 2 beta
217 print(proxy2[1])
218 -- prints: nil
220 cursor = setmetatable({
221 "alice", "bob", "charlie", pos=1
222 }, {
223 __call = function(self)
224 local value = self[self.pos]
225 if value == nil then
226 self.pos = 1
227 else
228 self.pos = self.pos + 1
229 end
230 return value
231 end,
232 __ipairs = function(self)
233 return "call", self
234 end
235 })
236 for i, v in ipairs(cursor) do print(i, v) end
237 -- prints:
238 -- 1 alice
239 -- 2 bob
240 -- 3 charlie
241 print(cursor())
242 -- prints: alice
243 for i, v in ipairs(cursor) do print(i, v) end
244 -- prints:
245 -- 1 bob
246 -- 2 charlie
247 -- (note that "alice" has been returned earlier)
249 coefficients = setmetatable({1.25, 3.14, 17.5}, {
250 __index = function(self) return 1 end,
251 __ipairs = function(self) return "raw", self end
252 })
253 for i, v in ipairs(coefficients) do print(i, v) end
254 -- prints:
255 -- 1 1.25
256 -- 2 3.14
257 -- 3 17.5
258 -- (note that iteration terminates even if coefficients[4] == 1)
259 print(coefficients[4])
260 -- prints: 1

Impressum / About Us