Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 44s
defmacro/macrolet/symbol-macrolet/macroexpand, gensym/gentemp, full LOOP macro (loop.sx) with all clause types. Phase 2 dynamic variables: cl-apply-dyn, cl-letstar-bind, cl-mark-special!/cl-special? for defvar/defparameter specials with let-based dynamic rebinding. 27 macro+LOOP tests; 182 eval tests (8 new dynamic var tests). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
205 lines
6.3 KiB
Plaintext
205 lines
6.3 KiB
Plaintext
;; lib/common-lisp/tests/macros.sx — Phase 5: defmacro, gensym, LOOP tests
|
|
;;
|
|
;; Depends on: runtime.sx, eval.sx, loop.sx already loaded.
|
|
;; Tests via (ev "...") using the CL evaluator.
|
|
|
|
(define ev (fn (src) (cl-eval-str src (cl-make-env))))
|
|
(define evall (fn (src) (cl-eval-all-str src (cl-make-env))))
|
|
|
|
(define passed 0)
|
|
(define failed 0)
|
|
(define failures (list))
|
|
|
|
(define
|
|
check
|
|
(fn
|
|
(label got expected)
|
|
(if
|
|
(= got expected)
|
|
(set! passed (+ passed 1))
|
|
(begin
|
|
(set! failed (+ failed 1))
|
|
(set!
|
|
failures
|
|
(append
|
|
failures
|
|
(list
|
|
(str
|
|
"FAIL ["
|
|
label
|
|
"]: got="
|
|
(inspect got)
|
|
" expected="
|
|
(inspect expected)))))))))
|
|
|
|
;; ── defmacro basics ──────────────────────────────────────────────────────────
|
|
|
|
(check
|
|
"defmacro returns name"
|
|
(ev "(defmacro my-or (a b) (list 'if a a b))")
|
|
"MY-OR")
|
|
|
|
(check
|
|
"defmacro expansion works"
|
|
(ev "(progn (defmacro my-inc (x) (list '+ x 1)) (my-inc 5))")
|
|
6)
|
|
|
|
(check
|
|
"defmacro with &rest"
|
|
(ev "(progn (defmacro my-list (&rest xs) (cons 'list xs)) (my-list 1 2 3))")
|
|
(list 1 2 3))
|
|
|
|
(check
|
|
"nested macro expansion"
|
|
(ev "(progn (defmacro sq (x) (list '* x x)) (sq 7))")
|
|
49)
|
|
|
|
(check
|
|
"macro in conditional"
|
|
(ev
|
|
"(progn (defmacro my-when (c &rest body) (list 'if c (cons 'progn body) nil)) (my-when t 10 20))")
|
|
20)
|
|
|
|
(check
|
|
"macro returns nil branch"
|
|
(ev
|
|
"(progn (defmacro my-when (c &rest body) (list 'if c (cons 'progn body) nil)) (my-when nil 42))")
|
|
nil)
|
|
|
|
;; ── macroexpand ───────────────────────────────────────────────────────────────
|
|
|
|
(check
|
|
"macroexpand returns expanded form"
|
|
(ev "(progn (defmacro double (x) (list '+ x x)) (macroexpand '(double 5)))")
|
|
(list "+" 5 5))
|
|
|
|
;; ── gensym ────────────────────────────────────────────────────────────────────
|
|
|
|
(check "gensym returns string" (ev "(stringp (gensym))") true)
|
|
|
|
(check
|
|
"gensym prefix"
|
|
(ev "(let ((g (gensym \"MY\"))) (not (= g nil)))")
|
|
true)
|
|
|
|
(check "gensyms are unique" (ev "(not (= (gensym) (gensym)))") true)
|
|
|
|
;; ── swap! macro with gensym ───────────────────────────────────────────────────
|
|
|
|
(check
|
|
"swap! macro"
|
|
(evall
|
|
"(defmacro swap! (a b) (let ((tmp (gensym))) (list 'let (list (list tmp a)) (list 'setq a b) (list 'setq b tmp)))) (defvar *a* 10) (defvar *b* 20) (swap! *a* *b*) (list *a* *b*)")
|
|
(list 20 10))
|
|
|
|
;; ── LOOP: basic repeat and collect ────────────────────────────────────────────
|
|
|
|
(check
|
|
"loop repeat collect"
|
|
(ev "(loop repeat 3 collect 99)")
|
|
(list 99 99 99))
|
|
|
|
(check
|
|
"loop for-in collect"
|
|
(ev "(loop for x in '(1 2 3) collect (* x x))")
|
|
(list 1 4 9))
|
|
|
|
(check
|
|
"loop for-from-to collect"
|
|
(ev "(loop for i from 1 to 5 collect i)")
|
|
(list 1 2 3 4 5))
|
|
|
|
(check
|
|
"loop for-from-below collect"
|
|
(ev "(loop for i from 0 below 4 collect i)")
|
|
(list 0 1 2 3))
|
|
|
|
(check
|
|
"loop for-downto collect"
|
|
(ev "(loop for i from 5 downto 1 collect i)")
|
|
(list 5 4 3 2 1))
|
|
|
|
(check
|
|
"loop for-by collect"
|
|
(ev "(loop for i from 0 to 10 by 2 collect i)")
|
|
(list 0 2 4 6 8 10))
|
|
|
|
;; ── LOOP: sum, count, maximize, minimize ─────────────────────────────────────
|
|
|
|
(check "loop sum" (ev "(loop for i from 1 to 5 sum i)") 15)
|
|
|
|
(check
|
|
"loop count"
|
|
(ev "(loop for x in '(1 2 3 4 5) count (> x 3))")
|
|
2)
|
|
|
|
(check
|
|
"loop maximize"
|
|
(ev "(loop for x in '(3 1 4 1 5 9 2 6) maximize x)")
|
|
9)
|
|
|
|
(check
|
|
"loop minimize"
|
|
(ev "(loop for x in '(3 1 4 1 5 9 2 6) minimize x)")
|
|
1)
|
|
|
|
;; ── LOOP: while and until ─────────────────────────────────────────────────────
|
|
|
|
(check
|
|
"loop while"
|
|
(ev "(loop for i from 1 to 10 while (< i 5) collect i)")
|
|
(list 1 2 3 4))
|
|
|
|
(check
|
|
"loop until"
|
|
(ev "(loop for i from 1 to 10 until (= i 5) collect i)")
|
|
(list 1 2 3 4))
|
|
|
|
;; ── LOOP: when / unless ───────────────────────────────────────────────────────
|
|
|
|
(check
|
|
"loop when filter"
|
|
(ev "(loop for i from 0 below 8 when (evenp i) collect i)")
|
|
(list 0 2 4 6))
|
|
|
|
(check
|
|
"loop unless filter"
|
|
(ev "(loop for i from 0 below 8 unless (evenp i) collect i)")
|
|
(list 1 3 5 7))
|
|
|
|
;; ── LOOP: append ─────────────────────────────────────────────────────────────
|
|
|
|
(check
|
|
"loop append"
|
|
(ev "(loop for x in '((1 2) (3 4) (5 6)) append x)")
|
|
(list 1 2 3 4 5 6))
|
|
|
|
;; ── LOOP: always, never, thereis ─────────────────────────────────────────────
|
|
|
|
(check
|
|
"loop always true"
|
|
(ev "(loop for x in '(2 4 6) always (evenp x))")
|
|
true)
|
|
|
|
(check
|
|
"loop always false"
|
|
(ev "(loop for x in '(2 3 6) always (evenp x))")
|
|
false)
|
|
|
|
(check "loop never" (ev "(loop for x in '(1 3 5) never (evenp x))") true)
|
|
|
|
(check "loop thereis" (ev "(loop for x in '(1 2 3) thereis (> x 2))") true)
|
|
|
|
;; ── LOOP: for = then (general iteration) ─────────────────────────────────────
|
|
|
|
(check
|
|
"loop for = then doubling"
|
|
(ev "(loop repeat 5 for x = 1 then (* x 2) collect x)")
|
|
(list 1 2 4 8 16))
|
|
|
|
;; ── summary ────────────────────────────────────────────────────────────────
|
|
|
|
(define macro-passed passed)
|
|
(define macro-failed failed)
|
|
(define macro-failures failures)
|