go: parse.sx — binary operators via Pratt precedence climbing + 9 tests [consumes-pratt]
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 39s

gp-parse-expr / gp-pratt-loop implement classic Pratt climbing
against go-precedence-table (entry shape from lib/guest/pratt.sx).
The kit gives us pratt-op-lookup + accessors; the climbing loop
itself stays per-language (per kit header — Lua and Prolog have
opposite conventions).

Left-associative ops raise the right-recursion min by 1; right-
associative would keep prec. All Go binary operators are left-assoc.

AST shape: a binary node is emitted as
  (ast-app (ast-var OP) [LHS RHS])
— canonical ast-app rather than a Go-specific binary node, since a
future evaluator can recognise operator-named apps without losing
information.

Coverage: equal-prec left-to-right, * tighter than +, && tighter
than ||, comparison tighter than &&, long left-assoc chains, mixed
literal+ident operands.

parse 26/26, total 155/155.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-27 07:39:03 +00:00
parent 976c6dd0ef
commit 750035d543
5 changed files with 143 additions and 21 deletions

View File

@@ -1,17 +1,18 @@
;; lib/go/parse.sx — Go parser. Tokenises via go-tokenize (lib/go/lex.sx),
;; builds canonical AST nodes per lib/guest/ast.sx, and uses the operator
;; entry shape from lib/guest/pratt.sx for precedence climbing (Pratt).
;; builds canonical AST nodes per lib/guest/ast.sx, and uses
;; pratt-op-lookup from lib/guest/pratt.sx for operator-precedence climbing.
;;
;; First slice: primary expressions only —
;; int / float / imag / string / rune literal(ast-literal VALUE)
;; identifier → (ast-var NAME)
;; Slices so far:
;; 1. Primary expressions — literal / identifier → ast-literal / ast-var
;; 2. Binary operators — Pratt precedence climbing against
;; go-precedence-table; binary application
;; emitted as (ast-app (ast-var OP) [LHS RHS]).
;;
;; Subsequent slices add binary operators (via gp-precedence-table +
;; pratt-op-lookup), function calls, type expressions, declarations,
;; and statements.
;; The climbing loop is per-language (see lib/guest/pratt.sx header on why)
;; but the entry shape and lookup are shared.
;;
;; All scanner locals are gp- prefixed (mirrors lib/go/lex.sx's gl- prefix):
;; SX host primitives silently shadow guest-language defines.
;; All scanner locals are gp- prefixed: SX host primitives silently shadow
;; guest-language defines.
(define
go-precedence-table
@@ -63,4 +64,39 @@
(= ty "ident")
(do (gp-advance!) (ast-var v))
:else nil))))
(gp-parse-primary))))
(define
gp-parse-expr
(fn
(min-prec)
(let ((left (gp-parse-primary))) (gp-pratt-loop left min-prec))))
(define
gp-pratt-loop
(fn
(left min-prec)
(cond
(= left nil) nil
:else
(let
((tok (gp-cur)))
(cond
(not (= (get tok :type) "op"))
left
:else (let
((entry (pratt-op-lookup go-precedence-table (get tok :value))))
(cond
(= entry nil)
left
(< (pratt-op-prec entry) min-prec)
left
:else (do
(gp-advance!)
(let
((next-min (if (= (pratt-op-assoc entry) :left) (+ (pratt-op-prec entry) 1) (pratt-op-prec entry))))
(let
((right (gp-parse-expr next-min)))
(gp-pratt-loop
(ast-app
(ast-var (get tok :value))
(list left right))
min-prec)))))))))))
(gp-parse-expr 1))))