Fork me on GitHub
#rewrite-clj
<
2023-11-18
>
Noah Bogart04:11:57

if i have a form with lots of nested values and i want to gather all of the nodes that match some predicate, how do i do that? there's no tree-seq, and pre/post walk work like in clojure, and the various find-next-* functions don't seem to go up unless i misread the docstring.

lread14:11:22

Hi again @UEENNMX0T! Here's what I came up with:

(require '[rewrite-clj.node :as n]
         '[rewrite-clj.zip :as z])

(def some-code "(let [x {:a 1 :b 2 :c {:d {:e 3}}}])")

(def zloc (z/of-string some-code))

;; an example of a predicate
(defn keyword-node? [zloc]
  (some-> zloc z/node n/keyword-node?))

;; little helper to find the way we'd like to
(defn find-pred [p? zloc]
  ;; use z/next to include all nodes
  (z/find-next zloc z/next p?))

(->> zloc
     z/up ;; start from root
     (find-pred keyword-node?) ;; move to first match
     (iterate #(find-pred keyword-node? %)) ;; iterate over all other matches
     (take-while #(not (z/end? %))) ;; until we reach the end
     (map z/string)) ;; and convert zloc as you see fit
;; => (":a" ":b" ":c" ":d" ":e")
How's that work for you?

Noah Bogart15:11:30

Oh interesting, so from the root, you step into each top level form and dive until your reach the end

Noah Bogart15:11:14

I wonder if this could be generalized into a “tree-seq”

Noah Bogart15:11:27

Thank you! I’ll give this a go and see how it works for me

lread17:11:06

Cool, come on back if you have more questions!