Three-phase foundations implementation:
Phase A — Activate dormant shift/reset continuations with 24 SX-native tests
covering basic semantics, predicates, stored continuations, nested reset,
scope interaction, and TCO.
Phase B — Bridge compile-time effect system to runtime: boundary_parser extracts
46 effect annotations, platform provides populate_effect_annotations() and
check_component_effects() for static analysis. 6 new type tests.
Phase C — Explicit CEK machine (frames.sx + cek.sx): evaluation state as data
({control, env, kont, phase, value}), 21 frame types, two-phase step function
(step-eval/step-continue), native shift/reset via frame capture. Bootstrapper
integration: --spec-modules cek transpiles to Python with iterative cek_run.
43 interpreted + 49 transpiled tests passing.
Bug fixes:
- inspect() shadowed by `import inspect` in PLATFORM_ASYNC_PY — renamed to
`import inspect as _inspect`
- dynamic-wind missing platform functions (call_thunk, push_wind!, pop_wind!) —
added with try/finally error safety via dynamic_wind_call
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
141 lines
4.3 KiB
Plaintext
141 lines
4.3 KiB
Plaintext
;; ==========================================================================
|
|
;; test-continuations.sx — Tests for delimited continuations (shift/reset)
|
|
;;
|
|
;; Requires: test-framework.sx loaded, continuations extension enabled.
|
|
;; ==========================================================================
|
|
|
|
|
|
;; --------------------------------------------------------------------------
|
|
;; 1. Basic shift/reset
|
|
;; --------------------------------------------------------------------------
|
|
|
|
(defsuite "basic-shift-reset"
|
|
(deftest "reset passthrough"
|
|
(assert-equal 42 (reset 42)))
|
|
|
|
(deftest "reset evaluates expression"
|
|
(assert-equal 3 (reset (+ 1 2))))
|
|
|
|
(deftest "shift aborts to reset"
|
|
(assert-equal 42 (reset (+ 1 (shift k 42)))))
|
|
|
|
(deftest "shift with single invoke"
|
|
(assert-equal 11 (reset (+ 1 (shift k (k 10))))))
|
|
|
|
(deftest "shift with multiple invokes"
|
|
(assert-equal (list 11 21)
|
|
(reset (+ 1 (shift k (list (k 10) (k 20)))))))
|
|
|
|
(deftest "shift returns string"
|
|
(assert-equal "aborted"
|
|
(reset (+ 1 (shift k "aborted")))))
|
|
|
|
(deftest "shift returns nil"
|
|
(assert-nil (reset (+ 1 (shift k nil)))))
|
|
|
|
(deftest "nested expression with shift"
|
|
(assert-equal 16
|
|
(+ 1 (reset (+ 10 (shift k (k 5))))))))
|
|
|
|
|
|
;; --------------------------------------------------------------------------
|
|
;; 2. Continuation predicates
|
|
;; --------------------------------------------------------------------------
|
|
|
|
(defsuite "continuation-predicates"
|
|
(deftest "k is a continuation inside shift"
|
|
(assert-true
|
|
(reset (shift k (continuation? k)))))
|
|
|
|
(deftest "number is not a continuation"
|
|
(assert-false (continuation? 42)))
|
|
|
|
(deftest "function is not a continuation"
|
|
(assert-false (continuation? (fn (x) x))))
|
|
|
|
(deftest "nil is not a continuation"
|
|
(assert-false (continuation? nil)))
|
|
|
|
(deftest "string is not a continuation"
|
|
(assert-false (continuation? "hello"))))
|
|
|
|
|
|
;; --------------------------------------------------------------------------
|
|
;; 3. Continuation as value
|
|
;; --------------------------------------------------------------------------
|
|
|
|
(defsuite "continuation-as-value"
|
|
(deftest "k returned from reset"
|
|
;; shift body returns k itself — reset returns the continuation
|
|
(let ((k (reset (+ 1 (shift k k)))))
|
|
(assert-true (continuation? k))
|
|
(assert-equal 11 (k 10))))
|
|
|
|
(deftest "invoke returned k multiple times"
|
|
(let ((k (reset (+ 1 (shift k k)))))
|
|
(assert-equal 11 (k 10))
|
|
(assert-equal 21 (k 20))
|
|
(assert-equal 2 (k 1))))
|
|
|
|
(deftest "pass k to another function"
|
|
(let ((apply-k (fn (k v) (k v))))
|
|
(assert-equal 15
|
|
(reset (+ 5 (shift k (apply-k k 10)))))))
|
|
|
|
(deftest "k in data structure"
|
|
(let ((result (reset (+ 1 (shift k (list k 42))))))
|
|
(assert-equal 42 (nth result 1))
|
|
(assert-equal 100 ((first result) 99)))))
|
|
|
|
|
|
;; --------------------------------------------------------------------------
|
|
;; 4. Nested reset
|
|
;; --------------------------------------------------------------------------
|
|
|
|
(defsuite "nested-reset"
|
|
(deftest "inner reset captures independently"
|
|
(assert-equal 12
|
|
(reset (+ 1 (reset (+ 10 (shift k (k 1))))))))
|
|
|
|
(deftest "inner abort outer continues"
|
|
(assert-equal 43
|
|
(reset (+ 1 (reset (+ 10 (shift k 42)))))))
|
|
|
|
(deftest "outer shift captures outer reset"
|
|
(assert-equal 100
|
|
(reset (+ 1 (shift k (k 99)))))))
|
|
|
|
|
|
;; --------------------------------------------------------------------------
|
|
;; 5. Interaction with scoped effects
|
|
;; --------------------------------------------------------------------------
|
|
|
|
(defsuite "continuations-with-scopes"
|
|
(deftest "provide survives resume"
|
|
(assert-equal "dark"
|
|
(reset (provide "theme" "dark"
|
|
(+ 0 (shift k (k 0)))
|
|
(context "theme")))))
|
|
|
|
(deftest "scope and emit across shift"
|
|
(assert-equal (list "a")
|
|
(reset (scope "acc"
|
|
(emit! "acc" "a")
|
|
(+ 0 (shift k (k 0)))
|
|
(emitted "acc"))))))
|
|
|
|
|
|
;; --------------------------------------------------------------------------
|
|
;; 6. TCO interaction
|
|
;; --------------------------------------------------------------------------
|
|
|
|
(defsuite "tco-interaction"
|
|
(deftest "shift in tail position"
|
|
(assert-equal 42
|
|
(reset (if true (shift k (k 42)) 0))))
|
|
|
|
(deftest "shift in let body"
|
|
(assert-equal 10
|
|
(reset (let ((x 5))
|
|
(+ x (shift k (k 5))))))))
|