view src/clojure/lang/Namespace.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 Jan 23, 2008 */
13 package clojure.lang;
15 import java.io.ObjectStreamException;
16 import java.io.Serializable;
17 import java.util.concurrent.ConcurrentHashMap;
18 import java.util.concurrent.atomic.AtomicReference;
20 public class Namespace extends AReference implements Serializable {
21 final public Symbol name;
22 transient final AtomicReference<IPersistentMap> mappings = new AtomicReference<IPersistentMap>();
23 transient final AtomicReference<IPersistentMap> aliases = new AtomicReference<IPersistentMap>();
25 final static ConcurrentHashMap<Symbol, Namespace> namespaces = new ConcurrentHashMap<Symbol, Namespace>();
27 public String toString(){
28 return name.toString();
29 }
31 Namespace(Symbol name){
32 super(name.meta());
33 this.name = name;
34 mappings.set(RT.DEFAULT_IMPORTS);
35 aliases.set(RT.map());
36 }
38 public static ISeq all(){
39 return RT.seq(namespaces.values());
40 }
42 public Symbol getName(){
43 return name;
44 }
46 public IPersistentMap getMappings(){
47 return mappings.get();
48 }
50 public Var intern(Symbol sym){
51 if(sym.ns != null)
52 {
53 throw new IllegalArgumentException("Can't intern namespace-qualified symbol");
54 }
55 IPersistentMap map = getMappings();
56 Object o;
57 Var v = null;
58 while((o = map.valAt(sym)) == null)
59 {
60 if(v == null)
61 v = new Var(this, sym);
62 IPersistentMap newMap = map.assoc(sym, v);
63 mappings.compareAndSet(map, newMap);
64 map = getMappings();
65 }
66 if(o instanceof Var && ((Var) o).ns == this)
67 return (Var) o;
69 if(v == null)
70 v = new Var(this, sym);
72 warnOrFailOnReplace(sym, o, v);
75 while(!mappings.compareAndSet(map, map.assoc(sym, v)))
76 map = getMappings();
78 return v;
79 }
81 private void warnOrFailOnReplace(Symbol sym, Object o, Object v){
82 if (o instanceof Var)
83 {
84 Namespace ns = ((Var)o).ns;
85 if (ns == this)
86 return;
87 if (ns != RT.CLOJURE_NS)
88 throw new IllegalStateException(sym + " already refers to: " + o + " in namespace: " + name);
89 }
90 RT.errPrintWriter().println("WARNING: " + sym + " already refers to: " + o + " in namespace: " + name
91 + ", being replaced by: " + v);
92 }
94 Object reference(Symbol sym, Object val){
95 if(sym.ns != null)
96 {
97 throw new IllegalArgumentException("Can't intern namespace-qualified symbol");
98 }
99 IPersistentMap map = getMappings();
100 Object o;
101 while((o = map.valAt(sym)) == null)
102 {
103 IPersistentMap newMap = map.assoc(sym, val);
104 mappings.compareAndSet(map, newMap);
105 map = getMappings();
106 }
107 if(o == val)
108 return o;
110 warnOrFailOnReplace(sym, o, val);
112 while(!mappings.compareAndSet(map, map.assoc(sym, val)))
113 map = getMappings();
115 return val;
117 }
119 public static boolean areDifferentInstancesOfSameClassName(Class cls1, Class cls2) {
120 return (cls1 != cls2) && (cls1.getName().equals(cls2.getName()));
121 }
123 Class referenceClass(Symbol sym, Class val){
124 if(sym.ns != null)
125 {
126 throw new IllegalArgumentException("Can't intern namespace-qualified symbol");
127 }
128 IPersistentMap map = getMappings();
129 Class c = (Class) map.valAt(sym);
130 while((c == null) || (areDifferentInstancesOfSameClassName(c, val)))
131 {
132 IPersistentMap newMap = map.assoc(sym, val);
133 mappings.compareAndSet(map, newMap);
134 map = getMappings();
135 c = (Class) map.valAt(sym);
136 }
137 if(c == val)
138 return c;
140 throw new IllegalStateException(sym + " already refers to: " + c + " in namespace: " + name);
141 }
143 public void unmap(Symbol sym) throws Exception{
144 if(sym.ns != null)
145 {
146 throw new IllegalArgumentException("Can't unintern namespace-qualified symbol");
147 }
148 IPersistentMap map = getMappings();
149 while(map.containsKey(sym))
150 {
151 IPersistentMap newMap = map.without(sym);
152 mappings.compareAndSet(map, newMap);
153 map = getMappings();
154 }
155 }
157 public Class importClass(Symbol sym, Class c){
158 return referenceClass(sym, c);
160 }
162 public Class importClass(Class c){
163 String n = c.getName();
164 return importClass(Symbol.intern(n.substring(n.lastIndexOf('.') + 1)), c);
165 }
167 public Var refer(Symbol sym, Var var){
168 return (Var) reference(sym, var);
170 }
172 public static Namespace findOrCreate(Symbol name){
173 Namespace ns = namespaces.get(name);
174 if(ns != null)
175 return ns;
176 Namespace newns = new Namespace(name);
177 ns = namespaces.putIfAbsent(name, newns);
178 return ns == null ? newns : ns;
179 }
181 public static Namespace remove(Symbol name){
182 if(name.equals(RT.CLOJURE_NS.name))
183 throw new IllegalArgumentException("Cannot remove clojure namespace");
184 return namespaces.remove(name);
185 }
187 public static Namespace find(Symbol name){
188 return namespaces.get(name);
189 }
191 public Object getMapping(Symbol name){
192 return mappings.get().valAt(name);
193 }
195 public Var findInternedVar(Symbol symbol){
196 Object o = mappings.get().valAt(symbol);
197 if(o != null && o instanceof Var && ((Var) o).ns == this)
198 return (Var) o;
199 return null;
200 }
203 public IPersistentMap getAliases(){
204 return aliases.get();
205 }
207 public Namespace lookupAlias(Symbol alias){
208 IPersistentMap map = getAliases();
209 return (Namespace) map.valAt(alias);
210 }
212 public void addAlias(Symbol alias, Namespace ns){
213 if (alias == null || ns == null)
214 throw new NullPointerException("Expecting Symbol + Namespace");
215 IPersistentMap map = getAliases();
216 while(!map.containsKey(alias))
217 {
218 IPersistentMap newMap = map.assoc(alias, ns);
219 aliases.compareAndSet(map, newMap);
220 map = getAliases();
221 }
222 // you can rebind an alias, but only to the initially-aliased namespace.
223 if(!map.valAt(alias).equals(ns))
224 throw new IllegalStateException("Alias " + alias + " already exists in namespace "
225 + name + ", aliasing " + map.valAt(alias));
226 }
228 public void removeAlias(Symbol alias) throws Exception{
229 IPersistentMap map = getAliases();
230 while(map.containsKey(alias))
231 {
232 IPersistentMap newMap = map.without(alias);
233 aliases.compareAndSet(map, newMap);
234 map = getAliases();
235 }
236 }
238 private Object readResolve() throws ObjectStreamException {
239 // ensures that serialized namespaces are "deserialized" to the
240 // namespace in the present runtime
241 return findOrCreate(name);
242 }
243 }