diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/clojure/boot.clj | 16 | ||||
-rw-r--r-- | src/jvm/clojure/lang/Compiler.java | 31 | ||||
-rw-r--r-- | src/jvm/clojure/lang/Namespace.java | 41 |
3 files changed, 78 insertions, 10 deletions
diff --git a/src/clojure/boot.clj b/src/clojure/boot.clj index 89cda99d..b585c5ca 100644 --- a/src/clojure/boot.clj +++ b/src/clojure/boot.clj @@ -1934,6 +1934,22 @@ not-every? (comp not every?)) (= ns (. v ns)))) (ns-map ns))) +(defn alias + "Add an alias in the current namespace to another + namespace. Arguments are two symbols: the alias to be used, and + the symbolic name of the target namespace." + [alias namespace-sym] + (.addAlias *ns* alias (find-ns namespace-sym))) + +(defn ns-aliases + "Returns a map of the aliases for the namespace." + [#^clojure.lang.Namespace ns] (.getAliases ns)) + +(defn ns-unalias + "Removes the alias for the symbol from the namespace." + [#^clojure.lang.Namespace ns sym] + (. ns (removeAlias sym))) + (defn take-nth "Returns a lazy seq of every nth item in coll." [n coll] diff --git a/src/jvm/clojure/lang/Compiler.java b/src/jvm/clojure/lang/Compiler.java index 700116c3..c3cba099 100644 --- a/src/jvm/clojure/lang/Compiler.java +++ b/src/jvm/clojure/lang/Compiler.java @@ -3748,9 +3748,9 @@ public static Object macroexpand1(Object x) throws Exception{ } else if(sym.ns != null) { - Symbol target = Symbol.intern(sym.ns); - if(Namespace.find(target) == null) + if(namespaceFor(sym) == null) { + Symbol target = Symbol.intern(sym.ns); Class c = HostExpr.maybeClass(target, false); if(c != null) { @@ -3884,9 +3884,9 @@ private static Expr analyzeSymbol(Symbol sym) throws Exception{ } else { - Symbol nsSym = Symbol.create(sym.ns); - if(Namespace.find(nsSym) == null) + if(namespaceFor(sym) == null) { + Symbol nsSym = Symbol.create(sym.ns); Class c = HostExpr.maybeClass(nsSym, false); if(c != null) { @@ -3916,13 +3916,27 @@ static Object resolve(Symbol sym) throws Exception{ return resolveIn(currentNS(), sym); } +static private Namespace namespaceFor(Symbol sym) { + //note, presumes non-nil sym.ns + // first check against currentNS' aliases... + Symbol nsSym = Symbol.create(sym.ns); + Namespace ns = currentNS().lookupAlias(nsSym); + if (ns == null) + { + // ...otherwise check the Namespaces map. + ns = Namespace.find(nsSym); + } + return ns; +} + static public Object resolveIn(Namespace n, Symbol sym) throws Exception{ //note - ns-qualified vars must already exist if(sym.ns != null) { - Namespace ns = Namespace.find(Symbol.create(sym.ns)); + Namespace ns = namespaceFor(sym); if(ns == null) throw new Exception("No such namespace: " + sym.ns); + Var v = ns.findInternedVar(Symbol.create(sym.name)); if(v == null) throw new Exception("No such var: " + sym); @@ -3943,11 +3957,12 @@ static public Object resolveIn(Namespace n, Symbol sym) throws Exception{ } } + static public Object maybeResolveIn(Namespace n, Symbol sym) throws Exception{ //note - ns-qualified vars must already exist if(sym.ns != null) { - Namespace ns = Namespace.find(Symbol.create(sym.ns)); + Namespace ns = namespaceFor(sym); if(ns == null) return null; Var v = ns.findInternedVar(Symbol.create(sym.name)); @@ -3966,14 +3981,14 @@ static public Object maybeResolveIn(Namespace n, Symbol sym) throws Exception{ } } + static Var lookupVar(Symbol sym, boolean internNew) throws Exception{ Var var = null; //note - ns-qualified vars in other namespaces must already exist if(sym.ns != null) { - Symbol nsSym = Symbol.create(sym.ns); - Namespace ns = Namespace.find(nsSym); + Namespace ns = namespaceFor(sym); if(ns == null) return null; //throw new Exception("No such namespace: " + sym.ns); diff --git a/src/jvm/clojure/lang/Namespace.java b/src/jvm/clojure/lang/Namespace.java index ec16c3be..bdbdb85b 100644 --- a/src/jvm/clojure/lang/Namespace.java +++ b/src/jvm/clojure/lang/Namespace.java @@ -15,19 +15,21 @@ package clojure.lang; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicReference; -public class Namespace { +public class Namespace{ final public Symbol name; final AtomicReference<IPersistentMap> mappings = new AtomicReference<IPersistentMap>(); +final AtomicReference<IPersistentMap> aliases = new AtomicReference<IPersistentMap>(); final static ConcurrentHashMap<Symbol, Namespace> namespaces = new ConcurrentHashMap<Symbol, Namespace>(); -public String toString() { +public String toString(){ return "#<Namespace: " + name + ">"; } Namespace(Symbol name){ this.name = name; mappings.set(RT.DEFAULT_IMPORTS); + aliases.set(RT.map()); } public static ISeq all(){ @@ -137,4 +139,39 @@ public Var findInternedVar(Symbol symbol){ return null; } + +public IPersistentMap getAliases(){ + return aliases.get(); +} + +public Namespace lookupAlias(Symbol alias){ + IPersistentMap map = getAliases(); + return (Namespace) map.valAt(alias); +} + +public void addAlias(Symbol alias, Namespace ns){ + if (alias == null || ns == null) + throw new NullPointerException("Expecting Symbol + Namespace"); + IPersistentMap map = getAliases(); + while(!map.containsKey(alias)) + { + IPersistentMap newMap = map.assoc(alias, ns); + aliases.compareAndSet(map, newMap); + map = getAliases(); + } + // you can rebind an alias, but only to the initially-aliased namespace. + if(!map.valAt(alias).equals(ns)) + throw new IllegalStateException("Alias " + alias + " already exists in namespace " + + name + ", aliasing " + map.valAt(alias)); +} + +public void removeAlias(Symbol alias) throws Exception{ + IPersistentMap map = getAliases(); + while(map.containsKey(alias)) + { + IPersistentMap newMap = map.without(alias); + aliases.compareAndSet(map, newMap); + map = getAliases(); + } } +}
\ No newline at end of file |