Mercurial > lasercutter
comparison src/clojure/contrib/macro_utils.clj @ 10:ef7dbbd6452c
added clojure source goodness
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Sat, 21 Aug 2010 06:25:44 -0400 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
9:35cf337adfcf | 10:ef7dbbd6452c |
---|---|
1 ;; Macrolet and symbol-macrolet | |
2 | |
3 ;; by Konrad Hinsen | |
4 ;; last updated January 14, 2010 | |
5 | |
6 ;; Copyright (c) Konrad Hinsen, 2009-2010. All rights reserved. The use | |
7 ;; and distribution terms for this software are covered by the Eclipse | |
8 ;; Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) | |
9 ;; which can be found in the file epl-v10.html at the root of this | |
10 ;; distribution. By using this software in any fashion, you are | |
11 ;; agreeing to be bound by the terms of this license. You must not | |
12 ;; remove this notice, or any other, from this software. | |
13 | |
14 (ns | |
15 ^{:author "Konrad Hinsen" | |
16 :doc "Local macros and symbol macros | |
17 | |
18 Local macros are defined by a macrolet form. They are usable only | |
19 inside its body. Symbol macros can be defined globally | |
20 (defsymbolmacro) or locally (symbol-macrolet). A symbol | |
21 macro defines a form that replaces a symbol during macro | |
22 expansion. Function arguments and symbols bound in let | |
23 forms are not subject to symbol macro expansion. | |
24 | |
25 Local macros are most useful in the definition of the expansion | |
26 of another macro, they may be used anywhere. Global symbol | |
27 macros can be used only inside a with-symbol-macros form."} | |
28 clojure.contrib.macro-utils | |
29 (:use [clojure.contrib.def :only (defvar-)])) | |
30 | |
31 ; A set of all special forms. Special forms are not macro-expanded, making | |
32 ; it impossible to shadow them by macro definitions. For most special | |
33 ; forms, all the arguments are simply macro-expanded, but some forms | |
34 ; get special treatment. | |
35 (defvar- special-forms | |
36 (into #{} (keys clojure.lang.Compiler/specials))) | |
37 ; Value in the Clojure 1.2 branch: | |
38 ; #{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} | |
39 | |
40 ; The following three vars are constantly redefined using the binding | |
41 ; form, imitating dynamic scoping. | |
42 ; | |
43 ; Local macros. | |
44 (defvar- macro-fns {}) | |
45 ; Local symbol macros. | |
46 (defvar- macro-symbols {}) | |
47 ; Symbols defined inside let forms or function arguments. | |
48 (defvar- protected-symbols #{}) | |
49 | |
50 (defn- reserved? | |
51 [symbol] | |
52 "Return true if symbol is a reserved symbol (starting or ending with a dot)." | |
53 (let [s (str symbol)] | |
54 (or (= "." (subs s 0 1)) | |
55 (= "." (subs s (dec (count s))))))) | |
56 | |
57 (defn- expand-symbol | |
58 "Expand symbol macros" | |
59 [symbol] | |
60 (cond (contains? protected-symbols symbol) symbol | |
61 (reserved? symbol) symbol | |
62 (contains? macro-symbols symbol) (get macro-symbols symbol) | |
63 :else (let [v (resolve symbol) | |
64 m (meta v)] | |
65 (if (:symbol-macro m) | |
66 (var-get v) | |
67 symbol)))) | |
68 | |
69 (defn- expand-1 | |
70 "Perform a single non-recursive macro expansion of form." | |
71 [form] | |
72 (cond | |
73 (seq? form) | |
74 (let [f (first form)] | |
75 (cond (contains? special-forms f) form | |
76 (contains? macro-fns f) (apply (get macro-fns f) (rest form)) | |
77 (symbol? f) (let [exp (expand-symbol f)] | |
78 (if (= exp f) | |
79 (clojure.core/macroexpand-1 form) | |
80 (cons exp (rest form)))) | |
81 ; handle defmacro macros and Java method special forms | |
82 :else (clojure.core/macroexpand-1 form))) | |
83 (symbol? form) | |
84 (expand-symbol form) | |
85 :else | |
86 form)) | |
87 | |
88 (defn- expand | |
89 "Perform repeated non-recursive macro expansion of form, until it no | |
90 longer changes." | |
91 [form] | |
92 (let [ex (expand-1 form)] | |
93 (if (identical? ex form) | |
94 form | |
95 (recur ex)))) | |
96 | |
97 (declare expand-all) | |
98 | |
99 (defn- expand-args | |
100 "Recursively expand the arguments of form, leaving its first | |
101 n elements unchanged." | |
102 ([form] | |
103 (expand-args form 1)) | |
104 ([form n] | |
105 (doall (concat (take n form) (map expand-all (drop n form)))))) | |
106 | |
107 (defn- expand-bindings | |
108 [bindings exprs] | |
109 (if (empty? bindings) | |
110 (list (doall (map expand-all exprs))) | |
111 (let [[[s b] & bindings] bindings] | |
112 (let [b (expand-all b)] | |
113 (binding [protected-symbols (conj protected-symbols s)] | |
114 (doall (cons [s b] (expand-bindings bindings exprs)))))))) | |
115 | |
116 (defn- expand-with-bindings | |
117 "Handle let* and loop* forms. The symbols defined in them are protected | |
118 from symbol macro expansion, the definitions and the body expressions | |
119 are expanded recursively." | |
120 [form] | |
121 (let [f (first form) | |
122 bindings (partition 2 (second form)) | |
123 exprs (rest (rest form)) | |
124 expanded (expand-bindings bindings exprs) | |
125 bindings (vec (apply concat (butlast expanded))) | |
126 exprs (last expanded)] | |
127 (cons f (cons bindings exprs)))) | |
128 | |
129 (defn- expand-fn-body | |
130 [[args & exprs]] | |
131 (binding [protected-symbols (reduce conj protected-symbols | |
132 (filter #(not (= % '&)) args))] | |
133 (cons args (doall (map expand-all exprs))))) | |
134 | |
135 (defn- expand-fn | |
136 "Handle fn* forms. The arguments are protected from symbol macro | |
137 expansion, the bodies are expanded recursively." | |
138 [form] | |
139 (let [[f & bodies] form | |
140 name (when (symbol? (first bodies)) (first bodies)) | |
141 bodies (if (symbol? (first bodies)) (rest bodies) bodies) | |
142 bodies (if (vector? (first bodies)) (list bodies) bodies) | |
143 bodies (doall (map expand-fn-body bodies))] | |
144 (if (nil? name) | |
145 (cons f bodies) | |
146 (cons f (cons name bodies))))) | |
147 | |
148 (defn- expand-method | |
149 "Handle a method in a deftype* or reify* form." | |
150 [m] | |
151 (rest (expand-fn (cons 'fn* m)))) | |
152 | |
153 (defn- expand-deftype | |
154 "Handle deftype* forms." | |
155 [[symbol typename classname fields implements interfaces & methods]] | |
156 (assert (= implements :implements)) | |
157 (let [expanded-methods (map expand-method methods)] | |
158 (concat | |
159 (list symbol typename classname fields implements interfaces) | |
160 expanded-methods))) | |
161 | |
162 (defn- expand-reify | |
163 "Handle reify* forms." | |
164 [[symbol interfaces & methods]] | |
165 (let [expanded-methods (map expand-method methods)] | |
166 (cons symbol (cons interfaces expanded-methods)))) | |
167 | |
168 ; Handlers for special forms that require special treatment. The default | |
169 ; is expand-args. | |
170 (defvar- special-form-handlers | |
171 {'quote identity | |
172 'var identity | |
173 'def #(expand-args % 2) | |
174 'new #(expand-args % 2) | |
175 'let* expand-with-bindings | |
176 'loop* expand-with-bindings | |
177 'fn* expand-fn | |
178 'deftype* expand-deftype | |
179 'reify* expand-reify}) | |
180 | |
181 (defn- expand-list | |
182 "Recursively expand a form that is a list or a cons." | |
183 [form] | |
184 (let [f (first form)] | |
185 (if (symbol? f) | |
186 (if (contains? special-forms f) | |
187 ((get special-form-handlers f expand-args) form) | |
188 (expand-args form)) | |
189 (doall (map expand-all form))))) | |
190 | |
191 (defn- expand-all | |
192 "Expand a form recursively." | |
193 [form] | |
194 (let [exp (expand form)] | |
195 (cond (symbol? exp) exp | |
196 (seq? exp) (expand-list exp) | |
197 (vector? exp) (into [] (map expand-all exp)) | |
198 (map? exp) (into {} (map expand-all (seq exp))) | |
199 :else exp))) | |
200 | |
201 (defmacro macrolet | |
202 "Define local macros that are used in the expansion of exprs. The | |
203 syntax is the same as for letfn forms." | |
204 [fn-bindings & exprs] | |
205 (let [names (map first fn-bindings) | |
206 name-map (into {} (map (fn [n] [(list 'quote n) n]) names)) | |
207 macro-map (eval `(letfn ~fn-bindings ~name-map))] | |
208 (binding [macro-fns (merge macro-fns macro-map) | |
209 macro-symbols (apply dissoc macro-symbols names)] | |
210 `(do ~@(doall (map expand-all exprs)))))) | |
211 | |
212 (defmacro symbol-macrolet | |
213 "Define local symbol macros that are used in the expansion of exprs. | |
214 The syntax is the same as for let forms." | |
215 [symbol-bindings & exprs] | |
216 (let [symbol-map (into {} (map vec (partition 2 symbol-bindings))) | |
217 names (keys symbol-map)] | |
218 (binding [macro-fns (apply dissoc macro-fns names) | |
219 macro-symbols (merge macro-symbols symbol-map)] | |
220 `(do ~@(doall (map expand-all exprs)))))) | |
221 | |
222 (defmacro defsymbolmacro | |
223 "Define a symbol macro. Because symbol macros are not part of | |
224 Clojure's built-in macro expansion system, they can be used only | |
225 inside a with-symbol-macros form." | |
226 [symbol expansion] | |
227 (let [meta-map (if (meta symbol) (meta symbol) {}) | |
228 meta-map (assoc meta-map :symbol-macro true)] | |
229 `(def ~(with-meta symbol meta-map) (quote ~expansion)))) | |
230 | |
231 (defmacro with-symbol-macros | |
232 "Fully expand exprs, including symbol macros." | |
233 [& exprs] | |
234 `(do ~@(doall (map expand-all exprs)))) | |
235 | |
236 (defmacro deftemplate | |
237 "Define a macro that expands into forms after replacing the | |
238 symbols in params (a vector) by the corresponding parameters | |
239 given in the macro call." | |
240 [name params & forms] | |
241 (let [param-map (for [p params] (list (list 'quote p) (gensym))) | |
242 template-params (vec (map second param-map)) | |
243 param-map (vec (apply concat param-map)) | |
244 expansion (list 'list (list 'quote `symbol-macrolet) param-map | |
245 (list 'quote (cons 'do forms)))] | |
246 `(defmacro ~name ~template-params ~expansion))) | |
247 | |
248 (defn mexpand-1 | |
249 "Like clojure.core/macroexpand-1, but takes into account symbol macros." | |
250 [form] | |
251 (binding [macro-fns {} | |
252 macro-symbols {} | |
253 protected-symbols #{}] | |
254 (expand-1 form))) | |
255 | |
256 (defn mexpand | |
257 "Like clojure.core/macroexpand, but takes into account symbol macros." | |
258 [form] | |
259 (binding [macro-fns {} | |
260 macro-symbols {} | |
261 protected-symbols #{}] | |
262 (expand form))) | |
263 | |
264 (defn mexpand-all | |
265 "Perform a full recursive macro expansion of a form." | |
266 [form] | |
267 (binding [macro-fns {} | |
268 macro-symbols {} | |
269 protected-symbols #{}] | |
270 (expand-all form))) |