Files
rose-ash/spec/tests/test-cek.sx
giles 05f7b10864 Phase 2: Move core spec files to spec/ and spec/tests/
git mv eval.sx, parser.sx, primitives.sx, render.sx, cek.sx, frames.sx,
continuations.sx, callcc.sx, types.sx, special-forms.sx → spec/
Tests → spec/tests/
Both bootstrappers verified — find files via spec/ → web/ → shared/sx/ref/

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 02:12:13 +00:00

242 lines
6.6 KiB
Plaintext

;; ==========================================================================
;; test-cek.sx — Tests for the explicit CEK machine evaluator
;;
;; Tests that eval-expr-cek produces identical results to eval-expr.
;; Requires: test-framework.sx, frames.sx, cek.sx loaded.
;; ==========================================================================
;; --------------------------------------------------------------------------
;; 1. Literals
;; --------------------------------------------------------------------------
(defsuite "cek-literals"
(deftest "number"
(assert-equal 42 (eval-expr-cek 42 (test-env))))
(deftest "string"
(assert-equal "hello" (eval-expr-cek "hello" (test-env))))
(deftest "boolean true"
(assert-equal true (eval-expr-cek true (test-env))))
(deftest "boolean false"
(assert-equal false (eval-expr-cek false (test-env))))
(deftest "nil"
(assert-nil (eval-expr-cek nil (test-env)))))
;; --------------------------------------------------------------------------
;; 2. Symbol lookup
;; --------------------------------------------------------------------------
(defsuite "cek-symbols"
(deftest "env lookup"
(assert-equal 42
(cek-eval "(do (define x 42) x)")))
(deftest "primitive call resolves"
(assert-equal "hello"
(cek-eval "(str \"hello\")"))))
;; --------------------------------------------------------------------------
;; 3. Special forms
;; --------------------------------------------------------------------------
(defsuite "cek-if"
(deftest "if true branch"
(assert-equal 1
(cek-eval "(if true 1 2)")))
(deftest "if false branch"
(assert-equal 2
(cek-eval "(if false 1 2)")))
(deftest "if no else"
(assert-nil (cek-eval "(if false 1)"))))
(defsuite "cek-when"
(deftest "when true"
(assert-equal 42
(cek-eval "(when true 42)")))
(deftest "when false"
(assert-nil (cek-eval "(when false 42)")))
(deftest "when multiple body"
(assert-equal 3
(cek-eval "(when true 1 2 3)"))))
(defsuite "cek-begin"
(deftest "do returns last"
(assert-equal 3
(cek-eval "(do 1 2 3)")))
(deftest "empty do"
(assert-nil (cek-eval "(do)"))))
(defsuite "cek-let"
(deftest "basic let"
(assert-equal 3
(cek-eval "(let ((x 1) (y 2)) (+ x y))")))
(deftest "let body sequence"
(assert-equal 10
(cek-eval "(let ((x 5)) 1 2 (+ x 5))")))
(deftest "nested let"
(assert-equal 5
(cek-eval "(let ((x 1)) (let ((y 2)) (+ x y (* x y))))"))))
(defsuite "cek-and-or"
(deftest "and all true"
(assert-equal 3
(cek-eval "(and 1 2 3)")))
(deftest "and short circuit"
(assert-false (cek-eval "(and 1 false 3)")))
(deftest "or first true"
(assert-equal 1
(cek-eval "(or 1 2 3)")))
(deftest "or all false"
(assert-false (cek-eval "(or false false false)"))))
(defsuite "cek-cond"
(deftest "cond first match"
(assert-equal "a"
(cek-eval "(cond true \"a\" true \"b\")")))
(deftest "cond second match"
(assert-equal "b"
(cek-eval "(cond false \"a\" true \"b\")")))
(deftest "cond else"
(assert-equal "c"
(cek-eval "(cond false \"a\" :else \"c\")"))))
(defsuite "cek-case"
(deftest "case match"
(assert-equal "yes"
(cek-eval "(case 1 1 \"yes\" 2 \"no\")")))
(deftest "case no match"
(assert-nil
(cek-eval "(case 3 1 \"yes\" 2 \"no\")")))
(deftest "case else"
(assert-equal "default"
(cek-eval "(case 3 1 \"yes\" :else \"default\")"))))
;; --------------------------------------------------------------------------
;; 4. Function calls
;; --------------------------------------------------------------------------
(defsuite "cek-calls"
(deftest "primitive call"
(assert-equal 3
(cek-eval "(+ 1 2)")))
(deftest "nested calls"
(assert-equal 6
(cek-eval "(+ 1 (+ 2 3))")))
(deftest "lambda call"
(assert-equal 10
(cek-eval "((fn (x) (* x 2)) 5)")))
(deftest "defined function"
(assert-equal 25
(cek-eval "(do (define square (fn (x) (* x x))) (square 5))"))))
;; --------------------------------------------------------------------------
;; 5. Define and set!
;; --------------------------------------------------------------------------
(defsuite "cek-define"
(deftest "define binds"
(assert-equal 42
(cek-eval "(do (define x 42) x)")))
(deftest "set! mutates"
(assert-equal 10
(cek-eval "(do (define x 1) (set! x 10) x)"))))
;; --------------------------------------------------------------------------
;; 6. Quote and quasiquote
;; --------------------------------------------------------------------------
(defsuite "cek-quote"
(deftest "quote"
(let ((result (cek-eval "(quote (1 2 3))")))
(assert-equal 3 (len result))))
(deftest "quasiquote with unquote"
(assert-equal (list 1 42 3)
(cek-eval "(let ((x 42)) `(1 ,x 3))"))))
;; --------------------------------------------------------------------------
;; 7. Thread-first
;; --------------------------------------------------------------------------
(defsuite "cek-thread-first"
(deftest "simple thread"
(assert-equal 3
(cek-eval "(-> 1 (+ 2))")))
(deftest "multi-step thread"
(assert-equal 6
(cek-eval "(-> 1 (+ 2) (* 2))"))))
;; --------------------------------------------------------------------------
;; 8. CEK-specific: stepping
;; --------------------------------------------------------------------------
(defsuite "cek-stepping"
(deftest "single step literal"
(let ((state (make-cek-state 42 (test-env) (list))))
(let ((stepped (cek-step state)))
(assert-equal "continue" (cek-phase stepped))
(assert-equal 42 (cek-value stepped))
(assert-true (cek-terminal? stepped)))))
(deftest "single step if pushes frame"
(let ((state (make-cek-state (sx-parse-one "(if true 1 2)") (test-env) (list))))
(let ((stepped (cek-step state)))
(assert-equal "eval" (cek-phase stepped))
;; Should have pushed an IfFrame
(assert-true (> (len (cek-kont stepped)) 0))
(assert-equal "if" (frame-type (first (cek-kont stepped))))))))
;; --------------------------------------------------------------------------
;; 9. Native continuations (shift/reset in CEK)
;; --------------------------------------------------------------------------
(defsuite "cek-continuations"
(deftest "reset passthrough"
(assert-equal 42
(cek-eval "(reset 42)")))
(deftest "shift abort"
(assert-equal 42
(cek-eval "(reset (+ 1 (shift k 42)))")))
(deftest "shift with invoke"
(assert-equal 11
(cek-eval "(reset (+ 1 (shift k (k 10))))"))))