This is the page for discussing the design of native macros in Clojurescript.
Clojurescript already has a non-native macro system in the form of Clojure macros. However, this system has some downsides, the most prominent being that they require the programmer to define them in a different file and namespace, and that they must be written in what is a slightly different dialect of the language. Also, if the Clojurescript compiler is ever to be a Clojure-in-Clojure compiler, then it must have its own macro system.
- Macros require that the compiler is able to evaluate functions written in the language.
- Since the syntax for defining macros is essentially the same as for defining functions, the defmacro parser should be able to call the defn parser.
- The compiler must call these functions with unevaluated code as input.
- Macroexpansion occurs in the compiler in the compiler/macroexpand-1 function, called from compiler/analyze.
- In order to run macros properly, all definitions must be evaluated (e.g. def, defn, deftype, extend-type).
- There is an implementation that follows the above design in the repository here.
- It is a fairly small and self-contained change to the compiler.
- It does not remove Clojure macros; it only adds Clojurescript macros.
- It can be run optionally.
- It compiles the existing test suite without error as well as newly-added tests that introduce macros.
- The implementation discussed above does not pass the &env and &form variables to macros that the Clojure compiler does. It should not be a very difficult change to add them, but it would be nice to have a discussion about whether they are truly useful features to have.
- In core.match for example, it seems that &env is the only way that it could be determined if a symbol is an existing local or a wildcard. This is a good thing, but is there a better way of doing it than having magic variables?
- Clojurescript uses the Clojure reader. In the Clojure reader, backquoted symbols are resolved to namespaces. Since the Clojure reader doesn't know what is defined in Clojurescript namespaces, it has no way of doing this correctly for Clojurescript macros. Thus it can incorrectly resolve backquoted symbols.
- This can be worked around by manually resolving symbols, but that is probably not the optimal situation.