;; lib/scheme/tests/eval.sx — exercises lib/scheme/eval.sx (Phase 2). (define scm-eval-pass 0) (define scm-eval-fail 0) (define scm-eval-fails (list)) (define scm-eval-test (fn (name actual expected) (if (= actual expected) (set! scm-eval-pass (+ scm-eval-pass 1)) (begin (set! scm-eval-fail (+ scm-eval-fail 1)) (append! scm-eval-fails {:name name :actual actual :expected expected}))))) (define scm-eval-src (fn (src env) (scheme-eval (scheme-parse src) env))) ;; A toy env with arithmetic + list primitives. (define scm-test-env (fn () (let ((env (scheme-make-env))) (scheme-env-bind! env "+" (fn (args) (+ (first args) (nth args 1)))) (scheme-env-bind! env "-" (fn (args) (- (first args) (nth args 1)))) (scheme-env-bind! env "*" (fn (args) (* (first args) (nth args 1)))) (scheme-env-bind! env "list" (fn (args) args)) env))) ;; ── self-evaluating ────────────────────────────────────────────── (scm-eval-test "lit: integer" (scm-eval-src "42" (scheme-make-env)) 42) (scm-eval-test "lit: float" (scm-eval-src "3.14" (scheme-make-env)) 3.14) (scm-eval-test "lit: #t" (scm-eval-src "#t" (scheme-make-env)) true) (scm-eval-test "lit: #f" (scm-eval-src "#f" (scheme-make-env)) false) (scm-eval-test "lit: empty list" (scm-eval-src "()" (scheme-make-env)) (list)) (scm-eval-test "lit: string" (scheme-string? (scm-eval-src "\"hello\"" (scheme-make-env))) true) (scm-eval-test "lit: char" (scheme-char? (scm-eval-src "#\\a" (scheme-make-env))) true) (scm-eval-test "lit: vector" (scheme-vector? (scm-eval-src "#(1 2 3)" (scheme-make-env))) true) ;; ── symbol lookup ──────────────────────────────────────────────── (scm-eval-test "sym: bound" (let ((env (scheme-make-env))) (scheme-env-bind! env "x" 100) (scm-eval-src "x" env)) 100) (scm-eval-test "sym: parent chain" (let ((p (scheme-make-env))) (scheme-env-bind! p "outer" 1) (let ((c (scheme-extend-env p))) (scheme-env-bind! c "inner" 2) (+ (scm-eval-src "outer" c) (scm-eval-src "inner" c)))) 3) (scm-eval-test "sym: shadowing" (let ((p (scheme-make-env))) (scheme-env-bind! p "x" 1) (let ((c (scheme-extend-env p))) (scheme-env-bind! c "x" 2) (scm-eval-src "x" c))) 2) ;; ── quote ──────────────────────────────────────────────────────── (scm-eval-test "quote: symbol" (scm-eval-src "(quote foo)" (scheme-make-env)) "foo") (scm-eval-test "quote: list" (scm-eval-src "(quote (+ 1 2))" (scheme-make-env)) (list "+" 1 2)) (scm-eval-test "quote: sugar 'x" (scm-eval-src "'x" (scheme-make-env)) "x") (scm-eval-test "quote: sugar list" (scm-eval-src "'(a b c)" (scheme-make-env)) (list "a" "b" "c")) (scm-eval-test "quote: nested" (scm-eval-src "''x" (scheme-make-env)) (list "quote" "x")) ;; ── primitive application ──────────────────────────────────────── (scm-eval-test "prim: +" (scm-eval-src "(+ 2 3)" (scm-test-env)) 5) (scm-eval-test "prim: nested +" (scm-eval-src "(+ (+ 1 2) (+ 3 4))" (scm-test-env)) 10) (scm-eval-test "prim: mixed ops" (scm-eval-src "(- (* 4 5) (+ 3 2))" (scm-test-env)) 15) (scm-eval-test "prim: list builds SX list" (scm-eval-src "(list 1 2 3)" (scm-test-env)) (list 1 2 3)) (scm-eval-test "prim: args eval in order" (let ((env (scm-test-env))) (scheme-env-bind! env "a" 10) (scheme-env-bind! env "b" 20) (scm-eval-src "(+ a b)" env)) 30) ;; ── env-as-value (the third-consumer demonstration) ───────────── ;; Scheme's env IS lib/guest/reflective/env.sx's canonical wire shape ;; with no adapter cfg. Verify the kit primitives work directly. (scm-eval-test "env: refl-env? on Scheme env" (refl-env? (scheme-make-env)) true) (scm-eval-test "env: lookup via kit" (let ((env (scheme-make-env))) (refl-env-bind! env "name" "scheme") (refl-env-lookup env "name")) "scheme") (scm-eval-test "env: find-frame walks parent" (let ((p (scheme-make-env))) (refl-env-bind! p "root-binding" 99) (let ((c (scheme-extend-env p))) (= (refl-env-find-frame c "root-binding") p))) true) (define scm-eval-tests-run! (fn () {:total (+ scm-eval-pass scm-eval-fail) :passed scm-eval-pass :failed scm-eval-fail :fails scm-eval-fails}))