scheme: Phase 3.5 — let/let*/cond/when/unless/and/or + 21 tests
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 27s
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 27s
Adds the rest of the standard syntactic operators, all built on the existing eval/closure infrastructure from Phase 3: - let — parallel bindings in fresh child env; values evaluated in outer env (RHS sees pre-let bindings only). Multi-body via scheme-eval-body. - let* — sequential bindings, each in a nested child env; later bindings see earlier ones. - cond — clauses walked in order; first truthy test wins. `else` symbol is the catch-all. Test-only clauses (no body) return the test value. Scheme truthiness: only #f is false. - when / unless — single-test conditional execution, multi-body body via scheme-eval-body. - and / or — short-circuit boolean. Empty `(and)` = true, `(or)` = false. Both return the actual value at the point of short-circuit (not coerced to bool), matching R7RS. 130 total Scheme tests (62 parse + 23 eval + 45 syntax). The Scheme port is now self-hosting enough to write any non-stdlib program — factorial, list operations via primitives, closures with mutable state, all working. Next phase: standard env (runtime.sx) with variadic +/-, list ops as Scheme-visible applicatives.
This commit is contained in:
@@ -234,4 +234,55 @@
|
||||
(let ((env (scm-syn-env))) (scm-syn-eval-all "(define x 42) 'x" env))
|
||||
"x")
|
||||
|
||||
;; ── let / let* ───────────────────────────────────────────────────
|
||||
(scm-syn-test "let: returns body"
|
||||
(scm-syn-eval "(let ((x 5)) (+ x 1))" (scm-syn-env)) 6)
|
||||
(scm-syn-test "let: multiple bindings"
|
||||
(scm-syn-eval "(let ((x 3) (y 4)) (+ x y))" (scm-syn-env)) 7)
|
||||
(scm-syn-test "let: parallel (RHS sees outer)"
|
||||
(let ((env (scm-syn-env)))
|
||||
(scm-syn-eval-all "(define x 1) (let ((x 10) (y x)) y)" env)) 1)
|
||||
(scm-syn-test "let: bindings don't leak"
|
||||
(let ((env (scm-syn-env)))
|
||||
(scm-syn-eval-all "(define x 1) (let ((x 99)) x) x" env)) 1)
|
||||
(scm-syn-test "let*: sequential"
|
||||
(scm-syn-eval "(let* ((x 1) (y (+ x 1)) (z (+ y 1))) z)"
|
||||
(scm-syn-env)) 3)
|
||||
(scm-syn-test "let*: shadow earlier"
|
||||
(scm-syn-eval "(let* ((x 1) (x 2)) x)" (scm-syn-env)) 2)
|
||||
|
||||
;; ── cond / when / unless ─────────────────────────────────────────
|
||||
(scm-syn-test "cond: first match"
|
||||
(scm-syn-eval "(cond (#f 1) (#t 2) (#t 3))" (scm-syn-env)) 2)
|
||||
(scm-syn-test "cond: else"
|
||||
(scm-syn-eval "(cond (#f 1) (else 99))" (scm-syn-env)) 99)
|
||||
(scm-syn-test "cond: untaken not evaluated"
|
||||
(scm-syn-eval "(cond (#t 7) (nope ignored))" (scm-syn-env)) 7)
|
||||
(scm-syn-test "cond: no match returns nil"
|
||||
(scm-syn-eval "(cond (#f 1) (#f 2))" (scm-syn-env)) nil)
|
||||
(scm-syn-test "cond: test-only clause"
|
||||
(scm-syn-eval "(cond (42))" (scm-syn-env)) 42)
|
||||
(scm-syn-test "when: true"
|
||||
(scm-syn-eval "(when #t 1 2 3)" (scm-syn-env)) 3)
|
||||
(scm-syn-test "when: false"
|
||||
(scm-syn-eval "(when #f nope)" (scm-syn-env)) nil)
|
||||
(scm-syn-test "unless: false"
|
||||
(scm-syn-eval "(unless #f 42)" (scm-syn-env)) 42)
|
||||
(scm-syn-test "unless: true"
|
||||
(scm-syn-eval "(unless #t nope)" (scm-syn-env)) nil)
|
||||
|
||||
;; ── and / or ─────────────────────────────────────────────────────
|
||||
(scm-syn-test "and: empty"
|
||||
(scm-syn-eval "(and)" (scm-syn-env)) true)
|
||||
(scm-syn-test "and: all truthy returns last"
|
||||
(scm-syn-eval "(and 1 2 3)" (scm-syn-env)) 3)
|
||||
(scm-syn-test "and: short-circuit on #f"
|
||||
(scm-syn-eval "(and 1 #f nope)" (scm-syn-env)) false)
|
||||
(scm-syn-test "or: empty"
|
||||
(scm-syn-eval "(or)" (scm-syn-env)) false)
|
||||
(scm-syn-test "or: first truthy"
|
||||
(scm-syn-eval "(or #f 42 nope)" (scm-syn-env)) 42)
|
||||
(scm-syn-test "or: all #f"
|
||||
(scm-syn-eval "(or #f #f #f)" (scm-syn-env)) false)
|
||||
|
||||
(define scm-syn-tests-run! (fn () {:total (+ scm-syn-pass scm-syn-fail) :passed scm-syn-pass :failed scm-syn-fail :fails scm-syn-fails}))
|
||||
|
||||
Reference in New Issue
Block a user