Fork me on GitHub
#rewrite-clj
<
2021-03-18
>
reefersleep18:03:52

I’m trying to use rewrite-clj to manipulate datastructures that include ::’ed keys, and I’m seeing a lot of :?_current-ns_?. I thought I could use

(n/sexpr v
         {:auto-resolve (fn [alias]
                          (prn "calling autoresolve")
                          (get {:current *ns*}
                               alias
                               (symbol (str alias "-unresolved"))))})
to do replace it with something else, but it seems like the :auto-resolve fn is never called.

reefersleep18:03:48

Actually, I could just do

(n/sexpr v
         {:auto-resolve (partial identity *ns*)})
, I guess.

borkdude18:03:22

you are never seeing the prns?

reefersleep18:03:45

I know that *ns* is not supported anymore ( 😞 ), but I don’t understand why the fn isn’t called.

reefersleep18:03:38

(and for resolving the ns dynamically, I guess I’ll have to travel the ns form and find the right symbol myself… and carry that down to the place where I need it.)

borkdude18:03:06

@reefersleep

user=> (require '[rewrite-clj.node :as n])
nil
user=> (require '[rewrite-clj.parser :as p])
nil
user=> (p/parse-string "::foo")
<token: ::foo>
user=> (n/sexpr (p/parse-string "::foo"))
:?_current-ns_?/foo
user=> (n/sexpr (p/parse-string "::foo") {:auto-resolve (fn [m] (prn m))})
:current
:foo

borkdude18:03:59

user=> (n/sexpr (p/parse-string "{:a ::foo}") {:auto-resolve (fn [m] (prn m))})
:current
{:a :foo}

lread19:03:19

@reefersleep, carrying on from @borkdude’s example but also using *ns*:

> clj
Clojure 1.10.3
user=> (require '[rewrite-clj.node :as n])
nil
user=> (require '[rewrite-clj.parser :as p])
nil
user=> (def my-node (p/parse-string "::foo"))
#'user/my-node
user=> (n/sexpr my-node {:auto-resolve (fn [x] (ns-name *ns*))})
:user/foo

lread19:03:58

But maybe binding *ns* to what you really want it to be will be the challenge? Dunno.

lread19:03:23

Also can’t remember if you are using zip API. If so you can provide :auto-resolve at zipper creation time and it will be used automatically for any zipper operations that auto-resolve.

lread19:03:27

Depending on your use case, you’ll also want to look at auto-resolve fn argument. As @borkdude illustrated, it will be :current for current namespace auto-resolves ::foo, and the ns alias for namespace alias auto-resolves ::my-ns-alias/foo

reefersleep19:03:48

@lee your example works as expected. Don’t know why my code does not!

reefersleep19:03:47

I’m a dumb. I was referring to the wrong value, I think. Let me investigate.

reefersleep19:03:53

If so, I’m really sorry for wasting your time!

lread19:03:12

Not a problem at all, we’ve all been there!

lread19:03:47

Actually I sometimes live there! simple_smile

lread19:03:10

When ya do figure it out, let us know what it was. It might help us to improve the docs or the library.

reefersleep19:03:29

It was nothing to do with rewrite-clj, I should have simplified my code example and/or more thoroughly inspected the values I was manipulating. The code had gotten a bit unwieldy, I guess 🙂 (And maybe I’m suffering from baby-related sleep deprivation issues 😉 )

lread19:03:38

Well, whatever the reason, glad you are back on track!

reefersleep19:03:10

The next challenge, as you said, is to get the correct ns.

reefersleep19:03:54

For (ns-name *ns*), I’m getting the ns I’m calling from, not the ns I’m navigating with rewrite-clj.

reefersleep19:03:35

(As stated in the docs, in some way)

lread19:03:14

Yeah, rewrite-clj doesn’t look at or modify *ns*.

reefersleep19:03:55

Is there a plan to provide the current ns in some other way?

lread19:03:08

Of the file you are parsing?

reefersleep19:03:18

Or does rewrite-clj just avoid doing it because it’s not really a compiler? 🙂

reefersleep19:03:53

I mean, I get that *ns* can be dynamically changed throughout a file, so it’s not straightforward

reefersleep19:03:49

plus it requires the full scope of the read/compiled file, and I guess that’s not really the mission of rewrite-clj.

lread19:03:21

I was considering parsing out namespace info in earlier designs of rewrite-clj v1. Thankfully @borkdude talked me out of it. I documented the https://github.com/clj-commons/rewrite-clj/blob/main/doc/design/namespaced-elements.adoc#sexpr-rabbit-hole.

lread19:03:07

Yeah, even if rewrite-clj did parse out this info (which it doesn’t and we don’t have plans for it to do so), it would not change or read *ns*.

reefersleep19:03:17

Wonderful notes, great investment!

lread19:03:45

Thanks, I write things down because I am rather forgetful!

lread20:03:35

It would not be difficult to get parsing of the current ns out of a source file correct most of the time. But most of the time isn’t good enough for rewrite-clj.

reefersleep20:03:42

I try to do the same, but I tend to forget that I have the notes or where they are 😅

lread20:03:10

Well chalk it up to sleep deprevation!

lread20:03:03

That said, I think cljfmt, which uses rewrite-clj does parse out ns info. You might want to look there for inspiration, if you are trying to do something similar.

reefersleep20:03:22

> most of the time isn’t good enough for rewrite-clj I totally get that. You’d be making promises you couldn’t keep. I guess I’ll try reading the ns form; I think we make very few ns gymnastics in our code base, but I might be surprised.

reefersleep20:03:34

Thanks, I’ll have a look!

lread20:03:54

If you are just looking for the current ns and not ns aliases, you’ll likely not have a terrible slog.

reefersleep20:03:10

That I am, and I’m thinking the same. I’ve read before that the ns form is terribly dynamic, but I don’t think we make particular use of that dynamism. (let [namespaze (-> zloc z/down z/right)] will probably work most of the time.

lread20:03:11

There’s also https://github.com/clj-kondo/clj-kondo/tree/master/analysis, if you want to look at that route.

reefersleep20:03:24

I might go for that in the next iteration. For now, cljfmt’s solution looks like what I had imagined doing 🙂

reefersleep20:03:54

Consider me unintentionally swayed 🙂

lread20:03:46

Ha! Do what works for you, all just ideas.

reefersleep20:03:16

Looks easy enough!

reefersleep20:03:56

I’m just reluctant to add more deps. This project has way too many already. But what I’m doing should really be refactored into its own project anyway, eventually.

reefersleep20:03:47

Yeah, like you did, that seems fine!

(defn get-namespace [^java.io.File file]
  (-> (clj-kondo/run! {:lint   [(.getPath file)]
                       :config {:output {:analysis true}}})
      :analysis
      :namespace-definitions
      first
      :name))

borkdude20:03:43

@reefersleep you can even compare the locations of var definitions reported by clj-kondo against your rewrite-clj node

borkdude20:03:51

and their namespaces

reefersleep20:03:47

That’s pretty cool, so you can get the exact ns for each node? Wow.

borkdude21:03:50

@reefersleep it seems you were interested in keywords though right?

borkdude21:03:03

you can get those too in the analysis with an extra option

borkdude21:03:17

:keywords true

reefersleep21:03:34

Trying to figure out how to match that with the rewrite-clj node, I’m expecting the node API to hold the row and col somewhere, just haven’t found it yet

reefersleep21:03:16

Ah. :track-position true

lread21:03:31

If you aren’t needing to keep track of changes to position you can opt out of :track-position and use https://cljdoc.org/d/rewrite-clj/rewrite-clj/1.0.591-alpha/doc/user-guide#nodes

lread21:03:11

@borkdude’s https://github.com/borkdude/carve might be a good clj-kondo/rewrite-clj example for you

borkdude21:03:48

@reefersleep yeah, just call meta on the node

borkdude21:03:11

This is what sold me to rewrite-clj initially: I needed location info of every possible thing in clojure code for clj-kondo

reefersleep21:03:33

Damn. Wrote the code blind, and it worked the first time around.

reefersleep21:03:13

Lovely! Fetched the row and col of each keyword node and composed the namespaced keyword from clj-kondo’s analysis.

reefersleep21:03:15

@lee and @borkdude, thanks for all your help!

🎉 6
lread21:03:47

Thanks for your interest and sharing your journey!