From 282a3d3d06aaf2b85484a05d32f13cf0534d5c4d Mon Sep 17 00:00:00 2001 From: giles Date: Fri, 8 May 2026 10:04:59 +0000 Subject: [PATCH] datalog: dl-eval-magic single-call magic-sets entry (206/206) Symmetric to dl-eval but routes single-positive-literal queries through dl-magic-query for goal-directed evaluation. Multi-literal query bodies fall back to standard dl-query (magic-sets is wired for single goals only). (dl-eval-magic source-string "?- ancestor(a, X).") 1 new api test. --- lib/datalog/api.sx | 29 +++++++++++++++++++++++++++++ lib/datalog/scoreboard.json | 8 ++++---- lib/datalog/scoreboard.md | 4 ++-- lib/datalog/tests/api.sx | 10 ++++++++++ 4 files changed, 45 insertions(+), 6 deletions(-) diff --git a/lib/datalog/api.sx b/lib/datalog/api.sx index 872b2017..72cb9dfd 100644 --- a/lib/datalog/api.sx +++ b/lib/datalog/api.sx @@ -169,6 +169,35 @@ (else (dl-query db (get (first queries) :query))))))) +;; (dl-eval-magic source query-source) — like dl-eval but routes a +;; single-positive-literal query through `dl-magic-query` for goal- +;; directed evaluation. Multi-literal query bodies fall back to the +;; standard dl-query path (magic-sets is currently only wired for +;; single-positive goals). The caller's source is parsed afresh +;; each call so successive invocations are independent. +(define + dl-eval-magic + (fn + (source query-source) + (let + ((db (dl-program source)) + (queries (dl-parse query-source))) + (cond + ((= (len queries) 0) (error "dl-eval-magic: query string is empty")) + ((not (has-key? (first queries) :query)) + (error + "dl-eval-magic: second arg must be a `?- ...` query clause")) + (else + (let + ((qbody (get (first queries) :query))) + (cond + ((and (= (len qbody) 1) + (list? (first qbody)) + (> (len (first qbody)) 0) + (symbol? (first (first qbody)))) + (dl-magic-query db (first qbody))) + (else (dl-query db qbody))))))))) + (define dl-rule-head-rels (fn diff --git a/lib/datalog/scoreboard.json b/lib/datalog/scoreboard.json index 9c238632..203984a5 100644 --- a/lib/datalog/scoreboard.json +++ b/lib/datalog/scoreboard.json @@ -1,8 +1,8 @@ { "lang": "datalog", - "total_passed": 205, + "total_passed": 206, "total_failed": 0, - "total": 205, + "total": 206, "suites": [ {"name":"tokenize","passed":26,"failed":0,"total":26}, {"name":"parse","passed":18,"failed":0,"total":18}, @@ -12,9 +12,9 @@ {"name":"semi_naive","passed":8,"failed":0,"total":8}, {"name":"negation","passed":10,"failed":0,"total":10}, {"name":"aggregates","passed":18,"failed":0,"total":18}, - {"name":"api","passed":14,"failed":0,"total":14}, + {"name":"api","passed":15,"failed":0,"total":15}, {"name":"magic","passed":21,"failed":0,"total":21}, {"name":"demo","passed":18,"failed":0,"total":18} ], - "generated": "2026-05-08T10:02:51+00:00" + "generated": "2026-05-08T10:04:46+00:00" } diff --git a/lib/datalog/scoreboard.md b/lib/datalog/scoreboard.md index 3ad41dc4..8af1890b 100644 --- a/lib/datalog/scoreboard.md +++ b/lib/datalog/scoreboard.md @@ -1,6 +1,6 @@ # datalog scoreboard -**205 / 205 passing** (0 failure(s)). +**206 / 206 passing** (0 failure(s)). | Suite | Passed | Total | Status | |-------|--------|-------|--------| @@ -12,6 +12,6 @@ | semi_naive | 8 | 8 | ok | | negation | 10 | 10 | ok | | aggregates | 18 | 18 | ok | -| api | 14 | 14 | ok | +| api | 15 | 15 | ok | | magic | 21 | 21 | ok | | demo | 18 | 18 | ok | diff --git a/lib/datalog/tests/api.sx b/lib/datalog/tests/api.sx index 0431ed1f..809946df 100644 --- a/lib/datalog/tests/api.sx +++ b/lib/datalog/tests/api.sx @@ -213,6 +213,16 @@ "?- p(X), q(X).") (list {:X 2} {:X 3})) + ;; dl-eval-magic — routes single-goal queries through + ;; magic-sets evaluation. + (dl-api-test-set! "dl-eval-magic ancestor" + (dl-eval-magic + "parent(a, b). parent(b, c). + ancestor(X, Y) :- parent(X, Y). + ancestor(X, Z) :- parent(X, Y), ancestor(Y, Z)." + "?- ancestor(a, X).") + (list {:X (quote b)} {:X (quote c)})) + ;; Comprehensive integration: recursion + stratified negation ;; + aggregation + comparison composed in a single program. ;; (Uses _Anything as a regular var instead of `_` so the