go: eval.sx — for / break / continue / inc-dec + 7 tests [nothing]
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 26s
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 26s
Phase 4 cont. go-eval-for handles all three for-header shapes:
for { ... } — infinite (cond defaults to true)
for cond { ... } — while-like (init=nil, post=nil)
for init ; cond ; post { ... } — C-style
Implementation:
* Run INIT (if any), extending env.
* Loop: eval COND. If false, exit with current env.
Eval body (a :block). Catch sentinels:
:return-value → propagate up
:break → exit loop with pre-break env
:continue → still runs POST, then re-loops
Otherwise: run POST, re-loop.
:break and :continue propagate as keyword sentinels through
go-eval-block alongside the existing :return-value sentinel. The
block returns whichever sentinel hit first; control-flow constructs
(for, switch, select) catch them.
inc-dec (x++ / x--) updates env via the same shadowing model used by
assign — `(go-env-extend env name (+ current 1))`.
**Iterative fact(5) = 120 and the classic sum-to-9 = 45 both
evaluate.** Demonstrates the for-loop machinery is solid enough for
real programs.
eval 40/40, total 417/417.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -348,6 +348,78 @@
|
|||||||
(body (nth stmt 4)))
|
(body (nth stmt 4)))
|
||||||
(go-env-extend env name (list :go-fn params body)))))
|
(go-env-extend env name (list :go-fn params body)))))
|
||||||
|
|
||||||
|
(define
|
||||||
|
go-eval-inc-dec
|
||||||
|
;; (:inc-dec OP EXPR) where OP is "++" or "--". EXPR should be (:var NAME).
|
||||||
|
(fn (env stmt)
|
||||||
|
(let ((op (nth stmt 1)) (operand (nth stmt 2)))
|
||||||
|
(cond
|
||||||
|
(not (and (list? operand) (= (first operand) :var)))
|
||||||
|
(list :eval-error :unsupported-lhs operand)
|
||||||
|
:else
|
||||||
|
(let ((current (go-eval env operand)))
|
||||||
|
(cond
|
||||||
|
(go-eval-error? current) current
|
||||||
|
:else
|
||||||
|
(let ((new-val
|
||||||
|
(cond
|
||||||
|
(= op "++") (+ current 1)
|
||||||
|
(= op "--") (- current 1)
|
||||||
|
:else current)))
|
||||||
|
(go-env-extend env (nth operand 1) new-val))))))))
|
||||||
|
|
||||||
|
(define
|
||||||
|
go-eval-for
|
||||||
|
;; (:for INIT COND POST BODY). Any may be nil.
|
||||||
|
(fn (env stmt)
|
||||||
|
(let ((init (nth stmt 1)) (cnd (nth stmt 2))
|
||||||
|
(post (nth stmt 3)) (body (nth stmt 4)))
|
||||||
|
(let ((env0
|
||||||
|
(cond
|
||||||
|
(= init nil) env
|
||||||
|
:else (go-eval-stmt env init))))
|
||||||
|
(cond
|
||||||
|
(go-eval-error? env0) env0
|
||||||
|
:else (go-for-loop env0 cnd post body))))))
|
||||||
|
|
||||||
|
(define
|
||||||
|
go-for-loop
|
||||||
|
(fn (env cnd post body)
|
||||||
|
(let ((c
|
||||||
|
(cond
|
||||||
|
(= cnd nil) true
|
||||||
|
:else (go-eval env cnd))))
|
||||||
|
(cond
|
||||||
|
(go-eval-error? c) c
|
||||||
|
(not c) env
|
||||||
|
:else
|
||||||
|
(let ((r
|
||||||
|
(cond
|
||||||
|
(= body nil) env
|
||||||
|
(and (list? body) (= (first body) :block))
|
||||||
|
(go-eval-block env (nth body 1))
|
||||||
|
:else env)))
|
||||||
|
(cond
|
||||||
|
(and (list? r) (= (first r) :return-value)) r
|
||||||
|
(= r :break) env
|
||||||
|
(= r :continue)
|
||||||
|
(let ((env1
|
||||||
|
(cond
|
||||||
|
(= post nil) env
|
||||||
|
:else (go-eval-stmt env post))))
|
||||||
|
(cond
|
||||||
|
(go-eval-error? env1) env1
|
||||||
|
:else (go-for-loop env1 cnd post body)))
|
||||||
|
(go-eval-error? r) r
|
||||||
|
:else
|
||||||
|
(let ((env1
|
||||||
|
(cond
|
||||||
|
(= post nil) r
|
||||||
|
:else (go-eval-stmt r post))))
|
||||||
|
(cond
|
||||||
|
(go-eval-error? env1) env1
|
||||||
|
:else (go-for-loop env1 cnd post body)))))))))
|
||||||
|
|
||||||
(define
|
(define
|
||||||
go-eval-stmt
|
go-eval-stmt
|
||||||
(fn (env stmt)
|
(fn (env stmt)
|
||||||
@@ -372,6 +444,12 @@
|
|||||||
(go-eval-block env (nth stmt 1))
|
(go-eval-block env (nth stmt 1))
|
||||||
(and (list? stmt) (= (first stmt) :if))
|
(and (list? stmt) (= (first stmt) :if))
|
||||||
(go-eval-if env stmt)
|
(go-eval-if env stmt)
|
||||||
|
(and (list? stmt) (= (first stmt) :for))
|
||||||
|
(go-eval-for env stmt)
|
||||||
|
(and (list? stmt) (= (first stmt) :break)) :break
|
||||||
|
(and (list? stmt) (= (first stmt) :continue)) :continue
|
||||||
|
(and (list? stmt) (= (first stmt) :inc-dec))
|
||||||
|
(go-eval-inc-dec env stmt)
|
||||||
(and (list? stmt) (= (first stmt) :func-decl))
|
(and (list? stmt) (= (first stmt) :func-decl))
|
||||||
(go-eval-func-decl env stmt)
|
(go-eval-func-decl env stmt)
|
||||||
:else
|
:else
|
||||||
@@ -389,6 +467,8 @@
|
|||||||
(let ((r (go-eval-stmt env (first stmts))))
|
(let ((r (go-eval-stmt env (first stmts))))
|
||||||
(cond
|
(cond
|
||||||
(and (list? r) (= (first r) :return-value)) r
|
(and (list? r) (= (first r) :return-value)) r
|
||||||
|
(= r :break) r
|
||||||
|
(= r :continue) r
|
||||||
(go-eval-error? r) r
|
(go-eval-error? r) r
|
||||||
:else (go-eval-block r (rest stmts)))))))
|
:else (go-eval-block r (rest stmts)))))))
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"language": "go",
|
"language": "go",
|
||||||
"total_pass": 410,
|
"total_pass": 417,
|
||||||
"total": 410,
|
"total": 417,
|
||||||
"suites": [
|
"suites": [
|
||||||
{"name":"lex","pass":129,"total":129,"status":"ok"},
|
{"name":"lex","pass":129,"total":129,"status":"ok"},
|
||||||
{"name":"parse","pass":176,"total":176,"status":"ok"},
|
{"name":"parse","pass":176,"total":176,"status":"ok"},
|
||||||
{"name":"types","pass":72,"total":72,"status":"ok"},
|
{"name":"types","pass":72,"total":72,"status":"ok"},
|
||||||
{"name":"eval","pass":33,"total":33,"status":"ok"},
|
{"name":"eval","pass":40,"total":40,"status":"ok"},
|
||||||
{"name":"runtime","pass":0,"total":0,"status":"pending"},
|
{"name":"runtime","pass":0,"total":0,"status":"pending"},
|
||||||
{"name":"stdlib","pass":0,"total":0,"status":"pending"},
|
{"name":"stdlib","pass":0,"total":0,"status":"pending"},
|
||||||
{"name":"e2e","pass":0,"total":0,"status":"pending"}
|
{"name":"e2e","pass":0,"total":0,"status":"pending"}
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
# Go-on-SX Scoreboard
|
# Go-on-SX Scoreboard
|
||||||
|
|
||||||
**Total: 410 / 410 tests passing**
|
**Total: 417 / 417 tests passing**
|
||||||
|
|
||||||
| | Suite | Pass | Total |
|
| | Suite | Pass | Total |
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
| ✅ | lex | 129 | 129 |
|
| ✅ | lex | 129 | 129 |
|
||||||
| ✅ | parse | 176 | 176 |
|
| ✅ | parse | 176 | 176 |
|
||||||
| ✅ | types | 72 | 72 |
|
| ✅ | types | 72 | 72 |
|
||||||
| ✅ | eval | 33 | 33 |
|
| ✅ | eval | 40 | 40 |
|
||||||
| ⬜ | runtime | 0 | 0 |
|
| ⬜ | runtime | 0 | 0 |
|
||||||
| ⬜ | stdlib | 0 | 0 |
|
| ⬜ | stdlib | 0 | 0 |
|
||||||
| ⬜ | e2e | 0 | 0 |
|
| ⬜ | e2e | 0 | 0 |
|
||||||
|
|||||||
@@ -146,6 +146,55 @@
|
|||||||
(go-eval env (go-parse "fib(5)")))
|
(go-eval env (go-parse "fib(5)")))
|
||||||
5)
|
5)
|
||||||
|
|
||||||
|
(go-eval-test
|
||||||
|
"for: count to 10 with sum"
|
||||||
|
(let
|
||||||
|
((env (go-eval-program go-env-empty (list (go-parse "var sum = 0") (go-parse "for i := 0; i < 10; i++ { sum = sum + i }")))))
|
||||||
|
(go-env-lookup env "sum"))
|
||||||
|
45)
|
||||||
|
|
||||||
|
(go-eval-test
|
||||||
|
"inc-dec: x++ updates env"
|
||||||
|
(let
|
||||||
|
((env (go-eval-program (go-env-extend go-env-empty "x" 5) (list (go-parse "x++")))))
|
||||||
|
(go-env-lookup env "x"))
|
||||||
|
6)
|
||||||
|
|
||||||
|
(go-eval-test
|
||||||
|
"inc-dec: x-- updates env"
|
||||||
|
(let
|
||||||
|
((env (go-eval-program (go-env-extend go-env-empty "x" 5) (list (go-parse "x--")))))
|
||||||
|
(go-env-lookup env "x"))
|
||||||
|
4)
|
||||||
|
|
||||||
|
(go-eval-test
|
||||||
|
"for: break exits the loop"
|
||||||
|
(let
|
||||||
|
((env (go-eval-program go-env-empty (list (go-parse "var i = 0") (go-parse "for i < 100 { if i == 5 { break } ; i++ }")))))
|
||||||
|
(go-env-lookup env "i"))
|
||||||
|
5)
|
||||||
|
|
||||||
|
(go-eval-test
|
||||||
|
"for: continue skips body but runs post"
|
||||||
|
(let
|
||||||
|
((env (go-eval-program go-env-empty (list (go-parse "var sum = 0") (go-parse "for i := 0; i < 5; i++ { if i == 2 { continue } ; sum = sum + i }")))))
|
||||||
|
(go-env-lookup env "sum"))
|
||||||
|
8)
|
||||||
|
|
||||||
|
(go-eval-test
|
||||||
|
"for: infinite + break with sum"
|
||||||
|
(let
|
||||||
|
((env (go-eval-program go-env-empty (list (go-parse "var s = 0") (go-parse "var i = 1") (go-parse "for { if i > 4 { break } ; s = s + i ; i++ }")))))
|
||||||
|
(go-env-lookup env "s"))
|
||||||
|
10)
|
||||||
|
|
||||||
|
(go-eval-test
|
||||||
|
"fn: iterative factorial via for-loop"
|
||||||
|
(let
|
||||||
|
((env (go-eval-program go-env-empty (list (go-parse "func fact(n int) int { r := 1 ; for i := 2 ; i <= n ; i++ { r = r * i } ; return r }")))))
|
||||||
|
(go-eval env (go-parse "fact(5)")))
|
||||||
|
120)
|
||||||
|
|
||||||
(define
|
(define
|
||||||
go-eval-test-summary
|
go-eval-test-summary
|
||||||
(str "eval " go-eval-test-pass "/" go-eval-test-count))
|
(str "eval " go-eval-test-pass "/" go-eval-test-count))
|
||||||
|
|||||||
@@ -270,8 +270,10 @@ Progress-log line → push `origin/loops/go`.
|
|||||||
- [x] Scaffold: env-as-value, literal decoding (decimal/hex/oct/bin
|
- [x] Scaffold: env-as-value, literal decoding (decimal/hex/oct/bin
|
||||||
with underscores), variable lookup (incl. predeclared true/false/nil),
|
with underscores), variable lookup (incl. predeclared true/false/nil),
|
||||||
arithmetic + comparison + logical binops. eval suite at 25/25.
|
arithmetic + comparison + logical binops. eval suite at 25/25.
|
||||||
- [/] Statement evaluation: block / return / short-decl / assign /
|
- [x] Statement evaluation: block / return / short-decl / assign /
|
||||||
var-decl / if done; for / break / continue pending.
|
var-decl / if / for (all three header shapes) / break / continue /
|
||||||
|
inc-dec all done. `:break` and `:continue` propagate as sentinel
|
||||||
|
keywords through `go-eval-block` until `go-for-loop` catches them.
|
||||||
- [ ] Variables as mutable cells; pointer semantics: `&x` returns the
|
- [ ] Variables as mutable cells; pointer semantics: `&x` returns the
|
||||||
cell, `*p` dereferences.
|
cell, `*p` dereferences.
|
||||||
- [ ] Slices: triple (length, capacity, backing-vector). `append`
|
- [ ] Slices: triple (length, capacity, backing-vector). `append`
|
||||||
@@ -283,7 +285,7 @@ Progress-log line → push `origin/loops/go`.
|
|||||||
- [ ] Channels: stub (Phase 5 wires them).
|
- [ ] Channels: stub (Phase 5 wires them).
|
||||||
- Tests: arithmetic, control flow, recursion, closures, slices, maps,
|
- Tests: arithmetic, control flow, recursion, closures, slices, maps,
|
||||||
structs, methods, pointer semantics, multiple-return.
|
structs, methods, pointer semantics, multiple-return.
|
||||||
- **Acceptance:** eval/ suite at 80+ tests. Current: 33/33. No concurrency yet.
|
- **Acceptance:** eval/ suite at 80+ tests. Current: 40/40. No concurrency yet.
|
||||||
|
|
||||||
### Phase 5 — Goroutines + channels + select (`lib/go/sched.sx`) ⬜
|
### Phase 5 — Goroutines + channels + select (`lib/go/sched.sx`) ⬜
|
||||||
- **Independent implementation.** Do NOT use lib/guest/scheduler/ — that
|
- **Independent implementation.** Do NOT use lib/guest/scheduler/ — that
|
||||||
@@ -567,6 +569,16 @@ Minimal repro: see `lib/go/lex.sx#gl-oct-digit?` and `#gl-match-op`.
|
|||||||
|
|
||||||
_Newest first. Append one dated entry per commit._
|
_Newest first. Append one dated entry per commit._
|
||||||
|
|
||||||
|
- 2026-05-27 — Phase 4 cont.: for-loops, break, continue, inc-dec.
|
||||||
|
`go-eval-for` handles all three for-header shapes (infinite, while-
|
||||||
|
like, C-style) including init+post stmts and missing-cond defaulting
|
||||||
|
to true. `:break` and `:continue` propagate as keyword sentinels
|
||||||
|
through `go-eval-block` (alongside the existing `:return-value`
|
||||||
|
sentinel) until `go-for-loop` catches them — break exits, continue
|
||||||
|
runs post and re-loops. Inc-dec `x++`/`x--` updates env via the
|
||||||
|
same shadowing model as assign. **Iterative `fact(5) = 120` and the
|
||||||
|
classic for-loop sum-to-9 (= 45) both evaluate.** +7 tests, eval
|
||||||
|
40/40, total 417/417. `[nothing]`.
|
||||||
- 2026-05-27 — Phase 4 cont.: statements + function application.
|
- 2026-05-27 — Phase 4 cont.: statements + function application.
|
||||||
`go-eval-stmt` handles `:return` (propagates a `:return-value`
|
`go-eval-stmt` handles `:return` (propagates a `:return-value`
|
||||||
sentinel up through blocks), `:var-decl`, `:short-decl`, `:assign`
|
sentinel up through blocks), `:var-decl`, `:short-decl`, `:assign`
|
||||||
|
|||||||
Reference in New Issue
Block a user