rewrite-clj 2024-09-09

for splint's rewriting, i am doing a fancy postwalk over a zipper. i want to not check forms that are quoted, so '(+ 1 x) should be skipped. using zip/next will move the zipper into the quoted forms. using zip/right only works when the quoted form isn't the final object in the enclosing form (`[foo 'bar baz]` works but [foo 'bar] doesn't). given that i could be nested arbitrarily deep, how do i go to the "next" form that would be found by calling zip/next at the end of the quoted form?

for example, given string input "(ns hello) [['(+ 1 x)]] ending":

:form (ns hello) :quote? false :right <vector: [['(+ 1 x)]]> :next <token: ns>
:form ns :quote? false :right <token: hello> :next <token: hello>
:form hello :quote? false :right nil :next <vector: [['(+ 1 x)]]>
:form [[(quote (+ 1 x))]] :quote? false :right <token: ending> :next <vector: ['(+ 1 x)]>
:form [(quote (+ 1 x))] :quote? false :right nil :next <quote: '(+ 1 x)>
:form (quote (+ 1 x)) :quote? true :right nil :next <list: (+ 1 x)>
:form (+ 1 x) :quote? false :right nil :next <token: +>
:form + :quote? false :right <token: 1> :next <token: 1>
:form 1 :quote? false :right <token: x> :next <token: x>
:form x :quote? false :right nil :next <token: ending>
:form ending :quote? false :right nil :next <token: ending>
once the zloc is looking at the vectors, it's hard to just call right and get out, but calling next will keep you inside of the quoted form

so if you see a quoted form, you call right, and then if it's nil, how do you go to the next outer form?

Calling zip/up doesn't work because you could be arbitrarily deep

do you call up in a loop until right returns non-nil?

looks like you can call (-> zloc next next rightmost next) to escape lol

;; given `(ns hello) [['(+ 1 x)]] ending`:
(-> zloc ;; 
    zip/next ;; 
    zip/rightmost ;; 
    zip/next ;; 
    )

oh dang, next is implemented as calling up in a loop until right returns non-nil

hmm that doesn't generalize, so i do have to use

(loop [p zloc]
  (if-let [loc (zip/up p)]
    (or (zip/right loc)
        (recur loc))
    (assoc p :end? true)))

Heya, I've got to run some errands but I will check in later. Are you still stuck and wanting help?

no, but knowing a built-in solution would be helpful

I did some thinking about skipping nodes a while back https://github.com/clj-commons/rewrite-clj/discussions/199. When I started experimenting with some code I realized a generic solution is a bit tricky.

👍 1