Most of my time this week was spent traveling and in meetings, but I did have a chance to work on the Clojurescript macro system that I have been working on.
Testing
Things didn't start too well for the system, since it would not run
the simplest of tests written for it in the Clojurescript testing
system. My test was a macro that would take a positive integer,
recursively decrease it until it was zero, and then output the
zero. (Clearly not the smartest macro in the world – it was just
meant to test recursion.) However, I kept getting errors saying
that the system didn't know how to test equality among numbers.
This seemed strange until I realized that the extend-type
call for
numbers wasn't getting executed because it wasn't expanded into a
def
. (I had been executing all def
calls, which defined all
functions and variables, but nothing else.)
So I briefly flirted with executing a bunch of other special forms,
including set!
and deftype
, but I could see that this would make
things pretty unwieldy, and that the compiler would be doing a lot
of confusing things, for example trying to execute a set!
that was
buried deep inside a function without being able to know anything
about the locals that it was being set to.
That was clearly the way of madness, so I eventually decided to execute every special form that was at the top level. This worked really well, and the tests started passing.
I also added tests to make sure that the namespaces work as
expected. You can use
or require
macros from other namespaces
just like other functions.
What's not there (yet)
So far I have not added the &env
and &form
variables to macros.
I expect that it will be necessary to add them at some point (and
honestly not too hard). I know they are extremely useful in some
projects like core.match, but that project has already been ported
to Clojurescript (via Clojure macros), so it might make more sense
to leave the large macros that need those facilities to Clojure.
Backquoted forms don't work as nicely as in Clojure. The reason is that we are using Clojure's reader, which qualifies backquoted symbols with their full namespace. Unfortunately, it doesn't know anything about Clojurescript namespaces, so expect to need to qualify symbols inside backquotes. This is an area where true reader macros inside Clojure would be really helpful, but we have to live with what we have.
One step closer
… to Clojure in Clojure. Clojurescript already has a reader and a compiler that can compile most of itself. The reader isn't totally complete – it doesn't have backquote working yet for example – but it is close. It recently got persistent vectors and persistent hash-maps. With macros added, all that's left for Clojure in Clojure is to finish up the reader and get rid of the calls to Java.