Hi all, I'm trying to write a :macroexpand hook for a string interpolation macro:
(def foo "bar")
(<< "foo's value is: #{ bar }")
I tried duplicating some of the macro's implementation in the hook, but I've found that some of the required API is unavailable - java.io.PushbackReader and slurp specifically. Any ideas for how I could make this work?
(you might recognize this as a version of Chas Emerick's string interpolation macro; many thanks to him. https://cemerick.com/blog/2009/12/04/string-interpolation-in-clojure.html)what do you need slurp for?
This is the function that reads the interpolated values:
(defn- silent-read
"Attempts to clojure.core/read a single form from the provided String, returning
a vector containing the read form and a String containing the unread remainder
of the provided String. Returns nil if no valid form can be read from the
head of the String."
[s]
(try
(let [r (-> s java.io.StringReader. java.io.PushbackReader.)]
[(read r) (string/triml (slurp r))])
(catch Exception e)))
this one is available:
'java.io.StringReader java.io.StringReader
'clojure.lang.LineNumberingPushbackReader clojure.lang.LineNumberingPushbackReaderyou can probably implement slurp in user space... let me think
I bet clojure.lang.LineNumberingPushbackReader will work for the pushback reader part, thanks.
yeah maybe not, perhaps it requires a pushback reader... not sure
clojure.lang.LineNumberingPushbackReader works in the actual macro impl so presumably works fine in the hook too. Now I think I just need to figure out the slurp replacement to get the remainder of the string
(defn reader->string [^java.io.Reader r]
(let [sb (StringBuilder.)
buf (char-array 4096)]
(loop []
(let [n (.read r buf)]
(when (pos? n)
(.append sb buf 0 n)
(recur))))
(str sb)))
Not sure if that works in hooksAh this one may work since StringWriter is included by default in SCI:
(defn reader->string [^java.io.Reader r]
(let [sw (java.io.StringWriter.)
buf (char-array 4096)]
(loop []
(let [n (.read r buf)]
(when (pos? n)
(.write sw buf 0 n)
(recur))))
(str sw)))Got a warning about the type hint but with that removed it appears to work. The hook still doesn't appear to be doing what I want but this gets me a lot closer. Thanks @borkdude!
so reader->string worked?
yep, it works in the macro impl, and I'm not seeing any complaints about it when linting w/ the hook. I'll run a repl for the hook impl in a bit to be sure, got some other stuff to deal with right now.
👍
Hook works correctly now. Thanks again!
nice!