rlm@10: ;; Various useful macros rlm@10: ;; rlm@10: ;; Everybody is invited to add their own little macros here! rlm@10: ;; rlm@10: ;; The use and distribution terms for this software are covered by the rlm@10: ;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) rlm@10: ;; which can be found in the file epl-v10.html at the root of this rlm@10: ;; distribution. By using this software in any fashion, you are rlm@10: ;; agreeing to be bound by the terms of this license. You must not rlm@10: ;; remove this notice, or any other, from this software. rlm@10: rlm@10: (ns rlm@10: ^{:author "Konrad Hinsen" rlm@10: :doc "Various small macros"} rlm@10: clojure.contrib.macros) rlm@10: rlm@10: ;; By Konrad Hinsen rlm@10: (defmacro const rlm@10: "Evaluate the constant expression expr at compile time." rlm@10: [expr] rlm@10: (eval expr)) rlm@10: rlm@10: ;; By Konrad Hinsen rlm@10: ; This macro is made obsolete by Clojure's built-in letfn. I renamed it to rlm@10: ; letfn- (to avoid a name clash) but leave it in for a while, since its rlm@10: ; syntax is not quite the same as Clojure's. Expect this to disappear rlm@10: ; in the long run! rlm@10: (defmacro letfn- rlm@10: "OBSOLETE: use clojure.core/letfn rlm@10: A variant of let for local function definitions. fn-bindings consists rlm@10: of name/args/body triples, with (letfn [name args body] ...) rlm@10: being equivalent to (let [name (fn name args body)] ...)." rlm@10: [fn-bindings & exprs] rlm@10: (let [makefn (fn [[name args body]] (list name (list 'fn name args body))) rlm@10: fns (vec (apply concat (map makefn (partition 3 fn-bindings))))] rlm@10: `(let ~fns ~@exprs))) rlm@10: rlm@10: ;; By Konrad Hinsen rlm@10: rlm@10: (defn- unqualified-symbol rlm@10: [s] rlm@10: (let [s-str (str s)] rlm@10: (symbol (subs s-str (inc (.indexOf s-str (int \/))))))) rlm@10: rlm@10: (defn- bound-var? rlm@10: [var] rlm@10: (try rlm@10: (do (deref var) true) rlm@10: (catch java.lang.IllegalStateException e false))) rlm@10: rlm@10: (defn- fns-from-ns rlm@10: [ns ns-symbol] rlm@10: (apply concat rlm@10: (for [[k v] (ns-publics ns) rlm@10: :when (and (bound-var? v) rlm@10: (fn? @v) rlm@10: (not (:macro (meta v))))] rlm@10: [k (symbol (str ns-symbol) (str k))]))) rlm@10: rlm@10: (defn- expand-symbol rlm@10: [ns-or-var-sym] rlm@10: (if (= ns-or-var-sym '*ns*) rlm@10: (fns-from-ns *ns* (ns-name *ns*)) rlm@10: (if-let [ns (find-ns ns-or-var-sym)] rlm@10: (fns-from-ns ns ns-or-var-sym) rlm@10: (list (unqualified-symbol ns-or-var-sym) ns-or-var-sym)))) rlm@10: rlm@10: (defmacro with-direct-linking rlm@10: "EXPERIMENTAL! rlm@10: Compiles the functions in body with direct links to the functions rlm@10: named in symbols, i.e. without a var lookup for each invocation. rlm@10: Symbols is a vector of symbols that name either vars or namespaces. rlm@10: A namespace reference is replaced by the list of all symbols in the rlm@10: namespace that are bound to functions. If symbols is not provided, rlm@10: the default value ['clojure.core] is used. The symbol *ns* can be rlm@10: used to refer to the current namespace." rlm@10: {:arglists '([symbols? & body])} rlm@10: [& body] rlm@10: (let [[symbols body] (if (vector? (first body)) rlm@10: [(first body) (rest body)] rlm@10: [['clojure.core] body]) rlm@10: bindings (vec (mapcat expand-symbol symbols))] rlm@10: `(let ~bindings ~@body))) rlm@10: