diff options
author | Rich Hickey <richhickey@gmail.com> | 2008-03-04 02:43:23 +0000 |
---|---|---|
committer | Rich Hickey <richhickey@gmail.com> | 2008-03-04 02:43:23 +0000 |
commit | 1a399df8f3f3bcb9d3a92a584fa9714832ab550f (patch) | |
tree | 7b80af17ec585c87937899f7b4a90f5d9ca37544 | |
parent | 50eed41cee8a274ac37a5052ae1f3cd232750176 (diff) |
sets - read/print/compile/metadata, hash-set, sorted-set, disj
-rw-r--r-- | src/boot.clj | 29 | ||||
-rw-r--r-- | src/jvm/clojure/lang/Compiler.java | 55 | ||||
-rw-r--r-- | src/jvm/clojure/lang/LispReader.java | 14 | ||||
-rw-r--r-- | src/jvm/clojure/lang/PersistentHashSet.java | 7 | ||||
-rw-r--r-- | src/jvm/clojure/lang/PersistentTreeSet.java | 72 | ||||
-rw-r--r-- | src/jvm/clojure/lang/RT.java | 17 |
6 files changed, 191 insertions, 3 deletions
diff --git a/src/boot.clj b/src/boot.clj index ee337356..fe444297 100644 --- a/src/boot.clj +++ b/src/boot.clj @@ -164,6 +164,13 @@ hash-map (. clojure.lang.PersistentHashMap (create keyvals)))) (defn + #^{:doc "Returns a new hash set with supplied keys."} +hash-set + ([] {}) + ([& keys] + (. clojure.lang.PersistentHashSet (create keys)))) + +(defn #^{:doc "keyval => key val Returns a new sorted map with supplied mappings."} sorted-map @@ -171,6 +178,13 @@ sorted-map (. clojure.lang.PersistentTreeMap (create keyvals)))) (defn + #^{:doc "Returns a new sorted set with supplied keys."} +sorted-set + ([] {}) + ([& keys] + (. clojure.lang.PersistentTreeSet (create keys)))) + +(defn #^{:doc "keyval => key val Returns a new sorted map with supplied mappings, using the supplied comparator."} @@ -223,8 +237,6 @@ true? [x] (identical? x true)) not [x] (if x false true)) - - (defn #^{:tag Boolean :doc "Equality. Returns true if obj1 equals obj2, false if @@ -675,6 +687,19 @@ dissoc ret)))) (defn + #^{:doc "disj[oin]. Returns a new set of the same + (hashed/sorted) type, that does not contain key(s)."} +disj + ([set] set) + ([#^clojure.lang.IPersistentSet set key] + (. set (disjoin key))) + ([set key & ks] + (let [ret (disj set key)] + (if ks + (recur ret (first ks) (rest ks)) + ret)))) + +(defn #^{:doc "Returns the map entry for key, or nil if key not present."} find [map key] (. clojure.lang.RT (find map key))) diff --git a/src/jvm/clojure/lang/Compiler.java b/src/jvm/clojure/lang/Compiler.java index 03114f65..c7ebc814 100644 --- a/src/jvm/clojure/lang/Compiler.java +++ b/src/jvm/clojure/lang/Compiler.java @@ -2059,6 +2059,7 @@ static String munge(String name){ static class EmptyExpr implements Expr{ final Object coll; final static Type HASHMAP_TYPE = Type.getType(PersistentHashMap.class); + final static Type HASHSET_TYPE = Type.getType(PersistentHashSet.class); final static Type VECTOR_TYPE = Type.getType(PersistentVector.class); final static Type LIST_TYPE = Type.getType(PersistentList.class); @@ -2080,6 +2081,8 @@ static class EmptyExpr implements Expr{ gen.getStatic(VECTOR_TYPE, "EMPTY", VECTOR_TYPE); else if(coll instanceof IPersistentMap) gen.getStatic(HASHMAP_TYPE, "EMPTY", HASHMAP_TYPE); + else if(coll instanceof IPersistentSet) + gen.getStatic(HASHSET_TYPE, "EMPTY", HASHSET_TYPE); else throw new UnsupportedOperationException("Unknown Collection type"); } @@ -2096,6 +2099,8 @@ static class EmptyExpr implements Expr{ return IPersistentVector.class; else if(coll instanceof IPersistentMap) return IPersistentMap.class; + else if(coll instanceof IPersistentSet) + return IPersistentSet.class; else throw new UnsupportedOperationException("Unknown Collection type"); } @@ -2183,6 +2188,54 @@ static class MapExpr implements Expr{ } } +static class SetExpr implements Expr{ + final IPersistentVector keys; + final static Method setMethod = Method.getMethod("clojure.lang.IPersistentSet set(Object[])"); + + + public SetExpr(IPersistentVector keys){ + this.keys = keys; + } + + public Object eval() throws Exception{ + Object[] ret = new Object[keys.count()]; + for(int i = 0; i < keys.count(); i++) + ret[i] = ((Expr) keys.nth(i)).eval(); + return RT.set(ret); + } + + public void emit(C context, FnExpr fn, GeneratorAdapter gen){ + MethodExpr.emitArgsAsArray(keys, fn, gen); + gen.invokeStatic(RT_TYPE, setMethod); + if(context == C.STATEMENT) + gen.pop(); + } + + public boolean hasJavaClass() throws Exception{ + return true; + } + + public Class getJavaClass() throws Exception{ + return IPersistentSet.class; + } + + + static public Expr parse(C context, IPersistentSet form) throws Exception{ + IPersistentVector keys = PersistentVector.EMPTY; + for(ISeq s = RT.seq(form); s != null; s = s.rest()) + { + Object e = s.first(); + keys = (IPersistentVector) keys.cons(analyze(context == C.EVAL ? context : C.EXPRESSION, e)); + } + Expr ret = new SetExpr(keys); + if(form instanceof IObj && ((IObj) form).meta() != null) + return new MetaExpr(ret, (MapExpr) MapExpr + .parse(context == C.EVAL ? context : C.EXPRESSION, ((IObj) form).meta())); + else + return ret; + } +} + static class VectorExpr implements Expr{ final IPersistentVector args; final static Method vectorMethod = Method.getMethod("clojure.lang.IPersistentVector vector(Object[])"); @@ -3131,6 +3184,8 @@ private static Expr analyze(C context, Object form, String name) throws Exceptio return VectorExpr.parse(context, (IPersistentVector) form); else if(form instanceof IPersistentMap) return MapExpr.parse(context, (IPersistentMap) form); + else if(form instanceof IPersistentSet) + return SetExpr.parse(context, (IPersistentSet) form); // else //throw new UnsupportedOperationException(); diff --git a/src/jvm/clojure/lang/LispReader.java b/src/jvm/clojure/lang/LispReader.java index cba2e149..2a4b647b 100644 --- a/src/jvm/clojure/lang/LispReader.java +++ b/src/jvm/clojure/lang/LispReader.java @@ -29,6 +29,7 @@ static Symbol CONCAT = Symbol.create("clojure", "concat"); static Symbol LIST = Symbol.create("clojure", "list");
static Symbol APPLY = Symbol.create("clojure", "apply");
static Symbol HASHMAP = Symbol.create("clojure", "hash-map");
+static Symbol HASHSET = Symbol.create("clojure", "hash-set");
static Symbol VECTOR = Symbol.create("clojure", "vector");
static Symbol WITH_META = Symbol.create("clojure", "with-meta");
static Symbol META = Symbol.create("clojure", "meta");
@@ -78,6 +79,7 @@ static dispatchMacros['\''] = new WrappingReader(Compiler.THE_VAR);
dispatchMacros['"'] = new RegexReader();
dispatchMacros['('] = new FnReader();
+ dispatchMacros['{'] = new SetReader();
}
static boolean isWhitespace(int ch){
@@ -538,6 +540,10 @@ static class SyntaxQuoteReader extends AFn{ {
ret = RT.list(APPLY, VECTOR, RT.cons(CONCAT, sqExpandList(((IPersistentVector) form).seq())));
}
+ else if(form instanceof IPersistentSet)
+ {
+ ret = RT.list(APPLY, HASHSET, RT.cons(CONCAT, sqExpandList(((IPersistentSet) form).seq())));
+ }
else if(form instanceof ISeq)
{
ISeq seq = RT.seq(form);
@@ -688,6 +694,14 @@ static class MapReader extends AFn{ }
+static class SetReader extends AFn{
+ public Object invoke(Object reader, Object leftbracket) throws Exception{
+ PushbackReader r = (PushbackReader) reader;
+ return PersistentHashSet.create(readDelimitedList('}', r, true));
+ }
+
+}
+
static class UnmatchedDelimiterReader extends AFn{
public Object invoke(Object reader, Object rightdelim) throws Exception{
throw new Exception("Unmatched delimiter: " + rightdelim);
diff --git a/src/jvm/clojure/lang/PersistentHashSet.java b/src/jvm/clojure/lang/PersistentHashSet.java index c28ff2cb..60794b97 100644 --- a/src/jvm/clojure/lang/PersistentHashSet.java +++ b/src/jvm/clojure/lang/PersistentHashSet.java @@ -57,9 +57,14 @@ public IPersistentSet disjoin(Object key) throws Exception{ return this; } -public IPersistentCollection cons(Object o){ +public IPersistentSet cons(Object o){ if(contains(o)) return this; return new PersistentHashSet(meta(),impl.assoc(o,o)); } + +public PersistentHashSet withMeta(IPersistentMap meta){ + return new PersistentHashSet(meta, impl); +} + } diff --git a/src/jvm/clojure/lang/PersistentTreeSet.java b/src/jvm/clojure/lang/PersistentTreeSet.java new file mode 100644 index 00000000..ae96940d --- /dev/null +++ b/src/jvm/clojure/lang/PersistentTreeSet.java @@ -0,0 +1,72 @@ +/** + * Copyright (c) Rich Hickey. All rights reserved. + * The use and distribution terms for this software are covered by the + * Common Public License 1.0 (http://opensource.org/licenses/cpl.php) + * which can be found in the file CPL.TXT at the root of this distribution. + * By using this software in any fashion, you are agreeing to be bound by + * the terms of this license. + * You must not remove this notice, or any other, from this software. + **/ + +/* rich Mar 3, 2008 */ + +package clojure.lang; + +import java.util.List; +import java.util.Iterator; + +public class PersistentTreeSet extends APersistentSet implements Reversible{ +static public final PersistentTreeSet EMPTY = new PersistentTreeSet(null, PersistentTreeMap.EMPTY); + +public static PersistentTreeSet create(Object... init){ + PersistentTreeSet ret = EMPTY; + for(int i = 0; i < init.length; i++) + { + ret = (PersistentTreeSet) ret.cons(init[i]); + } + return ret; +} + +public static PersistentTreeSet create(List init){ + PersistentTreeSet ret = EMPTY; + for(Iterator i = init.iterator(); i.hasNext();) + { + Object key = i.next(); + ret = (PersistentTreeSet) ret.cons(key); + } + return ret; +} + +static public PersistentTreeSet create(ISeq items){ + PersistentTreeSet ret = EMPTY; + for(; items != null; items = items.rest()) + { + ret = (PersistentTreeSet) ret.cons(items.first()); + } + return ret; +} + +PersistentTreeSet(IPersistentMap meta, IPersistentMap impl){ + super(meta, impl); +} + +public IPersistentSet disjoin(Object key) throws Exception{ + if(contains(key)) + return new PersistentTreeSet(meta(),impl.without(key)); + return this; +} + +public IPersistentSet cons(Object o){ + if(contains(o)) + return this; + return new PersistentTreeSet(meta(),impl.assoc(o,o)); +} + +public ISeq rseq() throws Exception{ + return APersistentMap.KeySeq.create(((Reversible) impl).rseq()); +} + +public PersistentTreeSet withMeta(IPersistentMap meta){ + return new PersistentTreeSet(meta, impl); +} +} diff --git a/src/jvm/clojure/lang/RT.java b/src/jvm/clojure/lang/RT.java index c61d8b8a..47acdc77 100644 --- a/src/jvm/clojure/lang/RT.java +++ b/src/jvm/clojure/lang/RT.java @@ -471,6 +471,8 @@ static public Object contains(Object coll, Object key){ return F; else if(coll instanceof Associative) return ((Associative) coll).containsKey(key) ? T : F; + else if(coll instanceof IPersistentSet) + return ((IPersistentSet) coll).contains(key) ? T : F; else if(coll instanceof Map) { Map m = (Map) coll; @@ -670,6 +672,10 @@ static public IPersistentMap map(Object... init){ return PersistentHashMap.create(init); } +static public IPersistentSet set(Object... init){ + return PersistentHashSet.create(init); +} + static public IPersistentVector vector(Object... init){ return PersistentVector.create(init); } @@ -922,6 +928,17 @@ static public void print(Object x, Writer w) throws Exception{ } w.write(']'); } + else if(x instanceof IPersistentSet) + { + w.write("#{"); + for(ISeq s = seq(x); s != null; s = s.rest()) + { + print(s.first(), w); + if(s.rest() != null) + w.write(" "); + } + w.write('}'); + } // else if(x instanceof Map.Entry) // { // Map.Entry e = (Map.Entry) x; |