Last active
May 26, 2022 13:14
-
-
Save fogus/3ad5a94fd7eb505f03585397b87b7116 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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