;; lib/prolog/hs-bridge.sx — Prolog ↔ Hyperscript bridge ;; ;; Two complementary integration styles: ;; ;; 1. Hook style — for `prolog(db, "goal(args)")` call syntax in Hyperscript: ;; (pl-install-hs-hook!) ;; call once at startup ;; Requires lib/hyperscript/plugins/prolog.sx (provides hs-set-prolog-hook!) ;; ;; 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. ;; ;; 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))))))) ;; --- 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)))