I Completely agree with Rich's decision to NOT support reader macros. In an activity as simple as writing this post, I found many, many places to make a mistake the hard way. This is an extremely difficult activity to get right, and the end result is something that is not quite the same as normal Clojure. Use the following information at your own risk.
The first thing to identify is a behavior that you would like to have a reader macro for. For our example, I am going to use a modified form of Chas Emerick's amazing string interpolation macro. You can find his original article here. I took a modified version of his code, and placed it in core.clj (Be sure to create a new git branch). The code I used is below
Now that the desired functionality is in core, it is time to modify the reader. In this case we need to modify the file LispReader.java. I defined a static variable INTERPOLATE_S, and I am going to assign it the "|" reader macro.
//Inserted at line 40
static Symbol INTERPOLATE_S = Symbol.create("clojure.core", "interpolate-s");
Now, in order for this to be found we need to make an entry in the macros array. This can be done like so:
//Inserted at line 86
macros['|'] = new WrappingReader(INTERPOLATE_S);
The WrappingReader class takes a Symbol object, and wraps it around the next form that is read. Recall how the following form
is expanded to (deref a-ref). In our case
|"A string ~(+ 2 2)"
will be expanded to
(interpolate-s "A string ~(+ 2 2)")
Let's rebuild clojure.jar and try this out at a REPL.
As you can see this works just like Chas' macro. There are still a few things that need to be covered, such as:
* How to create a multiple character reader macro
* How to create a delimited reader macro
These will be topics for another day.