From 8ba66e0dc93fca9355c95b43948b07fc4263b352 Mon Sep 17 00:00:00 2001 From: giles Date: Wed, 27 May 2026 08:02:08 +0000 Subject: [PATCH] =?UTF-8?q?go:=20parse.sx=20=E2=80=94=20slice/array/map/ch?= =?UTF-8?q?an=20type=20expressions=20+=2011=20tests;=20parse=20acceptance?= =?UTF-8?q?=20crossed=20[proposes-ast]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds the bulk of Go's type-expression grammar: []T → (list :ty-slice T) [N]T → (list :ty-array N T) — N is an expr map[K]V → (list :ty-map K V) chan T → (list :ty-chan :both T) chan<- T → (list :ty-chan :send T) <-chan T → (list :ty-chan :recv T) gp-parse-type now dispatches on the head token: *, [, map, chan, <-, or ident; each branch recurses for nested types. Channel direction is encoded as :both / :send / :recv (Go-specific tag). Coverage: nested types end-to-end — []*T, [][]int, map[string][]int, chan map[K]V, *[]int — all via the v.(T) assertion carrier. Logged a concrete kit-gap proposal in plans/go-on-sx.md Blockers for canonical type-node shapes. The first six (:ty-name, :ty-sel, :ty-ptr, :ty-slice, :ty-array, :ty-map) are universal across statically-typed guests and worth promoting on the next consumer; channel/func shapes stay guest-specific until a second user. Phase 2 parse acceptance bar (80+ tests) crossed: parse 81/81, total 210/210. Func / struct / interface types and full decls + stmts still keep Phase 2 open. Co-Authored-By: Claude Opus 4.7 (1M context) --- lib/go/parse.sx | 51 +++++++++++++++++++++++++---- lib/go/scoreboard.json | 6 ++-- lib/go/scoreboard.md | 4 +-- lib/go/tests/parse.sx | 73 ++++++++++++++++++++++++++++++++++++++++++ plans/go-on-sx.md | 43 ++++++++++++++++++++++--- 5 files changed, 161 insertions(+), 16 deletions(-) diff --git a/lib/go/parse.sx b/lib/go/parse.sx index ab5b1dad..654d20ff 100644 --- a/lib/go/parse.sx +++ b/lib/go/parse.sx @@ -97,19 +97,56 @@ args))))) (define gp-parse-type - ;; Minimal type-expression parser. This iteration handles: - ;; *T → (list :ty-ptr T) - ;; name → (list :ty-name "name") - ;; pkg.Name → (list :ty-sel "pkg" "Name") - ;; Full type grammar (slice, array, map, chan, func, struct, - ;; interface) is a separate Phase 2 sub-deliverable. + ;; Go type-expression parser. Covers: + ;; *T → (list :ty-ptr T) + ;; name → (list :ty-name "name") + ;; pkg.Name → (list :ty-sel "pkg" "Name") + ;; []T → (list :ty-slice T) + ;; [N]T → (list :ty-array N T) + ;; map[K]V → (list :ty-map K V) + ;; chan T → (list :ty-chan :both T) + ;; chan<- T → (list :ty-chan :send T) + ;; <-chan T → (list :ty-chan :recv T) + ;; Struct, interface, func types are deferred to a later slice. (fn () (cond (and (= (gp-tok-type) "op") (= (gp-tok-value) "*")) + (do (gp-advance!) (list :ty-ptr (gp-parse-type))) + (and (= (gp-tok-type) "op") (= (gp-tok-value) "[")) (do (gp-advance!) - (list :ty-ptr (gp-parse-type))) + (cond + (and (= (gp-tok-type) "op") (= (gp-tok-value) "]")) + (do (gp-advance!) (list :ty-slice (gp-parse-type))) + :else + (let ((sz (gp-parse-expr 1))) + (when (and (= (gp-tok-type) "op") (= (gp-tok-value) "]")) + (gp-advance!)) + (list :ty-array sz (gp-parse-type))))) + (and (= (gp-tok-type) "keyword") (= (gp-tok-value) "map")) + (do + (gp-advance!) + (when (and (= (gp-tok-type) "op") (= (gp-tok-value) "[")) + (gp-advance!)) + (let ((k (gp-parse-type))) + (when (and (= (gp-tok-type) "op") (= (gp-tok-value) "]")) + (gp-advance!)) + (let ((v (gp-parse-type))) + (list :ty-map k v)))) + (and (= (gp-tok-type) "op") (= (gp-tok-value) "<-")) + (do + (gp-advance!) + (when (and (= (gp-tok-type) "keyword") (= (gp-tok-value) "chan")) + (gp-advance!)) + (list :ty-chan :recv (gp-parse-type))) + (and (= (gp-tok-type) "keyword") (= (gp-tok-value) "chan")) + (do + (gp-advance!) + (cond + (and (= (gp-tok-type) "op") (= (gp-tok-value) "<-")) + (do (gp-advance!) (list :ty-chan :send (gp-parse-type))) + :else (list :ty-chan :both (gp-parse-type)))) (= (gp-tok-type) "ident") (let ((name (gp-tok-value))) (gp-advance!) diff --git a/lib/go/scoreboard.json b/lib/go/scoreboard.json index 6134f9f6..3f4c7ea0 100644 --- a/lib/go/scoreboard.json +++ b/lib/go/scoreboard.json @@ -1,10 +1,10 @@ { "language": "go", - "total_pass": 199, - "total": 199, + "total_pass": 210, + "total": 210, "suites": [ {"name":"lex","pass":129,"total":129,"status":"ok"}, - {"name":"parse","pass":70,"total":70,"status":"ok"}, + {"name":"parse","pass":81,"total":81,"status":"ok"}, {"name":"types","pass":0,"total":0,"status":"pending"}, {"name":"eval","pass":0,"total":0,"status":"pending"}, {"name":"runtime","pass":0,"total":0,"status":"pending"}, diff --git a/lib/go/scoreboard.md b/lib/go/scoreboard.md index 6c2a4b2c..7580251d 100644 --- a/lib/go/scoreboard.md +++ b/lib/go/scoreboard.md @@ -1,11 +1,11 @@ # Go-on-SX Scoreboard -**Total: 199 / 199 tests passing** +**Total: 210 / 210 tests passing** | | Suite | Pass | Total | |---|---|---|---| | ✅ | lex | 129 | 129 | -| ✅ | parse | 70 | 70 | +| ✅ | parse | 81 | 81 | | ⬜ | types | 0 | 0 | | ⬜ | eval | 0 | 0 | | ⬜ | runtime | 0 | 0 | diff --git a/lib/go/tests/parse.sx b/lib/go/tests/parse.sx index a1e6e4b9..d142308e 100644 --- a/lib/go/tests/parse.sx +++ b/lib/go/tests/parse.sx @@ -363,6 +363,79 @@ (list :assert (ast-var "v") (list :ty-name "int")) (ast-literal "1")))) +(go-parse-test + "ty: []int (slice)" + (go-parse "v.([]int)") + (list :assert (ast-var "v") (list :ty-slice (list :ty-name "int")))) + +(go-parse-test + "ty: [10]int (array)" + (go-parse "v.([10]int)") + (list + :assert (ast-var "v") + (list :ty-array (ast-literal "10") (list :ty-name "int")))) + +(go-parse-test + "ty: map[string]int" + (go-parse "v.(map[string]int)") + (list + :assert (ast-var "v") + (list :ty-map (list :ty-name "string") (list :ty-name "int")))) + +(go-parse-test + "ty: chan int (bidirectional)" + (go-parse "v.(chan int)") + (list :assert (ast-var "v") (list :ty-chan :both (list :ty-name "int")))) + +(go-parse-test + "ty: chan<- int (send-only)" + (go-parse "v.(chan<- int)") + (list :assert (ast-var "v") (list :ty-chan :send (list :ty-name "int")))) + +(go-parse-test + "ty: <-chan int (recv-only)" + (go-parse "v.(<-chan int)") + (list :assert (ast-var "v") (list :ty-chan :recv (list :ty-name "int")))) + +(go-parse-test + "ty: []*T (slice of pointers)" + (go-parse "v.([]*T)") + (list + :assert (ast-var "v") + (list :ty-slice (list :ty-ptr (list :ty-name "T"))))) + +(go-parse-test + "ty: [][]int (slice of slice)" + (go-parse "v.([][]int)") + (list + :assert (ast-var "v") + (list :ty-slice (list :ty-slice (list :ty-name "int"))))) + +(go-parse-test + "ty: map[string][]int (map with slice value)" + (go-parse "v.(map[string][]int)") + (list + :assert (ast-var "v") + (list + :ty-map (list :ty-name "string") + (list :ty-slice (list :ty-name "int"))))) + +(go-parse-test + "ty: chan map[K]V (chan of map type)" + (go-parse "v.(chan map[K]V)") + (list + :assert (ast-var "v") + (list + :ty-chan :both + (list :ty-map (list :ty-name "K") (list :ty-name "V"))))) + +(go-parse-test + "ty: *[]int (pointer to slice)" + (go-parse "v.(*[]int)") + (list + :assert (ast-var "v") + (list :ty-ptr (list :ty-slice (list :ty-name "int"))))) + (go-parse-test "non-primary: '+'" (go-parse "+") nil) (go-parse-test "non-primary: empty" (go-parse "") nil) diff --git a/plans/go-on-sx.md b/plans/go-on-sx.md index b950292d..dae41bdd 100644 --- a/plans/go-on-sx.md +++ b/plans/go-on-sx.md @@ -174,9 +174,10 @@ Progress-log line → push `origin/loops/go`. - [x] Type assertion `v.(T)`. `(list :assert OBJ TYPE)`. Includes a minimal `gp-parse-type` (named / qualified `pkg.T` / pointer `*T` / `**T`); full type grammar still pending below. -- [ ] Type expressions: basic, slice `[]T`, array `[N]T`, map `map[K]V`, - chan `chan T` / `chan<- T` / `<-chan T`, func, struct, interface, - pointer `*T`. +- [/] Type expressions: **slice `[]T`, array `[N]T`, map `map[K]V`, chan + `chan T` / `chan<- T` / `<-chan T`, pointer `*T`, named `T`, + qualified `pkg.T`** all done — kit has no type primitives. + func / struct / interface / generics deferred. - [ ] Composite literals: `T{...}`, `[]T{...}`, `map[K]V{...}`, `struct{...}{...}`. - [ ] Declarations: `package`, `import`, `var`, `const`, `type`, `func` @@ -186,7 +187,9 @@ Progress-log line → push `origin/loops/go`. assign, short-decl `:=`, send `ch <- v`, recv `<-ch`. - [ ] End-to-end: hello-world, fibonacci, FizzBuzz, goroutine ping-pong, struct + method. -- **Acceptance:** parse/ suite at 80+ tests. Current: 70/70. +- **Acceptance:** parse/ suite at 80+ tests. **Acceptance bar crossed: + 81/81.** Remaining sub-items (func/struct/interface types, composite + literals, decls, stmts, e2e) still keep Phase 2 open ⬜. ### Phase 3 — Bidirectional type checker, MVP (`lib/go/types.sx`) ⬜ - **Independent implementation.** Do NOT use lib/guest/static-types- @@ -446,6 +449,25 @@ Observed from building the Go parser: Minimal repro: see `lib/go/parse.sx#gp-parse-postfix` + `gp-parse-bracket`. +4. **No type-expression primitives.** Every statically-typed guest needs + to express types in source. Proposed canonical shapes: + + ``` + (list :ty-name "T") — named type + (list :ty-sel "pkg" "T") — qualified type + (list :ty-ptr T) — pointer to T + (list :ty-slice T) — slice / dynamic array of T + (list :ty-array N T) — fixed array, N is an expr + (list :ty-map K V) — map type (also Python dict, Rust HashMap) + ``` + + The first six are universal: Rust, Swift, TS, Kotlin, Scala, Hack + all need them. Go-specific extensions like `:ty-chan` (channel with + direction) and `:ty-func` (parameter+return) should stay + guest-specific until a second consumer wants them. + +Minimal repro: see `lib/go/parse.sx#gp-parse-type`. + ### Kit-gap proposals against `lib/guest/lex.sx` Observed from building the Go tokenizer. Not blocking Phase 2; surfaced @@ -469,6 +491,19 @@ Minimal repro: see `lib/go/lex.sx#gl-oct-digit?` and `#gl-match-op`. _Newest first. Append one dated entry per commit._ +- 2026-05-27 — Phase 2 cont.: type expressions — slice `[]T`, array + `[N]T`, map `map[K]V`, chan in all three directions (`chan T`, + `chan<- T`, `<-chan T`). `gp-parse-type` now dispatches on + `*`/`[`/`map`/`chan`/`<-`/ident; each branch recurses for nested + types. Channel direction is `:both`/`:send`/`:recv`. AST stays + Go-specific tagged lists — kit has no type primitives at all. + Covers nested types end-to-end (slice-of-pointer, slice-of-slice, + map-with-slice-value, chan-of-map, pointer-to-slice). **Parse + acceptance bar (80+) crossed: +11 tests, parse 81/81, total 210/210.** + Func / struct / interface types and generics still pending in Phase 2. + `[proposes-ast]` — surfaces concrete type-node proposals (slice / array + / map are universal across statically-typed guests; channel direction + is Go-specific). Logged in Blockers. - 2026-05-27 — Phase 2 cont.: type assertion `v.(T)` postfix form. Postfix `.` branch now disambiguates between `.field` (selector) and `.(...)` (type assertion) by peeking at the next token. New