scheme: Phase 4 standard env + set! bugfix + 78 tests
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 25s
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 25s
lib/scheme/runtime.sx — full R7RS-base surface: - Arithmetic: variadic +/-/*//, abs, min, max, modulo, quotient, remainder. Predicates zero?/positive?/negative?. - Comparison: chained =/</>/<=/>=. - Type predicates: number?/boolean?/symbol?/string?/char?/vector?/ null?/pair?/procedure?/not. - List: cons/car/cdr/list/length/reverse/append. - Higher-order: map/filter/fold-left/fold-right/for-each/apply. These re-enter scheme-apply to invoke user-supplied procs. - String: string-length/string=?/string-append/substring. - Char: char=?. - Vector: vector/vector-length/vector-ref/vector->list/list->vector/ make-vector. - Equality: eqv?/equal?/eq? (all = under the hood for now). Built via small adapters: scm-unary, scm-binary, scm-fold (variadic left-fold with identity + one-arity special), scm-chain (n-ary chained comparison). **Bugfix in eval.sx set! handler.** The :else branch had two expressions `(dict-set! ...) val` — SX cond branches don't run multiple expressions, they return nil silently (or evaluate only the first, depending on shape). Wrapped in (begin ...) to force sequential execution. This fix also unblocks 4 set!-dependent tests in lib/scheme/tests/syntax.sx that were silently raising during load (and thus not counted) — syntax test count jumps from 45 → 49. Classic programs verified: - factorial 10 → 3628800 - fib 10 → 55 - recursive list reverse → working - sum of squares via fold-left + map → 55 212 total Scheme tests: parse 62 + eval 23 + syntax 49 + runtime 78. All green. The env-as-value section in runtime tests demonstrates scheme-standard-env IS a refl-env? — kit primitives operate on it directly, confirming the third-consumer adoption with zero adapter.
This commit is contained in:
213
lib/scheme/tests/runtime.sx
Normal file
213
lib/scheme/tests/runtime.sx
Normal file
@@ -0,0 +1,213 @@
|
||||
;; lib/scheme/tests/runtime.sx — exercises the standard env.
|
||||
|
||||
(define scm-rt-pass 0)
|
||||
(define scm-rt-fail 0)
|
||||
(define scm-rt-fails (list))
|
||||
|
||||
(define
|
||||
scm-rt-test
|
||||
(fn
|
||||
(name actual expected)
|
||||
(if
|
||||
(= actual expected)
|
||||
(set! scm-rt-pass (+ scm-rt-pass 1))
|
||||
(begin
|
||||
(set! scm-rt-fail (+ scm-rt-fail 1))
|
||||
(append! scm-rt-fails {:name name :actual actual :expected expected})))))
|
||||
|
||||
(define
|
||||
scm-rt
|
||||
(fn (src) (scheme-eval (scheme-parse src) (scheme-standard-env))))
|
||||
|
||||
(define
|
||||
scm-rt-all
|
||||
(fn
|
||||
(src)
|
||||
(scheme-eval-program (scheme-parse-all src) (scheme-standard-env))))
|
||||
|
||||
;; ── Variadic arithmetic ─────────────────────────────────────────
|
||||
(scm-rt-test "+: zero" (scm-rt "(+)") 0)
|
||||
(scm-rt-test "+: one" (scm-rt "(+ 7)") 7)
|
||||
(scm-rt-test "+: many" (scm-rt "(+ 1 2 3 4 5)") 15)
|
||||
(scm-rt-test "-: one" (scm-rt "(- 10)") -10)
|
||||
(scm-rt-test "-: many" (scm-rt "(- 100 1 2 3)") 94)
|
||||
(scm-rt-test "*: zero" (scm-rt "(*)") 1)
|
||||
(scm-rt-test "*: many" (scm-rt "(* 1 2 3 4)") 24)
|
||||
(scm-rt-test "/: two" (scm-rt "(/ 20 5)") 4)
|
||||
|
||||
;; ── Chained comparison ──────────────────────────────────────────
|
||||
(scm-rt-test "<: chained" (scm-rt "(< 1 2 3 4 5)") true)
|
||||
(scm-rt-test "<: not strict" (scm-rt "(< 1 2 2 3)") false)
|
||||
(scm-rt-test ">: chained" (scm-rt "(> 5 4 3 2 1)") true)
|
||||
(scm-rt-test "<=: with equality" (scm-rt "(<= 1 1 2 3 3)") true)
|
||||
(scm-rt-test "=: chained" (scm-rt "(= 7 7 7)") true)
|
||||
|
||||
;; ── Numerical ───────────────────────────────────────────────────
|
||||
(scm-rt-test "abs neg" (scm-rt "(abs -5)") 5)
|
||||
(scm-rt-test "abs pos" (scm-rt "(abs 5)") 5)
|
||||
(scm-rt-test "min" (scm-rt "(min 3 1 4 1 5)") 1)
|
||||
(scm-rt-test "max" (scm-rt "(max 3 1 4 1 5)") 5)
|
||||
(scm-rt-test "modulo" (scm-rt "(modulo 10 3)") 1)
|
||||
(scm-rt-test "zero? 0" (scm-rt "(zero? 0)") true)
|
||||
(scm-rt-test "zero? 1" (scm-rt "(zero? 1)") false)
|
||||
(scm-rt-test "positive?" (scm-rt "(positive? 5)") true)
|
||||
(scm-rt-test "negative?" (scm-rt "(negative? -5)") true)
|
||||
|
||||
;; ── Type predicates ─────────────────────────────────────────────
|
||||
(scm-rt-test "number? int" (scm-rt "(number? 42)") true)
|
||||
(scm-rt-test "number? str" (scm-rt "(number? \"hi\")") false)
|
||||
(scm-rt-test "boolean? #t" (scm-rt "(boolean? #t)") true)
|
||||
(scm-rt-test "boolean? 0" (scm-rt "(boolean? 0)") false)
|
||||
(scm-rt-test "string? str" (scm-rt "(string? \"hi\")") true)
|
||||
(scm-rt-test "string? sym" (scm-rt "(string? 'foo)") false)
|
||||
(scm-rt-test "symbol? sym" (scm-rt "(symbol? 'foo)") true)
|
||||
(scm-rt-test "null? ()" (scm-rt "(null? '())") true)
|
||||
(scm-rt-test "null? (1)" (scm-rt "(null? '(1))") false)
|
||||
(scm-rt-test "pair? (1)" (scm-rt "(pair? '(1))") true)
|
||||
(scm-rt-test "pair? ()" (scm-rt "(pair? '())") false)
|
||||
(scm-rt-test "procedure? lambda" (scm-rt "(procedure? (lambda (x) x))") true)
|
||||
(scm-rt-test "procedure? +" (scm-rt "(procedure? +)") true)
|
||||
(scm-rt-test "procedure? 42" (scm-rt "(procedure? 42)") false)
|
||||
(scm-rt-test "not #t" (scm-rt "(not #t)") false)
|
||||
(scm-rt-test "not #f" (scm-rt "(not #f)") true)
|
||||
(scm-rt-test "not 0" (scm-rt "(not 0)") false)
|
||||
|
||||
;; ── List operations ─────────────────────────────────────────────
|
||||
(scm-rt-test
|
||||
"cons"
|
||||
(scm-rt "(cons 1 '(2 3))")
|
||||
(list 1 2 3))
|
||||
(scm-rt-test "car" (scm-rt "(car '(1 2 3))") 1)
|
||||
(scm-rt-test "cdr" (scm-rt "(cdr '(1 2 3))") (list 2 3))
|
||||
(scm-rt-test
|
||||
"list builds"
|
||||
(scm-rt "(list 1 2 3)")
|
||||
(list 1 2 3))
|
||||
(scm-rt-test "list empty" (scm-rt "(list)") (list))
|
||||
(scm-rt-test "length 3" (scm-rt "(length '(a b c))") 3)
|
||||
(scm-rt-test "length 0" (scm-rt "(length '())") 0)
|
||||
(scm-rt-test
|
||||
"reverse"
|
||||
(scm-rt "(reverse '(1 2 3))")
|
||||
(list 3 2 1))
|
||||
(scm-rt-test "reverse empty" (scm-rt "(reverse '())") (list))
|
||||
(scm-rt-test
|
||||
"append two"
|
||||
(scm-rt "(append '(1 2) '(3 4))")
|
||||
(list 1 2 3 4))
|
||||
(scm-rt-test
|
||||
"append three"
|
||||
(scm-rt "(append '(1) '(2) '(3))")
|
||||
(list 1 2 3))
|
||||
(scm-rt-test "append empty" (scm-rt "(append)") (list))
|
||||
|
||||
;; ── Higher-order combinators ────────────────────────────────────
|
||||
(scm-rt-test
|
||||
"map square"
|
||||
(scm-rt "(map (lambda (x) (* x x)) '(1 2 3 4))")
|
||||
(list 1 4 9 16))
|
||||
(scm-rt-test
|
||||
"map with primitive"
|
||||
(scm-rt-all "(define inc (lambda (x) (+ x 1))) (map inc '(10 20 30))")
|
||||
(list 11 21 31))
|
||||
(scm-rt-test
|
||||
"filter positives"
|
||||
(scm-rt "(filter positive? '(-2 -1 0 1 2))")
|
||||
(list 1 2))
|
||||
(scm-rt-test
|
||||
"filter empty result"
|
||||
(scm-rt "(filter (lambda (x) #f) '(1 2 3))")
|
||||
(list))
|
||||
(scm-rt-test
|
||||
"fold-left sum"
|
||||
(scm-rt "(fold-left + 0 '(1 2 3 4 5))")
|
||||
15)
|
||||
(scm-rt-test
|
||||
"fold-left build list"
|
||||
(scm-rt "(fold-left (lambda (acc x) (cons x acc)) '() '(1 2 3))")
|
||||
(list 3 2 1))
|
||||
(scm-rt-test
|
||||
"fold-right preserves order"
|
||||
(scm-rt "(fold-right cons '() '(1 2 3))")
|
||||
(list 1 2 3))
|
||||
(scm-rt-test
|
||||
"for-each side effect"
|
||||
(let
|
||||
((env (scheme-standard-env)))
|
||||
(scheme-eval-program
|
||||
(scheme-parse-all
|
||||
"(define sum 0) (for-each (lambda (n) (set! sum (+ sum n))) '(1 2 3 4 5)) sum")
|
||||
env))
|
||||
15)
|
||||
|
||||
;; ── apply ───────────────────────────────────────────────────────
|
||||
(scm-rt-test "apply +" (scm-rt "(apply + '(1 2 3 4 5))") 15)
|
||||
(scm-rt-test
|
||||
"apply lambda"
|
||||
(scm-rt "(apply (lambda (a b c) (+ a (* b c))) '(1 2 3))")
|
||||
7)
|
||||
(scm-rt-test
|
||||
"apply via map"
|
||||
(scm-rt "(apply + (map (lambda (x) (* x x)) '(1 2 3)))")
|
||||
14)
|
||||
|
||||
;; ── String / char / vector ──────────────────────────────────────
|
||||
(scm-rt-test "string-length" (scm-rt "(string-length \"hello\")") 5)
|
||||
(scm-rt-test "string=? same" (scm-rt "(string=? \"abc\" \"abc\")") true)
|
||||
(scm-rt-test "string=? diff" (scm-rt "(string=? \"abc\" \"abd\")") false)
|
||||
(scm-rt-test
|
||||
"string-append"
|
||||
(scheme-string-value (scm-rt "(string-append \"hello\" \" \" \"world\")"))
|
||||
"hello world")
|
||||
(scm-rt-test "vector?" (scm-rt "(vector? #(1 2 3))") true)
|
||||
(scm-rt-test "vector-length" (scm-rt "(vector-length #(1 2 3))") 3)
|
||||
(scm-rt-test "vector-ref" (scm-rt "(vector-ref #(10 20 30) 1)") 20)
|
||||
(scm-rt-test
|
||||
"vector->list"
|
||||
(scm-rt "(vector->list #(1 2 3))")
|
||||
(list 1 2 3))
|
||||
|
||||
;; ── Classic Scheme programs ─────────────────────────────────────
|
||||
(scm-rt-test
|
||||
"factorial 5"
|
||||
(scm-rt-all
|
||||
"(define (fact n) (if (<= n 1) 1 (* n (fact (- n 1))))) (fact 5)")
|
||||
120)
|
||||
(scm-rt-test
|
||||
"factorial 10"
|
||||
(scm-rt-all
|
||||
"(define (fact n) (if (<= n 1) 1 (* n (fact (- n 1))))) (fact 10)")
|
||||
3628800)
|
||||
(scm-rt-test
|
||||
"fib 10"
|
||||
(scm-rt-all
|
||||
"(define (fib n) (if (< n 2) n (+ (fib (- n 1)) (fib (- n 2))))) (fib 10)")
|
||||
55)
|
||||
(scm-rt-test
|
||||
"sum via reduce"
|
||||
(scm-rt "(fold-left + 0 (map (lambda (x) (* x x)) '(1 2 3 4 5)))")
|
||||
55)
|
||||
(scm-rt-test
|
||||
"length via reduce"
|
||||
(scm-rt-all
|
||||
"(define (len xs) (fold-left (lambda (acc _) (+ acc 1)) 0 xs)) (len '(a b c d))")
|
||||
4)
|
||||
(scm-rt-test
|
||||
"Y-ish reverse"
|
||||
(scm-rt-all
|
||||
"(define (rev xs) (if (null? xs) '() (append (rev (cdr xs)) (list (car xs))))) (rev '(1 2 3 4))")
|
||||
(list 4 3 2 1))
|
||||
|
||||
;; ── env-as-value (kit consumer demo) ────────────────────────────
|
||||
(scm-rt-test
|
||||
"env: standard-env is refl-env"
|
||||
(refl-env? (scheme-standard-env))
|
||||
true)
|
||||
(scm-rt-test
|
||||
"env: kit lookup finds primitive"
|
||||
(let
|
||||
((env (scheme-standard-env)))
|
||||
(callable? (refl-env-lookup env "+")))
|
||||
true)
|
||||
|
||||
(define scm-rt-tests-run! (fn () {:total (+ scm-rt-pass scm-rt-fail) :passed scm-rt-pass :failed scm-rt-fail :fails scm-rt-fails}))
|
||||
Reference in New Issue
Block a user