view 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
line wrap: on
line source
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 **/
11 /* rich Jul 31, 2007 */
13 package clojure.lang;
15 import java.util.concurrent.atomic.AtomicInteger;
18 public final class Var extends ARef implements IFn, IRef, Settable{
21 static class Frame{
22 //Var->Box
23 Associative bindings;
24 //Var->val
25 Associative frameBindings;
26 Frame prev;
29 public Frame(){
30 this(PersistentHashMap.EMPTY, PersistentHashMap.EMPTY, null);
31 }
33 public Frame(Associative frameBindings, Associative bindings, Frame prev){
34 this.frameBindings = frameBindings;
35 this.bindings = bindings;
36 this.prev = prev;
37 }
38 }
40 static ThreadLocal<Frame> dvals = new ThreadLocal<Frame>(){
42 protected Frame initialValue(){
43 return new Frame();
44 }
45 };
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");
54 volatile Object root;
55 transient final AtomicInteger count;
56 public final Symbol sym;
57 public final Namespace ns;
59 //IPersistentMap _meta;
61 public static Var intern(Namespace ns, Symbol sym, Object root){
62 return intern(ns, sym, root, true);
63 }
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 }
73 public String toString(){
74 if(ns != null)
75 return "#'" + ns.name + "/" + sym;
76 return "#<Var: " + (sym != null ? sym.toString() : "--unnamed--") + ">";
77 }
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 }
88 public static Var intern(Symbol nsName, Symbol sym){
89 Namespace ns = Namespace.findOrCreate(nsName);
90 return intern(ns, sym);
91 }
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 }
100 public static Var intern(Namespace ns, Symbol sym){
101 return ns.intern(sym);
102 }
105 public static Var create(){
106 return new Var(null, null);
107 }
109 public static Var create(Object root){
110 return new Var(null, null, root);
111 }
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 }
121 Var(Namespace ns, Symbol sym, Object root){
122 this(ns, sym);
123 this.root = root;
124 }
126 public boolean isBound(){
127 return hasRoot() || (count.get() > 0 && dvals.get().bindings.containsKey(this));
128 }
130 final public Object get(){
131 if(count.get() == 0 && root != dvals)
132 return root;
133 return deref();
134 }
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 }
145 public void setValidator(IFn vf){
146 if(hasRoot())
147 validate(vf, getRoot());
148 validator = vf;
149 }
151 public Object alter(IFn fn, ISeq args) throws Exception{
152 set(fn.applyTo(RT.cons(deref(), args)));
153 return this;
154 }
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 }
170 public Object doSet(Object val) throws Exception {
171 return set(val);
172 }
174 public Object doReset(Object val) throws Exception {
175 bindRoot(val);
176 return val;
177 }
179 public void setMeta(IPersistentMap m) {
180 //ensure these basis keys
181 resetMeta(m.assoc(nameKey, sym).assoc(nsKey, ns));
182 }
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 }
195 public boolean isMacro(){
196 return RT.booleanCast(meta().valAt(macroKey));
197 }
199 //public void setExported(boolean state){
200 // _meta = _meta.assoc(privateKey, state);
201 //}
203 public boolean isPublic(){
204 return !RT.booleanCast(meta().valAt(privateKey));
205 }
207 public Object getRoot(){
208 if(hasRoot())
209 return root;
210 throw new IllegalStateException(String.format("Var %s/%s is unbound.", ns, sym));
211 }
213 public Object getRawRoot(){
214 return root;
215 }
217 public Object getTag(){
218 return meta().valAt(RT.TAG_KEY);
219 }
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 }
232 final public boolean hasRoot(){
233 return root != dvals;
234 }
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 }
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 }
259 synchronized public void unbindRoot(){
260 this.root = dvals;
261 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
341 final public IFn fn(){
342 return (IFn) deref();
343 }
345 public Object call() throws Exception{
346 return invoke();
347 }
349 public void run(){
350 try
351 {
352 invoke();
353 }
354 catch(Exception e)
355 {
356 throw new RuntimeException(e);
357 }
358 }
360 public Object invoke() throws Exception{
361 return fn().invoke();
362 }
364 public Object invoke(Object arg1) throws Exception{
365 return fn().invoke(arg1);
366 }
368 public Object invoke(Object arg1, Object arg2) throws Exception{
369 return fn().invoke(arg1, arg2);
370 }
372 public Object invoke(Object arg1, Object arg2, Object arg3) throws Exception{
373 return fn().invoke(arg1, arg2, arg3);
374 }
376 public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4) throws Exception{
377 return fn().invoke(arg1, arg2, arg3, arg4);
378 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
481 public Object applyTo(ISeq arglist) throws Exception{
482 return AFn.applyToHelper(this, arglist);
483 }
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 }