From 3deba098ab6f20dd6016f7943b3af64f8f045308 Mon Sep 17 00:00:00 2001 From: "Basil L. Contovounesios" Date: Sun, 28 Feb 2021 12:16:45 +0000 Subject: [PATCH] Fix off-by-one regression in --iterate * dash.el (--iterate): Evaluate FORM N-1, not N, times, fixing a regression in Dash 2.18.0. Don't evaluate INIT if N is zero, fixing a bug since the introduction of the macro. * dev/examples.el (-flatten-n): Add regression test. (-iterate): Test for superfluous evaluations. Fixes #373. --- dash.el | 15 +++++++++------ dev/examples.el | 9 +++++++-- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/dash.el b/dash.el index 80d4ef91..9187c662 100644 --- a/dash.el +++ b/dash.el @@ -685,12 +685,15 @@ Thus function FN should return a list." (defmacro --iterate (form init n) "Anaphoric version of `-iterate'." (declare (debug (form form form))) - (let ((res (make-symbol "result"))) - `(let ((it ,init) ,res) - (dotimes (_ ,n) - (push it ,res) - (setq it ,form)) - (nreverse ,res)))) + (let ((res (make-symbol "result")) + (len (make-symbol "n"))) + `(let ((,len ,n)) + (when (> ,len 0) + (let* ((it ,init) + (,res (list it))) + (dotimes (_ (1- ,len)) + (push (setq it ,form) ,res)) + (nreverse ,res)))))) (defun -iterate (fun init n) "Return a list of iterated applications of FUN to INIT. diff --git a/dev/examples.el b/dev/examples.el index 35d3ecc8..a0b115f2 100644 --- a/dev/examples.el +++ b/dev/examples.el @@ -343,7 +343,8 @@ new list." (-flatten-n 3 '((1 2) ((3 4) ((5 6))))) => '(1 2 3 4 5 6) (-flatten-n 0 '(3 4)) => '(3 4) (-flatten-n 0 '((1 2) (3 4))) => '((1 2) (3 4)) - (-flatten-n 0 '(((1 2) (3 4)))) => '(((1 2) (3 4)))) + (-flatten-n 0 '(((1 2) (3 4)))) => '(((1 2) (3 4))) + (-flatten-n 1 '(((1 . 2)) ((3 . 4)))) => '((1 . 2) (3 . 4))) (defexamples -replace (-replace 1 "1" '(1 2 3 4 3 2 1)) => '("1" 2 3 4 3 2 "1") @@ -606,7 +607,11 @@ value rather than consuming a list to produce a single value." (--iterate nil nil 0) => () (--iterate nil nil 1) => '(nil) (--iterate nil nil 2) => '(nil nil) - (--iterate (setq it -1) 1 3) => '(1 -1 -1)) + (--iterate (setq it -1) 1 3) => '(1 -1 -1) + (let (l) (--iterate (push 1 l) (push 0 l) -1) l) => () + (let (l) (--iterate (push 1 l) (push 0 l) 0) l) => () + (let (l) (--iterate (push 1 l) (push 0 l) 1) l) => '(0) + (let (l) (--iterate (push 1 l) (push 0 l) 2) l) => '(1 0)) (defexamples -unfold (-unfold (lambda (x) (unless (= x 0) (cons x (1- x)))) 10) => '(10 9 8 7 6 5 4 3 2 1)