diff options
Diffstat (limited to 'src/clojure/contrib/macro_utils.clj')
-rw-r--r-- | src/clojure/contrib/macro_utils.clj | 270 |
1 files changed, 0 insertions, 270 deletions
diff --git a/src/clojure/contrib/macro_utils.clj b/src/clojure/contrib/macro_utils.clj deleted file mode 100644 index 37ab3b88..00000000 --- a/src/clojure/contrib/macro_utils.clj +++ /dev/null @@ -1,270 +0,0 @@ -;; Macrolet and symbol-macrolet - -;; by Konrad Hinsen -;; last updated January 14, 2010 - -;; Copyright (c) Konrad Hinsen, 2009-2010. All rights reserved. The use -;; and distribution terms for this software are covered by the Eclipse -;; Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) -;; which can be found in the file epl-v10.html at the root of this -;; distribution. By using this software in any fashion, you are -;; agreeing to be bound by the terms of this license. You must not -;; remove this notice, or any other, from this software. - -(ns - #^{:author "Konrad Hinsen" - :doc "Local macros and symbol macros - - Local macros are defined by a macrolet form. They are usable only - inside its body. Symbol macros can be defined globally - (defsymbolmacro) or locally (symbol-macrolet). A symbol - macro defines a form that replaces a symbol during macro - expansion. Function arguments and symbols bound in let - forms are not subject to symbol macro expansion. - - Local macros are most useful in the definition of the expansion - of another macro, they may be used anywhere. Global symbol - macros can be used only inside a with-symbol-macros form."} - clojure.contrib.macro-utils - (:use [clojure.contrib.def :only (defvar-)])) - -; A set of all special forms. Special forms are not macro-expanded, making -; it impossible to shadow them by macro definitions. For most special -; forms, all the arguments are simply macro-expanded, but some forms -; get special treatment. -(defvar- special-forms - (into #{} (keys clojure.lang.Compiler/specials))) -; Value in the Clojure 1.2 branch: -; #{deftype* new quote & var set! monitor-enter recur . case* clojure.core/import* reify* do fn* throw monitor-exit letfn* finally let* loop* try catch if def} - -; The following three vars are constantly redefined using the binding -; form, imitating dynamic scoping. -; -; Local macros. -(defvar- macro-fns {}) -; Local symbol macros. -(defvar- macro-symbols {}) -; Symbols defined inside let forms or function arguments. -(defvar- protected-symbols #{}) - -(defn- reserved? - [symbol] - "Return true if symbol is a reserved symbol (starting or ending with a dot)." - (let [s (str symbol)] - (or (= "." (subs s 0 1)) - (= "." (subs s (dec (count s))))))) - -(defn- expand-symbol - "Expand symbol macros" - [symbol] - (cond (contains? protected-symbols symbol) symbol - (reserved? symbol) symbol - (contains? macro-symbols symbol) (get macro-symbols symbol) - :else (let [v (resolve symbol) - m (meta v)] - (if (:symbol-macro m) - (var-get v) - symbol)))) - -(defn- expand-1 - "Perform a single non-recursive macro expansion of form." - [form] - (cond - (seq? form) - (let [f (first form)] - (cond (contains? special-forms f) form - (contains? macro-fns f) (apply (get macro-fns f) (rest form)) - (symbol? f) (let [exp (expand-symbol f)] - (if (= exp f) - (clojure.core/macroexpand-1 form) - (cons exp (rest form)))) - ; handle defmacro macros and Java method special forms - :else (clojure.core/macroexpand-1 form))) - (symbol? form) - (expand-symbol form) - :else - form)) - -(defn- expand - "Perform repeated non-recursive macro expansion of form, until it no - longer changes." - [form] - (let [ex (expand-1 form)] - (if (identical? ex form) - form - (recur ex)))) - -(declare expand-all) - -(defn- expand-args - "Recursively expand the arguments of form, leaving its first - n elements unchanged." - ([form] - (expand-args form 1)) - ([form n] - (doall (concat (take n form) (map expand-all (drop n form)))))) - -(defn- expand-bindings - [bindings exprs] - (if (empty? bindings) - (list (doall (map expand-all exprs))) - (let [[[s b] & bindings] bindings] - (let [b (expand-all b)] - (binding [protected-symbols (conj protected-symbols s)] - (doall (cons [s b] (expand-bindings bindings exprs)))))))) - -(defn- expand-with-bindings - "Handle let* and loop* forms. The symbols defined in them are protected - from symbol macro expansion, the definitions and the body expressions - are expanded recursively." - [form] - (let [f (first form) - bindings (partition 2 (second form)) - exprs (rest (rest form)) - expanded (expand-bindings bindings exprs) - bindings (vec (apply concat (butlast expanded))) - exprs (last expanded)] - (cons f (cons bindings exprs)))) - -(defn- expand-fn-body - [[args & exprs]] - (binding [protected-symbols (reduce conj protected-symbols - (filter #(not (= % '&)) args))] - (cons args (doall (map expand-all exprs))))) - -(defn- expand-fn - "Handle fn* forms. The arguments are protected from symbol macro - expansion, the bodies are expanded recursively." - [form] - (let [[f & bodies] form - name (when (symbol? (first bodies)) (first bodies)) - bodies (if (symbol? (first bodies)) (rest bodies) bodies) - bodies (if (vector? (first bodies)) (list bodies) bodies) - bodies (doall (map expand-fn-body bodies))] - (if (nil? name) - (cons f bodies) - (cons f (cons name bodies))))) - -(defn- expand-method - "Handle a method in a deftype* or reify* form." - [m] - (rest (expand-fn (cons 'fn* m)))) - -(defn- expand-deftype - "Handle deftype* forms." - [[symbol typename classname fields implements interfaces & methods]] - (assert (= implements :implements)) - (let [expanded-methods (map expand-method methods)] - (concat - (list symbol typename classname fields implements interfaces) - expanded-methods))) - -(defn- expand-reify - "Handle reify* forms." - [[symbol interfaces & methods]] - (let [expanded-methods (map expand-method methods)] - (cons symbol (cons interfaces expanded-methods)))) - -; Handlers for special forms that require special treatment. The default -; is expand-args. -(defvar- special-form-handlers - {'quote identity - 'var identity - 'def #(expand-args % 2) - 'new #(expand-args % 2) - 'let* expand-with-bindings - 'loop* expand-with-bindings - 'fn* expand-fn - 'deftype* expand-deftype - 'reify* expand-reify}) - -(defn- expand-list - "Recursively expand a form that is a list or a cons." - [form] - (let [f (first form)] - (if (symbol? f) - (if (contains? special-forms f) - ((get special-form-handlers f expand-args) form) - (expand-args form)) - (doall (map expand-all form))))) - -(defn- expand-all - "Expand a form recursively." - [form] - (let [exp (expand form)] - (cond (symbol? exp) exp - (seq? exp) (expand-list exp) - (vector? exp) (into [] (map expand-all exp)) - (map? exp) (into {} (map expand-all (seq exp))) - :else exp))) - -(defmacro macrolet - "Define local macros that are used in the expansion of exprs. The - syntax is the same as for letfn forms." - [fn-bindings & exprs] - (let [names (map first fn-bindings) - name-map (into {} (map (fn [n] [(list 'quote n) n]) names)) - macro-map (eval `(letfn ~fn-bindings ~name-map))] - (binding [macro-fns (merge macro-fns macro-map) - macro-symbols (apply dissoc macro-symbols names)] - `(do ~@(doall (map expand-all exprs)))))) - -(defmacro symbol-macrolet - "Define local symbol macros that are used in the expansion of exprs. - The syntax is the same as for let forms." - [symbol-bindings & exprs] - (let [symbol-map (into {} (map vec (partition 2 symbol-bindings))) - names (keys symbol-map)] - (binding [macro-fns (apply dissoc macro-fns names) - macro-symbols (merge macro-symbols symbol-map)] - `(do ~@(doall (map expand-all exprs)))))) - -(defmacro defsymbolmacro - "Define a symbol macro. Because symbol macros are not part of - Clojure's built-in macro expansion system, they can be used only - inside a with-symbol-macros form." - [symbol expansion] - (let [meta-map (if (meta symbol) (meta symbol) {}) - meta-map (assoc meta-map :symbol-macro true)] - `(def ~(with-meta symbol meta-map) (quote ~expansion)))) - -(defmacro with-symbol-macros - "Fully expand exprs, including symbol macros." - [& exprs] - `(do ~@(doall (map expand-all exprs)))) - -(defmacro deftemplate - "Define a macro that expands into forms after replacing the - symbols in params (a vector) by the corresponding parameters - given in the macro call." - [name params & forms] - (let [param-map (for [p params] (list (list 'quote p) (gensym))) - template-params (vec (map second param-map)) - param-map (vec (apply concat param-map)) - expansion (list 'list (list 'quote `symbol-macrolet) param-map - (list 'quote (cons 'do forms)))] - `(defmacro ~name ~template-params ~expansion))) - -(defn mexpand-1 - "Like clojure.core/macroexpand-1, but takes into account symbol macros." - [form] - (binding [macro-fns {} - macro-symbols {} - protected-symbols #{}] - (expand-1 form))) - -(defn mexpand - "Like clojure.core/macroexpand, but takes into account symbol macros." - [form] - (binding [macro-fns {} - macro-symbols {} - protected-symbols #{}] - (expand form))) - -(defn mexpand-all - "Perform a full recursive macro expansion of a form." - [form] - (binding [macro-fns {} - macro-symbols {} - protected-symbols #{}] - (expand-all form))) |