diff --git a/lib/guest/pratt.sx b/lib/guest/pratt.sx new file mode 100644 index 00000000..24138697 --- /dev/null +++ b/lib/guest/pratt.sx @@ -0,0 +1,28 @@ +;; 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))) diff --git a/lib/lua/parser.sx b/lib/lua/parser.sx index d604224b..1993294a 100644 --- a/lib/lua/parser.sx +++ b/lib/lua/parser.sx @@ -3,28 +3,33 @@ (define lua-tok-value (fn (t) (if (= t nil) nil (get t :value)))) (define - lua-binop-prec - (fn - (op) - (cond - ((= op "or") 1) - ((= op "and") 2) - ((= op "<") 3) - ((= op ">") 3) - ((= op "<=") 3) - ((= op ">=") 3) - ((= op "==") 3) - ((= op "~=") 3) - ((= op "..") 5) - ((= op "+") 6) - ((= op "-") 6) - ((= op "*") 7) - ((= op "/") 7) - ((= op "%") 7) - ((= op "^") 10) - (else 0)))) + lua-op-table + (list + (list "or" 1 :left) + (list "and" 2 :left) + (list "<" 3 :left) + (list ">" 3 :left) + (list "<=" 3 :left) + (list ">=" 3 :left) + (list "==" 3 :left) + (list "~=" 3 :left) + (list ".." 5 :right) + (list "+" 6 :left) + (list "-" 6 :left) + (list "*" 7 :left) + (list "/" 7 :left) + (list "%" 7 :left) + (list "^" 10 :right))) -(define lua-binop-right? (fn (op) (or (= op "..") (= op "^")))) +(define lua-binop-prec + (fn (op) + (let ((entry (pratt-op-lookup lua-op-table op))) + (if (= entry nil) 0 (pratt-op-prec entry))))) + +(define lua-binop-right? + (fn (op) + (let ((entry (pratt-op-lookup lua-op-table op))) + (and (not (= entry nil)) (= (pratt-op-assoc entry) :right))))) (define lua-parse diff --git a/lib/lua/test.sh b/lib/lua/test.sh index 13dabffc..ed7daa60 100755 --- a/lib/lua/test.sh +++ b/lib/lua/test.sh @@ -30,6 +30,7 @@ cat > "$TMPFILE" << 'EPOCHS' (epoch 1) (load "lib/guest/lex.sx") (load "lib/guest/prefix.sx") +(load "lib/guest/pratt.sx") (load "lib/lua/tokenizer.sx") (epoch 2) (load "lib/lua/parser.sx") diff --git a/lib/prolog/conformance.conf b/lib/prolog/conformance.conf index e31e74f0..6b1a542a 100644 --- a/lib/prolog/conformance.conf +++ b/lib/prolog/conformance.conf @@ -4,6 +4,7 @@ LANG_NAME=prolog MODE=dict PRELOADS=( + lib/guest/pratt.sx lib/prolog/tokenizer.sx lib/prolog/parser.sx lib/prolog/runtime.sx diff --git a/lib/prolog/parser.sx b/lib/prolog/parser.sx index d6ee00b7..aab0f159 100644 --- a/lib/prolog/parser.sx +++ b/lib/prolog/parser.sx @@ -104,18 +104,9 @@ (list ":-" 1200 "xfx") (list "mod" 400 "yfx"))) -(define - pl-op-find - (fn - (name table) - (cond - ((empty? table) nil) - ((= (first (first table)) name) (rest (first table))) - (true (pl-op-find name (rest table)))))) +(define pl-op-lookup (fn (name) (pratt-op-lookup pl-op-table name))) -(define pl-op-lookup (fn (name) (pl-op-find name pl-op-table))) - -;; Token → (name prec type) for known infix ops, else nil. +;; Token → entry (name prec type) for known infix ops, else nil. (define pl-token-op (fn @@ -123,14 +114,8 @@ (let ((ty (get t :type)) (vv (get t :value))) (cond - ((and (= ty "punct") (= vv ",")) - (let - ((info (pl-op-lookup ","))) - (if (nil? info) nil (cons "," info)))) - ((or (= ty "atom") (= ty "op")) - (let - ((info (pl-op-lookup vv))) - (if (nil? info) nil (cons vv info)))) + ((and (= ty "punct") (= vv ",")) (pl-op-lookup ",")) + ((or (= ty "atom") (= ty "op")) (pl-op-lookup vv)) (true nil))))) ;; ── Term parser ───────────────────────────────────────────────────── diff --git a/lib/prolog/scoreboard.json b/lib/prolog/scoreboard.json index 2c1d47ab..b03f44b7 100644 --- a/lib/prolog/scoreboard.json +++ b/lib/prolog/scoreboard.json @@ -3,5 +3,5 @@ "total_failed": 0, "total": 590, "suites": {"parse":{"passed":25,"total":25,"failed":0},"unify":{"passed":47,"total":47,"failed":0},"clausedb":{"passed":14,"total":14,"failed":0},"solve":{"passed":62,"total":62,"failed":0},"operators":{"passed":19,"total":19,"failed":0},"dynamic":{"passed":11,"total":11,"failed":0},"findall":{"passed":11,"total":11,"failed":0},"term_inspect":{"passed":14,"total":14,"failed":0},"append":{"passed":6,"total":6,"failed":0},"reverse":{"passed":6,"total":6,"failed":0},"member":{"passed":7,"total":7,"failed":0},"nqueens":{"passed":6,"total":6,"failed":0},"family":{"passed":10,"total":10,"failed":0},"atoms":{"passed":34,"total":34,"failed":0},"query_api":{"passed":16,"total":16,"failed":0},"iso_predicates":{"passed":29,"total":29,"failed":0},"meta_predicates":{"passed":25,"total":25,"failed":0},"list_predicates":{"passed":33,"total":33,"failed":0},"meta_call":{"passed":15,"total":15,"failed":0},"set_predicates":{"passed":15,"total":15,"failed":0},"char_predicates":{"passed":27,"total":27,"failed":0},"io_predicates":{"passed":24,"total":24,"failed":0},"assert_rules":{"passed":15,"total":15,"failed":0},"string_agg":{"passed":25,"total":25,"failed":0},"advanced":{"passed":21,"total":21,"failed":0},"compiler":{"passed":17,"total":17,"failed":0},"cross_validate":{"passed":17,"total":17,"failed":0},"integration":{"passed":20,"total":20,"failed":0},"hs_bridge":{"passed":19,"total":19,"failed":0}}, - "generated": "2026-05-06T22:23:38+00:00" + "generated": "2026-05-07T17:07:57+00:00" } diff --git a/lib/prolog/scoreboard.md b/lib/prolog/scoreboard.md index d0d4d3c5..b83007bb 100644 --- a/lib/prolog/scoreboard.md +++ b/lib/prolog/scoreboard.md @@ -1,7 +1,7 @@ # Prolog scoreboard **590 / 590 passing** (0 failure(s)). -Generated 2026-05-06T22:23:38+00:00. +Generated 2026-05-07T17:07:57+00:00. | Suite | Passed | Total | Status | |-------|--------|-------|--------|