go: parse.sx — slice/array/map/chan type expressions + 11 tests; parse acceptance crossed [proposes-ast]
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 18s

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) <noreply@anthropic.com>
This commit is contained in:
2026-05-27 08:02:08 +00:00
parent 503bdf12d6
commit 8ba66e0dc9
5 changed files with 161 additions and 16 deletions

View File

@@ -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!)

View File

@@ -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"},

View File

@@ -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 |

View File

@@ -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)