Skip to content

Instantly share code, notes, and snippets.

@JacekLach
Created December 25, 2012 08:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JacekLach/4372203 to your computer and use it in GitHub Desktop.
Save JacekLach/4372203 to your computer and use it in GitHub Desktop.
;; macroexpand without resolving class names
(defn safe-macroexpand-1 [form]
(if-not (seq? form)
form
(let [[op & body] form]
(cond
((some-fn special-symbol?
#(clojure.lang.Compiler/isMacro %)
(comp not symbol?)) op)
(macroexpand form) ;; these are safe, now java interop
;; (.substring s 2 5) => (. s substring 2 5)
(.startsWith (name op) ".")
`(. (identity ~(first body))
~(symbol (subs (name op) 1))
~@(rest body))
;; (class.Name/member ...) => (. class.Name member ...)
(clojure.lang.Compiler/namesStaticMember op)
(let [cls (symbol (namespace op))
memb (symbol (name op))]
`(. ~cls ~memb ~@body))
;; (ClassName. ...) is handled correctly by macroexpand
:else (macroexpand form)))))
(defn safe-macroexpand [form]
(let [ex (safe-macroexpand-1 form)]
(if (identical? ex form)
form
(safe-macroexpand ex))))
(comment
(macroexpand '(no.such.Class/member other args go here)) ;; ClassNotFoundException
(safe-macroexpand '(no.such.Class/member other args go here)) ;; (. no.such.Class member other args go here)
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment