Skip to content

Commit 4c38b36

Browse files
committed
first cut at namespace aliases, via Graham Fawcett
1 parent 5f52000 commit 4c38b36

3 files changed

Lines changed: 78 additions & 10 deletions

File tree

src/clojure/boot.clj

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1934,6 +1934,22 @@ not-every? (comp not every?))
19341934
(= ns (. v ns))))
19351935
(ns-map ns)))
19361936

1937+
(defn alias
1938+
"Add an alias in the current namespace to another
1939+
namespace. Arguments are two symbols: the alias to be used, and
1940+
the symbolic name of the target namespace."
1941+
[alias namespace-sym]
1942+
(.addAlias *ns* alias (find-ns namespace-sym)))
1943+
1944+
(defn ns-aliases
1945+
"Returns a map of the aliases for the namespace."
1946+
[#^clojure.lang.Namespace ns] (.getAliases ns))
1947+
1948+
(defn ns-unalias
1949+
"Removes the alias for the symbol from the namespace."
1950+
[#^clojure.lang.Namespace ns sym]
1951+
(. ns (removeAlias sym)))
1952+
19371953
(defn take-nth
19381954
"Returns a lazy seq of every nth item in coll."
19391955
[n coll]

src/jvm/clojure/lang/Compiler.java

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3748,9 +3748,9 @@ public static Object macroexpand1(Object x) throws Exception{
37483748
}
37493749
else if(sym.ns != null)
37503750
{
3751-
Symbol target = Symbol.intern(sym.ns);
3752-
if(Namespace.find(target) == null)
3751+
if(namespaceFor(sym) == null)
37533752
{
3753+
Symbol target = Symbol.intern(sym.ns);
37543754
Class c = HostExpr.maybeClass(target, false);
37553755
if(c != null)
37563756
{
@@ -3884,9 +3884,9 @@ private static Expr analyzeSymbol(Symbol sym) throws Exception{
38843884
}
38853885
else
38863886
{
3887-
Symbol nsSym = Symbol.create(sym.ns);
3888-
if(Namespace.find(nsSym) == null)
3887+
if(namespaceFor(sym) == null)
38893888
{
3889+
Symbol nsSym = Symbol.create(sym.ns);
38903890
Class c = HostExpr.maybeClass(nsSym, false);
38913891
if(c != null)
38923892
{
@@ -3916,13 +3916,27 @@ static Object resolve(Symbol sym) throws Exception{
39163916
return resolveIn(currentNS(), sym);
39173917
}
39183918

3919+
static private Namespace namespaceFor(Symbol sym) {
3920+
//note, presumes non-nil sym.ns
3921+
// first check against currentNS' aliases...
3922+
Symbol nsSym = Symbol.create(sym.ns);
3923+
Namespace ns = currentNS().lookupAlias(nsSym);
3924+
if (ns == null)
3925+
{
3926+
// ...otherwise check the Namespaces map.
3927+
ns = Namespace.find(nsSym);
3928+
}
3929+
return ns;
3930+
}
3931+
39193932
static public Object resolveIn(Namespace n, Symbol sym) throws Exception{
39203933
//note - ns-qualified vars must already exist
39213934
if(sym.ns != null)
39223935
{
3923-
Namespace ns = Namespace.find(Symbol.create(sym.ns));
3936+
Namespace ns = namespaceFor(sym);
39243937
if(ns == null)
39253938
throw new Exception("No such namespace: " + sym.ns);
3939+
39263940
Var v = ns.findInternedVar(Symbol.create(sym.name));
39273941
if(v == null)
39283942
throw new Exception("No such var: " + sym);
@@ -3943,11 +3957,12 @@ else if(sym.name.indexOf('.') > 0 || sym.name.charAt(0) == '[')
39433957
}
39443958
}
39453959

3960+
39463961
static public Object maybeResolveIn(Namespace n, Symbol sym) throws Exception{
39473962
//note - ns-qualified vars must already exist
39483963
if(sym.ns != null)
39493964
{
3950-
Namespace ns = Namespace.find(Symbol.create(sym.ns));
3965+
Namespace ns = namespaceFor(sym);
39513966
if(ns == null)
39523967
return null;
39533968
Var v = ns.findInternedVar(Symbol.create(sym.name));
@@ -3966,14 +3981,14 @@ else if(sym.name.indexOf('.') > 0 || sym.name.charAt(0) == '[')
39663981
}
39673982
}
39683983

3984+
39693985
static Var lookupVar(Symbol sym, boolean internNew) throws Exception{
39703986
Var var = null;
39713987

39723988
//note - ns-qualified vars in other namespaces must already exist
39733989
if(sym.ns != null)
39743990
{
3975-
Symbol nsSym = Symbol.create(sym.ns);
3976-
Namespace ns = Namespace.find(nsSym);
3991+
Namespace ns = namespaceFor(sym);
39773992
if(ns == null)
39783993
return null;
39793994
//throw new Exception("No such namespace: " + sym.ns);

src/jvm/clojure/lang/Namespace.java

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,21 @@
1515
import java.util.concurrent.ConcurrentHashMap;
1616
import java.util.concurrent.atomic.AtomicReference;
1717

18-
public class Namespace {
18+
public class Namespace{
1919
final public Symbol name;
2020
final AtomicReference<IPersistentMap> mappings = new AtomicReference<IPersistentMap>();
21+
final AtomicReference<IPersistentMap> aliases = new AtomicReference<IPersistentMap>();
2122

2223
final static ConcurrentHashMap<Symbol, Namespace> namespaces = new ConcurrentHashMap<Symbol, Namespace>();
2324

24-
public String toString() {
25+
public String toString(){
2526
return "#<Namespace: " + name + ">";
2627
}
2728

2829
Namespace(Symbol name){
2930
this.name = name;
3031
mappings.set(RT.DEFAULT_IMPORTS);
32+
aliases.set(RT.map());
3133
}
3234

3335
public static ISeq all(){
@@ -137,4 +139,39 @@ public Var findInternedVar(Symbol symbol){
137139
return null;
138140
}
139141

142+
143+
public IPersistentMap getAliases(){
144+
return aliases.get();
145+
}
146+
147+
public Namespace lookupAlias(Symbol alias){
148+
IPersistentMap map = getAliases();
149+
return (Namespace) map.valAt(alias);
150+
}
151+
152+
public void addAlias(Symbol alias, Namespace ns){
153+
if (alias == null || ns == null)
154+
throw new NullPointerException("Expecting Symbol + Namespace");
155+
IPersistentMap map = getAliases();
156+
while(!map.containsKey(alias))
157+
{
158+
IPersistentMap newMap = map.assoc(alias, ns);
159+
aliases.compareAndSet(map, newMap);
160+
map = getAliases();
161+
}
162+
// you can rebind an alias, but only to the initially-aliased namespace.
163+
if(!map.valAt(alias).equals(ns))
164+
throw new IllegalStateException("Alias " + alias + " already exists in namespace "
165+
+ name + ", aliasing " + map.valAt(alias));
166+
}
167+
168+
public void removeAlias(Symbol alias) throws Exception{
169+
IPersistentMap map = getAliases();
170+
while(map.containsKey(alias))
171+
{
172+
IPersistentMap newMap = map.without(alias);
173+
aliases.compareAndSet(map, newMap);
174+
map = getAliases();
175+
}
140176
}
177+
}

0 commit comments

Comments
 (0)