Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 28s
Phase 4 cont. go-eval-stmt dispatches on: :return → wraps value in (:return-value V) sentinel :var-decl → bind each NAME via go-eval-var-decl :short-decl → bind each (:var NAME) lhs to corresponding expr value :assign → immutable-env shadowing (true mutation deferred) :block → run stmts via go-eval-block, propagating :return-value :if / :else → cond-driven dispatch :func-decl → bind name to (list :go-fn PARAMS BODY) else → expression statement, evaluate for side effects go-eval-call extends the CALLER's env with param-names → arg-values (dynamic-scope-ish — closures don't capture lexical env yet), runs the body block, catches :return-value and unwraps. **Recursive fib(5) = 5 evaluates correctly.** Recursion works because top-level func bindings are in the calling env before the recursive call happens. True lexical closures (let bind sees outer var; assignments visible to nested funcs) need an env-cell model with mutation; deferred to a later slice. eval 33/33, total 410/410. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
152 lines
5.1 KiB
Plaintext
152 lines
5.1 KiB
Plaintext
;; Go evaluator tests.
|
|
|
|
(define go-eval-test-count 0)
|
|
(define go-eval-test-pass 0)
|
|
(define go-eval-test-fails (list))
|
|
|
|
(define
|
|
go-eval-test
|
|
(fn
|
|
(name actual expected)
|
|
(set! go-eval-test-count (+ go-eval-test-count 1))
|
|
(if
|
|
(= actual expected)
|
|
(set! go-eval-test-pass (+ go-eval-test-pass 1))
|
|
(append! go-eval-test-fails {:name name :expected expected :actual actual}))))
|
|
|
|
(define gtev (fn (env src) (go-eval env (go-parse src))))
|
|
|
|
;; ── env ──────────────────────────────────────────────────────────
|
|
(go-eval-test
|
|
"env: empty lookup returns nil"
|
|
(go-env-lookup go-env-empty "x")
|
|
nil)
|
|
|
|
(go-eval-test
|
|
"env: extend then lookup"
|
|
(go-env-lookup (go-env-extend go-env-empty "x" 42) "x")
|
|
42)
|
|
|
|
;; ── literals ────────────────────────────────────────────────────
|
|
(go-eval-test "lit: 42 → 42" (gtev go-env-empty "42") 42)
|
|
|
|
(go-eval-test "lit: 0 → 0" (gtev go-env-empty "0") 0)
|
|
|
|
(go-eval-test "lit: 0xFF → 255" (gtev go-env-empty "0xFF") 255)
|
|
|
|
(go-eval-test "lit: 0b1010 → 10" (gtev go-env-empty "0b1010") 10)
|
|
|
|
(go-eval-test "lit: 0o17 → 15" (gtev go-env-empty "0o17") 15)
|
|
|
|
(go-eval-test
|
|
"lit: underscore separator 1_000 → 1000"
|
|
(gtev go-env-empty "1_000")
|
|
1000)
|
|
|
|
(go-eval-test "lit: string" (gtev go-env-empty "\"hello\"") "hello")
|
|
|
|
;; ── predeclared ─────────────────────────────────────────────────
|
|
(go-eval-test "var: true" (gtev go-env-empty "true") true)
|
|
(go-eval-test "var: false" (gtev go-env-empty "false") false)
|
|
(go-eval-test "var: nil" (gtev go-env-empty "nil") nil)
|
|
|
|
;; ── variable lookup ─────────────────────────────────────────────
|
|
(go-eval-test
|
|
"var: bound x → 5"
|
|
(go-eval (go-env-extend go-env-empty "x" 5) (go-parse "x"))
|
|
5)
|
|
|
|
(go-eval-test
|
|
"var: unbound y → :eval-error"
|
|
(gtev go-env-empty "y")
|
|
(list :eval-error :unbound "y"))
|
|
|
|
;; ── binary ops ─────────────────────────────────────────────────
|
|
(go-eval-test "binop: 1 + 2 → 3" (gtev go-env-empty "1 + 2") 3)
|
|
(go-eval-test "binop: 10 - 4 → 6" (gtev go-env-empty "10 - 4") 6)
|
|
(go-eval-test "binop: 3 * 7 → 21" (gtev go-env-empty "3 * 7") 21)
|
|
(go-eval-test "binop: 42 / 7 → 6" (gtev go-env-empty "42 / 7") 6)
|
|
(go-eval-test
|
|
"binop: 2 + 3 * 4 → 14 (prec)"
|
|
(gtev go-env-empty "2 + 3 * 4")
|
|
14)
|
|
(go-eval-test
|
|
"binop: a + b uses env"
|
|
(go-eval
|
|
(go-env-extend (go-env-extend go-env-empty "a" 3) "b" 4)
|
|
(go-parse "a + b"))
|
|
7)
|
|
|
|
(go-eval-test "binop: 1 < 2 → true" (gtev go-env-empty "1 < 2") true)
|
|
(go-eval-test "binop: 5 == 5 → true" (gtev go-env-empty "5 == 5") true)
|
|
(go-eval-test "binop: 5 != 5 → false" (gtev go-env-empty "5 != 5") false)
|
|
(go-eval-test
|
|
"binop: true && false → false"
|
|
(gtev go-env-empty "true && false")
|
|
false)
|
|
(go-eval-test
|
|
"binop: false || true → true"
|
|
(gtev go-env-empty "false || true")
|
|
true)
|
|
|
|
;; ── report ──────────────────────────────────────────────────────
|
|
(go-eval-test
|
|
"var-decl: var x = 5 — env has x=5"
|
|
(go-env-lookup
|
|
(go-eval-program go-env-empty (list (go-parse "var x = 5")))
|
|
"x")
|
|
5)
|
|
|
|
(go-eval-test
|
|
"short-decl: a, b := 3, 4 — env has both"
|
|
(let
|
|
((env (go-eval-program go-env-empty (list (go-parse "a, b := 3, 4")))))
|
|
(list (go-env-lookup env "a") (go-env-lookup env "b")))
|
|
(list 3 4))
|
|
|
|
(go-eval-test
|
|
"assign: x = 5 then x → 5"
|
|
(let
|
|
((env (go-eval-program (go-env-extend go-env-empty "x" 1) (list (go-parse "x = 5")))))
|
|
(go-env-lookup env "x"))
|
|
5)
|
|
|
|
(go-eval-test
|
|
"if: true branch evaluates"
|
|
(let
|
|
((env (go-eval-program (go-env-extend go-env-empty "x" 0) (list (go-parse "if true { x = 1 }")))))
|
|
(go-env-lookup env "x"))
|
|
1)
|
|
|
|
(go-eval-test
|
|
"if-else: false → else branch"
|
|
(let
|
|
((env (go-eval-program (go-env-extend go-env-empty "x" 0) (list (go-parse "if false { x = 1 } else { x = 2 }")))))
|
|
(go-env-lookup env "x"))
|
|
2)
|
|
|
|
(go-eval-test
|
|
"fn: define + call — double(7) = 14"
|
|
(let
|
|
((env (go-eval-program go-env-empty (list (go-parse "func double(x int) int { return x * 2 }")))))
|
|
(go-eval env (go-parse "double(7)")))
|
|
14)
|
|
|
|
(go-eval-test
|
|
"fn: add(2, 3) = 5"
|
|
(let
|
|
((env (go-eval-program go-env-empty (list (go-parse "func add(x, y int) int { return x + y }")))))
|
|
(go-eval env (go-parse "add(2, 3)")))
|
|
5)
|
|
|
|
(go-eval-test
|
|
"fn: recursive fib(5) = 5"
|
|
(let
|
|
((env (go-eval-program go-env-empty (list (go-parse "func fib(n int) int { if n < 2 { return n } return fib(n-1) + fib(n-2) }")))))
|
|
(go-eval env (go-parse "fib(5)")))
|
|
5)
|
|
|
|
(define
|
|
go-eval-test-summary
|
|
(str "eval " go-eval-test-pass "/" go-eval-test-count))
|