go: parse.sx — statements (return / short-decl / assign / block) + 9 tests [nothing]
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 31s
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 31s
First slice of Phase 2 statements. Replaces the func-decl ':body'
sentinel with real (:block STMTS) parsing.
gp-parse-stmt dispatches on the leading token:
return [exprs] — (list :return EXPRS)
{ ... } — nested block (recurses into block-body)
lhs := exprs — (list :short-decl LHS-LIST EXPRS)
lhs = exprs — (list :assign LHS-LIST EXPRS)
lhs OP= expr — (list :assign-op OP LHS-LIST [EXPR])
expr — bare expression statement
var/const/type/func keywords — fall through to gp-parse-decl
LHS may be a comma-separated list. Compound-assign covers all 11 Go
forms (+= -= *= /= %= &= |= ^= <<= >>= &^=).
gp-parse-block-body iterates: skips semis, terminates on '}', and for
non-trivial tokens calls gp-parse-stmt. **Two progress guards** added
to avoid infinite loops on unsupported syntax:
* gp-block-body-loop force-advances one token if gp-parse-stmt
returns nil without consuming.
* gp-parse-composite-elems does the same when its expr parser
returns nil — fixes a hang on '`if true {`x := 1`}`' where the
parser was misreading `if true{...}` as a composite literal then
spinning on `:=` inside the brace body.
Existing func/method decl tests updated from the ':body' sentinel to
the new (:block STMTS) shape. Old `gp-skip-block!` left as dead code
(removed once control-flow stmts make the misinterpretation issue
moot).
Control-flow stmts (if/for/switch/select/defer/go/break/continue) and
channel send (`ch <- v`) deferred to subsequent iterations.
parse 141/141, total 270/270.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
137
lib/go/parse.sx
137
lib/go/parse.sx
@@ -99,19 +99,22 @@
|
||||
(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!))
|
||||
(let ((saved-idx gp-idx))
|
||||
(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
|
||||
(when (not (= first nil))
|
||||
(append! elems first))))
|
||||
(when (and (= (gp-tok-type) "op")
|
||||
(= (gp-tok-value) ","))
|
||||
(gp-advance!))
|
||||
(when (= gp-idx saved-idx) (gp-advance!)))
|
||||
(gp-comp-loop)))))
|
||||
(gp-comp-loop)
|
||||
elems)))
|
||||
@@ -713,14 +716,116 @@
|
||||
(when (and (= (gp-tok-type) "op")
|
||||
(= (gp-tok-value) "{"))
|
||||
(gp-advance!)
|
||||
(gp-skip-block!)
|
||||
(set! body :body))
|
||||
(set! body (gp-parse-block-body)))
|
||||
(cond
|
||||
(= recv nil)
|
||||
(list :func-decl name params results body)
|
||||
:else
|
||||
(list :method-decl recv name params results body))))))
|
||||
:else nil))))
|
||||
(define
|
||||
gp-stmt-assign-ops
|
||||
;; Compound assignment operators per Go spec § Assignment operations.
|
||||
(list "+=" "-=" "*=" "/=" "%=" "&=" "|=" "^="
|
||||
"<<=" ">>=" "&^="))
|
||||
(define
|
||||
gp-parse-stmt
|
||||
;; Parses one Go statement. Recognises:
|
||||
;; return [exprs]
|
||||
;; { ... } — nested block
|
||||
;; lhs := exprs — short declaration
|
||||
;; lhs = exprs — assignment
|
||||
;; lhs OP= expr — compound assignment
|
||||
;; expr — expression statement
|
||||
;; LHS may be a comma-separated list. Block-level declarations
|
||||
;; (var/const/type/func) route through gp-parse-decl.
|
||||
(fn
|
||||
()
|
||||
(cond
|
||||
(= (gp-tok-type) "semi")
|
||||
(do (gp-advance!) (gp-parse-stmt))
|
||||
(and (= (gp-tok-type) "keyword")
|
||||
(or (= (gp-tok-value) "var") (= (gp-tok-value) "const")
|
||||
(= (gp-tok-value) "type") (= (gp-tok-value) "func")))
|
||||
(gp-parse-decl)
|
||||
(and (= (gp-tok-type) "keyword") (= (gp-tok-value) "return"))
|
||||
(do
|
||||
(gp-advance!)
|
||||
(cond
|
||||
(or (= (gp-tok-type) "semi") (= (gp-tok-type) "eof")
|
||||
(and (= (gp-tok-type) "op") (= (gp-tok-value) "}")))
|
||||
(list :return (list))
|
||||
:else (list :return (gp-parse-expr-list))))
|
||||
(and (= (gp-tok-type) "op") (= (gp-tok-value) "{"))
|
||||
(do (gp-advance!) (gp-parse-block-body))
|
||||
:else
|
||||
(let ((lhs (gp-parse-expr 1)))
|
||||
(cond
|
||||
(= lhs nil) nil
|
||||
:else
|
||||
(let ((lhs-list (list lhs)))
|
||||
(define
|
||||
gp-stmt-lhs-rest
|
||||
(fn
|
||||
()
|
||||
(when (and (= (gp-tok-type) "op")
|
||||
(= (gp-tok-value) ","))
|
||||
(gp-advance!)
|
||||
(let ((e (gp-parse-expr 1)))
|
||||
(when (not (= e nil)) (append! lhs-list e)))
|
||||
(gp-stmt-lhs-rest))))
|
||||
(gp-stmt-lhs-rest)
|
||||
(cond
|
||||
(and (= (gp-tok-type) "op") (= (gp-tok-value) ":="))
|
||||
(do (gp-advance!)
|
||||
(list :short-decl lhs-list (gp-parse-expr-list)))
|
||||
(and (= (gp-tok-type) "op") (= (gp-tok-value) "="))
|
||||
(do (gp-advance!)
|
||||
(list :assign lhs-list (gp-parse-expr-list)))
|
||||
(and (= (gp-tok-type) "op")
|
||||
(some (fn (o) (= o (gp-tok-value)))
|
||||
gp-stmt-assign-ops))
|
||||
(let ((op (gp-tok-value)))
|
||||
(gp-advance!)
|
||||
(list :assign-op op lhs-list
|
||||
(list (gp-parse-expr 1))))
|
||||
:else
|
||||
;; Plain expression statement — return the single expr.
|
||||
;; (If somehow there was a comma chain without =/:=, just
|
||||
;; return the first expr; permissive.)
|
||||
(cond
|
||||
(= (len lhs-list) 1) lhs
|
||||
:else lhs))))))))
|
||||
(define
|
||||
gp-parse-block-body
|
||||
;; Caller has consumed '{'. Parses statements (and possibly nested
|
||||
;; declarations) until '}'. Returns (list :block STMTS).
|
||||
(fn
|
||||
()
|
||||
(let ((stmts (list)))
|
||||
(define
|
||||
gp-block-body-loop
|
||||
(fn
|
||||
()
|
||||
(cond
|
||||
(= (gp-tok-type) "eof") nil
|
||||
(and (= (gp-tok-type) "op") (= (gp-tok-value) "}"))
|
||||
(gp-advance!)
|
||||
(= (gp-tok-type) "semi")
|
||||
(do (gp-advance!) (gp-block-body-loop))
|
||||
:else
|
||||
(do
|
||||
;; Progress guard: if gp-parse-stmt returns nil without
|
||||
;; advancing, force one token forward to avoid spinning
|
||||
;; on unsupported syntax (e.g., 'if' before stmt parser
|
||||
;; learns it). Belt-and-braces against future bugs too.
|
||||
(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-block-body-loop)))))
|
||||
(gp-block-body-loop)
|
||||
(list :block stmts))))
|
||||
(define
|
||||
gp-parse-decl
|
||||
;; Single declaration: package / import / var / const / type.
|
||||
@@ -773,5 +878,5 @@
|
||||
(= (gp-tok-value) "type")
|
||||
(= (gp-tok-value) "func")))
|
||||
(gp-parse-decl)
|
||||
:else (gp-parse-expr 1))))
|
||||
:else (gp-parse-stmt))))
|
||||
(gp-parse-top))))
|
||||
|
||||
Reference in New Issue
Block a user