Files
rose-ash/lib/guest/pratt.sx
giles da27958d67 GUEST: step 4 — lib/guest/pratt.sx operator-table format + lookup
Extracted the data-half of Pratt-style precedence parsing: the operator
table format and lookup. The climbing loop stays per-language because
the two canaries use opposite conventions (lua: higher prec = tighter;
prolog: lower prec = tighter, with xfx/xfy/yfx assoc tags) — forcing
one shared loop adds callback indirection that obscures more than it
shares. The brief's literal ask is "Grammar is a dict, not hardcoded
cond" and that's what gets shared.

Entry shape: (NAME PREC ASSOC). Three accessors: pratt-op-name /
pratt-op-prec / pratt-op-assoc. One traversal: pratt-op-lookup.

Ported lua/parser.sx — replaced 18-clause cond and the
lua-binop-right? hardcoded `or` with a 15-entry lua-op-table, now
queried via pratt-op-lookup. Ported prolog/parser.sx — pl-op-find
(linear walk reimpl) deleted; pl-op-lookup wraps pratt-op-lookup;
pl-token-op simplified to return the entry directly.

Verification:
- lua/test.sh: 185/185 = baseline.
- prolog/conformance.sh: 590/590 = baseline (timestamp-only diff).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 17:17:17 +00:00

29 lines
1.1 KiB
Plaintext

;; lib/guest/pratt.sx — operator-table format + lookup for Pratt-style
;; precedence climbing.
;;
;; The climbing loop stays per-language because the two canaries use
;; opposite conventions (Lua: higher prec = tighter; Prolog: lower prec =
;; tighter, with xfx/xfy/yfx assoc tags). Forcing a single loop adds
;; callback indirection that obscures more than it shares.
;;
;; What IS shared and gets extracted: the operator-table format and lookup.
;; "Grammar is a dict, not hardcoded cond."
;;
;; Entry shape: (NAME PREC ASSOC).
;; NAME — string, the operator's source token.
;; PREC — integer, in the host's own convention.
;; ASSOC — :left | :right | :none for languages with traditional
;; associativity, or "xfx" / "xfy" / "yfx" for Prolog-style.
(define
pratt-op-lookup
(fn (table name)
(cond
((empty? table) nil)
((= (first (first table)) name) (first table))
(:else (pratt-op-lookup (rest table) name)))))
(define pratt-op-name (fn (entry) (first entry)))
(define pratt-op-prec (fn (entry) (nth entry 1)))
(define pratt-op-assoc (fn (entry) (nth entry 2)))