go: parse.sx — func + method declarations + 8 tests [shapes-static-types-bidirectional]
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 28s

Adds Go func and method declarations:
  func main() {}
  func add(x, y int) int { return x + y }
  func mix(x int, y string) {}
  func divmod(a, b int) (int, int) {}
  func sig(x int) int                            (no body)
  func (p *Point) String() string { ... }        (method, pointer recv)
  func (s Stack) Len() int { ... }               (method, value recv)
  func nested() { if true { x := 1; { y := 2 } } }   (nested braces)

New gp-parse-decl-param-group implements named-greedy disambiguation:
collects consecutive 'ident [, ident]*' then parses a type. Anonymous
mixed lists like 'func(int, string)' are a known limitation (parser
treats first ident as a name); flagged in plan.

gp-skip-block! brace-balances over the body; the AST stores ':body'
as a sentinel until statement parsing lands. Methods use the receiver
parameter shape directly.

AST:
  (list :func-decl   NAME PARAMS RESULTS BODY)
  (list :method-decl RECV NAME PARAMS RESULTS BODY)

**All five `:field` binding-group consumers now exist** across the
parser: struct fields, var, const, func params, method receivers.
That's strong cross-deliverable validation of the ast-binding-group
proposal from Blockers — five different declaration contexts, one
shared shape.

This is the chisel-relevant insight for sister plan static-types-
bidirectional: an entry has been appended to its design diary
describing how `:field` will be the load-bearing input shape for
the bidirectional checker's `check Γ e T` judgment across these
contexts.

parse 132/132, total 261/261.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-27 19:52:07 +00:00
parent 4922b6e987
commit ad21776002
6 changed files with 249 additions and 14 deletions

View File

@@ -594,6 +594,133 @@
(let ((t (gp-parse-type)))
(list :type-decl name t)))
:else nil)))
(define
gp-parse-decl-param-group
;; Parses one parameter binding group inside a func decl param list.
;; Returns (list :field NAMES TYPE). Named-greedy: collects all
;; consecutive idents separated by commas, then a type. Fails for
;; mixed anonymous lists like func(int, string) — flagged in plan.
(fn
()
(cond
(not (= (gp-tok-type) "ident"))
(list :field (list) (gp-parse-type))
:else
(let ((names (list)) (candidate (gp-tok-value)))
(gp-advance!)
(define
gp-dpg-loop
(fn
()
(when (and (= (gp-tok-type) "op") (= (gp-tok-value) ","))
(let ((saved-idx gp-idx))
(gp-advance!)
(cond
(= (gp-tok-type) "ident")
(do
(append! names candidate)
(set! candidate (gp-tok-value))
(gp-advance!)
(gp-dpg-loop))
:else
(set! gp-idx saved-idx))))))
(gp-dpg-loop)
(cond
(and (= (gp-tok-type) "op")
(or (= (gp-tok-value) ")") (= (gp-tok-value) ",")))
(list :field names (list :ty-name candidate))
:else
(do
(append! names candidate)
(list :field names (gp-parse-type))))))))
(define
gp-parse-func-decl-params
;; Func-decl parameter list — comma-separated binding groups.
;; Caller positioned BEFORE '('. Consumes ')'.
(fn
()
(when (and (= (gp-tok-type) "op") (= (gp-tok-value) "("))
(gp-advance!))
(let ((groups (list)))
(cond
(and (= (gp-tok-type) "op") (= (gp-tok-value) ")"))
(do (gp-advance!) groups)
:else
(do
(append! groups (gp-parse-decl-param-group))
(define
gp-fdp-rest
(fn
()
(cond
(and (= (gp-tok-type) "op") (= (gp-tok-value) ","))
(do
(gp-advance!)
(append! groups (gp-parse-decl-param-group))
(gp-fdp-rest))
(and (= (gp-tok-type) "op") (= (gp-tok-value) ")"))
(gp-advance!)
:else nil)))
(gp-fdp-rest)
groups)))))
(define
gp-skip-block!
;; Brace-balanced skip. Caller has consumed the opening '{'.
;; Statement parsing arrives in a later iteration; for now the
;; body is opaque and stored as the keyword :body in the AST.
(fn
()
(let ((depth 1))
(define
gp-block-loop
(fn
()
(cond
(= (gp-tok-type) "eof") nil
(and (= (gp-tok-type) "op") (= (gp-tok-value) "{"))
(do (set! depth (+ depth 1)) (gp-advance!) (gp-block-loop))
(and (= (gp-tok-type) "op") (= (gp-tok-value) "}"))
(do
(set! depth (- depth 1))
(gp-advance!)
(when (> depth 0) (gp-block-loop)))
:else (do (gp-advance!) (gp-block-loop)))))
(gp-block-loop))))
(define
gp-parse-func-decl
;; Caller has consumed 'func'.
;; func NAME (params) [results] { body }
;; func (recv) NAME (params) [results] { body } — method
;; AST:
;; (list :func-decl NAME PARAMS RESULTS BODY)
;; (list :method-decl RECV NAME PARAMS RESULTS BODY)
;; BODY is :body (opaque) if a block was present, else nil.
(fn
()
(let ((recv nil))
(when (and (= (gp-tok-type) "op") (= (gp-tok-value) "("))
(gp-advance!)
(set! recv (gp-parse-decl-param-group))
(when (and (= (gp-tok-type) "op") (= (gp-tok-value) ")"))
(gp-advance!)))
(cond
(= (gp-tok-type) "ident")
(let ((name (gp-tok-value)))
(gp-advance!)
(let ((params (gp-parse-func-decl-params)))
(let ((results (gp-parse-func-type-results)))
(let ((body nil))
(when (and (= (gp-tok-type) "op")
(= (gp-tok-value) "{"))
(gp-advance!)
(gp-skip-block!)
(set! body :body))
(cond
(= recv nil)
(list :func-decl name params results body)
:else
(list :method-decl recv name params results body))))))
:else nil))))
(define
gp-parse-decl
;; Single declaration: package / import / var / const / type.
@@ -625,6 +752,8 @@
(do (gp-advance!) (gp-parse-var-or-const :const-decl))
(and (= (gp-tok-type) "keyword") (= (gp-tok-value) "type"))
(do (gp-advance!) (gp-parse-type-decl))
(and (= (gp-tok-type) "keyword") (= (gp-tok-value) "func"))
(do (gp-advance!) (gp-parse-func-decl))
:else nil)))
(define
gp-parse-top
@@ -641,7 +770,8 @@
(= (gp-tok-value) "import")
(= (gp-tok-value) "var")
(= (gp-tok-value) "const")
(= (gp-tok-value) "type")))
(= (gp-tok-value) "type")
(= (gp-tok-value) "func")))
(gp-parse-decl)
:else (gp-parse-expr 1))))
(gp-parse-top))))