diff --git a/lib/datalog/db.sx b/lib/datalog/db.sx index 9df4234b..93544c7e 100644 --- a/lib/datalog/db.sx +++ b/lib/datalog/db.sx @@ -48,17 +48,37 @@ (and (has-key? edb rel-key) (has-key? (get edb rel-key) tk))))) -;; Evaluation strategy. Default :semi-naive (the only strategy -;; currently implemented). :magic is reserved for goal-directed -;; magic-sets evaluation — calling it now logs a one-time "deferred" -;; note and falls back to semi-naive. +;; Evaluation strategy. Default :semi-naive (used by dl-saturate!). +;; :naive selects dl-saturate-naive! (slower but easier to reason +;; about). :magic is a marker — goal-directed magic-sets evaluation +;; is invoked separately via `dl-magic-query`; setting :magic here +;; is purely informational. Any other value is rejected so typos +;; don't silently fall back to the default. +(define + dl-strategy-values + (list :semi-naive :naive :magic)) + (define dl-set-strategy! (fn (db strategy) - (do - (dict-set! db :strategy strategy) - db))) + (cond + ((not (dl-keyword-member? strategy dl-strategy-values)) + (error (str "dl-set-strategy!: unknown strategy " strategy + " — must be one of " dl-strategy-values))) + (else + (do + (dict-set! db :strategy strategy) + db))))) + +(define + dl-keyword-member? + (fn + (k xs) + (cond + ((= (len xs) 0) false) + ((= k (first xs)) true) + (else (dl-keyword-member? k (rest xs)))))) (define dl-get-strategy diff --git a/lib/datalog/scoreboard.json b/lib/datalog/scoreboard.json index e7621023..4dd9e4b1 100644 --- a/lib/datalog/scoreboard.json +++ b/lib/datalog/scoreboard.json @@ -1,13 +1,13 @@ { "lang": "datalog", - "total_passed": 275, + "total_passed": 276, "total_failed": 0, - "total": 275, + "total": 276, "suites": [ {"name":"tokenize","passed":31,"failed":0,"total":31}, {"name":"parse","passed":23,"failed":0,"total":23}, {"name":"unify","passed":29,"failed":0,"total":29}, - {"name":"eval","passed":43,"failed":0,"total":43}, + {"name":"eval","passed":44,"failed":0,"total":44}, {"name":"builtins","passed":26,"failed":0,"total":26}, {"name":"semi_naive","passed":8,"failed":0,"total":8}, {"name":"negation","passed":12,"failed":0,"total":12}, @@ -16,5 +16,5 @@ {"name":"magic","passed":37,"failed":0,"total":37}, {"name":"demo","passed":21,"failed":0,"total":21} ], - "generated": "2026-05-11T09:34:17+00:00" + "generated": "2026-05-11T09:40:12+00:00" } diff --git a/lib/datalog/scoreboard.md b/lib/datalog/scoreboard.md index 4676d363..c06a2f24 100644 --- a/lib/datalog/scoreboard.md +++ b/lib/datalog/scoreboard.md @@ -1,13 +1,13 @@ # datalog scoreboard -**275 / 275 passing** (0 failure(s)). +**276 / 276 passing** (0 failure(s)). | Suite | Passed | Total | Status | |-------|--------|-------|--------| | tokenize | 31 | 31 | ok | | parse | 23 | 23 | ok | | unify | 29 | 29 | ok | -| eval | 43 | 43 | ok | +| eval | 44 | 44 | ok | | builtins | 26 | 26 | ok | | semi_naive | 8 | 8 | ok | | negation | 12 | 12 | ok | diff --git a/lib/datalog/tests/eval.sx b/lib/datalog/tests/eval.sx index 937a49dc..2625f04e 100644 --- a/lib/datalog/tests/eval.sx +++ b/lib/datalog/tests/eval.sx @@ -359,6 +359,16 @@ (do (dl-set-strategy! db :magic) (dl-get-strategy db))) :magic) + ;; Unknown strategy values are rejected so typos don't silently + ;; fall back to the default. + (dl-et-test! + "unknown strategy rejected" + (dl-et-throws? + (fn () + (let ((db (dl-make-db))) + (dl-set-strategy! db :semi_naive)))) + true) + ;; dl-saturated?: no-work-left predicate. (dl-et-test! "saturated? after saturation" (let ((db (dl-program diff --git a/plans/datalog-on-sx.md b/plans/datalog-on-sx.md index 791c77d8..d1b84163 100644 --- a/plans/datalog-on-sx.md +++ b/plans/datalog-on-sx.md @@ -15,7 +15,7 @@ for rose-ash data (e.g. federation graph, content relationships). ## Status (rolling) -`bash lib/datalog/conformance.sh` → **275/275 across 11 suites** +`bash lib/datalog/conformance.sh` → **276/276 across 11 suites** (tokenize, parse, unify, eval, builtins, semi_naive, negation, aggregates, api, magic, demo). Source is ~3100 LOC, tests ~2900 LOC, public API documented in `lib/datalog/datalog.sx`. @@ -320,6 +320,13 @@ large graphs. _Newest first._ +- 2026-05-11 — `dl-set-strategy!` accepted arbitrary keyword values + silently. Typos like `:semi_naive` or `:semiNaive` were stored + uninspected; the saturator then used the default and the user + never learned their setting was a typo. Validator added: strategy + must be one of `:semi-naive`, `:naive`, `:magic`. 1 regression test; + 276/276. + - 2026-05-11 — Anonymous-variable renamer collided with user-written `_anon` symbols. The renamer started counter at 0 and produced `_anon1, _anon2, ...` unconditionally; if the user wrote