Skip to content

Instantly share code, notes, and snippets.

@bsless
Last active March 1, 2020 18:08
Show Gist options
  • Save bsless/67073be8ce0e6fcc0b70442161dbb8a0 to your computer and use it in GitHub Desktop.
Save bsless/67073be8ce0e6fcc0b70442161dbb8a0 to your computer and use it in GitHub Desktop.
Emit Clojure code to warp java class
(defn camel->snake
[s]
(-> s
(clojure.string/replace #"([^_A-Z])([A-Z])" "$1-$2")
clojure.string/lower-case))
(defn gen-param*
[c]
(->
c
str
(clojure.string/split #"\.")
last
first
str
clojure.string/lower-case))
(defn gen-param
[cnt c]
[(inc cnt) (symbol (str (gen-param* c) cnt))])
(defn emit-wrapper-body
[class {:keys [name parameter-types]}]
(let [[_this & params]
(nth
(reduce
(fn [[cnt ps] c]
(let [[cnt p] (gen-param cnt c)]
[cnt (conj ps p)]))
[0 ['c]]
parameter-types) 1)
method (symbol (str "." name))]
`([~(with-meta 'c {:tag class}) ~@params]
(~method ~_this ~@params))))
(defn emit-wrapper
[class [method decls]]
(let [fn-name (-> method str camel->snake symbol)
return-type (vary-meta (:return-type (first decls)) empty)
fn-name (if (#{'void} return-type) fn-name (with-meta fn-name {:tag return-type}))
bodies (map (partial emit-wrapper-body class) decls)]
(list* 'defn fn-name bodies)))
(defn wrapping-candidates
[c]
(group-by
:name
(filter
(comp :public :flags)
(:members (clojure.reflect/reflect c)))))
(defn wrap
[c]
(map
(partial emit-wrapper c)
(remove
(fn [[method _]]
(= (resolve method) c))
(wrapping-candidates c))))
(defmacro wrap!
[c]
(let [c (resolve c)]
`(do ~@(wrap c))))
;; surprise yourself with: (set! *print-meta* true)
(wrap java.util.HashMap)
(binding [*print-meta* true]
(doseq [e (wrap java.util.HashMap)]
(clojure.pprint/pprint e)))
(wrap! java.util.HashMap)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment