go: parse.sx — switch + select + 8 tests; stmts done [shapes-scheduler]
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 32s
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 32s
Adds Go's switch and select statements:
switch TAG { case V1, V2: a; case V3: b; default: c }
switch { case cond: ... } — tagless
select { case x := <-ch: a; case ch <- v: b; default: c }
AST shapes:
(list :switch TAG CASES) — TAG nil for tagless
(list :case VALUES BODY) — VALUES is expr-list
(list :select CASES)
(list :select-case COMM-STMT BODY) — COMM-STMT is send/recv-assign/bare-recv
(list :default BODY)
gp-parse-case-body reads stmts until the next case/default/}/eof
without consuming the terminator — used by both switch and select.
select-case parsing reuses gp-parse-stmt for the comm-stmt, so all
four shapes (send, x := <-ch, x = <-ch, bare <-ch) fall out from the
existing stmt parser. Composite-lit suppression is engaged for the
switch tag expression.
Type-switch (`switch v := x.(type) { case int: ... }`) is the one
deferred shape; needs the `.(type)` pseudo-syntax recognised in the
expression layer. Phase 2 statement coverage is otherwise complete.
This is also a chiselling iteration for scheduler sister kit. Diary
updated with select-case design insights:
* All four select-case shapes share (list :select-case STMT BODY)
— kit primitive sched-select accepts a uniform list of cases.
* Default vs no-default determines blocking semantics. Erlang's
`receive ... after Timeout -> ...` is the analogue — both fit
"non-blocking fallback case" in the kit API.
parse 169/169, total 298/298.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
124
lib/go/parse.sx
124
lib/go/parse.sx
@@ -728,6 +728,126 @@
|
||||
:else
|
||||
(list :method-decl recv name params results body))))))
|
||||
:else nil))))
|
||||
(define
|
||||
gp-parse-case-body
|
||||
;; Stmts inside a switch/select case clause. Reads until the next
|
||||
;; 'case'/'default'/'}'/eof without consuming those terminators.
|
||||
(fn
|
||||
()
|
||||
(let ((stmts (list)))
|
||||
(define
|
||||
gp-cb-loop
|
||||
(fn
|
||||
()
|
||||
(cond
|
||||
(= (gp-tok-type) "eof") nil
|
||||
(and (= (gp-tok-type) "op") (= (gp-tok-value) "}")) nil
|
||||
(and (= (gp-tok-type) "keyword")
|
||||
(or (= (gp-tok-value) "case")
|
||||
(= (gp-tok-value) "default")))
|
||||
nil
|
||||
(= (gp-tok-type) "semi") (do (gp-advance!) (gp-cb-loop))
|
||||
:else
|
||||
(do
|
||||
(let ((saved-idx gp-idx))
|
||||
(let ((s (gp-parse-stmt)))
|
||||
(when (not (= s nil)) (append! stmts s)))
|
||||
(when (= gp-idx saved-idx) (gp-advance!)))
|
||||
(gp-cb-loop)))))
|
||||
(gp-cb-loop)
|
||||
stmts)))
|
||||
(define
|
||||
gp-parse-switch
|
||||
;; Caller has consumed 'switch'. Two shapes:
|
||||
;; switch { ...cases... } — tagless (each case is a bool)
|
||||
;; switch TAG { ...cases... } — tagged (match against TAG)
|
||||
;; AST: (list :switch TAG CASES) — TAG may be nil.
|
||||
;; Each case: (list :case VALUES BODY) or (list :default BODY).
|
||||
;; Type-switch (`switch v := x.(type)`) deferred to a follow-up.
|
||||
(fn
|
||||
()
|
||||
(set! gp-no-comp-lit (+ gp-no-comp-lit 1))
|
||||
(let ((tag nil) (cases (list)))
|
||||
(when (not (and (= (gp-tok-type) "op") (= (gp-tok-value) "{")))
|
||||
(set! tag (gp-parse-expr 1)))
|
||||
(set! gp-no-comp-lit (- gp-no-comp-lit 1))
|
||||
(when (and (= (gp-tok-type) "op") (= (gp-tok-value) "{"))
|
||||
(gp-advance!))
|
||||
(define
|
||||
gp-sw-loop
|
||||
(fn
|
||||
()
|
||||
(cond
|
||||
(= (gp-tok-type) "semi")
|
||||
(do (gp-advance!) (gp-sw-loop))
|
||||
(and (= (gp-tok-type) "op") (= (gp-tok-value) "}"))
|
||||
(gp-advance!)
|
||||
(and (= (gp-tok-type) "keyword") (= (gp-tok-value) "case"))
|
||||
(do
|
||||
(gp-advance!)
|
||||
(let ((vals (gp-parse-expr-list)))
|
||||
(when (and (= (gp-tok-type) "op")
|
||||
(= (gp-tok-value) ":"))
|
||||
(gp-advance!))
|
||||
(append! cases
|
||||
(list :case vals (gp-parse-case-body))))
|
||||
(gp-sw-loop))
|
||||
(and (= (gp-tok-type) "keyword")
|
||||
(= (gp-tok-value) "default"))
|
||||
(do
|
||||
(gp-advance!)
|
||||
(when (and (= (gp-tok-type) "op")
|
||||
(= (gp-tok-value) ":"))
|
||||
(gp-advance!))
|
||||
(append! cases
|
||||
(list :default (gp-parse-case-body)))
|
||||
(gp-sw-loop))
|
||||
:else (do (gp-advance!) (gp-sw-loop)))))
|
||||
(gp-sw-loop)
|
||||
(list :switch tag cases))))
|
||||
(define
|
||||
gp-parse-select
|
||||
;; Caller has consumed 'select'. Each case is a communication stmt
|
||||
;; (send / recv) or a recv-assignment.
|
||||
;; AST: (list :select CASES).
|
||||
;; Each case: (list :select-case COMM-STMT BODY) or (list :default BODY).
|
||||
(fn
|
||||
()
|
||||
(let ((cases (list)))
|
||||
(when (and (= (gp-tok-type) "op") (= (gp-tok-value) "{"))
|
||||
(gp-advance!))
|
||||
(define
|
||||
gp-sel-loop
|
||||
(fn
|
||||
()
|
||||
(cond
|
||||
(= (gp-tok-type) "semi")
|
||||
(do (gp-advance!) (gp-sel-loop))
|
||||
(and (= (gp-tok-type) "op") (= (gp-tok-value) "}"))
|
||||
(gp-advance!)
|
||||
(and (= (gp-tok-type) "keyword") (= (gp-tok-value) "case"))
|
||||
(do
|
||||
(gp-advance!)
|
||||
(let ((comm (gp-parse-stmt)))
|
||||
(when (and (= (gp-tok-type) "op")
|
||||
(= (gp-tok-value) ":"))
|
||||
(gp-advance!))
|
||||
(append! cases
|
||||
(list :select-case comm (gp-parse-case-body))))
|
||||
(gp-sel-loop))
|
||||
(and (= (gp-tok-type) "keyword")
|
||||
(= (gp-tok-value) "default"))
|
||||
(do
|
||||
(gp-advance!)
|
||||
(when (and (= (gp-tok-type) "op")
|
||||
(= (gp-tok-value) ":"))
|
||||
(gp-advance!))
|
||||
(append! cases
|
||||
(list :default (gp-parse-case-body)))
|
||||
(gp-sel-loop))
|
||||
:else (do (gp-advance!) (gp-sel-loop)))))
|
||||
(gp-sel-loop)
|
||||
(list :select cases))))
|
||||
(define
|
||||
gp-parse-control-cond
|
||||
;; Parses an expression as a control-flow condition with the
|
||||
@@ -915,6 +1035,10 @@
|
||||
(do (gp-advance!) (gp-parse-if))
|
||||
(and (= (gp-tok-type) "keyword") (= (gp-tok-value) "for"))
|
||||
(do (gp-advance!) (gp-parse-for))
|
||||
(and (= (gp-tok-type) "keyword") (= (gp-tok-value) "switch"))
|
||||
(do (gp-advance!) (gp-parse-switch))
|
||||
(and (= (gp-tok-type) "keyword") (= (gp-tok-value) "select"))
|
||||
(do (gp-advance!) (gp-parse-select))
|
||||
(and (= (gp-tok-type) "op") (= (gp-tok-value) "{"))
|
||||
(do (gp-advance!) (gp-parse-block-body))
|
||||
:else
|
||||
|
||||
Reference in New Issue
Block a user