jolt/stdlib/clojure/walk.clj
Yogthos ea609d72eb clojure.walk: preserve record types
walk treated a record as a plain map (record? implies map?), rebuilding it via
(into (empty form) ...) which yields a bare map and drops the type. Add a record
branch before the map branch that conj-es the walked entries back onto the
original, matching JVM clojure.walk's IRecord case. Type-dispatched walks need it
— integrant resolves #ig/ref by detecting its Ref record while postwalking the
config, so without this every ref silently fails to resolve.

clojure.walk is baked into the prelude, so the seed is re-minted. Corpus gains
five JVM-certified rows for record type/instance? survival through pre/postwalk.
2026-06-24 01:26:16 -04:00

57 lines
2 KiB
Clojure

; Jolt Standard Library: clojure.walk
; Tree walking for Clojure data structures.
(defn walk
[inner outer form]
(cond
; vectors/maps first so seq? can't swallow them (a vector is not seq? on
; jolt, but keep the concrete branches authoritative)
(vector? form) (outer (vec (map inner form)))
; a record is also map?, but (empty record) yields a plain map — rebuild by
; conj-ing the walked entries back onto the original so the record TYPE
; survives. Type-dispatched walks depend on it (e.g. integrant resolves
; #ig/ref by detecting its Ref record while postwalking the config).
(record? form) (outer (reduce (fn [r x] (conj r (inner x))) form form))
(map? form) (outer (into (empty form) (map inner form)))
; lists rebuild as lists, other seqs (incl. macro/template output: cons/
; concat/lazy-seq) walk too — without this, postwalk-replace silently no-op'd
; a quoted list, breaking clojure.template/apply-template
(list? form) (outer (apply list (map inner form)))
(seq? form) (outer (map inner form))
:else (outer form)))
(defn postwalk
[f form]
(walk (partial postwalk f) f form))
(defn prewalk
[f form]
(walk (partial prewalk f) identity (f form)))
(defn postwalk-demo
"Demonstrates the behavior of postwalk by printing each form as it is walked."
[form]
(postwalk (fn [x] (print "Walked: ") (prn x) x) form))
(defn prewalk-demo
"Demonstrates the behavior of prewalk by printing each form as it is walked."
[form]
(prewalk (fn [x] (print "Walked: ") (prn x) x) form))
(defn postwalk-replace
[smap form]
(postwalk (fn [x] (if (contains? smap x) (get smap x) x)) form))
(defn prewalk-replace
[smap form]
(prewalk (fn [x] (if (contains? smap x) (get smap x) x)) form))
(defn keywordize-keys
[m]
(let [f (fn [[k v]] (if (string? k) [(keyword k) v] [k v]))]
(postwalk (fn [x] (if (map? x) (into {} (map f x)) x)) m)))
(defn stringify-keys
[m]
(let [f (fn [[k v]] (if (keyword? k) [(name k) v] [k v]))]
(postwalk (fn [x] (if (map? x) (into {} (map f x)) x)) m)))