Now we have a Compiler written in Clojure (ClojureScript) we should explore making compilation phases pluggable. This will allow the development of more powerful tools like source analyzers and type checkers.
Analysis phase seems the most useful phase to expose.
Racket achieves this via macros. http://docs.racket-lang.org/reference/syntax.html
For example, #%module-begin (a macro) can be overridden to perform some custom analysis.
Here is how #%module-begin is used by the compiler.
macroexpands to ...
We can see that module-begin wraps every form in the body of a module.
We can override #%module-begin to perform custom analysis.
This example first expands each form after passing them to #%plain-module-begin, then performs some type checking at compile time with type-check-module-body.
(This example is from Typed Racket, see: Advanced Macrology and the Implementation of Typed Scheme)
- hiredman (paraphrased from #clojure): Shouldn't use "binding" form to effect compilation of forms, because it depends on how the "binding" macro expands. Bindings might stop working if the form is wrapped in a "try"
- hiredman: Perhaps extend the "ns" declaration to allow compiler extensions
- Hold a global register of compiler hooks, a keywords-to-function map.
- Annotate forms with reader metadata for the Compiler to dispatch on.
Example - Type Checking