go: parse.sx — package/import/var/const/type declarations + 10 tests [consumes-ast]
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 33s
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 33s
First slice of Phase 2 declarations:
package main → (list :package "main")
import "fmt" → (ast-import "fmt") [from kit]
var x int → var-decl + :field binding
var x = 5 → init only (type inferred)
var x int = 5 → both type and init
var x, y int = 1, 2 → multi-name shared type
const Pi = 3.14 → const-decl
const C int = 42 → typed const
type T int → named alias
type Point struct { x, y int } → named struct
New gp-parse-top dispatches on the leading keyword: routes
package/import/var/const/type to gp-parse-decl; everything else
still goes through gp-parse-expr. Existing expression tests are
unaffected (cur won't be a decl keyword at expression start).
var/const decls use the (:field NAMES TYPE) shape from the
ast-binding-group proposal — first concrete cross-deliverable use:
struct fields, var decls, const decls all envelope through the
same node. That's the smell test for whether the kit shape is
right; so far it's clean.
import uses the canonical ast-import from lib/guest/ast.sx — first
direct use of a kit constructor for a declaration shape.
Grouped/parenthesized decls (var (...), import (...), const (...),
type (...)) and func decls (with method receivers + named params)
deferred to subsequent iterations.
parse 124/124, total 253/253.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
117
lib/go/parse.sx
117
lib/go/parse.sx
@@ -529,4 +529,119 @@
|
||||
(ast-var (get tok :value))
|
||||
(list left right))
|
||||
min-prec)))))))))))
|
||||
(gp-parse-expr 1))))
|
||||
(define
|
||||
gp-parse-expr-list
|
||||
;; Comma-separated expressions; reused by var/const initialisers.
|
||||
(fn
|
||||
()
|
||||
(let ((exprs (list)))
|
||||
(let ((first (gp-parse-expr 1)))
|
||||
(when (not (= first nil)) (append! exprs first)))
|
||||
(define
|
||||
gp-exprs-rest
|
||||
(fn
|
||||
()
|
||||
(when (and (= (gp-tok-type) "op") (= (gp-tok-value) ","))
|
||||
(gp-advance!)
|
||||
(let ((e (gp-parse-expr 1)))
|
||||
(when (not (= e nil)) (append! exprs e)))
|
||||
(gp-exprs-rest))))
|
||||
(gp-exprs-rest)
|
||||
exprs)))
|
||||
(define
|
||||
gp-parse-var-or-const
|
||||
;; Caller has consumed 'var' or 'const'. TAG is :var-decl or :const-decl.
|
||||
;; Shape: TAG (list :field NAMES TYPE-OR-NIL) EXPRS-OR-NIL
|
||||
;; Both type and init are optional (must have at least one in Go;
|
||||
;; lexer is permissive).
|
||||
(fn
|
||||
(tag)
|
||||
(let ((names (list)))
|
||||
(when (= (gp-tok-type) "ident")
|
||||
(append! names (gp-tok-value))
|
||||
(gp-advance!))
|
||||
(define
|
||||
gp-names-rest
|
||||
(fn
|
||||
()
|
||||
(when (and (= (gp-tok-type) "op") (= (gp-tok-value) ","))
|
||||
(gp-advance!)
|
||||
(when (= (gp-tok-type) "ident")
|
||||
(append! names (gp-tok-value))
|
||||
(gp-advance!))
|
||||
(gp-names-rest))))
|
||||
(gp-names-rest)
|
||||
(let ((ty nil) (exprs nil))
|
||||
(when (and (not (= (gp-tok-type) "eof"))
|
||||
(not (= (gp-tok-type) "semi"))
|
||||
(not (and (= (gp-tok-type) "op")
|
||||
(= (gp-tok-value) "="))))
|
||||
(set! ty (gp-parse-type)))
|
||||
(when (and (= (gp-tok-type) "op") (= (gp-tok-value) "="))
|
||||
(gp-advance!)
|
||||
(set! exprs (gp-parse-expr-list)))
|
||||
(list tag (list :field names ty) exprs)))))
|
||||
(define
|
||||
gp-parse-type-decl
|
||||
;; Caller has consumed 'type'. Single-decl form only:
|
||||
;; type NAME TYPE → (list :type-decl "NAME" TYPE)
|
||||
(fn
|
||||
()
|
||||
(cond
|
||||
(= (gp-tok-type) "ident")
|
||||
(let ((name (gp-tok-value)))
|
||||
(gp-advance!)
|
||||
(let ((t (gp-parse-type)))
|
||||
(list :type-decl name t)))
|
||||
:else nil)))
|
||||
(define
|
||||
gp-parse-decl
|
||||
;; Single declaration: package / import / var / const / type.
|
||||
;; Grouped/parenthesized forms and func decls are deferred.
|
||||
(fn
|
||||
()
|
||||
(cond
|
||||
(and (= (gp-tok-type) "keyword") (= (gp-tok-value) "package"))
|
||||
(do
|
||||
(gp-advance!)
|
||||
(cond
|
||||
(= (gp-tok-type) "ident")
|
||||
(let ((name (gp-tok-value)))
|
||||
(gp-advance!)
|
||||
(list :package name))
|
||||
:else nil))
|
||||
(and (= (gp-tok-type) "keyword") (= (gp-tok-value) "import"))
|
||||
(do
|
||||
(gp-advance!)
|
||||
(cond
|
||||
(= (gp-tok-type) "string")
|
||||
(let ((path (gp-tok-value)))
|
||||
(gp-advance!)
|
||||
(ast-import path))
|
||||
:else nil))
|
||||
(and (= (gp-tok-type) "keyword") (= (gp-tok-value) "var"))
|
||||
(do (gp-advance!) (gp-parse-var-or-const :var-decl))
|
||||
(and (= (gp-tok-type) "keyword") (= (gp-tok-value) "const"))
|
||||
(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))
|
||||
:else nil)))
|
||||
(define
|
||||
gp-parse-top
|
||||
;; Top-level dispatch: declaration keywords go to gp-parse-decl,
|
||||
;; everything else is parsed as an expression. ASI semis at the
|
||||
;; start are skipped.
|
||||
(fn
|
||||
()
|
||||
(cond
|
||||
(= (gp-tok-type) "semi")
|
||||
(do (gp-advance!) (gp-parse-top))
|
||||
(and (= (gp-tok-type) "keyword")
|
||||
(or (= (gp-tok-value) "package")
|
||||
(= (gp-tok-value) "import")
|
||||
(= (gp-tok-value) "var")
|
||||
(= (gp-tok-value) "const")
|
||||
(= (gp-tok-value) "type")))
|
||||
(gp-parse-decl)
|
||||
:else (gp-parse-expr 1))))
|
||||
(gp-parse-top))))
|
||||
|
||||
Reference in New Issue
Block a user