Mercurial > lasercutter
comparison src/clojure/lang/Var.java @ 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 /** | |
2 * Copyright (c) Rich Hickey. All rights reserved. | |
3 * The use and distribution terms for this software are covered by the | |
4 * Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) | |
5 * which can be found in the file epl-v10.html at the root of this distribution. | |
6 * By using this software in any fashion, you are agreeing to be bound by | |
7 * the terms of this license. | |
8 * You must not remove this notice, or any other, from this software. | |
9 **/ | |
10 | |
11 /* rich Jul 31, 2007 */ | |
12 | |
13 package clojure.lang; | |
14 | |
15 import java.util.concurrent.atomic.AtomicInteger; | |
16 | |
17 | |
18 public final class Var extends ARef implements IFn, IRef, Settable{ | |
19 | |
20 | |
21 static class Frame{ | |
22 //Var->Box | |
23 Associative bindings; | |
24 //Var->val | |
25 Associative frameBindings; | |
26 Frame prev; | |
27 | |
28 | |
29 public Frame(){ | |
30 this(PersistentHashMap.EMPTY, PersistentHashMap.EMPTY, null); | |
31 } | |
32 | |
33 public Frame(Associative frameBindings, Associative bindings, Frame prev){ | |
34 this.frameBindings = frameBindings; | |
35 this.bindings = bindings; | |
36 this.prev = prev; | |
37 } | |
38 } | |
39 | |
40 static ThreadLocal<Frame> dvals = new ThreadLocal<Frame>(){ | |
41 | |
42 protected Frame initialValue(){ | |
43 return new Frame(); | |
44 } | |
45 }; | |
46 | |
47 static Keyword privateKey = Keyword.intern(null, "private"); | |
48 static IPersistentMap privateMeta = new PersistentArrayMap(new Object[]{privateKey, Boolean.TRUE}); | |
49 static Keyword macroKey = Keyword.intern(null, "macro"); | |
50 static Keyword nameKey = Keyword.intern(null, "name"); | |
51 static Keyword nsKey = Keyword.intern(null, "ns"); | |
52 //static Keyword tagKey = Keyword.intern(null, "tag"); | |
53 | |
54 volatile Object root; | |
55 transient final AtomicInteger count; | |
56 public final Symbol sym; | |
57 public final Namespace ns; | |
58 | |
59 //IPersistentMap _meta; | |
60 | |
61 public static Var intern(Namespace ns, Symbol sym, Object root){ | |
62 return intern(ns, sym, root, true); | |
63 } | |
64 | |
65 public static Var intern(Namespace ns, Symbol sym, Object root, boolean replaceRoot){ | |
66 Var dvout = ns.intern(sym); | |
67 if(!dvout.hasRoot() || replaceRoot) | |
68 dvout.bindRoot(root); | |
69 return dvout; | |
70 } | |
71 | |
72 | |
73 public String toString(){ | |
74 if(ns != null) | |
75 return "#'" + ns.name + "/" + sym; | |
76 return "#<Var: " + (sym != null ? sym.toString() : "--unnamed--") + ">"; | |
77 } | |
78 | |
79 public static Var find(Symbol nsQualifiedSym){ | |
80 if(nsQualifiedSym.ns == null) | |
81 throw new IllegalArgumentException("Symbol must be namespace-qualified"); | |
82 Namespace ns = Namespace.find(Symbol.create(nsQualifiedSym.ns)); | |
83 if(ns == null) | |
84 throw new IllegalArgumentException("No such namespace: " + nsQualifiedSym.ns); | |
85 return ns.findInternedVar(Symbol.create(nsQualifiedSym.name)); | |
86 } | |
87 | |
88 public static Var intern(Symbol nsName, Symbol sym){ | |
89 Namespace ns = Namespace.findOrCreate(nsName); | |
90 return intern(ns, sym); | |
91 } | |
92 | |
93 public static Var internPrivate(String nsName, String sym){ | |
94 Namespace ns = Namespace.findOrCreate(Symbol.intern(nsName)); | |
95 Var ret = intern(ns, Symbol.intern(sym)); | |
96 ret.setMeta(privateMeta); | |
97 return ret; | |
98 } | |
99 | |
100 public static Var intern(Namespace ns, Symbol sym){ | |
101 return ns.intern(sym); | |
102 } | |
103 | |
104 | |
105 public static Var create(){ | |
106 return new Var(null, null); | |
107 } | |
108 | |
109 public static Var create(Object root){ | |
110 return new Var(null, null, root); | |
111 } | |
112 | |
113 Var(Namespace ns, Symbol sym){ | |
114 this.ns = ns; | |
115 this.sym = sym; | |
116 this.count = new AtomicInteger(); | |
117 this.root = dvals; //use dvals as magic not-bound value | |
118 setMeta(PersistentHashMap.EMPTY); | |
119 } | |
120 | |
121 Var(Namespace ns, Symbol sym, Object root){ | |
122 this(ns, sym); | |
123 this.root = root; | |
124 } | |
125 | |
126 public boolean isBound(){ | |
127 return hasRoot() || (count.get() > 0 && dvals.get().bindings.containsKey(this)); | |
128 } | |
129 | |
130 final public Object get(){ | |
131 if(count.get() == 0 && root != dvals) | |
132 return root; | |
133 return deref(); | |
134 } | |
135 | |
136 final public Object deref(){ | |
137 Box b = getThreadBinding(); | |
138 if(b != null) | |
139 return b.val; | |
140 if(hasRoot()) | |
141 return root; | |
142 throw new IllegalStateException(String.format("Var %s/%s is unbound.", ns, sym)); | |
143 } | |
144 | |
145 public void setValidator(IFn vf){ | |
146 if(hasRoot()) | |
147 validate(vf, getRoot()); | |
148 validator = vf; | |
149 } | |
150 | |
151 public Object alter(IFn fn, ISeq args) throws Exception{ | |
152 set(fn.applyTo(RT.cons(deref(), args))); | |
153 return this; | |
154 } | |
155 | |
156 public Object set(Object val){ | |
157 validate(getValidator(), val); | |
158 Box b = getThreadBinding(); | |
159 if(b != null) | |
160 return (b.val = val); | |
161 //jury still out on this | |
162 // if(hasRoot()) | |
163 // { | |
164 // bindRoot(val); | |
165 // return val; | |
166 // } | |
167 throw new IllegalStateException(String.format("Can't change/establish root binding of: %s with set", sym)); | |
168 } | |
169 | |
170 public Object doSet(Object val) throws Exception { | |
171 return set(val); | |
172 } | |
173 | |
174 public Object doReset(Object val) throws Exception { | |
175 bindRoot(val); | |
176 return val; | |
177 } | |
178 | |
179 public void setMeta(IPersistentMap m) { | |
180 //ensure these basis keys | |
181 resetMeta(m.assoc(nameKey, sym).assoc(nsKey, ns)); | |
182 } | |
183 | |
184 public void setMacro() { | |
185 try | |
186 { | |
187 alterMeta(assoc, RT.list(macroKey, RT.T)); | |
188 } | |
189 catch (Exception e) | |
190 { | |
191 throw new RuntimeException(e); | |
192 } | |
193 } | |
194 | |
195 public boolean isMacro(){ | |
196 return RT.booleanCast(meta().valAt(macroKey)); | |
197 } | |
198 | |
199 //public void setExported(boolean state){ | |
200 // _meta = _meta.assoc(privateKey, state); | |
201 //} | |
202 | |
203 public boolean isPublic(){ | |
204 return !RT.booleanCast(meta().valAt(privateKey)); | |
205 } | |
206 | |
207 public Object getRoot(){ | |
208 if(hasRoot()) | |
209 return root; | |
210 throw new IllegalStateException(String.format("Var %s/%s is unbound.", ns, sym)); | |
211 } | |
212 | |
213 public Object getRawRoot(){ | |
214 return root; | |
215 } | |
216 | |
217 public Object getTag(){ | |
218 return meta().valAt(RT.TAG_KEY); | |
219 } | |
220 | |
221 public void setTag(Symbol tag) { | |
222 try | |
223 { | |
224 alterMeta(assoc, RT.list(RT.TAG_KEY, tag)); | |
225 } | |
226 catch (Exception e) | |
227 { | |
228 throw new RuntimeException(e); | |
229 } | |
230 } | |
231 | |
232 final public boolean hasRoot(){ | |
233 return root != dvals; | |
234 } | |
235 | |
236 //binding root always clears macro flag | |
237 synchronized public void bindRoot(Object root){ | |
238 validate(getValidator(), root); | |
239 Object oldroot = hasRoot()?this.root:null; | |
240 this.root = root; | |
241 try | |
242 { | |
243 alterMeta(dissoc, RT.list(macroKey)); | |
244 } | |
245 catch (Exception e) | |
246 { | |
247 throw new RuntimeException(e); | |
248 } | |
249 notifyWatches(oldroot,this.root); | |
250 } | |
251 | |
252 synchronized void swapRoot(Object root){ | |
253 validate(getValidator(), root); | |
254 Object oldroot = hasRoot()?this.root:null; | |
255 this.root = root; | |
256 notifyWatches(oldroot,root); | |
257 } | |
258 | |
259 synchronized public void unbindRoot(){ | |
260 this.root = dvals; | |
261 } | |
262 | |
263 synchronized public void commuteRoot(IFn fn) throws Exception{ | |
264 Object newRoot = fn.invoke(root); | |
265 validate(getValidator(), newRoot); | |
266 Object oldroot = getRoot(); | |
267 this.root = newRoot; | |
268 notifyWatches(oldroot,newRoot); | |
269 } | |
270 | |
271 synchronized public Object alterRoot(IFn fn, ISeq args) throws Exception{ | |
272 Object newRoot = fn.applyTo(RT.cons(root, args)); | |
273 validate(getValidator(), newRoot); | |
274 Object oldroot = getRoot(); | |
275 this.root = newRoot; | |
276 notifyWatches(oldroot,newRoot); | |
277 return newRoot; | |
278 } | |
279 | |
280 public static void pushThreadBindings(Associative bindings){ | |
281 Frame f = dvals.get(); | |
282 Associative bmap = f.bindings; | |
283 for(ISeq bs = bindings.seq(); bs != null; bs = bs.next()) | |
284 { | |
285 IMapEntry e = (IMapEntry) bs.first(); | |
286 Var v = (Var) e.key(); | |
287 v.validate(v.getValidator(), e.val()); | |
288 v.count.incrementAndGet(); | |
289 bmap = bmap.assoc(v, new Box(e.val())); | |
290 } | |
291 dvals.set(new Frame(bindings, bmap, f)); | |
292 } | |
293 | |
294 public static void popThreadBindings(){ | |
295 Frame f = dvals.get(); | |
296 if(f.prev == null) | |
297 throw new IllegalStateException("Pop without matching push"); | |
298 for(ISeq bs = RT.keys(f.frameBindings); bs != null; bs = bs.next()) | |
299 { | |
300 Var v = (Var) bs.first(); | |
301 v.count.decrementAndGet(); | |
302 } | |
303 dvals.set(f.prev); | |
304 } | |
305 | |
306 public static void releaseThreadBindings(){ | |
307 Frame f = dvals.get(); | |
308 if(f.prev == null) | |
309 throw new IllegalStateException("Release without full unwind"); | |
310 for(ISeq bs = RT.keys(f.bindings); bs != null; bs = bs.next()) | |
311 { | |
312 Var v = (Var) bs.first(); | |
313 v.count.decrementAndGet(); | |
314 } | |
315 dvals.set(null); | |
316 } | |
317 | |
318 public static Associative getThreadBindings(){ | |
319 Frame f = dvals.get(); | |
320 IPersistentMap ret = PersistentHashMap.EMPTY; | |
321 for(ISeq bs = f.bindings.seq(); bs != null; bs = bs.next()) | |
322 { | |
323 IMapEntry e = (IMapEntry) bs.first(); | |
324 Var v = (Var) e.key(); | |
325 Box b = (Box) e.val(); | |
326 ret = ret.assoc(v, b.val); | |
327 } | |
328 return ret; | |
329 } | |
330 | |
331 public final Box getThreadBinding(){ | |
332 if(count.get() > 0) | |
333 { | |
334 IMapEntry e = dvals.get().bindings.entryAt(this); | |
335 if(e != null) | |
336 return (Box) e.val(); | |
337 } | |
338 return null; | |
339 } | |
340 | |
341 final public IFn fn(){ | |
342 return (IFn) deref(); | |
343 } | |
344 | |
345 public Object call() throws Exception{ | |
346 return invoke(); | |
347 } | |
348 | |
349 public void run(){ | |
350 try | |
351 { | |
352 invoke(); | |
353 } | |
354 catch(Exception e) | |
355 { | |
356 throw new RuntimeException(e); | |
357 } | |
358 } | |
359 | |
360 public Object invoke() throws Exception{ | |
361 return fn().invoke(); | |
362 } | |
363 | |
364 public Object invoke(Object arg1) throws Exception{ | |
365 return fn().invoke(arg1); | |
366 } | |
367 | |
368 public Object invoke(Object arg1, Object arg2) throws Exception{ | |
369 return fn().invoke(arg1, arg2); | |
370 } | |
371 | |
372 public Object invoke(Object arg1, Object arg2, Object arg3) throws Exception{ | |
373 return fn().invoke(arg1, arg2, arg3); | |
374 } | |
375 | |
376 public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4) throws Exception{ | |
377 return fn().invoke(arg1, arg2, arg3, arg4); | |
378 } | |
379 | |
380 public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5) throws Exception{ | |
381 return fn().invoke(arg1, arg2, arg3, arg4, arg5); | |
382 } | |
383 | |
384 public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6) throws Exception{ | |
385 return fn().invoke(arg1, arg2, arg3, arg4, arg5, arg6); | |
386 } | |
387 | |
388 public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7) | |
389 throws Exception{ | |
390 return fn().invoke(arg1, arg2, arg3, arg4, arg5, arg6, arg7); | |
391 } | |
392 | |
393 public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, | |
394 Object arg8) throws Exception{ | |
395 return fn().invoke(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); | |
396 } | |
397 | |
398 public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, | |
399 Object arg8, Object arg9) throws Exception{ | |
400 return fn().invoke(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); | |
401 } | |
402 | |
403 public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, | |
404 Object arg8, Object arg9, Object arg10) throws Exception{ | |
405 return fn().invoke(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10); | |
406 } | |
407 | |
408 public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, | |
409 Object arg8, Object arg9, Object arg10, Object arg11) throws Exception{ | |
410 return fn().invoke(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11); | |
411 } | |
412 | |
413 public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, | |
414 Object arg8, Object arg9, Object arg10, Object arg11, Object arg12) throws Exception{ | |
415 return fn().invoke(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12); | |
416 } | |
417 | |
418 public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, | |
419 Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13) | |
420 throws Exception{ | |
421 return fn().invoke(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13); | |
422 } | |
423 | |
424 public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, | |
425 Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14) | |
426 throws Exception{ | |
427 return fn().invoke(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14); | |
428 } | |
429 | |
430 public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, | |
431 Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, | |
432 Object arg15) throws Exception{ | |
433 return fn().invoke(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15); | |
434 } | |
435 | |
436 public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, | |
437 Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, | |
438 Object arg15, Object arg16) throws Exception{ | |
439 return fn().invoke(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, | |
440 arg16); | |
441 } | |
442 | |
443 public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, | |
444 Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, | |
445 Object arg15, Object arg16, Object arg17) throws Exception{ | |
446 return fn().invoke(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, | |
447 arg16, arg17); | |
448 } | |
449 | |
450 public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, | |
451 Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, | |
452 Object arg15, Object arg16, Object arg17, Object arg18) throws Exception{ | |
453 return fn().invoke(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, | |
454 arg16, arg17, arg18); | |
455 } | |
456 | |
457 public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, | |
458 Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, | |
459 Object arg15, Object arg16, Object arg17, Object arg18, Object arg19) throws Exception{ | |
460 return fn().invoke(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, | |
461 arg16, arg17, arg18, arg19); | |
462 } | |
463 | |
464 public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, | |
465 Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, | |
466 Object arg15, Object arg16, Object arg17, Object arg18, Object arg19, Object arg20) | |
467 throws Exception{ | |
468 return fn().invoke(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, | |
469 arg16, arg17, arg18, arg19, arg20); | |
470 } | |
471 | |
472 public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, | |
473 Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, | |
474 Object arg15, Object arg16, Object arg17, Object arg18, Object arg19, Object arg20, | |
475 Object... args) | |
476 throws Exception{ | |
477 return fn().invoke(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, | |
478 arg16, arg17, arg18, arg19, arg20, args); | |
479 } | |
480 | |
481 public Object applyTo(ISeq arglist) throws Exception{ | |
482 return AFn.applyToHelper(this, arglist); | |
483 } | |
484 | |
485 static IFn assoc = new AFn(){ | |
486 @Override | |
487 public Object invoke(Object m, Object k, Object v) throws Exception { | |
488 return RT.assoc(m, k, v); | |
489 } | |
490 }; | |
491 static IFn dissoc = new AFn() { | |
492 @Override | |
493 public Object invoke(Object c, Object k) throws Exception { | |
494 return RT.dissoc(c, k); | |
495 } | |
496 }; | |
497 } |