;; lib/scheme/tests/reflection.sx — Phase 7 reflective primitives. (define scm-ref-pass 0) (define scm-ref-fail 0) (define scm-ref-fails (list)) (define scm-ref-test (fn (name actual expected) (if (= actual expected) (set! scm-ref-pass (+ scm-ref-pass 1)) (begin (set! scm-ref-fail (+ scm-ref-fail 1)) (append! scm-ref-fails {:name name :actual actual :expected expected}))))) (define scm-ref (fn (src) (scheme-eval (scheme-parse src) (scheme-standard-env)))) (define scm-ref-all (fn (src) (scheme-eval-program (scheme-parse-all src) (scheme-standard-env)))) ;; ── eval ───────────────────────────────────────────────────────── (scm-ref-test "eval: arithmetic" (scm-ref "(eval '(+ 1 2 3) (interaction-environment))") 6) (scm-ref-test "eval: nested" (scm-ref "(eval '(* (+ 1 2) (- 5 1)) (interaction-environment))") 12) (scm-ref-test "eval: constructed form" (scm-ref "(eval (list '+ 10 20) (interaction-environment))") 30) (scm-ref-test "eval: variable reference" (scm-ref-all "(define x 42) (eval 'x (interaction-environment))") 42) ;; ── interaction-environment ───────────────────────────────────── (scm-ref-test "interaction-environment: is an env" (scm-ref "(environment? (interaction-environment))") true) (scm-ref-test "interaction-environment: define persists" (scm-ref-all "(define ie (interaction-environment))\n (eval '(define stashed 99) ie)\n (eval 'stashed ie)") 99) (scm-ref-test "interaction-environment: same env across calls" (scm-ref-all "(define a (interaction-environment))\n (define b (interaction-environment))\n (eqv? a b)") true) ;; ── null-environment ──────────────────────────────────────────── (scm-ref-test "null-environment: is an env" (scm-ref "(environment? (null-environment 7))") true) (scm-ref-test "null-environment: has no + binding" (scm-ref-all "(define ne (null-environment 7))\n (guard (e (else 'unbound)) (eval '+ ne))") "unbound") ;; ── scheme-report-environment ─────────────────────────────────── (scm-ref-test "scheme-report-environment: is an env" (scm-ref "(environment? (scheme-report-environment 7))") true) (scm-ref-test "scheme-report-environment: has +" (scm-ref "(eval '(+ 1 2) (scheme-report-environment 7))") 3) (scm-ref-test "scheme-report-environment: distinct from interaction" (scm-ref-all "(define ie (interaction-environment))\n (define re (scheme-report-environment 7))\n (eval '(define only-in-ie 1) ie)\n (guard (e (else 'unbound)) (eval 'only-in-ie re))") "unbound") ;; ── eval with explicit env for sandboxing ────────────────────── (scm-ref-test "eval: sandbox with null-environment" (scm-ref-all "(define sandbox (null-environment 7))\n (guard (e (else 'unbound))\n (eval '(+ 1 1) sandbox))") "unbound") ;; ── quasiquote / unquote / unquote-splicing ───────────────────── (scm-ref-test "qq: plain atom" (scm-ref "`hello") "hello") (scm-ref-test "qq: plain list" (scm-ref "`(a b c)") (list "a" "b" "c")) (scm-ref-test "qq: unquote substitutes value" (scm-ref-all "(define x 42) `(a ,x b)") (list "a" 42 "b")) (scm-ref-test "qq: unquote-splicing splices list" (scm-ref-all "(define xs '(1 2 3)) `(a ,@xs b)") (list "a" 1 2 3 "b")) (scm-ref-test "qq: splice at start" (scm-ref-all "(define xs '(1 2)) `(,@xs c)") (list 1 2 "c")) (scm-ref-test "qq: splice at end" (scm-ref-all "(define xs '(9 8)) `(a b ,@xs)") (list "a" "b" 9 8)) (scm-ref-test "qq: nested list with unquote" (scm-ref-all "(define x 5) `(a (b ,x) c)") (list "a" (list "b" 5) "c")) (scm-ref-test "qq: unquote evaluates expression" (scm-ref "`(a ,(+ 1 2) b)") (list "a" 3 "b")) (scm-ref-test "qq: error on splicing non-list" (scm-ref-all "(define x 42) (guard (e (else 'raised)) `(a ,@x b))") "raised") (scm-ref-test "qq: bare unquote at top level errors" (scm-ref "(guard (e (else 'raised)) (unquote 5))") "raised") (define scm-ref-tests-run! (fn () {:total (+ scm-ref-pass scm-ref-fail) :passed scm-ref-pass :failed scm-ref-fail :fails scm-ref-fails}))