new 33c0e9569b8825f53d773343cc90e4377118edca
[tagua/yd.git] / src / luaapi / lfunclib.c
bloba5daff67bbbf7e58bde59bbe490046f0c9283705
1 /*
2 Copyright (c) 2006 Maurizio Monge <maurizio.monge@kdemail.net>
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This file has been contributed by Rici Lake under the Lua license:
11 Copyright (c) 2006 Rici Lake
13 Permission is hereby granted, free of charge, to any person obtaining a copy
14 of this software and associated documentation files (the "Software"), to
15 deal in the Software without restriction, including without limitation the
16 rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
17 sell copies of the Software, and to permit persons to whom the Software is
18 furnished to do so, subject to the following conditions:
20 The above copyright notice and this permission notice shall be included in
21 all copies or substantial portions of the Software.
23 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29 THE SOFTWARE.
32 #include <lua.h>
33 #include <lauxlib.h>
34 #include <lualib.h>
35 #include "luaapi/lfunclib.h"
37 /* "Constructors" (or collectors, if you prefer). Take an iterator
38 * and return a value.
41 /* foreach just applies the self-function to each iteration tuple
42 * in turn. The return the result is the last return value
43 * of the function
45 * func:foreach(<iter>) ==>
47 * local rv...
48 * for val... in <iter> do
49 * rv... = func(val...)
50 * end
51 * return rv...
55 static int f_foreach (lua_State *L) {
56 lua_settop(L, 4);
57 for (;;) {
58 int callbase = lua_gettop(L);
59 lua_pushvalue(L, 2);
60 lua_pushvalue(L, 3);
61 lua_pushvalue(L, 4);
62 lua_call(L, 2, LUA_MULTRET);
63 if (lua_isnoneornil(L, callbase + 1)) {
64 lua_settop(L, callbase);
65 return callbase - 4;
67 lua_pushvalue(L, callbase + 1);
68 lua_replace(L, 4); /* ctl = newctl */
69 lua_pushvalue(L, 1);
70 if (callbase == 4) {
71 lua_insert(L, 5);
73 else {
74 lua_replace(L, 5);
75 for (; callbase > 5; --callbase)
76 lua_remove(L, callbase);
78 lua_call(L, lua_gettop(L) - 5, LUA_MULTRET);
82 /* first calls the self-function on each iteration tuple in turn,
83 * and returns the first true (not non-null) return of the self-function.
85 func:first(<iter>) ==>
86 for val... in <iter> do
87 local rv... = func(val...)
88 if (rv...) then return rv... end
89 end
90 end
92 1: self_func 2: iter_func 3: base 4: control
93 5: copy_self 6: returned control
96 static int f_first (lua_State *L) {
97 for (;;) {
98 lua_settop(L, 4);
99 lua_pushvalue(L, 1);
100 lua_pushvalue(L, 2);
101 lua_pushvalue(L, 3);
102 lua_pushvalue(L, 4);
103 lua_call(L, 2, LUA_MULTRET);
104 if (lua_isnoneornil(L, 6)) return 0;
105 lua_pushvalue(L, 6);
106 lua_replace(L, 4);
107 lua_call(L, lua_gettop(L) - 5, LUA_MULTRET);
108 if (lua_toboolean(L, 5)) return lua_gettop(L) - 5;
113 func:fold1(init, <iter>)
114 for val... in <iter> do
115 init = func(init, val...)
117 return init
119 func:fold2(init, <iter>)
120 for val, rest... in <iter> do
121 init = func(init, rest...)
123 return init
126 1: self_func 2: init val 3: iter_func 4: base 5: control
127 6: copy self 7: copy init 8: returned control
128 6: returned init
131 static int f_fold1 (lua_State *L) {
132 lua_settop(L, 5);
133 for (;;) {
134 lua_pushvalue(L, 1);
135 lua_pushvalue(L, 2);
136 lua_pushvalue(L, 3);
137 lua_pushvalue(L, 4);
138 lua_pushvalue(L, 5);
139 lua_call(L, 2, LUA_MULTRET);
140 if (lua_isnoneornil(L, 8)) { lua_settop(L, 7); return 1; }
141 lua_pushvalue(L, 8);
142 lua_replace(L, 5);
143 lua_call(L, lua_gettop(L) - 6, 1);
144 lua_replace(L, 2);
149 static int f_fold2 (lua_State *L) {
150 lua_settop(L, 5);
151 for (;;) {
152 lua_pushvalue(L, 1);
153 lua_pushvalue(L, 2);
154 lua_pushvalue(L, 3);
155 lua_pushvalue(L, 4);
156 lua_pushvalue(L, 5);
157 lua_call(L, 2, LUA_MULTRET);
158 if (lua_isnoneornil(L, 8)) { lua_settop(L, 7); return 1; }
159 lua_pushvalue(L, 8);
160 lua_replace(L, 5);
161 lua_remove(L, 8);
162 lua_call(L, lua_gettop(L) - 6, 1);
163 lua_replace(L, 2);
168 /* func:reduce{1,2}(default, <iter>) is like
169 * func:fold{1,2}(init, <iter>) except that the initial
170 * value is taken from the first iteration of the loop.
171 * If the loop fails to produce even one value, the default
172 * argument is returned. Otherwise, default is not used.
175 static int f_reduce1 (lua_State *L) {
176 lua_settop(L, 5);
177 lua_pushvalue(L, 3);
178 lua_pushvalue(L, 4);
179 lua_pushvalue(L, 5);
180 lua_call(L, 2, 1);
181 if (lua_isnil(L, -1)) { lua_settop(L, 2); return 1; }
182 lua_pushvalue(L, -1);
183 lua_replace(L, 2);
184 lua_replace(L, 5);
185 return f_fold1(L);
188 static int f_reduce2 (lua_State *L) {
189 lua_settop(L, 5);
190 lua_pushvalue(L, 3);
191 lua_pushvalue(L, 4);
192 lua_pushvalue(L, 5);
193 lua_call(L, 2, 2);
194 if (lua_isnil(L, -2)) { lua_settop(L, 2); return 1; }
195 lua_replace(L, 2);
196 lua_replace(L, 5);
197 return f_fold2(L);
200 /* These ones could easily be implemented in terms of fold, but
201 * the direct implementation uses fewer temporary objects.
202 * Unlike the other stuff in this module, these are not
203 * function methods; they're just functions in the collect
204 * library.
207 /* collect
208 * .keys => an array of the keys (or control variable, anyway)
209 * .vals => an array of the second iterator return
210 * .pairs => an table of (first) = (second)
211 * .keyset => a set of (first) = true
212 * .valset => a set of (second) = true
215 static int c_advance_aux (lua_State *L, int iter, int nr, int cb) {
216 lua_settop(L, cb - 1);
217 lua_pushvalue(L, iter);
218 lua_pushvalue(L, iter+1);
219 lua_pushvalue(L, iter+2);
220 lua_call(L, 2, nr);
221 if (lua_isnoneornil(L, cb)) return 0;
222 lua_pushvalue(L, cb);
223 lua_replace(L, iter+2);
224 return 1;
227 static int c_keys (lua_State *L) {
228 int index = 0;
229 lua_newtable(L);
230 lua_insert(L, 1);
231 while (c_advance_aux(L, 2, 1, 5))
232 lua_rawseti(L, 1, ++index);
233 lua_settop(L, 1);
234 return 1;
237 static int c_vals (lua_State *L) {
238 int index = 0;
239 lua_newtable(L);
240 lua_insert(L, 1);
241 while (c_advance_aux(L, 2, 2, 5))
242 lua_rawseti(L, 1, ++index);
243 lua_settop(L, 1);
244 return 1;
247 static int c_pairs (lua_State *L) {
248 lua_newtable(L);
249 lua_insert(L, 1);
250 while (c_advance_aux(L, 2, 2, 5))
251 lua_rawset(L, 1);
252 lua_settop(L, 1);
253 return 1;
256 static int c_keyset (lua_State *L) {
257 lua_newtable(L);
258 lua_insert(L, 1);
259 while (c_advance_aux(L, 2, 1, 5)) {
260 lua_pushboolean(L, 1);
261 lua_rawset(L, 1);
263 lua_settop(L, 1);
264 return 1;
267 static int c_valset (lua_State *L) {
268 lua_newtable(L);
269 lua_insert(L, 1);
270 while (c_advance_aux(L, 2, 2, 5)) {
271 lua_pushboolean(L, 1);
272 lua_rawset(L, 1);
274 lua_settop(L, 1);
275 return 1;
279 /* func:dropping(i) -> function
280 * The returned function drops its ith argument (default 1) and
281 * returns the application of func to the remaining arguments.
282 * This is useful for removing keys from iterators in some of
283 * these iterator methods
286 static int f_dropping_aux (lua_State *L) {
287 int i = lua_tointeger(L, lua_upvalueindex(2));
288 int top = lua_gettop(L);
289 lua_pushvalue(L, lua_upvalueindex(1));
290 lua_insert(L, 1);
291 if (i <= top) { lua_remove(L, i + 1); --top; }
292 lua_call(L, top, LUA_MULTRET);
293 return lua_gettop(L);
296 static int f_dropping (lua_State *L) {
297 luaL_checkany(L, 1);
298 lua_settop(L, 2);
299 if (lua_isnil(L, 2)) {
300 lua_pushinteger(L, 1);
301 lua_replace(L, 2);
303 else {
304 luaL_checknumber(L, 2);
306 lua_pushcclosure(L, f_dropping_aux, 2);
307 return 1;
310 /* Yuk. */
311 static int aux_nups (lua_State *L) {
312 lua_Debug ar;
313 lua_getstack(L, 0, &ar);
314 lua_getinfo(L, "u", &ar);
315 return ar.nups;
319 static int aux_insertupvalues (lua_State *L, int where) {
320 int i;
321 int nups = aux_nups(L);
322 luaL_checkstack(L, nups, "insert upvalues");
323 if (where > 0) {
324 for (i = 1; i <= nups; ++i, ++where) {
325 lua_pushvalue(L, lua_upvalueindex(i));
326 lua_insert(L, where);
329 else if (where < 0) {
330 --where;
331 for (i = 1; i <= nups; ++i) {
332 lua_pushvalue(L, lua_upvalueindex(i));
333 lua_insert(L, where);
336 else {
337 for (i = 1; i <= nups; ++i)
338 lua_pushvalue(L, lua_upvalueindex(i));
340 return nups;
343 /* func:partial(...) -> function
344 * The returned function is the original function with the given
345 * arguments "filled in" from the left.
348 static int f_partial_aux (lua_State *L) {
349 aux_insertupvalues(L, 1);
350 lua_call(L, lua_gettop(L) - 1, LUA_MULTRET);
351 return lua_gettop(L);
354 static int f_partial (lua_State *L) {
355 int top = lua_gettop(L);
356 if (top >= LUAI_MAXUPVALUES) {
357 luaL_error(L, "too many arguments, maximum is %d", LUAI_MAXUPVALUES);
359 if (lua_tocfunction(L, 1) == f_partial_aux) {
360 int i = 1;
361 /* We should find out how many there are, really. */
362 luaL_checkstack(L, LUAI_MAXUPVALUES, "partial combination");
363 for (; lua_getupvalue(L, 1, i); ++i) {
364 lua_insert(L, i + 1);
366 top += i - 2;
368 lua_pushcclosure(L, f_partial_aux, top);
369 return 1;
372 /* Building block */
373 #if 0
374 static int f_reorder_aux (lua_State *L) {
375 const char *format = lua_tostring(L, lua_upvalueindex(1));
376 int nups = lua_tointeger(L, lua_upvalueindex(2));
377 int top = lua_gettop(L);
378 lua_pushvalue(L, lua_upvalueindex(3)); /* The function */
379 for (;;) {
380 switch (*format++) {
381 case '%': {
382 int base = *format++ - '0';
383 int ch;
384 for (ch = *format; '0' <= ch && ch <= '9'; ch = *++format)
385 base = base * 10 + ch - '0';
386 if (ch == '.') {
387 while (*++format == '.');
388 if (base <= nups) {
389 luaL_checkstack(L, nups - base, "");
390 for (; base <= nups; ++base)
391 lua_pushvalue(L, lua_upvalueindex(base + 3));
394 else if (base <= nups)
395 lua_pushvalue(L, lua_upvalueindex(base));
396 else
397 lua_pushnil(L);
398 break;
400 case '$': {
401 /* duplicate above, but with top */
403 case '(': {
404 int func = lua_gettop(L);
405 /* recursive call */
406 /* get count or ... */
407 lua_call(L, lua_gettop(L) - func, nups);
408 break;
410 case ')': {
411 return;
413 case '\0': {
414 return lua_gettop(L) - top;
419 #endif
422 /* Functions which take iterators and return iterators */
424 /* for vals... in f:map(<iter>) do <block> end
425 * ==>
426 * for temp... in <iter> do
427 * local vals... = f(temp...)
428 * <block>
429 * end
432 static int f_map_aux (lua_State *L) {
433 lua_settop(L, 0);
434 lua_pushvalue(L, lua_upvalueindex(1));
435 lua_pushvalue(L, lua_upvalueindex(2));
436 lua_pushvalue(L, lua_upvalueindex(3));
437 lua_pushvalue(L, lua_upvalueindex(4));
438 lua_call(L, 2, LUA_MULTRET);
439 if (lua_isnoneornil(L, 2)) return 0;
440 lua_pushvalue(L, 2);
441 lua_replace(L, lua_upvalueindex(4));
442 lua_call(L, lua_gettop(L) - 1, LUA_MULTRET);
443 return lua_gettop(L);
446 static int f_map (lua_State *L) {
447 lua_settop(L, 4);
448 lua_pushcclosure(L, f_map_aux, 4);
449 return 1;
452 /* Possibly more useful.
453 * for k, vals... in f:mapvals(<iter>) do <block> end
454 * ==>
455 * for k, temp... in <iter> do
456 * local vals... = f(temp...)
457 * <block>
458 * end
461 static int f_mapvals_aux (lua_State *L) {
462 lua_pushvalue(L, lua_upvalueindex(2));
463 lua_insert(L, 1);
464 lua_call(L, lua_gettop(L) - 1, LUA_MULTRET);
465 if (lua_isnoneornil(L, 1)) return 0;
466 lua_pushvalue(L, lua_upvalueindex(1));
467 lua_insert(L, 2);
468 lua_call(L, lua_gettop(L) - 2, LUA_MULTRET);
469 return lua_gettop(L);
472 /* Factor this out */
473 static int f_mapvals (lua_State *L) {
474 lua_settop(L, 4);
475 lua_pushvalue(L, 1);
476 lua_pushvalue(L, 2);
477 lua_pushcclosure(L, f_mapvals_aux, 2);
478 lua_replace(L, 2);
479 return 3;
483 /* for vals... in f:filter(<iter>) do <block> end
484 * ==>
485 * for vals... in <iter> do
486 * if f(vals...) then
487 * <block>
488 * end
489 * end
492 static int f_filter_aux (lua_State *L) {
493 int i, top;
494 do {
495 lua_settop(L, 2);
496 lua_pushvalue(L, 1);
497 lua_pushvalue(L, 2);
498 lua_pushvalue(L, lua_upvalueindex(2));
499 lua_replace(L, 2); /* Obj IterFunc Obj Ctl */
500 lua_call(L, 2, LUA_MULTRET);
501 top = lua_gettop(L);
502 if (top == 1 || lua_isnil(L, 2)) return 0;
503 luaL_checkstack(L, top, "filtered iterator returned too many results");
504 lua_pushvalue(L, lua_upvalueindex(1));
505 for (i = 2; i <= top; ++i) lua_pushvalue(L, i);
506 lua_call(L, top - 1, 1);
507 } while (!lua_toboolean(L, -1));
508 lua_pop(L, 1);
509 return top - 1;
512 static int f_filter (lua_State *L) {
513 lua_settop(L, 4);
514 lua_pushvalue(L, 1);
515 lua_pushvalue(L, 2);
516 lua_pushcclosure(L, f_filter_aux, 2);
517 lua_replace(L, 2);
518 return 3;
521 /* TODO:
522 * Things to add:
523 * pcall, coroutine.wrap -> both are appropriate function methods
524 * possibly some introspection stuff
525 * something like the new python with modifier: i.e. safely do a call
526 * with a prelude and postlude.
529 static const luaL_reg func_funcs[] = {
530 { "first", f_first },
531 { "foreach", f_foreach },
532 { "fold1", f_fold1 },
533 { "fold2", f_fold2 },
534 { "reduce1", f_reduce1 },
535 { "reduce2", f_reduce2 },
536 { "dropping", f_dropping },
537 { "partial", f_partial },
538 { "map", f_map },
539 { "mapvals", f_mapvals },
540 { "filter", f_filter },
541 { NULL, NULL }
544 static const luaL_reg collect_funcs[] = {
545 { "keys", c_keys },
546 { "vals", c_vals },
547 { "pairs", c_pairs },
548 { "keyset", c_keyset },
549 { "valset", c_valset },
550 { NULL, NULL }
553 int luaopen_func (lua_State *L) {
554 luaL_register(L, LUA_FUNCLIBNAME, func_funcs);
555 lua_pushcfunction(L, luaopen_func); /* A function */
556 if (!lua_getmetatable(L, -1)) {
557 lua_createtable(L, 0, 0);
558 lua_pushvalue(L, -3);
559 lua_setfield(L, -2, "__index");
560 lua_setmetatable(L, -2);
561 lua_pop(L, 1);
563 else lua_pop(L, 2);
564 return 1;
567 int luaopen_collect (lua_State *L) {
568 luaL_register(L, LUA_COLLECTLIBNAME, collect_funcs);
569 return 1;