From bf754693b59f0419d17d4a23d355078403ab6dbb Mon Sep 17 00:00:00 2001 From: Yogthos Date: Thu, 4 Jun 2026 23:35:19 -0400 Subject: [PATCH] =?UTF-8?q?feat:=20SCI=20bootstrap=20loads=20completely=20?= =?UTF-8?q?(422/422)=20=E2=80=94=20fix=20with-meta=20+=20select-keys?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The last two keystone forms in namespaces.cljc now load, so the entire SCI source in the harness's load order evaluates with ZERO failures (was 420/2). Two real bugs fixed to get there: - with-meta crashed on non-collections: (with-meta a-fn {...}) did (keys fn) -> 'expected iterable, got function'. SCI marks core fns private this way. Now returns functions/scalars unchanged (Jolt can't attach meta to a raw fn). - select-keys ignored a vector key-list: (each k ks) iterated the pvec's table instead of its elements, so (select-keys m [:a]) returned {}. Now realizes ks. Plus: add clojure.set/join (the only missing clojure.set fn), assert 0 failures in test-load-sci so it's a real regression guard, drop debug instrumentation. Jolt now fully loads SCI's reader-independent implementation: every pure-Clojure module, the entire clojure.core aggregation map, and the clojure.* namespace wiring. conformance 218/218, features 78/78, jank 120. --- src/jolt/clojure/set.clj | 27 +++++++++++++++++++++++++++ src/jolt/core.janet | 26 ++++++++++++++++---------- test/test-load-sci.janet | 8 +++++++- 3 files changed, 50 insertions(+), 11 deletions(-) diff --git a/src/jolt/clojure/set.clj b/src/jolt/clojure/set.clj index 82b5d8a..f480754 100644 --- a/src/jolt/clojure/set.clj +++ b/src/jolt/clojure/set.clj @@ -40,6 +40,33 @@ [xrel ks] (reduce (fn [m x] (let [ik (select-keys x ks)] (assoc m ik (conj (get m ik #{}) x)))) {} xrel)) +(defn join + "When passed 2 rels, returns the rel corresponding to the natural join. + When passed an additional keymap, joins on the corresponding keys." + ([xrel yrel] + (if (and (seq xrel) (seq yrel)) + (let [ks (intersection (set (keys (first xrel))) (set (keys (first yrel)))) + [r s] (if (<= (count xrel) (count yrel)) [xrel yrel] [yrel xrel]) + idx (index r ks)] + (reduce (fn [ret x] + (let [found (idx (select-keys x ks))] + (if found + (reduce (fn [acc y] (conj acc (merge y x))) ret found) + ret))) + #{} s)) + #{})) + ([xrel yrel km] + (let [[r s k] (if (<= (count xrel) (count yrel)) + [xrel yrel (map-invert km)] + [yrel xrel km]) + idx (index r (vals k))] + (reduce (fn [ret x] + (let [found (idx (rename-keys (select-keys x (keys k)) k))] + (if found + (reduce (fn [acc y] (conj acc (merge y x))) ret found) + ret))) + #{} s)))) + (defn subset? [set1 set2] (and (<= (count set1) (count set2)) diff --git a/src/jolt/core.janet b/src/jolt/core.janet index 6694839..843f952 100644 --- a/src/jolt/core.janet +++ b/src/jolt/core.janet @@ -494,7 +494,7 @@ (defn core-select-keys [m ks] (var result @{}) - (each k ks + (each k (realize-for-iteration ks) (let [v (core-get m k)] (if (not (nil? v)) (put result k v)))) (if (struct? m) (table/to-struct result) result)) @@ -2237,15 +2237,21 @@ (put prefs dispatch-val-a dispatch-val-b) mm-var)) (defn core-with-meta [obj meta] - (var new-obj @{}) - (each k (keys obj) - (put new-obj k (get obj k))) - # table/setproto requires a table, convert struct meta to table - (var meta-tab @{}) - (each k (keys meta) (put meta-tab k (get meta k))) - (table/setproto new-obj meta-tab) - (put new-obj :jolt/meta meta) - new-obj) + # Functions and scalars can't carry metadata in Jolt's model — return as-is + # rather than crashing (Clojure attaches meta only to IObj values). + (if (or (function? obj) (cfunction? obj) (number? obj) (boolean? obj) + (nil? obj) (string? obj) (keyword? obj) (buffer? obj)) + obj + (do + (var new-obj @{}) + (each k (keys obj) + (put new-obj k (get obj k))) + # table/setproto requires a table, convert struct meta to table + (var meta-tab @{}) + (each k (keys meta) (put meta-tab k (get meta k))) + (table/setproto new-obj meta-tab) + (put new-obj :jolt/meta meta) + new-obj))) (defn core-var-dynamic? [v] (var-dynamic? v)) diff --git a/test/test-load-sci.janet b/test/test-load-sci.janet index bdecc20..35080e8 100644 --- a/test/test-load-sci.janet +++ b/test/test-load-sci.janet @@ -42,8 +42,9 @@ (flush) (if (try (do (eval-form ctx @{} form) true) - ([err] + ([err fib] (printf " FAIL: %q\n" err) + (when (os/getenv "SCI_TRACE") (debug/stacktrace fib "")) (array/push failures {:form-number count :error (string err) :form (string form)}) false)) (do @@ -104,3 +105,8 @@ (each f all-failures (printf "[%s:%d] %s\n" (f :file) (f :form-number) (f :error)) (printf " form: %s\n" (f :form)))) + +# Regression guard: every form in the loaded SCI modules must evaluate cleanly. +(assert (= 0 total-fail) + (string total-fail " SCI form(s) failed to load (see FAILURES above)")) +(print "\nAll SCI bootstrap forms loaded successfully.")