go: parse.sx — type assertion v.(T) + minimal type parser + 9 tests [nothing]
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 18s
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 18s
Postfix '.' branch now peeks at the next token to disambiguate: .ident → selector / member access (list :select OBJ "field") .(TYPE) → type assertion (list :assert OBJ TYPE) New gp-parse-type covers the minimum types needed for assertions: name → (list :ty-name "int") pkg.Name → (list :ty-sel "pkg" "Name") *T / **T → (list :ty-ptr (list :ty-ptr ...)) Full type grammar — slice []T, array [N]T, map[K]V, chan, func, struct, interface — is a separate Phase 2 sub-deliverable. Type AST shapes are Go-specific tagged lists; the canonical AST kit has no type-system primitives at all yet. Worth a richer kit discussion once Phase 3 (bidirectional type checker) lands and the sister plan static-types-bidirectional has a real surface to react to. parse 70/70, total 199/199. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -95,6 +95,36 @@
|
||||
:else nil)))
|
||||
(gp-args-rest)
|
||||
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.
|
||||
(fn
|
||||
()
|
||||
(cond
|
||||
(and (= (gp-tok-type) "op") (= (gp-tok-value) "*"))
|
||||
(do
|
||||
(gp-advance!)
|
||||
(list :ty-ptr (gp-parse-type)))
|
||||
(= (gp-tok-type) "ident")
|
||||
(let ((name (gp-tok-value)))
|
||||
(gp-advance!)
|
||||
(cond
|
||||
(and (= (gp-tok-type) "op") (= (gp-tok-value) "."))
|
||||
(do
|
||||
(gp-advance!)
|
||||
(cond
|
||||
(= (gp-tok-type) "ident")
|
||||
(let ((sel-name (gp-tok-value)))
|
||||
(gp-advance!)
|
||||
(list :ty-sel name sel-name))
|
||||
:else (list :ty-name name)))
|
||||
:else (list :ty-name name)))
|
||||
:else nil)))
|
||||
(define
|
||||
gp-parse-bracket-expr
|
||||
;; Optional expression inside brackets — returns nil if next token
|
||||
@@ -159,13 +189,24 @@
|
||||
(and (= (get tok :type) "op") (= (get tok :value) "."))
|
||||
(do
|
||||
(gp-advance!)
|
||||
(let ((field-tok (gp-cur)))
|
||||
(let ((next-tok (gp-cur)))
|
||||
(cond
|
||||
(= (get field-tok :type) "ident")
|
||||
;; .(T) — type assertion
|
||||
(and (= (get next-tok :type) "op")
|
||||
(= (get next-tok :value) "("))
|
||||
(do
|
||||
(gp-advance!)
|
||||
(let ((ty (gp-parse-type)))
|
||||
(when (and (= (gp-tok-type) "op")
|
||||
(= (gp-tok-value) ")"))
|
||||
(gp-advance!))
|
||||
(gp-postfix-loop (list :assert base ty))))
|
||||
;; .ident — selector / member access
|
||||
(= (get next-tok :type) "ident")
|
||||
(do
|
||||
(gp-advance!)
|
||||
(gp-postfix-loop
|
||||
(list :select base (get field-tok :value))))
|
||||
(list :select base (get next-tok :value))))
|
||||
:else base)))
|
||||
(and (= (get tok :type) "op") (= (get tok :value) "("))
|
||||
(do
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
{
|
||||
"language": "go",
|
||||
"total_pass": 190,
|
||||
"total": 190,
|
||||
"total_pass": 199,
|
||||
"total": 199,
|
||||
"suites": [
|
||||
{"name":"lex","pass":129,"total":129,"status":"ok"},
|
||||
{"name":"parse","pass":61,"total":61,"status":"ok"},
|
||||
{"name":"parse","pass":70,"total":70,"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: 190 / 190 tests passing**
|
||||
**Total: 199 / 199 tests passing**
|
||||
|
||||
| | Suite | Pass | Total |
|
||||
|---|---|---|---|
|
||||
| ✅ | lex | 129 | 129 |
|
||||
| ✅ | parse | 61 | 61 |
|
||||
| ✅ | parse | 70 | 70 |
|
||||
| ⬜ | types | 0 | 0 |
|
||||
| ⬜ | eval | 0 | 0 |
|
||||
| ⬜ | runtime | 0 | 0 |
|
||||
|
||||
@@ -310,6 +310,59 @@
|
||||
(go-parse "a[i:j]")
|
||||
(list :slice (ast-var "a") (ast-var "i") (ast-var "j") nil))
|
||||
|
||||
(go-parse-test
|
||||
"assert: v.(int)"
|
||||
(go-parse "v.(int)")
|
||||
(list :assert (ast-var "v") (list :ty-name "int")))
|
||||
|
||||
(go-parse-test
|
||||
"assert: v.(string)"
|
||||
(go-parse "v.(string)")
|
||||
(list :assert (ast-var "v") (list :ty-name "string")))
|
||||
|
||||
(go-parse-test
|
||||
"assert: v.(MyType) (user-defined)"
|
||||
(go-parse "v.(MyType)")
|
||||
(list :assert (ast-var "v") (list :ty-name "MyType")))
|
||||
|
||||
(go-parse-test
|
||||
"assert: v.(*T) (pointer type)"
|
||||
(go-parse "v.(*T)")
|
||||
(list :assert (ast-var "v") (list :ty-ptr (list :ty-name "T"))))
|
||||
|
||||
(go-parse-test
|
||||
"assert: v.(**T) (pointer-to-pointer)"
|
||||
(go-parse "v.(**T)")
|
||||
(list
|
||||
:assert (ast-var "v")
|
||||
(list :ty-ptr (list :ty-ptr (list :ty-name "T")))))
|
||||
|
||||
(go-parse-test
|
||||
"assert: v.(pkg.T) (qualified type)"
|
||||
(go-parse "v.(pkg.T)")
|
||||
(list :assert (ast-var "v") (list :ty-sel "pkg" "T")))
|
||||
|
||||
(go-parse-test
|
||||
"assert: f().(int) (on call result)"
|
||||
(go-parse "f().(int)")
|
||||
(list :assert (ast-app (ast-var "f") (list)) (list :ty-name "int")))
|
||||
|
||||
(go-parse-test
|
||||
"assert: obj.field.(int) (after selector)"
|
||||
(go-parse "obj.field.(int)")
|
||||
(list
|
||||
:assert (list :select (ast-var "obj") "field")
|
||||
(list :ty-name "int")))
|
||||
|
||||
(go-parse-test
|
||||
"assert: v.(int) + 1 (assert binds tighter than binary +)"
|
||||
(go-parse "v.(int) + 1")
|
||||
(ast-app
|
||||
(ast-var "+")
|
||||
(list
|
||||
(list :assert (ast-var "v") (list :ty-name "int"))
|
||||
(ast-literal "1"))))
|
||||
|
||||
(go-parse-test "non-primary: '+'" (go-parse "+") nil)
|
||||
|
||||
(go-parse-test "non-primary: empty" (go-parse "") nil)
|
||||
|
||||
Reference in New Issue
Block a user