diff options
author | Rich Hickey <richhickey@gmail.com> | 2010-01-19 14:25:26 -0500 |
---|---|---|
committer | Rich Hickey <richhickey@gmail.com> | 2010-01-19 14:25:26 -0500 |
commit | 430dd4fa711d0008137d7a82d4b4cd27b6e2d6d1 (patch) | |
tree | f599f6a0bf560363f73b66bb322b5e00dd139553 | |
parent | 277f0235c1387ddd6247a72857597814a3e10bc3 (diff) |
metadata for fns
-rw-r--r-- | src/clj/clojure/core.clj | 12 | ||||
-rw-r--r-- | src/jvm/clojure/lang/AFn.java | 13 | ||||
-rw-r--r-- | src/jvm/clojure/lang/AFunction.java | 10 | ||||
-rw-r--r-- | src/jvm/clojure/lang/APersistentMap.java | 9 | ||||
-rw-r--r-- | src/jvm/clojure/lang/APersistentSet.java | 3 | ||||
-rw-r--r-- | src/jvm/clojure/lang/APersistentVector.java | 19 | ||||
-rw-r--r-- | src/jvm/clojure/lang/Compiler.java | 126 | ||||
-rw-r--r-- | src/jvm/clojure/lang/PersistentArrayMap.java | 11 | ||||
-rw-r--r-- | src/jvm/clojure/lang/PersistentHashMap.java | 10 | ||||
-rw-r--r-- | src/jvm/clojure/lang/PersistentHashSet.java | 11 | ||||
-rw-r--r-- | src/jvm/clojure/lang/PersistentList.java | 8 | ||||
-rw-r--r-- | src/jvm/clojure/lang/PersistentStructMap.java | 12 | ||||
-rw-r--r-- | src/jvm/clojure/lang/PersistentTreeMap.java | 13 | ||||
-rw-r--r-- | src/jvm/clojure/lang/PersistentTreeSet.java | 9 | ||||
-rw-r--r-- | src/jvm/clojure/lang/PersistentVector.java | 12 | ||||
-rw-r--r-- | src/jvm/clojure/lang/Symbol.java | 11 | ||||
-rw-r--r-- | test/clojure/test_clojure/evaluation.clj | 4 |
17 files changed, 210 insertions, 83 deletions
diff --git a/src/clj/clojure/core.clj b/src/clj/clojure/core.clj index ddc42e95..99c7bd15 100644 --- a/src/clj/clojure/core.clj +++ b/src/clj/clojure/core.clj @@ -36,7 +36,9 @@ (def #^{:macro true} - fn (fn* fn [&form &env & decl] (cons 'fn* decl))) + fn (fn* fn [&form &env & decl] + (.withMeta #^clojure.lang.IObj (cons 'fn* decl) + (.meta #^clojure.lang.IMeta &form)))) (def #^{:arglists '([coll]) @@ -241,10 +243,10 @@ (if (instance? clojure.lang.Symbol iname) false true)) ;; inserts the same fn name to the inline fn if it does not have one (assoc m :inline (cons ifn (cons name (next inline)))) - m))] - (list 'def (with-meta name (conj (if (meta name) (meta name) {}) m)) - (cons `fn (cons name fdecl)))))) - ;(cons `fn fdecl))))) + m)) + m (conj (if (meta name) (meta name) {}) m)] + (list 'def (with-meta name m) + (list '.withMeta (cons `fn (cons name fdecl)) (list '.meta (list 'var name))))))) (. (var defn) (setMacro)) diff --git a/src/jvm/clojure/lang/AFn.java b/src/jvm/clojure/lang/AFn.java index 9a86cd2a..075448e5 100644 --- a/src/jvm/clojure/lang/AFn.java +++ b/src/jvm/clojure/lang/AFn.java @@ -14,18 +14,7 @@ package clojure.lang; import java.io.Serializable; -public abstract class AFn extends Obj implements IFn, Serializable{ - -public AFn(IPersistentMap meta){ - super(meta); -} - -public AFn(){ -} - -public Obj withMeta(IPersistentMap meta){ - throw new UnsupportedOperationException(); -} +public abstract class AFn implements IFn, Serializable{ public Object call() throws Exception{ return invoke(); diff --git a/src/jvm/clojure/lang/AFunction.java b/src/jvm/clojure/lang/AFunction.java index d89e88e6..260bbb3e 100644 --- a/src/jvm/clojure/lang/AFunction.java +++ b/src/jvm/clojure/lang/AFunction.java @@ -14,19 +14,11 @@ package clojure.lang; import java.util.Comparator; -public abstract class AFunction extends AFn implements Comparator, Fn{ +public abstract class AFunction extends AFn implements IObj, Comparator, Fn{ //note - this is not even volatile by design public MethodImplCache __methodImplCache; -public AFunction(IPersistentMap meta){ - super(meta); -} - -public AFunction(){ - super(); -} - public int compare(Object o1, Object o2){ try { diff --git a/src/jvm/clojure/lang/APersistentMap.java b/src/jvm/clojure/lang/APersistentMap.java index 743f4480..e693a802 100644 --- a/src/jvm/clojure/lang/APersistentMap.java +++ b/src/jvm/clojure/lang/APersistentMap.java @@ -15,15 +15,6 @@ import java.util.*; public abstract class APersistentMap extends AFn implements IPersistentMap, Map, Iterable{
int _hash = -1;
-
-protected APersistentMap(IPersistentMap meta){
- super(meta);
-}
-
-
-protected APersistentMap(){
-}
-
public String toString(){
return RT.printString(this);
}
diff --git a/src/jvm/clojure/lang/APersistentSet.java b/src/jvm/clojure/lang/APersistentSet.java index d6e815e9..988ff5dd 100644 --- a/src/jvm/clojure/lang/APersistentSet.java +++ b/src/jvm/clojure/lang/APersistentSet.java @@ -20,8 +20,7 @@ public abstract class APersistentSet extends AFn implements IPersistentSet, Coll int _hash = -1; final IPersistentMap impl; -protected APersistentSet(IPersistentMap meta, IPersistentMap impl){ - super(meta); +protected APersistentSet(IPersistentMap impl){ this.impl = impl; } diff --git a/src/jvm/clojure/lang/APersistentVector.java b/src/jvm/clojure/lang/APersistentVector.java index a11217e3..4fcde2d1 100644 --- a/src/jvm/clojure/lang/APersistentVector.java +++ b/src/jvm/clojure/lang/APersistentVector.java @@ -13,20 +13,12 @@ package clojure.lang; import java.util.*; -import java.util.concurrent.atomic.AtomicInteger; public abstract class APersistentVector extends AFn implements IPersistentVector, Iterable, List, RandomAccess, Comparable, Streamable{ int _hash = -1; -public APersistentVector(IPersistentMap meta){ - super(meta); -} - -protected APersistentVector(){ -} - public String toString(){ return RT.printString(this); } @@ -516,14 +508,17 @@ static class RSeq extends ASeq implements IndexedSeq, Counted{ } } -static class SubVector extends APersistentVector{ +static class SubVector extends APersistentVector implements IObj{ final IPersistentVector v; final int start; final int end; + final IPersistentMap _meta; + public SubVector(IPersistentMap meta, IPersistentVector v, int start, int end){ - super(meta); + this._meta = meta; + if(v instanceof APersistentVector.SubVector) { APersistentVector.SubVector sv = (APersistentVector.SubVector) v; @@ -575,5 +570,9 @@ static class SubVector extends APersistentVector{ return this; return new SubVector(meta, v, start, end); } + + public IPersistentMap meta(){ + return _meta; + } } } diff --git a/src/jvm/clojure/lang/Compiler.java b/src/jvm/clojure/lang/Compiler.java index 9f58b794..18882651 100644 --- a/src/jvm/clojure/lang/Compiler.java +++ b/src/jvm/clojure/lang/Compiler.java @@ -181,6 +181,9 @@ static final public Var LOOP_LABEL = Var.create(); //vector<object> static final public Var CONSTANTS = Var.create(); +//IdentityHashMap +static final public Var CONSTANT_IDS = Var.create(); + //vector<keyword> static final public Var KEYWORD_CALLSITES = Var.create(); @@ -359,12 +362,6 @@ static class DefExpr implements Expr{ public void emit(C context, ObjExpr objx, GeneratorAdapter gen){ objx.emitVar(gen, var); - if(initProvided) - { - gen.dup(); - init.emit(C.EXPRESSION, objx, gen); - gen.invokeVirtual(VAR_TYPE, bindRootMethod); - } if(meta != null) { gen.dup(); @@ -372,6 +369,12 @@ static class DefExpr implements Expr{ gen.checkCast(IPERSISTENTMAP_TYPE); gen.invokeVirtual(VAR_TYPE, setMetaMethod); } + if(initProvided) + { + gen.dup(); + init.emit(C.EXPRESSION, objx, gen); + gen.invokeVirtual(VAR_TYPE, bindRootMethod); + } if(context == C.STATEMENT) gen.pop(); @@ -3070,6 +3073,14 @@ static public class FnExpr extends ObjExpr{ super(tag); } + public boolean hasJavaClass() throws Exception{ + return true; + } + + public Class getJavaClass() throws Exception{ + return AFunction.class; + } + protected void emitMethods(ClassVisitor cv){ //override of invoke/doInvoke for each method for(ISeq s = RT.seq(methods); s != null; s = s.next()) @@ -3093,6 +3104,7 @@ static public class FnExpr extends ObjExpr{ } static Expr parse(C context, ISeq form, String name) throws Exception{ + ISeq origForm = form; FnExpr fn = new FnExpr(tagOf(form)); ObjMethod enclosingMethod = (ObjMethod) METHOD.deref(); if(((IMeta) form.first()).meta() != null) @@ -3117,6 +3129,7 @@ static public class FnExpr extends ObjExpr{ { Var.pushThreadBindings( RT.map(CONSTANTS, PersistentVector.EMPTY, + CONSTANT_IDS, new IdentityHashMap(), KEYWORDS, PersistentHashMap.EMPTY, VARS, PersistentHashMap.EMPTY, KEYWORD_CALLSITES, PersistentVector.EMPTY, @@ -3188,7 +3201,11 @@ static public class FnExpr extends ObjExpr{ fn.compile(fn.isVariadic() ? "clojure/lang/RestFn" : "clojure/lang/AFunction",null,fn.onceOnly); fn.getCompiledClass(); - return fn; + if(origForm instanceof IObj && ((IObj) origForm).meta() != null) + return new MetaExpr(fn, (MapExpr) MapExpr + .parse(context == C.EVAL ? context : C.EXPRESSION, ((IObj) origForm).meta())); + else + return fn; } public final ObjMethod variadicMethod(){ @@ -3315,9 +3332,7 @@ static public class ObjExpr implements Expr{ Type[] ctorTypes(){ - if(closes.count() == 0) - return ARG_TYPES[0]; - PersistentVector tv = PersistentVector.EMPTY; + IPersistentVector tv = isDeftype()?PersistentVector.EMPTY:RT.vector(IPERSISTENTMAP_TYPE); for(ISeq s = RT.keys(closes); s != null; s = s.next()) { LocalBinding lb = (LocalBinding) s.first(); @@ -3451,6 +3466,10 @@ static public class ObjExpr implements Expr{ clinitgen.returnValue(); clinitgen.endMethod(); + if(!isDeftype()) + { + cv.visitField(ACC_FINAL, "__meta", IPERSISTENTMAP_TYPE.getDescriptor(), null, null); + } //instance fields for closed-overs for(ISeq s = RT.keys(closes); s != null; s = s.next()) { @@ -3510,7 +3529,14 @@ static public class ObjExpr implements Expr{ // } // else // ctorgen.invokeConstructor(aFnType, voidctor); - int a = 1; + if(!isDeftype()) + { + ctorgen.loadThis(); + ctorgen.visitVarInsn(IPERSISTENTMAP_TYPE.getOpcode(Opcodes.ILOAD), 1); + ctorgen.putField(objtype, "__meta", IPERSISTENTMAP_TYPE); + } + + int a = isDeftype()?1:2; for(ISeq s = RT.keys(closes); s != null; s = s.next(), ++a) { LocalBinding lb = (LocalBinding) s.first(); @@ -3563,6 +3589,76 @@ static public class ObjExpr implements Expr{ ctorgen.endMethod(); } + if(!isDeftype()) + { + //ctor that takes closed-overs but not meta + Type[] ctorTypes = ctorTypes(); + Type[] noMetaCtorTypes = new Type[ctorTypes.length-1]; + for(int i=1;i<ctorTypes.length;i++) + noMetaCtorTypes[i-1] = ctorTypes[i]; + Method alt = new Method("<init>", Type.VOID_TYPE, noMetaCtorTypes); + ctorgen = new GeneratorAdapter(ACC_PUBLIC, + alt, + null, + null, + cv); + ctorgen.visitCode(); + ctorgen.loadThis(); + ctorgen.visitInsn(Opcodes.ACONST_NULL); //null meta + ctorgen.loadArgs(); + ctorgen.invokeConstructor(objtype, new Method("<init>", Type.VOID_TYPE, ctorTypes)); + + ctorgen.returnValue(); + ctorgen.endMethod(); + + //meta() + Method meth = Method.getMethod("clojure.lang.IPersistentMap meta()"); + + GeneratorAdapter gen = new GeneratorAdapter(ACC_PUBLIC, + meth, + null, + null, + cv); + gen.visitCode(); + gen.loadThis(); + gen.getField(objtype,"__meta",IPERSISTENTMAP_TYPE); + + gen.returnValue(); + gen.endMethod(); + + //withMeta() + meth = Method.getMethod("clojure.lang.IObj withMeta(clojure.lang.IPersistentMap)"); + + gen = new GeneratorAdapter(ACC_PUBLIC, + meth, + null, + null, + cv); + gen.visitCode(); + gen.newInstance(objtype); + gen.dup(); + gen.loadArg(0); + + for(ISeq s = RT.keys(closes); s != null; s = s.next(), ++a) + { + LocalBinding lb = (LocalBinding) s.first(); + gen.loadThis(); + Class primc = lb.getPrimitiveType(); + if(primc != null) + { + gen.getField(objtype, lb.name, Type.getType(primc)); + } + else + { + gen.getField(objtype, lb.name, OBJECT_TYPE); + } + } + + gen.invokeConstructor(objtype, new Method("<init>", Type.VOID_TYPE, ctorTypes)); + gen.returnValue(); + gen.endMethod(); + } + emitMethods(cv); if(keywordCallsites.count() > 0) @@ -3888,6 +3984,7 @@ static public class ObjExpr implements Expr{ { gen.newInstance(objtype); gen.dup(); + gen.visitInsn(Opcodes.ACONST_NULL); for(ISeq s = RT.seq(closesExprs); s != null; s = s.next()) { LocalBindingExpr lbe = (LocalBindingExpr) s.first(); @@ -5280,7 +5377,12 @@ private static int registerConstant(Object o){ if(!CONSTANTS.isBound()) return -1; PersistentVector v = (PersistentVector) CONSTANTS.deref(); + IdentityHashMap<Object,Integer> ids = (IdentityHashMap<Object,Integer>) CONSTANT_IDS.deref(); + Integer i = ids.get(o); + if(i != null) + return i; CONSTANTS.set(RT.conj(v, o)); + ids.put(o, v.count()); return v.count(); } @@ -5757,6 +5859,7 @@ public static Object compile(Reader rdr, String sourcePath, String sourceName) t LINE_BEFORE, pushbackReader.getLineNumber(), LINE_AFTER, pushbackReader.getLineNumber(), CONSTANTS, PersistentVector.EMPTY, + CONSTANT_IDS, new IdentityHashMap(), KEYWORDS, PersistentHashMap.EMPTY, VARS, PersistentHashMap.EMPTY ,LOADER, RT.makeClassLoader() @@ -5970,6 +6073,7 @@ static public class NewInstanceExpr extends ObjExpr{ { Var.pushThreadBindings( RT.map(CONSTANTS, PersistentVector.EMPTY, + CONSTANT_IDS, new IdentityHashMap(), KEYWORDS, PersistentHashMap.EMPTY, VARS, PersistentHashMap.EMPTY, KEYWORD_CALLSITES, PersistentVector.EMPTY, diff --git a/src/jvm/clojure/lang/PersistentArrayMap.java b/src/jvm/clojure/lang/PersistentArrayMap.java index 75ebe964..8f63e5f8 100644 --- a/src/jvm/clojure/lang/PersistentArrayMap.java +++ b/src/jvm/clojure/lang/PersistentArrayMap.java @@ -25,12 +25,13 @@ import java.util.Map; * null keys and values are ok, but you won't be able to distinguish a null value via valAt - use contains/entryAt */ -public class PersistentArrayMap extends APersistentMap implements IEditableCollection { +public class PersistentArrayMap extends APersistentMap implements IObj, IEditableCollection { final Object[] array; static final int HASHTABLE_THRESHOLD = 16; public static final PersistentArrayMap EMPTY = new PersistentArrayMap(); +private final IPersistentMap _meta; static public IPersistentMap create(Map other){ ITransientMap ret = EMPTY.asTransient(); @@ -44,6 +45,7 @@ static public IPersistentMap create(Map other){ protected PersistentArrayMap(){ this.array = new Object[]{}; + this._meta = null; } public PersistentArrayMap withMeta(IPersistentMap meta){ @@ -65,11 +67,12 @@ IPersistentMap createHT(Object[] init){ */ public PersistentArrayMap(Object[] init){ this.array = init; + this._meta = null; } public PersistentArrayMap(IPersistentMap meta, Object[] init){ - super(meta); + this._meta = meta; this.array = init; } @@ -198,6 +201,10 @@ public ISeq seq(){ return null; } +public IPersistentMap meta(){ + return _meta; +} + static class Seq extends ASeq implements Counted{ final Object[] array; final int i; diff --git a/src/jvm/clojure/lang/PersistentHashMap.java b/src/jvm/clojure/lang/PersistentHashMap.java index 1f223e61..4fae3f30 100644 --- a/src/jvm/clojure/lang/PersistentHashMap.java +++ b/src/jvm/clojure/lang/PersistentHashMap.java @@ -25,12 +25,13 @@ import java.util.concurrent.atomic.AtomicReference; Any errors are my own */ -public class PersistentHashMap extends APersistentMap implements IEditableCollection { +public class PersistentHashMap extends APersistentMap implements IEditableCollection, IObj { final int count; final INode root; final boolean hasNull; final Object nullValue; +final IPersistentMap _meta; final public static PersistentHashMap EMPTY = new PersistentHashMap(0, null, false, null); final private static Object NOT_FOUND = new Object(); @@ -93,10 +94,11 @@ PersistentHashMap(int count, INode root, boolean hasNull, Object nullValue){ this.root = root; this.hasNull = hasNull; this.nullValue = nullValue; + this._meta = null; } public PersistentHashMap(IPersistentMap meta, int count, INode root, boolean hasNull, Object nullValue){ - super(meta); + this._meta = meta; this.count = count; this.root = root; this.hasNull = hasNull; @@ -186,6 +188,10 @@ public TransientHashMap asTransient() { return new TransientHashMap(this); } +public IPersistentMap meta(){ + return _meta; +} + static final class TransientHashMap extends ATransientMap { AtomicReference<Thread> edit; INode root; diff --git a/src/jvm/clojure/lang/PersistentHashSet.java b/src/jvm/clojure/lang/PersistentHashSet.java index 73a5a61f..eced8663 100644 --- a/src/jvm/clojure/lang/PersistentHashSet.java +++ b/src/jvm/clojure/lang/PersistentHashSet.java @@ -14,10 +14,12 @@ package clojure.lang; import java.util.List; -public class PersistentHashSet extends APersistentSet implements IEditableCollection { +public class PersistentHashSet extends APersistentSet implements IObj, IEditableCollection { static public final PersistentHashSet EMPTY = new PersistentHashSet(null, PersistentHashMap.EMPTY); +final IPersistentMap _meta; + public static PersistentHashSet create(Object... init){ PersistentHashSet ret = EMPTY; for(int i = 0; i < init.length; i++) @@ -46,7 +48,8 @@ static public PersistentHashSet create(ISeq items){ } PersistentHashSet(IPersistentMap meta, IPersistentMap impl){ - super(meta, impl); + super(impl); + this._meta = meta; } public IPersistentSet disjoin(Object key) throws Exception{ @@ -73,6 +76,10 @@ public ITransientCollection asTransient() { return new TransientHashSet(((PersistentHashMap) impl).asTransient()); } +public IPersistentMap meta(){ + return _meta; +} + static final class TransientHashSet extends ATransientSet { TransientHashSet(ITransientMap impl) { super(impl); diff --git a/src/jvm/clojure/lang/PersistentList.java b/src/jvm/clojure/lang/PersistentList.java index 912d2f8d..477d1cba 100644 --- a/src/jvm/clojure/lang/PersistentList.java +++ b/src/jvm/clojure/lang/PersistentList.java @@ -37,6 +37,14 @@ public static IFn creator = new RestFn(){ list.add(s.first()); return create(list); } + + public IObj withMeta(IPersistentMap meta){ + throw new UnsupportedOperationException(); + } + + public IPersistentMap meta(){ + return null; + } }; final public static EmptyList EMPTY = new EmptyList(null); diff --git a/src/jvm/clojure/lang/PersistentStructMap.java b/src/jvm/clojure/lang/PersistentStructMap.java index 1331ceb1..b015203f 100644 --- a/src/jvm/clojure/lang/PersistentStructMap.java +++ b/src/jvm/clojure/lang/PersistentStructMap.java @@ -16,7 +16,7 @@ import java.util.Iterator; import java.util.Map; import java.io.Serializable; -public class PersistentStructMap extends APersistentMap{ +public class PersistentStructMap extends APersistentMap implements IObj{ public static class Def implements Serializable{ final ISeq keys; @@ -31,6 +31,8 @@ public static class Def implements Serializable{ final Def def; final Object[] vals; final IPersistentMap ext; +final IPersistentMap _meta; + static public Def createSlotMap(ISeq keys){ if(keys == null) @@ -94,7 +96,7 @@ static public IFn getAccessor(final Def def, Object key){ } protected PersistentStructMap(IPersistentMap meta, Def def, Object[] vals, IPersistentMap ext){ - super(meta); + this._meta = meta; this.ext = ext; this.def = def; this.vals = vals; @@ -111,12 +113,16 @@ protected PersistentStructMap makeNew(IPersistentMap meta, Def def, Object[] val return new PersistentStructMap(meta, def, vals, ext); } -public Obj withMeta(IPersistentMap meta){ +public IObj withMeta(IPersistentMap meta){ if(meta == _meta) return this; return makeNew(meta, def, vals, ext); } +public IPersistentMap meta(){ + return _meta; +} + public boolean containsKey(Object key){ return def.keyslots.containsKey(key) || ext.containsKey(key); } diff --git a/src/jvm/clojure/lang/PersistentTreeMap.java b/src/jvm/clojure/lang/PersistentTreeMap.java index d69952b9..4fd987f4 100644 --- a/src/jvm/clojure/lang/PersistentTreeMap.java +++ b/src/jvm/clojure/lang/PersistentTreeMap.java @@ -22,11 +22,12 @@ import java.util.*; * See Okasaki, Kahrs, Larsen et al */ -public class PersistentTreeMap extends APersistentMap implements Reversible, Sorted{ +public class PersistentTreeMap extends APersistentMap implements IObj, Reversible, Sorted{ public final Comparator comp; public final Node tree; public final int _count; +final IPersistentMap _meta; final static public PersistentTreeMap EMPTY = new PersistentTreeMap(); @@ -54,14 +55,14 @@ private PersistentTreeMap(Comparator comp){ public PersistentTreeMap(IPersistentMap meta, Comparator comp){ - super(meta); this.comp = comp; + this._meta = meta; tree = null; _count = 0; } PersistentTreeMap(IPersistentMap meta, Comparator comp, Node tree, int _count){ - super(meta); + this._meta = meta; this.comp = comp; this.tree = tree; this._count = _count; @@ -441,7 +442,7 @@ Node replace(Node t, Object key, Object val){ } PersistentTreeMap(Comparator comp, Node tree, int count, IPersistentMap meta){ - super(meta); + this._meta = meta; this.comp = comp; this.tree = tree; this._count = count; @@ -471,6 +472,10 @@ static Black black(Object key, Object val, Node left, Node right){ return new BlackBranchVal(key, val, left, right); } +public IPersistentMap meta(){ + return _meta; +} + static abstract class Node extends AMapEntry{ final Object key; diff --git a/src/jvm/clojure/lang/PersistentTreeSet.java b/src/jvm/clojure/lang/PersistentTreeSet.java index 22979f11..d55452c7 100644 --- a/src/jvm/clojure/lang/PersistentTreeSet.java +++ b/src/jvm/clojure/lang/PersistentTreeSet.java @@ -14,8 +14,9 @@ package clojure.lang; import java.util.Comparator; -public class PersistentTreeSet extends APersistentSet implements Reversible, Sorted{ +public class PersistentTreeSet extends APersistentSet implements IObj, Reversible, Sorted{ static public final PersistentTreeSet EMPTY = new PersistentTreeSet(null, PersistentTreeMap.EMPTY); +final IPersistentMap _meta; static public PersistentTreeSet create(ISeq items){ @@ -37,7 +38,8 @@ static public PersistentTreeSet create(Comparator comp, ISeq items){ } PersistentTreeSet(IPersistentMap meta, IPersistentMap impl){ - super(meta, impl); + super(impl); + this._meta = meta; } public IPersistentSet disjoin(Object key) throws Exception{ @@ -82,4 +84,7 @@ public ISeq seqFrom(Object key, boolean ascending){ return RT.keys(m.seqFrom(key,ascending)); } +public IPersistentMap meta(){ + return _meta; +} } diff --git a/src/jvm/clojure/lang/PersistentVector.java b/src/jvm/clojure/lang/PersistentVector.java index 392599c9..878d5711 100644 --- a/src/jvm/clojure/lang/PersistentVector.java +++ b/src/jvm/clojure/lang/PersistentVector.java @@ -15,7 +15,7 @@ package clojure.lang; import java.util.List; import java.util.concurrent.atomic.AtomicReference; -public class PersistentVector extends APersistentVector implements IEditableCollection{ +public class PersistentVector extends APersistentVector implements IObj, IEditableCollection{ static class Node{ final AtomicReference<Thread> edit; @@ -39,6 +39,8 @@ final int cnt; final int shift; final Node root; final Object[] tail; +final IPersistentMap _meta; + public final static PersistentVector EMPTY = new PersistentVector(0, 5, EMPTY_NODE, new Object[]{}); @@ -64,7 +66,7 @@ static public PersistentVector create(Object... items){ } PersistentVector(int cnt, int shift, Node root, Object[] tail){ - super(null); + this._meta = null; this.cnt = cnt; this.shift = shift; this.root = root; @@ -73,7 +75,7 @@ PersistentVector(int cnt, int shift, Node root, Object[] tail){ PersistentVector(IPersistentMap meta, int cnt, int shift, Node root, Object[] tail){ - super(meta); + this._meta = meta; this.cnt = cnt; this.shift = shift; this.root = root; @@ -149,6 +151,10 @@ public PersistentVector withMeta(IPersistentMap meta){ return new PersistentVector(meta, cnt, shift, root, tail); } +public IPersistentMap meta(){ + return _meta; +} + public PersistentVector cons(Object val){ int i = cnt; diff --git a/src/jvm/clojure/lang/Symbol.java b/src/jvm/clojure/lang/Symbol.java index 001043d9..dbf3b36e 100644 --- a/src/jvm/clojure/lang/Symbol.java +++ b/src/jvm/clojure/lang/Symbol.java @@ -16,11 +16,12 @@ import java.io.Serializable; import java.io.ObjectStreamException; -public class Symbol extends AFn implements Comparable, Named, Serializable{ +public class Symbol extends AFn implements IObj, Comparable, Named, Serializable{ //these must be interned strings! final String ns; final String name; final int hash; +final IPersistentMap _meta; public String toString(){ if(ns != null) @@ -60,6 +61,7 @@ private Symbol(String ns_interned, String name_interned){ this.name = name_interned; this.ns = ns_interned; this.hash = Util.hashCombine(name.hashCode(), Util.hash(ns)); + this._meta = null; } public boolean equals(Object o){ @@ -78,14 +80,14 @@ public int hashCode(){ return hash; } -public Obj withMeta(IPersistentMap meta){ +public IObj withMeta(IPersistentMap meta){ return new Symbol(meta, ns, name); } private Symbol(IPersistentMap meta, String ns, String name){ - super(meta); this.name = name; this.ns = ns; + this._meta = meta; this.hash = Util.hashCombine(name.hashCode(), Util.hash(ns)); } @@ -118,4 +120,7 @@ public Object invoke(Object obj, Object notFound) throws Exception{ return RT.get(obj, this, notFound); } +public IPersistentMap meta(){ + return _meta; +} } diff --git a/test/clojure/test_clojure/evaluation.clj b/test/clojure/test_clojure/evaluation.clj index 283896c5..3269c58f 100644 --- a/test/clojure/test_clojure/evaluation.clj +++ b/test/clojure/test_clojure/evaluation.clj @@ -184,10 +184,6 @@ (defstruct struct-with-symbols (with-meta 'k {:a "A"})) (deftest Metadata - (test-that - "If a Symbol has metadata, it will not be part of the resulting value" - (is (not (nil? (meta (with-meta (symbol "test") {:doc "doc"}))))) - (is (nil? (meta (eval (with-meta (symbol "test") {:doc "doc"})))))) (test-that "find returns key symbols and their metadata" |