merge loops/prolog: complete Prolog-on-SX implementation
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 47s

590 tests passing across 29 suites. Brings in: parser, runtime,
query API, compiler, conformance harness, integration suite, and
hs-bridge (combined hook + factory styles).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-06 11:20:44 +00:00
42 changed files with 8980 additions and 124 deletions

View File

@@ -1,21 +1,84 @@
;; lib/prolog/hs-bridge.sx — Prolog ↔ _hyperscript bridge
;; lib/prolog/hs-bridge.sx — Prolog ↔ Hyperscript bridge
;;
;; Installs the prolog hook into the hyperscript runtime so that
;; hyperscript scripts can call:
;; Two complementary integration styles:
;;
;; prolog(db, "goal(args)") → true (at least one solution)
;; → false (no solution)
;; 1. Hook style — for `prolog(db, "goal(args)")` call syntax in Hyperscript:
;; (pl-install-hs-hook!) ;; call once at startup
;; Requires lib/hyperscript/runtime.sx (provides hs-set-prolog-hook!)
;;
;; Usage:
;; (pl-install-hs-hook!) ;; call once at startup, after loading both libs
;; 2. Factory style — for named conditions like `when allowed(user, action)`:
;; (define allowed (pl-hs-predicate/2 pl-db "allowed"))
;; No parser/compiler changes needed: Hyperscript compiles
;; `allowed(user, action)` to `(allowed user action)` — a plain SX call.
;;
;; Depends on:
;; lib/hyperscript/runtime.sx — provides hs-set-prolog-hook!
;; lib/prolog/runtime.sx — provides pl-query-one (Phase 3+)
;; Requires tokenizer.sx, parser.sx, runtime.sx, query.sx loaded first.
;; --- Hook style ---
(define
pl-install-hs-hook!
(fn
()
(hs-set-prolog-hook!
(fn (db goal) (not (= nil (pl-query-one db goal)))))))
(fn (db goal) (not (= nil (pl-query-one db goal)))))))
;; --- Factory style ---
;; Test whether a ground Prolog goal succeeds against db.
;; Returns true/false (not a solution dict).
(define
pl-hs-query
(fn (db goal-str) (not (nil? (pl-query-one db goal-str)))))
;; Build a Prolog goal string from a predicate name and arg list.
;; SX values: strings/keywords pass through; numbers are stringified via str.
(define
pl-hs-build-goal
(fn
(pred-name args)
(str pred-name "(" (join ", " (map (fn (a) (str a)) args)) ")")))
;; Return a 1-arg SX function that succeeds iff pred(a) holds in db.
(define
pl-hs-predicate/1
(fn
(db pred-name)
(fn (a) (pl-hs-query db (pl-hs-build-goal pred-name (list a))))))
;; Return a 2-arg SX function that succeeds iff pred(a, b) holds in db.
(define
pl-hs-predicate/2
(fn
(db pred-name)
(fn (a b) (pl-hs-query db (pl-hs-build-goal pred-name (list a b))))))
;; Return a 3-arg SX function that succeeds iff pred(a, b, c) holds in db.
(define
pl-hs-predicate/3
(fn
(db pred-name)
(fn (a b c) (pl-hs-query db (pl-hs-build-goal pred-name (list a b c))))))
;; Install every predicate in install-list as a named SX function backed by db.
;; install-list: list of (name arity) pairs.
;; Returns a dict {name → fn} for the caller to destructure.
(define
pl-hs-install
(fn
(db install-list)
(reduce
(fn
(acc entry)
(let
((pred-name (first entry)) (arity (nth entry 1)))
(dict-set!
acc
pred-name
(cond
((= arity 1) (pl-hs-predicate/1 db pred-name))
((= arity 2) (pl-hs-predicate/2 db pred-name))
((= arity 3) (pl-hs-predicate/3 db pred-name))
(true (fn (a b) false))))
acc))
{}
install-list)))