简体   繁体   中英

Nesting macros in Clojure

Consider this pseudo code:

(defrc name
  "string"
    [a :A]
    [:div a])

Where defrc would be a macro, that would expand to the following

(let [a (rum/react (atom :A))]
  (rum/defc name < rum/reactive []
    [:div a]))

Where rum/defc is itself a macro. I came up with the code below:

(defmacro defrc
          [name subj bindings & body]
          (let [map-bindings# (apply array-map bindings)
                keys# (keys map-bindings#)
                vals# (vals map-bindings#)
                atomised-vals# (atom-map vals#)]
               `(let ~(vec (interleave keys# (map (fn [v] (list 'rum/react v)) (vals atomised-vals#))))
                     (rum/defc ~name < rum/reactive [] ~@body))))

Which almost works:

(macroexpand-all '(defrc aname
       #_=>   "string"
       #_=>   [a :A]
       #_=>   [:div a]))
(let* [a (rum/react #object[clojure.lang.Atom 0x727ed2e6 {:status :ready, :val nil}])] (rum/defc aname clojure.core/< rum/reactive [] [:div a]))

However when used it results in a syntax error:

ERROR: Syntax error at (clojure.core/< rum.core/reactive [] [:div a])

Is this because the inner macro is not being expanded?

Turns out the macro was working correctly but the problem occurred because < was inside the syntax quote it got expanded to clojure.core/<, and Rum simply looks for a quoted <, relevant snippet from Rum's source:

...(cond
        (and (empty? res) (symbol? x))
          (recur {:name x} next nil)
        (fn-body? xs)        (assoc res :bodies (list xs))
        (every? fn-body? xs) (assoc res :bodies xs)
        (string? x)          (recur (assoc res :doc x) next nil)
        (= '< x)             (recur res next :mixins)
        (= mode :mixins)
          (recur (update-in res [:mixins] (fnil conj []) x) next :mixins)
        :else
          (throw (IllegalArgumentException. (str "Syntax error at " xs))))...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM