               (children-zips-by-generation kids)))
     nil))
 
+
+;; === tags
+
+(defn get-tags
+  [node pred-map]
+  (vec (for [[kw pred] pred-map
+             :when (pred node)]
+         kw)))
+
+(defn get-tag-map
+  [tree pred-map]
+  (reduce (fn [tag-map node]
+            (assoc tag-map
+                   (:id node)
+                   (get-tags node pred-map)))
+          {}
+          (tree-seq map? :children tree)))
+
+(defn mk-get-tag-fn
+  [tag-map]
+  (fn [tree]
+    (-> tree
+        :id
+        tag-map)))
+
+;; === zippers
+
+(defn tree->zipper
+  [tree]
+  (z/zipper map?
+            #(-> % :children not-empty)
+            #(assoc % :children %2)
+            tree))
+
+(defn traverse-assoc-zipper
+  [zipr]
+  (if (z/end? zipr)
+    (-> zipr z/root)
+    (recur (-> zipr
+               (z/edit assoc :zipper zipr)
+               z/next))))
+
+(defn traverse-tree-assoc-zipper
+  [tree]
+  (-> tree
+      tree->zipper
+      traverse-assoc-zipper))
+
+;; move this to trace or utils?
+(defn traverse-tree
+  [tree f]
+  (assoc (f tree)
+         :children (mapv #(traverse-tree % f)
+                         (:children tree))))
+
+(defn traverse-tree-dissoc-zipper
+  [tree]
+  (traverse-tree tree #(dissoc % :zipper)))
+
+;; === query
+
+(defn query-tree
+  [qry-fn tree]
+  (if-not (nil? tree)
+    (let [e' (update-in tree [:children]
+                        (partial mapcat
+                                 (partial query-tree
+                                          qry-fn)))]
+      (if (qry-fn tree)
+        [e']
+        (:children e')))
+    []))
+
+(defn query-dos
+  [tree pred-map pred-final-fn] ;; pred-final-fn takes a node (w/ :zipper) and fn to retrieve tags from a node
+  (let [tag-map (get-tag-map tree pred-map)
+        get-tag-fn (mk-get-tag-fn tag-map)
+        pred-final-fn' #(pred-final-fn % get-tag-fn)]
+    (->> tree
+         tree->zipper
+         traverse-assoc-zipper
+         (query-tree pred-final-fn'))))
+
+(defn query-uno
+  [tree pred-fn]
+  (query-tree pred-fn tree))
+
+(defn query
+  ([tree pred-fn] (query-uno tree pred-fn))
+  ([tree pred-map pred-final-fn] (query-dos tree pred-map pred-final-fn)))
+
+;; === macro interface
+
+
+(defn get-some*
+  [f v]
+  (cond
+    (fn? f)
+    (f v)
+
+    (set? f)
+    (f v)
+
+    :default
+    (get v f)))
+
+(defn get-some
+  [coll v]
+  (loop [coll coll
+         v v]
+    (if ((some-fn empty? nil?) coll)
+      v
+      (let [[f & r] coll]
+        (when-let [v' (get-some* f v)]
+          (recur r v'))))))
+
+(defn eq* [pred v]
+  (cond (fn? pred)
+        (pred v)
+
+        (set? pred)
+        (pred v)
+
+        (instance? java.util.regex.Pattern pred)
+        (->> v
+             str
+             (re-matches pred))
+
+        :default (= pred v)))
+
+(defn mk-query-fn
+  [query-coll]
+  (let [path (drop-last query-coll)
+        pred (last query-coll)]
+    (fn [v]
+      (try
+        (->> v
+             (get-some path)
+             (eq* pred))
+        (catch Exception ex
+          nil)))))
+
+(defn some-mk-query-fn
+  [queries]
+  (->> queries
+       (map mk-query-fn)
+       (apply some-fn)))
+
+(defn every-pred-2
+  [& preds]
+  (fn [node tag-fn]
+    (loop [[f & r] preds]
+      (and (f node tag-fn)
+           (if (not-empty r)
+             (recur r)
+             true)))))
+
+
 (defn mk-lazy-descendant-tag-seq
   [node tag-fn dist]
-  (def n' node)
-  (def tag-fn' tag-fn)
-  (def d' dist)
   (let [generations-seq (->> node
                              :zipper
                              children-zips-by-generation)

  (->> z
       (iter-while-identity z/up)
       rest))

(defn children-zips [z]
  (->> z
       z/down
       (iter-while-identity z/right)))

(defn descendant-depth-firstish-zips [z]
  (let [kids (children-zips z)]
    (lazy-cat kids
              (mapcat descendant-depth-firstish-zips
                      kids))))

;; === helpers

(defn some-zippers
  [zipr-seq node tags-fn pred-fn]
  (->> zipr-seq
       (map z/node)
       (map tags-fn)
       (some pred-fn)))

(defmacro defn-zipper->>
  [name & body]
  `(defn ~name
     [node#]
     (->> node#
          :zipper
          ~@body)))

(defmacro defn-tags-functor
  [name & body]
  `(defn ~name
     [node# tags-fn#]
     (->> node#
          ~@body
          (map z/node)
          (map tags-fn#))))

(defn-zipper->> lazy-ancestor-zipr-seq ancestor-zips)
(defn-tags-functor lazy-ancestor-tag-seq lazy-ancestor-zipr-seq)

(defn-zipper->> lazy-descendant-zipr-seq descendant-depth-firstish-zips)
(defn-tags-functor lazy-descendant-tag-seq lazy-descendant-zipr-seq)

(defn-zipper->> lazy-sibling-zipr-seq all-sib-zips)
(defn-tags-functor lazy-sibling-tag-seq lazy-sibling-zipr-seq)

(defn some-tags
  [tag-set tag-seq]
  (some (partial some
                 tag-set)
        tag-seq))

(defmacro defn-tag-seq-fnr->>
  [name args & body]
  `(defn ~name
     ~(conj args 'tag-seq-functor)
     (fn [~'node ~'tag-fn]
       (->> (~'tag-seq-functor ~'node ~'tag-fn)
            ~@body))))

(defn-tag-seq-fnr->> mk-some-tags-in-seq-fn [tag-set] (some-tags tag-set))
(defn-tag-seq-fnr->> take-lazy-tag-seq-functor [n] (take n))
(defn-tag-seq-fnr->> prepend-node-to-lazy-tag-seq-functor [] (lazy-cat [(tag-fn node)]))

;; === tags

(defn get-tags
  [node pred-map]
  (vec (for [[kw pred] pred-map
             :when (pred node)]
         kw)))

(defn get-tag-map
  [tree pred-map]
  (reduce (fn [tag-map node]
            (assoc tag-map
                   (:id node)
                   (get-tags node pred-map)))
          {}
          (tree-seq map? :children tree)))

(defn mk-get-tag-fn
  [tag-map]
  (fn [tree]
    (-> tree
        :id
        tag-map)))

;; === zippers

(defn tree->zipper
  [tree]
  (z/zipper map?
            #(-> % :children not-empty)
            #(assoc % :children %2)
            tree))

(defn traverse-assoc-zipper
  [zipr]
  (if (z/end? zipr)
    (-> zipr z/root)
    (recur (-> zipr
               (z/edit assoc :zipper zipr)
               z/next))))

(defn traverse-tree-assoc-zipper
  [tree]
  (-> tree
      tree->zipper
      traverse-assoc-zipper))

;; move this to trace or utils?
(defn traverse-tree
  [tree f]
  (assoc (f tree)
         :children (mapv #(traverse-tree % f)
                         (:children tree))))

(defn traverse-tree-dissoc-zipper
  [tree]
  (traverse-tree tree #(dissoc % :zipper)))

;; === query

(defn query-tree
  [qry-fn tree]
  (if-not (nil? tree)
    (let [e' (update-in tree [:children]
                        (partial mapcat
                                 (partial query-tree
                                          qry-fn)))]
      (if (qry-fn tree)
        [e']
        (:children e')))
    []))

(defn query-dos
  [tree pred-map pred-final-fn] ;; pred-final-fn takes a node (w/ :zipper) and fn to retrieve tags from a node
  (let [tag-map (get-tag-map tree pred-map)
        get-tag-fn (mk-get-tag-fn tag-map)
        pred-final-fn' #(pred-final-fn % get-tag-fn)]
    (->> tree
         tree->zipper
         traverse-assoc-zipper
         (query-tree pred-final-fn'))))

(defn query-uno
  [tree pred-fn]
  (query-tree pred-fn tree))

(defn query
  ([tree pred-fn] (query-uno tree pred-fn))
  ([tree pred-map pred-final-fn] (query-dos tree pred-map pred-final-fn)))

;; === macro interface


(defn get-some*
  [f v]
  (cond
    (fn? f)
    (f v)

    (set? f)
    (f v)

    :default
    (get v f)))

(defn get-some
  [coll v]
  (loop [coll coll
         v v]
    (if ((some-fn empty? nil?) coll)
      v
      (let [[f & r] coll]
        (when-let [v' (get-some* f v)]
          (recur r v'))))))

(defn eq* [pred v]
  (cond (fn? pred)
        (pred v)

        (set? pred)
        (pred v)

        (instance? java.util.regex.Pattern pred)
        (->> v
             str
             (re-matches pred))

        :default (= pred v)))

(defn mk-query-fn
  [query-coll]
  (let [path (drop-last query-coll)
        pred (last query-coll)]
    (fn [v]
      (try
        (->> v
             (get-some path)
             (eq* pred))
        (catch Exception ex
          nil)))))

(defn some-mk-query-fn
  [queries]
  (->> queries
       (map mk-query-fn)
       (apply some-fn)))

(defn some-fn-2
  [& preds]
  (fn [node tag-fn]
    (loop [[f & r] preds]
      (or (f node tag-fn)
          (when (not-empty r)
            (recur r))))))

(defn every-pred-2
  [& preds]
  (fn [node tag-fn]
    (loop [[f & r] preds]
      (and (f node tag-fn)
           (if (not-empty r)
             (recur r)
             true)))))

#_ (defn mk-relative-final-qry-fn
     [opts tag-set & [dist]]
     (let [opts' (util/obj-pred-action-else opts
                                            (partial some #{:w})
                                            :t [:a :s :d])
           f' (fn [tag-seq-fnr]
                (let [taker (if dist
                              (partial take-lazy-tag-seq-functor dist)
                              identity)
                      stis (->> tag-seq-fnr
                                taker
                                prepend-node-to-lazy-tag-seq-functor
                                (mk-some-tags-in-seq-fn tag-set))]
                  stis))
           rel-seq-map {:a lazy-descendant-tag-seq
                        :s lazy-sibling-tag-seq
                        :d lazy-ancestor-tag-seq}]
       (->> opts'
            (keep rel-seq-map)
            (map f')
            (apply some-fn-2))))

(defn children-zips [zipr]
  (some->> zipr

         (mapcat tag-fn))))


(defn mk-lazy-sibling-tag-seq
  [node tag-fn dist]
  (let [generations-seq (->> node
                             :zipper
                             all-sib-zips)
        g-seq (if dist
                (take dist generations-seq)
                generations-seq)]
    (->> g-seq
         (map z/node)
         (mapcat tag-fn))))

(defn mk-lazy-ancestor-tag-seq
  [node tag-fn dist]
  (let [generations-seq (->> node
                             :zipper
                             ancestor-zips)
        g-seq (if dist
                (take dist generations-seq)
                generations-seq)]
    (->> g-seq
         (map z/node)
         (mapcat tag-fn))))

(defn mk-relative-final-qry-fn
  [opts tag-set & [dist]]
