go: parse.sx — multi-form file parsing + 7 e2e tests; PHASE 2 COMPLETE [nothing]
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 28s
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 28s
Final Phase 2 sub-deliverable. go-parse now handles whole Go files:
- Empty source → nil
- Single top-level form → that form (backward-compatible with ~169
existing single-stmt / single-decl tests)
- Multiple forms → (list :file FORMS), the canonical Go file shape
Implementation: gp-parse-all loops gp-parse-top until eof, tolerating
ASI semis between forms, then returns based on form count.
End-to-end test set (asserts the top-level decl-tag sequence via a
new decl-tags helper, not the full AST tree — that'd be unwieldy):
- hello-world :package :import :func-decl
- recursive fibonacci :package :func-decl
- FizzBuzz :package :import :func-decl
- goroutine ping-pong :package :func-decl :func-decl
- struct + method :package :type-decl :method-decl :func-decl
- interface + method :package :type-decl :type-decl :method-decl
- defer + select + range :package :func-decl
Type-switch (`switch v := x.(type) { ... }`) is the one syntactic
shape still deferred from Phase 2; doesn't gate Phase 3.
**Phase 2 (parser) is complete.** parse 176/176, total 305/305. Next:
Phase 3 — bidirectional type checker. The sister-plan diary for
static-types-bidirectional already has the :field binding-group
insight; Phase 3 will add the synth/check shape that emerges.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1175,4 +1175,34 @@
|
|||||||
(= (gp-tok-value) "func")))
|
(= (gp-tok-value) "func")))
|
||||||
(gp-parse-decl)
|
(gp-parse-decl)
|
||||||
:else (gp-parse-stmt))))
|
:else (gp-parse-stmt))))
|
||||||
(gp-parse-top))))
|
(define
|
||||||
|
gp-parse-all
|
||||||
|
;; Parse all top-level forms until eof. Returns:
|
||||||
|
;; nil — empty input
|
||||||
|
;; single form — backward-compatible with single-stmt
|
||||||
|
;; /single-decl tests; ~169 of them.
|
||||||
|
;; (list :file FORMS) — multiple forms (canonical Go file shape)
|
||||||
|
(fn
|
||||||
|
()
|
||||||
|
(let ((forms (list)))
|
||||||
|
(define
|
||||||
|
gp-all-loop
|
||||||
|
(fn
|
||||||
|
()
|
||||||
|
(cond
|
||||||
|
(= (gp-tok-type) "eof") nil
|
||||||
|
(= (gp-tok-type) "semi")
|
||||||
|
(do (gp-advance!) (gp-all-loop))
|
||||||
|
:else
|
||||||
|
(do
|
||||||
|
(let ((saved-idx gp-idx))
|
||||||
|
(let ((d (gp-parse-top)))
|
||||||
|
(when (not (= d nil)) (append! forms d)))
|
||||||
|
(when (= gp-idx saved-idx) (gp-advance!)))
|
||||||
|
(gp-all-loop)))))
|
||||||
|
(gp-all-loop)
|
||||||
|
(cond
|
||||||
|
(= (len forms) 0) nil
|
||||||
|
(= (len forms) 1) (first forms)
|
||||||
|
:else (list :file forms)))))
|
||||||
|
(gp-parse-all))))
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
{
|
{
|
||||||
"language": "go",
|
"language": "go",
|
||||||
"total_pass": 298,
|
"total_pass": 305,
|
||||||
"total": 298,
|
"total": 305,
|
||||||
"suites": [
|
"suites": [
|
||||||
{"name":"lex","pass":129,"total":129,"status":"ok"},
|
{"name":"lex","pass":129,"total":129,"status":"ok"},
|
||||||
{"name":"parse","pass":169,"total":169,"status":"ok"},
|
{"name":"parse","pass":176,"total":176,"status":"ok"},
|
||||||
{"name":"types","pass":0,"total":0,"status":"pending"},
|
{"name":"types","pass":0,"total":0,"status":"pending"},
|
||||||
{"name":"eval","pass":0,"total":0,"status":"pending"},
|
{"name":"eval","pass":0,"total":0,"status":"pending"},
|
||||||
{"name":"runtime","pass":0,"total":0,"status":"pending"},
|
{"name":"runtime","pass":0,"total":0,"status":"pending"},
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
# Go-on-SX Scoreboard
|
# Go-on-SX Scoreboard
|
||||||
|
|
||||||
**Total: 298 / 298 tests passing**
|
**Total: 305 / 305 tests passing**
|
||||||
|
|
||||||
| | Suite | Pass | Total |
|
| | Suite | Pass | Total |
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
| ✅ | lex | 129 | 129 |
|
| ✅ | lex | 129 | 129 |
|
||||||
| ✅ | parse | 169 | 169 |
|
| ✅ | parse | 176 | 176 |
|
||||||
| ⬜ | types | 0 | 0 |
|
| ⬜ | types | 0 | 0 |
|
||||||
| ⬜ | eval | 0 | 0 |
|
| ⬜ | eval | 0 | 0 |
|
||||||
| ⬜ | runtime | 0 | 0 |
|
| ⬜ | runtime | 0 | 0 |
|
||||||
|
|||||||
@@ -1127,6 +1127,66 @@
|
|||||||
(list (ast-var "a")))
|
(list (ast-var "a")))
|
||||||
(list :default (list (ast-var "b"))))))
|
(list :default (list (ast-var "b"))))))
|
||||||
|
|
||||||
|
(define
|
||||||
|
decl-tags
|
||||||
|
(fn
|
||||||
|
(parsed)
|
||||||
|
(cond
|
||||||
|
(and (list? parsed) (= (first parsed) :file))
|
||||||
|
(map (fn (d) (first d)) (nth parsed 1))
|
||||||
|
(list? parsed)
|
||||||
|
(list (first parsed))
|
||||||
|
:else (list))))
|
||||||
|
|
||||||
|
(go-parse-test
|
||||||
|
"e2e: hello-world top-level tags"
|
||||||
|
(decl-tags
|
||||||
|
(go-parse
|
||||||
|
"package main\nimport \"fmt\"\nfunc main() { fmt.Println(\"hello, world\") }"))
|
||||||
|
(list :package :import :func-decl))
|
||||||
|
|
||||||
|
(go-parse-test
|
||||||
|
"e2e: recursive fibonacci"
|
||||||
|
(decl-tags
|
||||||
|
(go-parse
|
||||||
|
"package main\nfunc fib(n int) int {\n if n < 2 { return n }\n return fib(n-1) + fib(n-2)\n}"))
|
||||||
|
(list :package :func-decl))
|
||||||
|
|
||||||
|
(go-parse-test
|
||||||
|
"e2e: FizzBuzz with for + if-else chain"
|
||||||
|
(decl-tags
|
||||||
|
(go-parse
|
||||||
|
"package main\nimport \"fmt\"\nfunc fizzbuzz(n int) {\n for i := 1; i <= n; i++ {\n if i % 15 == 0 { fmt.Println(\"FizzBuzz\") } else if i % 3 == 0 { fmt.Println(\"Fizz\") } else if i % 5 == 0 { fmt.Println(\"Buzz\") } else { fmt.Println(i) }\n }\n}"))
|
||||||
|
(list :package :import :func-decl))
|
||||||
|
|
||||||
|
(go-parse-test
|
||||||
|
"e2e: goroutine ping-pong (channels)"
|
||||||
|
(decl-tags
|
||||||
|
(go-parse
|
||||||
|
"package main\nfunc sender(ch chan int) { ch <- 1 }\nfunc main() {\n ch := make(chan int)\n go sender(ch)\n x := <-ch\n print(x)\n}"))
|
||||||
|
(list :package :func-decl :func-decl))
|
||||||
|
|
||||||
|
(go-parse-test
|
||||||
|
"e2e: struct + method"
|
||||||
|
(decl-tags
|
||||||
|
(go-parse
|
||||||
|
"package main\ntype Point struct { x, y int }\nfunc (p Point) Sum() int { return p.x + p.y }\nfunc main() {\n p := Point{1, 2}\n print(p.Sum())\n}"))
|
||||||
|
(list :package :type-decl :method-decl :func-decl))
|
||||||
|
|
||||||
|
(go-parse-test
|
||||||
|
"e2e: interface + structural satisfaction setup"
|
||||||
|
(decl-tags
|
||||||
|
(go-parse
|
||||||
|
"package main\ntype Stringer interface { String() string }\ntype T struct { v int }\nfunc (t T) String() string { return \"t\" }"))
|
||||||
|
(list :package :type-decl :type-decl :method-decl))
|
||||||
|
|
||||||
|
(go-parse-test
|
||||||
|
"e2e: defer + select + range"
|
||||||
|
(decl-tags
|
||||||
|
(go-parse
|
||||||
|
"package main\nfunc worker(jobs chan int, results chan int) {\n defer close(results)\n for j := range jobs {\n select {\n case results <- j * 2:\n default:\n return\n }\n }\n}"))
|
||||||
|
(list :package :func-decl))
|
||||||
|
|
||||||
(go-parse-test "non-primary: '+'" (go-parse "+") nil)
|
(go-parse-test "non-primary: '+'" (go-parse "+") nil)
|
||||||
|
|
||||||
(go-parse-test "non-primary: empty" (go-parse "") nil)
|
(go-parse-test "non-primary: empty" (go-parse "") nil)
|
||||||
|
|||||||
@@ -153,7 +153,7 @@ Progress-log line → push `origin/loops/go`.
|
|||||||
- **Acceptance:** lex/ suite at 50+ tests. Current: 129/129. **Phase 1
|
- **Acceptance:** lex/ suite at 50+ tests. Current: 129/129. **Phase 1
|
||||||
done** — hex floats deferred (rare). Move to Phase 2 next.
|
done** — hex floats deferred (rare). Move to Phase 2 next.
|
||||||
|
|
||||||
### Phase 2 — Parser (`lib/go/parse.sx`) ⬜
|
### Phase 2 — Parser (`lib/go/parse.sx`) ✅
|
||||||
- [x] Parser scaffold + Go operator-precedence table (entry shape from
|
- [x] Parser scaffold + Go operator-precedence table (entry shape from
|
||||||
`lib/guest/pratt.sx`) + primary expressions (int/float/imag/string/
|
`lib/guest/pratt.sx`) + primary expressions (int/float/imag/string/
|
||||||
rune/ident → ast-literal / ast-var via `lib/guest/ast.sx`).
|
rune/ident → ast-literal / ast-var via `lib/guest/ast.sx`).
|
||||||
@@ -203,11 +203,15 @@ Progress-log line → push `origin/loops/go`.
|
|||||||
bare-recv / default)** all done. Composite-literal `{` suppression
|
bare-recv / default)** all done. Composite-literal `{` suppression
|
||||||
active in control-flow conditions. Type-switch (`switch v :=
|
active in control-flow conditions. Type-switch (`switch v :=
|
||||||
x.(type)`) deferred to a follow-up.
|
x.(type)`) deferred to a follow-up.
|
||||||
- [ ] End-to-end: hello-world, fibonacci, FizzBuzz, goroutine ping-pong,
|
- [x] End-to-end: hello-world, fibonacci, FizzBuzz, goroutine ping-pong,
|
||||||
struct + method.
|
struct + method, interface, defer+select+range. `go-parse` extended
|
||||||
- **Acceptance:** parse/ suite at 80+ tests. **Acceptance bar crossed:
|
to handle multi-form files: returns the single form for one-form
|
||||||
169/169.** Remaining sub-item (end-to-end programs) keeps Phase 2
|
input (backward compat) or `(list :file FORMS)` for multiple.
|
||||||
open ⬜.
|
Structural tests assert top-level decl-tag sequences via the
|
||||||
|
`decl-tags` helper rather than full ASTs.
|
||||||
|
- **Acceptance:** parse/ suite at 80+ tests. Current: **176/176**.
|
||||||
|
**Phase 2 complete.** Type-switch is the one syntactic shape still
|
||||||
|
deferred to a follow-up; it doesn't gate Phase 3.
|
||||||
|
|
||||||
### Phase 3 — Bidirectional type checker, MVP (`lib/go/types.sx`) ⬜
|
### Phase 3 — Bidirectional type checker, MVP (`lib/go/types.sx`) ⬜
|
||||||
- **Independent implementation.** Do NOT use lib/guest/static-types-
|
- **Independent implementation.** Do NOT use lib/guest/static-types-
|
||||||
@@ -524,6 +528,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 2 complete.** End-to-end multi-form file parsing.
|
||||||
|
`go-parse` now returns single forms for backward compat (~169 tests
|
||||||
|
unchanged) or `(list :file FORMS)` for multi-form input. Tests cover
|
||||||
|
hello-world, fibonacci, FizzBuzz, goroutine ping-pong, struct+method,
|
||||||
|
interface+method, and defer+select+range — each asserted via top-
|
||||||
|
level `decl-tags`. Type-switch is the one syntactic shape still
|
||||||
|
deferred. +7 tests, parse 176/176, total 305/305. Next: Phase 3
|
||||||
|
(bidirectional type checker). `[nothing]` — pure Go parser
|
||||||
|
composition; the cross-language insights are already in the sister-
|
||||||
|
plan diaries from earlier Phase 2 commits.
|
||||||
- 2026-05-27 — Phase 2 cont.: `switch` and `select` statements.
|
- 2026-05-27 — Phase 2 cont.: `switch` and `select` statements.
|
||||||
Tagged + tagless switch, multi-value cases, `default`, and select
|
Tagged + tagless switch, multi-value cases, `default`, and select
|
||||||
with recv-into-var / send / bare-recv / default cases. New
|
with recv-into-var / send / bare-recv / default cases. New
|
||||||
|
|||||||
Reference in New Issue
Block a user