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@25
|
6 * allow ``ipairs(seq)`` to accept tables as well as functions,
|
jbe@25
|
7 * add a new function ``string.concat(separator, seq)`` to concat either table
|
jbe@25
|
8 entries or function return values,
|
jbe@23
|
9 * provide auxiliary C functions and macros to simplify iterating over both
|
jbe@0
|
10 tables and iterator functions with the same statement.
|
jbe@0
|
11
|
jbe@25
|
12 In other words:
|
jbe@25
|
13 When calling ``ipairs(seq)`` or ``string.concat(separator, seq)``,
|
jbe@25
|
14 then ``seq`` may either be a (table) sequence or a (function) iterator.
|
jbe@25
|
15 Auxiliary C functions and macros are provided to simplify extending your own
|
jbe@25
|
16 C functions in the same manner.
|
jbe@25
|
17
|
jbe@0
|
18 This library completely ignores the ``__ipairs`` metamethod (as it is
|
jbe@18
|
19 deprecated since Lua 5.3.0-alpha). It respects, however, any ``__index`` and
|
jbe@18
|
20 ``__call`` metamethods (this may cause unexpected behavior when passing
|
jbe@18
|
21 callable tables to ``ipairs``). The ``__call`` metamethod takes precedence over
|
jbe@18
|
22 an existing ``__index`` metamethod.
|
jbe@0
|
23
|
jbe@0
|
24
|
jbe@0
|
25
|
jbe@0
|
26 Lua part of the library
|
jbe@0
|
27 -----------------------
|
jbe@0
|
28
|
jbe@25
|
29 The modified ``ipairs(seq)`` function and the new ``string.concat`` function
|
jbe@25
|
30 work as demonstrated in the following examples:
|
jbe@0
|
31
|
jbe@0
|
32 require "seqlua"
|
jbe@0
|
33
|
jbe@0
|
34 t = {"a", "b", "c"}
|
jbe@0
|
35
|
jbe@0
|
36 for i, v in ipairs(t) do
|
jbe@0
|
37 print(i, v)
|
jbe@0
|
38 end
|
jbe@0
|
39 -- prints:
|
jbe@0
|
40 -- 1 a
|
jbe@0
|
41 -- 2 b
|
jbe@0
|
42 -- 3 c
|
jbe@0
|
43
|
jbe@25
|
44 print(string.concat(",", t))
|
jbe@25
|
45 -- prints: a,b,c
|
jbe@25
|
46
|
jbe@19
|
47 function alphabet()
|
jbe@0
|
48 local letter = nil
|
jbe@0
|
49 return function()
|
jbe@0
|
50 if letter == nil then
|
jbe@19
|
51 letter = "a"
|
jbe@19
|
52 elseif letter == "z" then
|
jbe@0
|
53 return nil
|
jbe@0
|
54 else
|
jbe@0
|
55 letter = string.char(string.byte(letter) + 1)
|
jbe@0
|
56 end
|
jbe@0
|
57 return letter
|
jbe@0
|
58 end
|
jbe@0
|
59 end
|
jbe@0
|
60
|
jbe@23
|
61 for i, v in ipairs(alphabet()) do
|
jbe@0
|
62 print(i, v)
|
jbe@0
|
63 end
|
jbe@0
|
64 -- prints:
|
jbe@0
|
65 -- 1 a
|
jbe@0
|
66 -- 2 b
|
jbe@0
|
67 -- 3 c
|
jbe@0
|
68 -- ...
|
jbe@0
|
69 -- 25 y
|
jbe@0
|
70 -- 26 z
|
jbe@0
|
71
|
jbe@25
|
72 print(string.concat(",", alphabet()))
|
jbe@25
|
73 -- 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
|
74
|
jbe@26
|
75 function filter(f)
|
jbe@26
|
76 return function(seq)
|
jbe@26
|
77 return coroutine.wrap(function()
|
jbe@26
|
78 for i, v in ipairs(seq) do f(v) end
|
jbe@26
|
79 end)
|
jbe@26
|
80 end
|
jbe@0
|
81 end
|
jbe@19
|
82
|
jbe@26
|
83 number_to_trues = filter(function(v)
|
jbe@23
|
84 local type_v = type(v)
|
jbe@23
|
85 if type_v == "string" then
|
jbe@23
|
86 coroutine.yield(v)
|
jbe@23
|
87 elseif type_v == "number" then
|
jbe@23
|
88 for i = 1, v do
|
jbe@23
|
89 coroutine.yield(true)
|
jbe@23
|
90 end
|
jbe@0
|
91 end
|
jbe@26
|
92 end)
|
jbe@0
|
93
|
jbe@26
|
94 for v in number_to_trues{"a", "b", 3, "c"} do
|
jbe@0
|
95 print(v)
|
jbe@0
|
96 end
|
jbe@0
|
97 -- prints:
|
jbe@23
|
98 -- a
|
jbe@23
|
99 -- b
|
jbe@23
|
100 -- true
|
jbe@23
|
101 -- true
|
jbe@23
|
102 -- true
|
jbe@23
|
103 -- c
|
jbe@0
|
104
|
jbe@26
|
105 print((","):concat(number_to_trues{"a", "b", 3, "c"}))
|
jbe@25
|
106 -- prints: a,b,true,true,true,c
|
jbe@25
|
107
|
jbe@0
|
108
|
jbe@0
|
109 C part of the library
|
jbe@0
|
110 ---------------------
|
jbe@0
|
111
|
jbe@0
|
112 In ``seqlualib.h``, the following macro is defined:
|
jbe@0
|
113
|
jbe@0
|
114 #define seqlua_iterloop(L, iter, idx) \
|
jbe@0
|
115 for ( \
|
jbe@0
|
116 seqlua_iterinit((L), (iter), (idx)); \
|
jbe@0
|
117 seqlua_iternext(iter); \
|
jbe@25
|
118 )
|
jbe@25
|
119
|
jbe@25
|
120 and
|
jbe@25
|
121
|
jbe@25
|
122 #define seqlua_iterloopauto(L, iter, idx) \
|
jbe@25
|
123 for ( \
|
jbe@25
|
124 seqlua_iterinit((L), (iter), (idx)); \
|
jbe@25
|
125 seqlua_iternext(iter); \
|
jbe@0
|
126 lua_pop((L), 1) \
|
jbe@0
|
127 )
|
jbe@0
|
128
|
jbe@23
|
129 This macro allows iteration over either tables or iterator functions as the
|
jbe@23
|
130 following example function demonstrates:
|
jbe@0
|
131
|
jbe@0
|
132 int printcsv(lua_State *L) {
|
jbe@0
|
133 seqlua_Iterator iter;
|
jbe@0
|
134 seqlua_iterloop(L, &iter, 1) {
|
jbe@0
|
135 if (seqlua_itercount(&iter) > 1) fputs(",", stdout);
|
jbe@0
|
136 fputs(luaL_tolstring(L, -1, NULL), stdout);
|
jbe@25
|
137 // two values need to be popped (the value pushed by
|
jbe@25
|
138 // seqlua_iternext and the value pushed by luaL_tolstring)
|
jbe@25
|
139 lua_pop(L, 2);
|
jbe@0
|
140 }
|
jbe@0
|
141 fputs("\n", stdout);
|
jbe@0
|
142 return 0;
|
jbe@0
|
143 }
|
jbe@0
|
144
|
jbe@11
|
145 printcsv{"a", "b", "c"}
|
jbe@11
|
146 -- prints: a,b,c
|
jbe@11
|
147
|
jbe@11
|
148 printcsv(assert(io.open("testfile")):lines())
|
jbe@11
|
149 -- prints: line1,line2,... of "testfile"
|
jbe@0
|
150
|
jbe@0
|
151
|