Skip to content

Instantly share code, notes, and snippets.

@aamedina
Last active August 29, 2015 14:01
Show Gist options
  • Select an option

  • Save aamedina/c26a0b8a243c85810044 to your computer and use it in GitHub Desktop.

Select an option

Save aamedina/c26a0b8a243c85810044 to your computer and use it in GitHub Desktop.
(ns cljc.core
(:refer-clojure :exclude [fn reify deftype]))
(defmacro reify
[& impls]
`(clojure.core/reify ~@impls))
(defmacro deftype
[t fields & impls]
`(clojure.core/deftype ~t ~fields ~@impls))
(def
^{:macro true
:arglists '([name doc-string? [params*] & body])}
defmacro1
(reify clojure.lang.IFn
(invoke [_ &form &env name args]
(let [[doc-string? args body]
(cond
(string? (first args)) [(first args) (second args) (nnext args)]
(vector? (first args)) [nil (first args) (rest args)]
:else (throw (ex-info "Args must be in vector" {})))]
(list 'do
(list 'def (with-meta name {:macro true :doc doc-string?})
`(reify clojure.lang.IFn
(invoke [_ &form &env ~@args]
~@body)))
(list 'var name))))))
(defmacro fn
[& sigs]
(let [env &env
mform (macroexpand (list* 'clojure.core/fn sigs))
[sym sigs] (if (symbol? (second mform))
[(second mform) (nnext mform)]
[nil (next mform)])
variadic? (some #(contains? (set %) '&) (map first sigs))
[sigs variadic] (if-let [sigs (partition-by #(contains? (set (first %))
'&) sigs)]
(if (== (count sigs) 2)
sigs
[nil (first sigs)]))
variadic
(if (> (count variadic) 1)
(throw (ex-info "Can't have more than 1 variadic overload" {}))
(first variadic))
variadic-arity (when variadic (dec (count (first variadic))))
max-fixed-arity (when sigs (apply max (map (comp count first) sigs)))
sigs
(mapv (reify clojure.lang.IFn
(invoke [_ sig]
(let [[args & body] sig
params (repeatedly (count args) gensym)]
(list 'invoke (into [(gensym)] params)
(list* 'let [(vec args) (vec params)] body))))) sigs)
sigs (if (nil? variadic)
sigs
(let [[args & body] variadic
params (vec (repeatedly (inc variadic-arity) gensym))]
(conj sigs (list 'invoke params
(list* 'let (if (> (count args) 2)
[(vec (drop-last 2 args))
(vec (butlast (next params)))
(vec (take-last 2 args))
(last params)]
[(vec args)
(last params)])
body)))))]
`(with-meta (reify clojure.lang.Fn
clojure.lang.IFn
~@sigs) {:tag ~(:tag (meta sym))})))
(defmacro defn
[name args & body]
`(def ~name (fn ~name ~args ~@body)))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment