;; 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}))