From 3c99c1c4af8d0fe71f1bbc82150c6e2d36f337dc Mon Sep 17 00:00:00 2001 From: Steve Kemp Date: Sun, 9 Oct 2022 18:22:25 +0300 Subject: [PATCH] Rewrite the (while ..) macro. This now allows the use of an arbitrary body, as can be seen in the following test: ``` (set! p 4) (while (<= p 10) (print "Pxx: %s" p) (set! p (+ p 1) true) ) ``` The new approach defines a local lambda, with a random name, and calls that recursively when the conditional is true. This closes #21, though we still need to use the three-argument form of (set!) as our scoping/environment is confused - that is tracked in #22. --- stdlib/mal.lisp | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/stdlib/mal.lisp b/stdlib/mal.lisp index 36511d8..5b0d5d6 100644 --- a/stdlib/mal.lisp +++ b/stdlib/mal.lisp @@ -35,23 +35,18 @@ (defmacro! when (fn* (pred &rest) `(if ~pred (do ~@rest)))) ;; -;; Part of our while-implementation. ;; If the specified predicate is true, then run the body. ;; ;; NOTE: This recurses, so it will eventually explode the stack. ;; -(define while-fun (lambda (predicate body) - (when (predicate) - (body) - (while-fun predicate body)))) - -;; -;; Now a macro to use the while-fun body as part of a while-function -;; -(defmacro! while (fn* (expression body) - (list 'while-fun - (list 'lambda '() expression) - (list 'lambda '() body)))) +(defmacro! while (fn* (condition &body) + (let* (inner-sym (gensym)) + `(let* (~inner-sym (fn* () + (if ~condition + (do + ~@body + (~inner-sym))))) + (~inner-sym))))) ;;