go: parse.sx — composite literals + 8 tests [nothing]
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 26s
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 26s
Adds Go composite literals:
T{} empty
T{1, 2} positional
T{X: 1, Y: 2} keyed
[]int{1, 2, 3} slice
[3]int{1, 2, 3} array
map[string]int{"a": 1} map
pkg.Point{1, 2} qualified
[]Point{Point{1,2}, Point{3,4}} nested
AST: (list :composite TYPE-OR-EXPR ELEMS). Each element is an
expression or (list :kv KEY VALUE).
Two parser entry points feed the same AST:
* gp-parse-primary picks up type-prefixed composites by seeing
a literal-type starter ([, map, struct) and parsing a type
first, then optionally a '{' body.
* The postfix loop picks up ident-prefixed composites — after
any base expression, '{' wraps it as a composite literal.
Known limitation flagged in plan: when statement parsing arrives,
the postfix '{' branch will misread `if cond { ... }` as a composite
literal. Standard fix: parser-mode flag suppressing composite-lit
disambiguation in control-flow expression positions. Added to plan.
Elided types in nested composites (`[][]int{{1,2},{3,4}}` with the
inner `{1,2}` typed implicitly) deferred.
parse 114/114, total 243/243.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -63,7 +63,58 @@
|
||||
(do (gp-advance!) (ast-literal v))
|
||||
(= ty "ident")
|
||||
(do (gp-advance!) (ast-var v))
|
||||
;; Type-prefixed composite literal starters: [, map, struct.
|
||||
;; We parse a full type, then if '{' follows it's a composite
|
||||
;; literal; otherwise the type is the operand (the caller
|
||||
;; decides what to do — currently statement parsing isn't here).
|
||||
(or (and (= ty "op") (= v "["))
|
||||
(and (= ty "keyword")
|
||||
(or (= v "map") (= v "struct"))))
|
||||
(let ((tytree (gp-parse-type)))
|
||||
(cond
|
||||
(and (= (gp-tok-type) "op") (= (gp-tok-value) "{"))
|
||||
(do
|
||||
(gp-advance!)
|
||||
(list :composite tytree (gp-parse-composite-elems)))
|
||||
:else tytree))
|
||||
:else nil))))
|
||||
(define
|
||||
gp-parse-composite-elems
|
||||
;; Caller has consumed '{'. Parses elements until '}'.
|
||||
;; Each element: either an expression, or KEY ':' VALUE.
|
||||
;; KEY can be an ident (struct field name) or an expression
|
||||
;; (map key) — parser is permissive, types phase disambiguates.
|
||||
;; Returns a list of expression nodes or (list :kv KEY VALUE).
|
||||
(fn
|
||||
()
|
||||
(let ((elems (list)))
|
||||
(define
|
||||
gp-comp-loop
|
||||
(fn
|
||||
()
|
||||
(cond
|
||||
(= (gp-tok-type) "semi")
|
||||
(do (gp-advance!) (gp-comp-loop))
|
||||
(and (= (gp-tok-type) "op") (= (gp-tok-value) "}"))
|
||||
(gp-advance!)
|
||||
:else
|
||||
(do
|
||||
(let ((first (gp-parse-expr 1)))
|
||||
(cond
|
||||
(and (= (gp-tok-type) "op")
|
||||
(= (gp-tok-value) ":"))
|
||||
(do
|
||||
(gp-advance!)
|
||||
(let ((val (gp-parse-expr 1)))
|
||||
(append! elems (list :kv first val))))
|
||||
:else
|
||||
(append! elems first)))
|
||||
(when (and (= (gp-tok-type) "op")
|
||||
(= (gp-tok-value) ","))
|
||||
(gp-advance!))
|
||||
(gp-comp-loop)))))
|
||||
(gp-comp-loop)
|
||||
elems)))
|
||||
(define
|
||||
gp-parse-call-args
|
||||
;; Parse comma-separated args inside (...). Caller has already
|
||||
@@ -413,6 +464,14 @@
|
||||
(do
|
||||
(gp-advance!)
|
||||
(gp-postfix-loop (gp-parse-bracket base)))
|
||||
;; Ident-prefixed composite literal: T{...}. The base is
|
||||
;; the AST expression for the type-name (an ast-var or a
|
||||
;; :select node); a later phase resolves it as a type.
|
||||
(and (= (get tok :type) "op") (= (get tok :value) "{"))
|
||||
(do
|
||||
(gp-advance!)
|
||||
(gp-postfix-loop
|
||||
(list :composite base (gp-parse-composite-elems))))
|
||||
:else base)))))
|
||||
(define
|
||||
gp-unary-ops
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
{
|
||||
"language": "go",
|
||||
"total_pass": 235,
|
||||
"total": 235,
|
||||
"total_pass": 243,
|
||||
"total": 243,
|
||||
"suites": [
|
||||
{"name":"lex","pass":129,"total":129,"status":"ok"},
|
||||
{"name":"parse","pass":106,"total":106,"status":"ok"},
|
||||
{"name":"parse","pass":114,"total":114,"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"},
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
# Go-on-SX Scoreboard
|
||||
|
||||
**Total: 235 / 235 tests passing**
|
||||
**Total: 243 / 243 tests passing**
|
||||
|
||||
| | Suite | Pass | Total |
|
||||
|---|---|---|---|
|
||||
| ✅ | lex | 129 | 129 |
|
||||
| ✅ | parse | 106 | 106 |
|
||||
| ✅ | parse | 114 | 114 |
|
||||
| ⬜ | types | 0 | 0 |
|
||||
| ⬜ | eval | 0 | 0 |
|
||||
| ⬜ | runtime | 0 | 0 |
|
||||
|
||||
@@ -650,6 +650,70 @@
|
||||
(list (list :ty-name "int")))
|
||||
(list :method "Close" (list) (list))))))
|
||||
|
||||
(go-parse-test
|
||||
"comp: Point{} (empty)"
|
||||
(go-parse "Point{}")
|
||||
(list :composite (ast-var "Point") (list)))
|
||||
|
||||
(go-parse-test
|
||||
"comp: Point{1, 2} (positional)"
|
||||
(go-parse "Point{1, 2}")
|
||||
(list
|
||||
:composite (ast-var "Point")
|
||||
(list (ast-literal "1") (ast-literal "2"))))
|
||||
|
||||
(go-parse-test
|
||||
"comp: Point{X: 1, Y: 2} (keyed)"
|
||||
(go-parse "Point{X: 1, Y: 2}")
|
||||
(list
|
||||
:composite (ast-var "Point")
|
||||
(list
|
||||
(list :kv (ast-var "X") (ast-literal "1"))
|
||||
(list :kv (ast-var "Y") (ast-literal "2")))))
|
||||
|
||||
(go-parse-test
|
||||
"comp: []int{1, 2, 3} (slice literal)"
|
||||
(go-parse "[]int{1, 2, 3}")
|
||||
(list
|
||||
:composite (list :ty-slice (list :ty-name "int"))
|
||||
(list (ast-literal "1") (ast-literal "2") (ast-literal "3"))))
|
||||
|
||||
(go-parse-test
|
||||
"comp: [3]int{1, 2, 3} (array literal)"
|
||||
(go-parse "[3]int{1, 2, 3}")
|
||||
(list
|
||||
:composite (list :ty-array (ast-literal "3") (list :ty-name "int"))
|
||||
(list (ast-literal "1") (ast-literal "2") (ast-literal "3"))))
|
||||
|
||||
(go-parse-test
|
||||
"comp: map[string]int{\"a\": 1, \"b\": 2} (map literal)"
|
||||
(go-parse "map[string]int{\"a\": 1, \"b\": 2}")
|
||||
(list
|
||||
:composite (list :ty-map (list :ty-name "string") (list :ty-name "int"))
|
||||
(list
|
||||
(list :kv (ast-literal "a") (ast-literal "1"))
|
||||
(list :kv (ast-literal "b") (ast-literal "2")))))
|
||||
|
||||
(go-parse-test
|
||||
"comp: pkg.Point{1, 2} (qualified type)"
|
||||
(go-parse "pkg.Point{1, 2}")
|
||||
(list
|
||||
:composite (list :select (ast-var "pkg") "Point")
|
||||
(list (ast-literal "1") (ast-literal "2"))))
|
||||
|
||||
(go-parse-test
|
||||
"comp: nested — []Point{Point{1,2}, Point{3,4}}"
|
||||
(go-parse "[]Point{Point{1, 2}, Point{3, 4}}")
|
||||
(list
|
||||
:composite (list :ty-slice (list :ty-name "Point"))
|
||||
(list
|
||||
(list
|
||||
:composite (ast-var "Point")
|
||||
(list (ast-literal "1") (ast-literal "2")))
|
||||
(list
|
||||
:composite (ast-var "Point")
|
||||
(list (ast-literal "3") (ast-literal "4"))))))
|
||||
|
||||
(go-parse-test "non-primary: '+'" (go-parse "+") nil)
|
||||
|
||||
(go-parse-test "non-primary: empty" (go-parse "") nil)
|
||||
|
||||
@@ -181,8 +181,13 @@ Progress-log line → push `origin/loops/go`.
|
||||
with methods + embedded interfaces (named and qualified)** all
|
||||
done — kit has no type primitives. Field tags, struct embeds,
|
||||
variadic, named func-params, Go 1.18 type sets, generics deferred.
|
||||
- [ ] Composite literals: `T{...}`, `[]T{...}`, `map[K]V{...}`,
|
||||
`struct{...}{...}`.
|
||||
- [x] Composite literals: `T{...}`, `[]T{...}`, `[N]T{...}`,
|
||||
`map[K]V{...}`, `pkg.T{...}`, nested. Positional and keyed
|
||||
(`X: 1, Y: 2`) elements. AST `(list :composite TYPE-OR-EXPR ELEMS)`;
|
||||
elements are exprs or `(list :kv KEY VALUE)`. Note: in statement
|
||||
context (e.g. `if cond { ... }`) my parser would WRONGLY treat
|
||||
the body as a composite; statement parsing will need a "no-
|
||||
composite-here" mode flag — to be added when statements arrive.
|
||||
- [ ] Declarations: `package`, `import`, `var`, `const`, `type`, `func`
|
||||
(including methods, parameter lists, return types).
|
||||
- [ ] Statements: `if`/`else`, `for` (C-style + range), `switch` (expr +
|
||||
@@ -191,8 +196,7 @@ Progress-log line → push `origin/loops/go`.
|
||||
- [ ] End-to-end: hello-world, fibonacci, FizzBuzz, goroutine ping-pong,
|
||||
struct + method.
|
||||
- **Acceptance:** parse/ suite at 80+ tests. **Acceptance bar crossed:
|
||||
106/106.** Remaining sub-items (composite literals, decls, stmts,
|
||||
e2e) still keep Phase 2 open ⬜.
|
||||
114/114.** Remaining sub-items (decls, stmts, e2e) keep Phase 2 open ⬜.
|
||||
|
||||
### Phase 3 — Bidirectional type checker, MVP (`lib/go/types.sx`) ⬜
|
||||
- **Independent implementation.** Do NOT use lib/guest/static-types-
|
||||
@@ -509,6 +513,17 @@ 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.: composite literals. `T{}`, `T{1, 2}`,
|
||||
`T{X: 1, Y: 2}`, `[]T{...}`, `[N]T{...}`, `map[K]V{...}`,
|
||||
`pkg.T{...}`, nested composites. AST shape
|
||||
`(list :composite TYPE-OR-EXPR ELEMS)`; each element is an expression
|
||||
or `(list :kv KEY VALUE)`. Two parser entry points: type-prefixed
|
||||
(`gp-parse-primary` adds `[`/`map`/`struct` branches) and
|
||||
ident-prefixed (postfix loop adds `{` branch). **Known limitation
|
||||
flagged in plan:** when statement parsing arrives, the postfix `{`
|
||||
branch will misread `if cond { ... }` as composite literal — needs a
|
||||
"no-composite-here" parser-mode flag. +8 tests, parse 114/114, total
|
||||
243/243. `[nothing]` — pure Go parser shape work.
|
||||
- 2026-05-27 — Phase 2 cont.: interface-type expressions. `interface {}`,
|
||||
`interface { Close() }`, `interface { String() string }`,
|
||||
`interface { Read([]byte) (int, error) }`, plus embedded interfaces
|
||||
|
||||
Reference in New Issue
Block a user