;; 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 ;; pratt-op-lookup from lib/guest/pratt.sx for operator-precedence climbing. ;; ;; 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]). ;; ;; 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: SX host primitives silently shadow ;; guest-language defines. (define go-precedence-table (list (list "*" 5 :left) (list "/" 5 :left) (list "%" 5 :left) (list "<<" 5 :left) (list ">>" 5 :left) (list "&" 5 :left) (list "&^" 5 :left) (list "+" 4 :left) (list "-" 4 :left) (list "|" 4 :left) (list "^" 4 :left) (list "==" 3 :left) (list "!=" 3 :left) (list "<" 3 :left) (list "<=" 3 :left) (list ">" 3 :left) (list ">=" 3 :left) (list "&&" 2 :left) (list "||" 1 :left))) (define go-parse (fn (src) (let ((gp-tokens (go-tokenize src)) (gp-idx 0)) (define gp-cur (fn () (nth gp-tokens gp-idx))) (define gp-advance! (fn () (set! gp-idx (+ gp-idx 1)))) (define gp-tok-type (fn () (get (gp-cur) :type))) (define gp-tok-value (fn () (get (gp-cur) :value))) (define gp-parse-primary (fn () (let ((ty (gp-tok-type)) (v (gp-tok-value))) (cond (or (= ty "int") (= ty "float") (= ty "imag") (= ty "string") (= ty "rune")) (do (gp-advance!) (ast-literal v)) (= ty "ident") (do (gp-advance!) (ast-var v)) :else nil)))) (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))))