annotate 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
rev   line source
rlm@10 1 /**
rlm@10 2 * Copyright (c) Rich Hickey. All rights reserved.
rlm@10 3 * The use and distribution terms for this software are covered by the
rlm@10 4 * Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
rlm@10 5 * which can be found in the file epl-v10.html at the root of this distribution.
rlm@10 6 * By using this software in any fashion, you are agreeing to be bound by
rlm@10 7 * the terms of this license.
rlm@10 8 * You must not remove this notice, or any other, from this software.
rlm@10 9 **/
rlm@10 10
rlm@10 11 /* rich Jan 23, 2008 */
rlm@10 12
rlm@10 13 package clojure.lang;
rlm@10 14
rlm@10 15 import java.io.ObjectStreamException;
rlm@10 16 import java.io.Serializable;
rlm@10 17 import java.util.concurrent.ConcurrentHashMap;
rlm@10 18 import java.util.concurrent.atomic.AtomicReference;
rlm@10 19
rlm@10 20 public class Namespace extends AReference implements Serializable {
rlm@10 21 final public Symbol name;
rlm@10 22 transient final AtomicReference<IPersistentMap> mappings = new AtomicReference<IPersistentMap>();
rlm@10 23 transient final AtomicReference<IPersistentMap> aliases = new AtomicReference<IPersistentMap>();
rlm@10 24
rlm@10 25 final static ConcurrentHashMap<Symbol, Namespace> namespaces = new ConcurrentHashMap<Symbol, Namespace>();
rlm@10 26
rlm@10 27 public String toString(){
rlm@10 28 return name.toString();
rlm@10 29 }
rlm@10 30
rlm@10 31 Namespace(Symbol name){
rlm@10 32 super(name.meta());
rlm@10 33 this.name = name;
rlm@10 34 mappings.set(RT.DEFAULT_IMPORTS);
rlm@10 35 aliases.set(RT.map());
rlm@10 36 }
rlm@10 37
rlm@10 38 public static ISeq all(){
rlm@10 39 return RT.seq(namespaces.values());
rlm@10 40 }
rlm@10 41
rlm@10 42 public Symbol getName(){
rlm@10 43 return name;
rlm@10 44 }
rlm@10 45
rlm@10 46 public IPersistentMap getMappings(){
rlm@10 47 return mappings.get();
rlm@10 48 }
rlm@10 49
rlm@10 50 public Var intern(Symbol sym){
rlm@10 51 if(sym.ns != null)
rlm@10 52 {
rlm@10 53 throw new IllegalArgumentException("Can't intern namespace-qualified symbol");
rlm@10 54 }
rlm@10 55 IPersistentMap map = getMappings();
rlm@10 56 Object o;
rlm@10 57 Var v = null;
rlm@10 58 while((o = map.valAt(sym)) == null)
rlm@10 59 {
rlm@10 60 if(v == null)
rlm@10 61 v = new Var(this, sym);
rlm@10 62 IPersistentMap newMap = map.assoc(sym, v);
rlm@10 63 mappings.compareAndSet(map, newMap);
rlm@10 64 map = getMappings();
rlm@10 65 }
rlm@10 66 if(o instanceof Var && ((Var) o).ns == this)
rlm@10 67 return (Var) o;
rlm@10 68
rlm@10 69 if(v == null)
rlm@10 70 v = new Var(this, sym);
rlm@10 71
rlm@10 72 warnOrFailOnReplace(sym, o, v);
rlm@10 73
rlm@10 74
rlm@10 75 while(!mappings.compareAndSet(map, map.assoc(sym, v)))
rlm@10 76 map = getMappings();
rlm@10 77
rlm@10 78 return v;
rlm@10 79 }
rlm@10 80
rlm@10 81 private void warnOrFailOnReplace(Symbol sym, Object o, Object v){
rlm@10 82 if (o instanceof Var)
rlm@10 83 {
rlm@10 84 Namespace ns = ((Var)o).ns;
rlm@10 85 if (ns == this)
rlm@10 86 return;
rlm@10 87 if (ns != RT.CLOJURE_NS)
rlm@10 88 throw new IllegalStateException(sym + " already refers to: " + o + " in namespace: " + name);
rlm@10 89 }
rlm@10 90 RT.errPrintWriter().println("WARNING: " + sym + " already refers to: " + o + " in namespace: " + name
rlm@10 91 + ", being replaced by: " + v);
rlm@10 92 }
rlm@10 93
rlm@10 94 Object reference(Symbol sym, Object val){
rlm@10 95 if(sym.ns != null)
rlm@10 96 {
rlm@10 97 throw new IllegalArgumentException("Can't intern namespace-qualified symbol");
rlm@10 98 }
rlm@10 99 IPersistentMap map = getMappings();
rlm@10 100 Object o;
rlm@10 101 while((o = map.valAt(sym)) == null)
rlm@10 102 {
rlm@10 103 IPersistentMap newMap = map.assoc(sym, val);
rlm@10 104 mappings.compareAndSet(map, newMap);
rlm@10 105 map = getMappings();
rlm@10 106 }
rlm@10 107 if(o == val)
rlm@10 108 return o;
rlm@10 109
rlm@10 110 warnOrFailOnReplace(sym, o, val);
rlm@10 111
rlm@10 112 while(!mappings.compareAndSet(map, map.assoc(sym, val)))
rlm@10 113 map = getMappings();
rlm@10 114
rlm@10 115 return val;
rlm@10 116
rlm@10 117 }
rlm@10 118
rlm@10 119 public static boolean areDifferentInstancesOfSameClassName(Class cls1, Class cls2) {
rlm@10 120 return (cls1 != cls2) && (cls1.getName().equals(cls2.getName()));
rlm@10 121 }
rlm@10 122
rlm@10 123 Class referenceClass(Symbol sym, Class val){
rlm@10 124 if(sym.ns != null)
rlm@10 125 {
rlm@10 126 throw new IllegalArgumentException("Can't intern namespace-qualified symbol");
rlm@10 127 }
rlm@10 128 IPersistentMap map = getMappings();
rlm@10 129 Class c = (Class) map.valAt(sym);
rlm@10 130 while((c == null) || (areDifferentInstancesOfSameClassName(c, val)))
rlm@10 131 {
rlm@10 132 IPersistentMap newMap = map.assoc(sym, val);
rlm@10 133 mappings.compareAndSet(map, newMap);
rlm@10 134 map = getMappings();
rlm@10 135 c = (Class) map.valAt(sym);
rlm@10 136 }
rlm@10 137 if(c == val)
rlm@10 138 return c;
rlm@10 139
rlm@10 140 throw new IllegalStateException(sym + " already refers to: " + c + " in namespace: " + name);
rlm@10 141 }
rlm@10 142
rlm@10 143 public void unmap(Symbol sym) throws Exception{
rlm@10 144 if(sym.ns != null)
rlm@10 145 {
rlm@10 146 throw new IllegalArgumentException("Can't unintern namespace-qualified symbol");
rlm@10 147 }
rlm@10 148 IPersistentMap map = getMappings();
rlm@10 149 while(map.containsKey(sym))
rlm@10 150 {
rlm@10 151 IPersistentMap newMap = map.without(sym);
rlm@10 152 mappings.compareAndSet(map, newMap);
rlm@10 153 map = getMappings();
rlm@10 154 }
rlm@10 155 }
rlm@10 156
rlm@10 157 public Class importClass(Symbol sym, Class c){
rlm@10 158 return referenceClass(sym, c);
rlm@10 159
rlm@10 160 }
rlm@10 161
rlm@10 162 public Class importClass(Class c){
rlm@10 163 String n = c.getName();
rlm@10 164 return importClass(Symbol.intern(n.substring(n.lastIndexOf('.') + 1)), c);
rlm@10 165 }
rlm@10 166
rlm@10 167 public Var refer(Symbol sym, Var var){
rlm@10 168 return (Var) reference(sym, var);
rlm@10 169
rlm@10 170 }
rlm@10 171
rlm@10 172 public static Namespace findOrCreate(Symbol name){
rlm@10 173 Namespace ns = namespaces.get(name);
rlm@10 174 if(ns != null)
rlm@10 175 return ns;
rlm@10 176 Namespace newns = new Namespace(name);
rlm@10 177 ns = namespaces.putIfAbsent(name, newns);
rlm@10 178 return ns == null ? newns : ns;
rlm@10 179 }
rlm@10 180
rlm@10 181 public static Namespace remove(Symbol name){
rlm@10 182 if(name.equals(RT.CLOJURE_NS.name))
rlm@10 183 throw new IllegalArgumentException("Cannot remove clojure namespace");
rlm@10 184 return namespaces.remove(name);
rlm@10 185 }
rlm@10 186
rlm@10 187 public static Namespace find(Symbol name){
rlm@10 188 return namespaces.get(name);
rlm@10 189 }
rlm@10 190
rlm@10 191 public Object getMapping(Symbol name){
rlm@10 192 return mappings.get().valAt(name);
rlm@10 193 }
rlm@10 194
rlm@10 195 public Var findInternedVar(Symbol symbol){
rlm@10 196 Object o = mappings.get().valAt(symbol);
rlm@10 197 if(o != null && o instanceof Var && ((Var) o).ns == this)
rlm@10 198 return (Var) o;
rlm@10 199 return null;
rlm@10 200 }
rlm@10 201
rlm@10 202
rlm@10 203 public IPersistentMap getAliases(){
rlm@10 204 return aliases.get();
rlm@10 205 }
rlm@10 206
rlm@10 207 public Namespace lookupAlias(Symbol alias){
rlm@10 208 IPersistentMap map = getAliases();
rlm@10 209 return (Namespace) map.valAt(alias);
rlm@10 210 }
rlm@10 211
rlm@10 212 public void addAlias(Symbol alias, Namespace ns){
rlm@10 213 if (alias == null || ns == null)
rlm@10 214 throw new NullPointerException("Expecting Symbol + Namespace");
rlm@10 215 IPersistentMap map = getAliases();
rlm@10 216 while(!map.containsKey(alias))
rlm@10 217 {
rlm@10 218 IPersistentMap newMap = map.assoc(alias, ns);
rlm@10 219 aliases.compareAndSet(map, newMap);
rlm@10 220 map = getAliases();
rlm@10 221 }
rlm@10 222 // you can rebind an alias, but only to the initially-aliased namespace.
rlm@10 223 if(!map.valAt(alias).equals(ns))
rlm@10 224 throw new IllegalStateException("Alias " + alias + " already exists in namespace "
rlm@10 225 + name + ", aliasing " + map.valAt(alias));
rlm@10 226 }
rlm@10 227
rlm@10 228 public void removeAlias(Symbol alias) throws Exception{
rlm@10 229 IPersistentMap map = getAliases();
rlm@10 230 while(map.containsKey(alias))
rlm@10 231 {
rlm@10 232 IPersistentMap newMap = map.without(alias);
rlm@10 233 aliases.compareAndSet(map, newMap);
rlm@10 234 map = getAliases();
rlm@10 235 }
rlm@10 236 }
rlm@10 237
rlm@10 238 private Object readResolve() throws ObjectStreamException {
rlm@10 239 // ensures that serialized namespaces are "deserialized" to the
rlm@10 240 // namespace in the present runtime
rlm@10 241 return findOrCreate(name);
rlm@10 242 }
rlm@10 243 }