go: eval.sx scaffold — literals + vars + binops + 25 tests; Phase 3 closed [nothing]
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 24s
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 24s
Phase 3 — bidirectional type checker — is fully ticked (short-decl
was already implemented). Phase 4 starts here.
lib/go/eval.sx single judgment:
(go-eval ENV EXPR) → VALUE | (list :eval-error TAG ...)
ENV is an association list of (NAME VALUE) bindings — same shape as
the type checker's ctx, but the entries are runtime values. Values
are represented directly in SX: integers/floats as SX numbers,
strings as SX strings, booleans as true/false, nil as nil. Composite
values (slices/maps/structs/pointers/channels) arrive in later slices.
First-slice coverage:
* go-env-empty / -lookup / -extend
* Literal decoding:
decimal (with underscores)
hex (0x.. / 0X..)
oct (0o.. / 0O..)
bin (0b.. / 0B..)
via go-hex-digit-value (explicit char equality — SX's nth on
strings returns single-char strings, not numeric codes; the
arithmetic-on-char-codes pattern from the OCaml kernel ports
doesn't work here).
* Identifier lookup with predeclared true / false / nil.
* Binops: + - * / and the six comparison ops and && / ||.
* Errors as (:eval-error TAG ...) sentinels.
Statements (block / return / short-decl / assign), control flow
(if / for), and function application / closures arrive in subsequent
slices.
eval 25/25, total 402/402.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -30,6 +30,7 @@ SUITES=(
|
||||
"lex|go-test-pass|go-test-count"
|
||||
"parse|go-parse-test-pass|go-parse-test-count"
|
||||
"types|go-types-test-pass|go-types-test-count"
|
||||
"eval|go-eval-test-pass|go-eval-test-count"
|
||||
)
|
||||
|
||||
cat > "$TMPFILE" <<'EPOCHS'
|
||||
@@ -40,9 +41,11 @@ cat > "$TMPFILE" <<'EPOCHS'
|
||||
(load "lib/go/lex.sx")
|
||||
(load "lib/go/parse.sx")
|
||||
(load "lib/go/types.sx")
|
||||
(load "lib/go/eval.sx")
|
||||
(load "lib/go/tests/lex.sx")
|
||||
(load "lib/go/tests/parse.sx")
|
||||
(load "lib/go/tests/types.sx")
|
||||
(load "lib/go/tests/eval.sx")
|
||||
EPOCHS
|
||||
|
||||
idx=0
|
||||
@@ -107,7 +110,6 @@ cat > lib/go/scoreboard.json <<JSON
|
||||
"total_pass": $TOTAL_PASS,
|
||||
"total": $TOTAL_COUNT,
|
||||
"suites": [$JSON_SUITES,
|
||||
{"name":"eval","pass":0,"total":0,"status":"pending"},
|
||||
{"name":"runtime","pass":0,"total":0,"status":"pending"},
|
||||
{"name":"stdlib","pass":0,"total":0,"status":"pending"},
|
||||
{"name":"e2e","pass":0,"total":0,"status":"pending"}
|
||||
@@ -122,8 +124,7 @@ cat > lib/go/scoreboard.md <<MD
|
||||
|
||||
| | Suite | Pass | Total |
|
||||
|---|---|---|---|
|
||||
$MD_ROWS| ⬜ | eval | 0 | 0 |
|
||||
| ⬜ | runtime | 0 | 0 |
|
||||
$MD_ROWS| ⬜ | runtime | 0 | 0 |
|
||||
| ⬜ | stdlib | 0 | 0 |
|
||||
| ⬜ | e2e | 0 | 0 |
|
||||
|
||||
|
||||
215
lib/go/eval.sx
Normal file
215
lib/go/eval.sx
Normal file
@@ -0,0 +1,215 @@
|
||||
;; lib/go/eval.sx — Go tree-walk evaluator.
|
||||
;;
|
||||
;; (go-eval ENV EXPR) → VALUE | (list :eval-error TAG ...)
|
||||
;;
|
||||
;; ENV is an association list of (NAME VALUE) bindings. Per-block scope
|
||||
;; via fresh extension. Values:
|
||||
;; integers → SX numbers (decimal/hex/oct/bin literals all decoded)
|
||||
;; strings → SX strings
|
||||
;; booleans → SX true/false
|
||||
;; nil → SX nil
|
||||
;; Composite Go values (slices, maps, structs, pointers, channels)
|
||||
;; arrive in later slices.
|
||||
|
||||
(define go-env-empty (list))
|
||||
|
||||
(define
|
||||
go-env-lookup
|
||||
(fn
|
||||
(env name)
|
||||
(cond
|
||||
(= (len env) 0)
|
||||
nil
|
||||
(= (first (first env)) name)
|
||||
(nth (first env) 1)
|
||||
:else (go-env-lookup (rest env) name))))
|
||||
|
||||
(define go-env-extend (fn (env name value) (cons (list name value) env)))
|
||||
|
||||
(define
|
||||
go-eval-error?
|
||||
(fn
|
||||
(x)
|
||||
(and
|
||||
(list? x)
|
||||
(not (= (len x) 0))
|
||||
(= (first x) :eval-error))))
|
||||
|
||||
;; ── literal parsing ──────────────────────────────────────────────
|
||||
|
||||
(define
|
||||
go-hex-digit-value
|
||||
(fn
|
||||
(c)
|
||||
(cond
|
||||
(= c "0")
|
||||
0
|
||||
(= c "1")
|
||||
1
|
||||
(= c "2")
|
||||
2
|
||||
(= c "3")
|
||||
3
|
||||
(= c "4")
|
||||
4
|
||||
(= c "5")
|
||||
5
|
||||
(= c "6")
|
||||
6
|
||||
(= c "7")
|
||||
7
|
||||
(= c "8")
|
||||
8
|
||||
(= c "9")
|
||||
9
|
||||
(= c "a")
|
||||
10
|
||||
(= c "b")
|
||||
11
|
||||
(= c "c")
|
||||
12
|
||||
(= c "d")
|
||||
13
|
||||
(= c "e")
|
||||
14
|
||||
(= c "f")
|
||||
15
|
||||
(= c "A")
|
||||
10
|
||||
(= c "B")
|
||||
11
|
||||
(= c "C")
|
||||
12
|
||||
(= c "D")
|
||||
13
|
||||
(= c "E")
|
||||
14
|
||||
(= c "F")
|
||||
15
|
||||
:else -1)))
|
||||
|
||||
(define
|
||||
go-parse-radix-from
|
||||
(fn
|
||||
(v start radix)
|
||||
(define
|
||||
grf-loop
|
||||
(fn
|
||||
(i acc)
|
||||
(cond
|
||||
(>= i (len v))
|
||||
acc
|
||||
(= (nth v i) "_")
|
||||
(grf-loop (+ i 1) acc)
|
||||
:else (let
|
||||
((d (go-hex-digit-value (nth v i))))
|
||||
(cond
|
||||
(or (< d 0) (>= d radix))
|
||||
acc
|
||||
:else (grf-loop (+ i 1) (+ (* acc radix) d)))))))
|
||||
(grf-loop start 0)))
|
||||
|
||||
(define
|
||||
go-parse-int-literal
|
||||
(fn
|
||||
(v)
|
||||
(cond
|
||||
(and
|
||||
(>= (len v) 2)
|
||||
(= (nth v 0) "0")
|
||||
(or (= (nth v 1) "x") (= (nth v 1) "X")))
|
||||
(go-parse-radix-from v 2 16)
|
||||
(and
|
||||
(>= (len v) 2)
|
||||
(= (nth v 0) "0")
|
||||
(or (= (nth v 1) "b") (= (nth v 1) "B")))
|
||||
(go-parse-radix-from v 2 2)
|
||||
(and
|
||||
(>= (len v) 2)
|
||||
(= (nth v 0) "0")
|
||||
(or (= (nth v 1) "o") (= (nth v 1) "O")))
|
||||
(go-parse-radix-from v 2 8)
|
||||
:else (go-parse-radix-from v 0 10))))
|
||||
|
||||
(define
|
||||
go-eval-literal
|
||||
(fn
|
||||
(v)
|
||||
(let
|
||||
((k (go-classify-literal-string v)))
|
||||
(cond (= k :int) (go-parse-int-literal v) (= k :string) v :else v))))
|
||||
|
||||
;; ── binary ops ───────────────────────────────────────────────────
|
||||
|
||||
(define
|
||||
go-eval-binop
|
||||
(fn
|
||||
(op l r)
|
||||
(cond
|
||||
(= op "+")
|
||||
(+ l r)
|
||||
(= op "-")
|
||||
(- l r)
|
||||
(= op "*")
|
||||
(* l r)
|
||||
(= op "/")
|
||||
(/ l r)
|
||||
(= op "==")
|
||||
(= l r)
|
||||
(= op "!=")
|
||||
(not (= l r))
|
||||
(= op "<")
|
||||
(< l r)
|
||||
(= op "<=")
|
||||
(<= l r)
|
||||
(= op ">")
|
||||
(> l r)
|
||||
(= op ">=")
|
||||
(>= l r)
|
||||
(= op "&&")
|
||||
(and l r)
|
||||
(= op "||")
|
||||
(or l r)
|
||||
:else (list :eval-error :unsupported-binop op))))
|
||||
|
||||
;; ── main eval ────────────────────────────────────────────────────
|
||||
|
||||
(define
|
||||
go-eval
|
||||
(fn
|
||||
(env expr)
|
||||
(cond
|
||||
(and (list? expr) (= (first expr) :literal))
|
||||
(go-eval-literal (nth expr 1))
|
||||
(and (list? expr) (= (first expr) :var))
|
||||
(let
|
||||
((name (nth expr 1)))
|
||||
(cond
|
||||
(= name "true")
|
||||
true
|
||||
(= name "false")
|
||||
false
|
||||
(= name "nil")
|
||||
nil
|
||||
:else (let
|
||||
((v (go-env-lookup env name)))
|
||||
(cond (= v nil) (list :eval-error :unbound name) :else v))))
|
||||
(and
|
||||
(list? expr)
|
||||
(= (first expr) :app)
|
||||
(list? (nth expr 1))
|
||||
(= (first (nth expr 1)) :var)
|
||||
(= (len (nth expr 2)) 2))
|
||||
(let
|
||||
((op (nth (nth expr 1) 1))
|
||||
(args (nth expr 2)))
|
||||
(let
|
||||
((lv (go-eval env (first args)))
|
||||
(rv (go-eval env (nth args 1))))
|
||||
(cond
|
||||
(go-eval-error? lv)
|
||||
lv
|
||||
(go-eval-error? rv)
|
||||
rv
|
||||
:else (go-eval-binop op lv rv))))
|
||||
:else (list :eval-error :unsupported-eval expr))))
|
||||
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"language": "go",
|
||||
"total_pass": 377,
|
||||
"total": 377,
|
||||
"total_pass": 402,
|
||||
"total": 402,
|
||||
"suites": [
|
||||
{"name":"lex","pass":129,"total":129,"status":"ok"},
|
||||
{"name":"parse","pass":176,"total":176,"status":"ok"},
|
||||
{"name":"types","pass":72,"total":72,"status":"ok"},
|
||||
{"name":"eval","pass":0,"total":0,"status":"pending"},
|
||||
{"name":"eval","pass":25,"total":25,"status":"ok"},
|
||||
{"name":"runtime","pass":0,"total":0,"status":"pending"},
|
||||
{"name":"stdlib","pass":0,"total":0,"status":"pending"},
|
||||
{"name":"e2e","pass":0,"total":0,"status":"pending"}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
# Go-on-SX Scoreboard
|
||||
|
||||
**Total: 377 / 377 tests passing**
|
||||
**Total: 402 / 402 tests passing**
|
||||
|
||||
| | Suite | Pass | Total |
|
||||
|---|---|---|---|
|
||||
| ✅ | lex | 129 | 129 |
|
||||
| ✅ | parse | 176 | 176 |
|
||||
| ✅ | types | 72 | 72 |
|
||||
| ⬜ | eval | 0 | 0 |
|
||||
| ✅ | eval | 25 | 25 |
|
||||
| ⬜ | runtime | 0 | 0 |
|
||||
| ⬜ | stdlib | 0 | 0 |
|
||||
| ⬜ | e2e | 0 | 0 |
|
||||
|
||||
95
lib/go/tests/eval.sx
Normal file
95
lib/go/tests/eval.sx
Normal file
@@ -0,0 +1,95 @@
|
||||
;; 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 ──────────────────────────────────────────────────────
|
||||
(define
|
||||
go-eval-test-summary
|
||||
(str "eval " go-eval-test-pass "/" go-eval-test-count))
|
||||
Reference in New Issue
Block a user