ref: 40b76da107627b529cabd18c6c03304a6226e4d5
parent: db405e1a4af5f93671d269d65fa716b8dbdcbdf0
author: Sigrid Solveig Haflínudóttir <[email protected]>
date: Thu Dec 5 20:04:09 EST 2024
for-each: work with multiple lists Fixes: https://todo.sr.ht/~ft/femtolisp/15
--- a/flisp.c
+++ b/flisp.c
@@ -2099,19 +2099,32 @@
BUILTIN("for-each", for_each)
{
- argcount(nargs, 2);
+ if(nargs < 2)
+ argcount(nargs, 2);
intptr_t argSP = args-FL(stack);
assert(argSP >= 0 && argSP < FL(nstack));
- if(FL(sp)+2 > FL(nstack))
+ if(FL(sp)+nargs > FL(nstack))
grow_stack();
- FL(sp) += 2;
- while(iscons(FL(stack)[argSP+1])){
- FL(stack)[FL(sp)-2] = FL(stack)[argSP];
- FL(stack)[FL(sp)-1] = car_(FL(stack)[argSP+1]);
- _applyn(1);
- FL(stack)[argSP+1] = cdr_(FL(stack)[argSP+1]);
+ FL(sp) += nargs;
+
+ for(uint32_t n = 0;; n++){
+ FL(stack)[FL(sp)-nargs] = FL(stack)[argSP];
+
+ uint32_t i, c;
+ for(i = c = 1; i < nargs; i++){
+ if(iscons(FL(stack)[argSP+i])){
+ FL(stack)[FL(sp)-nargs+i] = car_(FL(stack)[argSP+i]);
+ FL(stack)[argSP+i] = cdr_(FL(stack)[argSP+i]);
+ c++;
+ }
+ if(c != i+1 && c != 1)
+ lerrorf(FL(ArgError), "list %d is of different length", i-1);
+ }
+ if(c == 1)
+ break;
+ _applyn(nargs-1);
}
- POPN(2);
+ POPN(nargs);
return FL(t);
}
--- a/test/unittest.lsp
+++ b/test/unittest.lsp
@@ -393,6 +393,15 @@
(assert (null? (caaar '())))
(assert (null? (cdddr '())))
+;; for-each with multiple lists
+(define q '())
+(for-each (λ (x y z) (set! q (cons (+ x y z) q)))
+ '(1 2 3) '(4 5 6) '(7 8 9))
+(assert (equal? q '(18 15 12)))
+(assert-fail (eval '(for-each (λ (x y) (+ x y)) '(1) '(2 3))))
+(assert-fail (eval '(for-each (λ (x y) (+ x y)) '(1 2) '(3))))
+(assert-fail (eval '(for-each (λ (x y z) (+ x y z)) '(1 2) '(3) '(4 5))))
+
;; make many initialized tables large enough not to be stored in-line
(for 1 100 (λ (i)
(table eq? 2 eqv? 2