Share your thoughts in the 2024 State of Clojure Survey!

Welcome! Please see the About page for a little more info on how this works.

0 votes
in tools.reader by
retagged by

I'm using clojure.tools.reader/read for reading clojure and cljs forms from files.

Everything works fine but reading namespaced keywords like ::keyword get read as :user/keyword.

I know the reader uses ns dynamic var to figure out the current namespace for reading symbols and keywords but I don't know how to use it to read a non existing namespace, like the one from the file I'm just reading.

I'm trying a (in-ns file-ns-symbol) before doing the read so it creates the ns before reading and it works but sometimes I'm getting java.lang.IllegalStateException: Can't change/establish root binding of: *ns* with set

Just doing

(binding [*ns* file-ns-symbol]
  (reader/read ...))

doesn't work since it will try to call (the-ns file-ns-symbol) for a ns that doesn't exist.

Any ideas or pointers on how to do this?

Thanks!

1 Answer

+1 vote
by
selected by
 
Best answer

If you know how to resolve the autoresolved keyword aliases, you can set the *alias-map* dynamic binding and plug something in there: http://clojure.github.io/tools.reader/#clojure.tools.reader/*alias-map*

It's described as a map, but it's invoked as a function, so I think a function would work too.

by
Thanks for the quick response Alex, and yeah I'm already using *alias-map* as a function but that only works for the ::alias/key cases, my problem is with the ones that should resolve to current namespace.
by
Ah right, alias map will only be used with aliases. Can you use create-ns to actually create the ns?

    user=> (create-ns 'x)
    #object[clojure.lang.Namespace 0x4397a639 "x"]
    user=> (binding [*ns* (find-ns 'x)] (r/read-string "::foo"))
    :x/foo
by
Nice, that create-ns was what I was looking for, it worked! Thanks again Alex!
...