How can I force evaluation of nested macros in Clojurescript?

Viewed 476

I have a CLJC file that produces the following desired output in Clojure:

(ns myproj.macros-ns)

(defmacro inner-macro [s]
  `['(my-ns/my-fn) :from ['~s :all]])

(defmacro outer-macro [y xs]
  `(into ['~y '~'<-] (eval '~xs)))

(defmacro macro-context [other-macros]
  (let [symbols (eval other-macros)
        _ (println "Expanded in macro context" symbols)]
    {:result `(list '~symbols '~'+ '~'further-rearrangement)}))


(macro-context (outer-macro ?sym-a (inner-macro ?sym-b)))

Expanded in macro context [?sym-a <- (my-ns/my-fn) :from [?sym-b :all]]

=> {:result ([?sym-a <- (my-ns/my-fn) :from [?sym-b :all]] + further-rearrangement)}

My question is: How can I get the same result in Clojurescript?

My CLJS file looks like this:

(ns myproj.app-ns
   (:require-macros [myproj.macros-ns :refer [outer-macro
                                              inner-macro
                                              macro-context]]))

(enable-console-print!)

(macro-context (outer-macro ?sym-a (inner-macro ?sym-b)))

Error I'm getting is:

clojure.lang.ExceptionInfo: java.lang.RuntimeException: Unable to 
resolve symbol: outer-macro in this context, compiling:
(/private/var/folders/2g/sfp74ftj6_q1vw51ytjbgvph0000gn/T/form-
init4244939051951953637.clj:13:3) at line 12 
test/macros/cljs/myproj/app_ns.cljs

What am I ultimately trying to do and why?

I'm writing a framework that wraps https://github.com/cerner/clara-rules. Clara has its own macro, defrule, that uses the following DSL syntax

(defrule my-rule
 [?fact <- (my-ns/my-fn) :from [:all (= ?e (:e this))]
 ...

I have a macro that expands the following to the previous:

(macro-context my-rule
 [?fact <- (my-ns/my-fn) :from [?e :all]]
...

The macro that does this is basically the macro-context in the more general example above. When I am only parsing syntax like this, I don't call eval or macroexpand. I'm able to treat everything as a symbol, rewrite it to Clara's DSL, then pass it to defrule.

Here's where I think that breaks down:

(macro-context
 [(outer-macro ?fact (inner-macro ?e))]
 ...

Inside the macro-context macro, outer-macro and inner-macro are unevaluated and at that point I need their expansion. By calling eval, I can get that in Clojure, but for some reason when compiling Clojurescript I receive "unable to resolve symbol outer-macro in this context.

2 Answers
Related