Idioms for compiler development in Clojure

clojure, compiler-construction

Solution

Here's the simplest trivial example I can think of, using an AST tree built from s-expressions with keyword operators:

;; functions map, can be easily extended with new functions
;; map is of keyword -> code generating function
(def funcs {:if 
                 (fn [cond exp1 exp2] `(if ~cond ~exp1 ~exp2))
            :neg 
                 (fn [exp1] `(- 0 ~exp1))
            :plus 
                 (fn [& exps] `(+ ~@exps))})

;; compile directly to Clojure source code
(defn my-compile [code]
 (cond 
   (sequential? code)   ;; if we have a list, look up the function in funcs
     (cons (funcs (first code)) (map compile (rest code))) 
   :else                ;; treat anything else as a constant literal
     code))

;; example compilation to a Clojure expression
(my-compile `(:if true (:neg 10) (:plus 10 20 30)))
=> (if true (clojure.core/- 0 10) (clojure.core/+ 10 20 30))

;; evaluate compiled code
(eval (my-compile `(:if true (:neg 10) (:plus 10 20 30))))
=> -10

Hopefully that's enough to give you some ideas / get you started. Obvious extensions to consider would be:

- Compile to AST tree with metadata rather than directly to Clojure source. A Clojure `defrecord` might be suitable as an AST node representation

- Add other operators, looping constructs, "goto" etc.

- Simple optimisations, e.g. evaluation of constant expressions at compile time

- Have some form of execution context allowing assignment, dynamic variable lookup etc. The compiler output could be a function that takes the initial context as input and returns the final context.

Problem

I'd like to explore the power of Clojure for compiler development, but I cannot find example to start with. I am a total newbie (coming from Ruby), but I'm convinced that Clojure should be ideal for this purpose. Let's precise what I'm looking for : - start from a simple AST defined in clojure (for let say a simple sequential language : if, while, func, assign, expression) - simple visitor for this AST (pretty printer for example) - I am not really interested by lexing/parsing (as I consider s-expression as sufficient for my DSL syntax) What are the right idioms for this in Clojure ?

Original source