Skip to content

Instantly share code, notes, and snippets.

@fogus
Last active May 26, 2022 13:14
Show Gist options
  • Save fogus/3ad5a94fd7eb505f03585397b87b7116 to your computer and use it in GitHub Desktop.
Save fogus/3ad5a94fd7eb505f03585397b87b7116 to your computer and use it in GitHub Desktop.
/**
* An interned mapping is one where a var's ns matches the current ns and its sym matches the mapping key.
* Once established, interned mappings should never change.
*/
private boolean isInternedMapping(Symbol sym, Object o){
return(o instanceof Var &&
((Var) o).ns == this &&
((Var) o).sym.equals(sym));
}
public Var intern(Symbol sym){
if(sym.ns != null)
{
throw new IllegalArgumentException("Can't intern namespace-qualified symbol");
}
IPersistentMap map = getMappings();
Object o;
Var v = null;
while((o = map.valAt(sym)) == null)
{
if(v == null)
v = new Var(this, sym);
IPersistentMap newMap = map.assoc(sym, v);
mappings.compareAndSet(map, newMap);
map = getMappings();
}
if(isInternedMapping(sym, o))
return (Var) o;
if(v == null)
v = new Var(this, sym);
if(checkReplacement(sym, o, v)){
while (!mappings.compareAndSet(map, map.assoc(sym, v)))
map = getMappings();
return v;
}
return (Var) o;
}
/*
This method checks if a namespace's mapping is applicable and warns on problematic cases.
The semantics of what constitutes a legal replacement mapping is summarized as follows:
| classification | in namespace ns | newval = anything other than ns/name | newval = ns/name |
|----------------+------------------------+--------------------------------------+-------------------------------------|
| native mapping | name -> ns/name | no replace, warn-if newval not-core | no replace, warn-if newval not-core |
| alias mapping | name -> other/whatever | warn + replace | warn + replace |
*/
private boolean checkReplacement(Symbol sym, Object old, Object neu){
if(old instanceof Var) {
Namespace ons = ((Var)old).ns;
Namespace nns = neu instanceof Var ? ((Var) neu).ns : null;
if(isInternedMapping(sym, old)){
if(nns != RT.CLOJURE_NS){
RT.errPrintWriter().println("REJECTED ATTEMPT: attempt to replace interned var, "
+ old + " with " + neu + " in " + name + ", you must ns-unmap first");
return false;
}
else
return false;
}
}
RT.errPrintWriter().println("WARNING: " + sym + " already refers to: " + old + " in namespace: " + name
+ ", being replaced by: " + neu);
return true;
}
Object reference(Symbol sym, Object val){
if(sym.ns != null)
{
throw new IllegalArgumentException("Can't intern namespace-qualified symbol");
}
IPersistentMap map = getMappings();
Object o;
while((o = map.valAt(sym)) == null)
{
IPersistentMap newMap = map.assoc(sym, val);
mappings.compareAndSet(map, newMap);
map = getMappings();
}
if(o == val)
return o;
if(checkReplacement(sym, o, val)){
while (!mappings.compareAndSet(map, map.assoc(sym, val)))
map = getMappings();
return val;
}
return o;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment