summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRich Hickey <richhickey@gmail.com>2008-07-21 18:59:53 +0000
committerRich Hickey <richhickey@gmail.com>2008-07-21 18:59:53 +0000
commit5f52000facfdbc65ee4e52834dfe9626040e54fe (patch)
tree39a47b48dbeca1558f872fed0ebf28b6725c7176
parent6dad2754a87b142ba536c2b7c8ab546a60a70892 (diff)
new clj code hierarchy, old still in place
-rw-r--r--src/clojure/boot.clj2670
-rw-r--r--src/clojure/genclass.clj517
-rw-r--r--src/clojure/inspector/inspector.clj110
-rw-r--r--src/clojure/parallel/parallel.clj248
-rw-r--r--src/clojure/proxy.clj307
-rw-r--r--src/clojure/set/set.clj116
-rw-r--r--src/clojure/xml/xml.clj117
-rw-r--r--src/clojure/zip/zip.clj248
-rw-r--r--src/jvm/clojure/lang/Compiler.java11
-rw-r--r--src/jvm/clojure/lang/RT.java11
-rw-r--r--src/jvm/clojure/lang/Reflector.java11
11 files changed, 4356 insertions, 10 deletions
diff --git a/src/clojure/boot.clj b/src/clojure/boot.clj
new file mode 100644
index 00000000..89cda99d
--- /dev/null
+++ b/src/clojure/boot.clj
@@ -0,0 +1,2670 @@
+; 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.
+
+(in-ns 'clojure)
+
+(def
+ #^{:arglists '([& items])
+ :doc "Creates a new list containing the items."}
+ list (. clojure.lang.PersistentList creator))
+
+(def
+ #^{:arglists '([x seq])
+ :doc "Returns a new seq where x is the first element and seq is
+ the rest."}
+
+ cons (fn* cons [x seq] (. clojure.lang.RT (cons x seq))))
+
+;during bootstrap we don't have destructuring let, loop or fn, will redefine later
+(def
+ #^{:macro true}
+ let (fn* let [& decl] (cons 'let* decl)))
+
+(def
+ #^{:macro true}
+ loop (fn* loop [& decl] (cons 'loop* decl)))
+
+(def
+ #^{:macro true}
+ fn (fn* fn [& decl] (cons 'fn* decl)))
+
+(def
+ #^{:arglists '([coll])
+ :doc "Returns the first item in the collection. Calls seq on its
+ argument. If coll is nil, returns nil."}
+ first (fn first [coll] (. clojure.lang.RT (first coll))))
+
+(def
+ #^{:arglists '([coll])
+ :doc "Returns a seq of the items after the first. Calls seq on its
+ argument. If there are no more items, returns nil."}
+ rest (fn rest [x] (. clojure.lang.RT (rest x))))
+
+(def
+ #^{:arglists '([coll x] [coll x & xs])
+ :doc "conj[oin]. Returns a new collection with the xs
+ 'added'. (conj nil item) returns (item). The 'addition' may
+ happen at different 'places' depending on the concrete type."}
+ conj (fn conj
+ ([coll x] (. clojure.lang.RT (conj coll x)))
+ ([coll x & xs]
+ (if xs
+ (recur (conj coll x) (first xs) (rest xs))
+ (conj coll x)))))
+
+(def
+ #^{:doc "Same as (first (rest x))"
+ :arglists '([x])}
+ second (fn second [x] (first (rest x))))
+
+(def
+ #^{:doc "Same as (first (first x))"
+ :arglists '([x])}
+ ffirst (fn ffirst [x] (first (first x))))
+
+(def
+ #^{:doc "Same as (rest (first x))"
+ :arglists '([x])}
+ rfirst (fn rfirst [x] (rest (first x))))
+
+(def
+ #^{:doc "Same as (first (rest x))"
+ :arglists '([x])}
+ frest (fn frest [x] (first (rest x))))
+
+(def
+ #^{:doc "Same as (rest (rest x))"
+ :arglists '([x])}
+ rrest (fn rrest [x] (rest (rest x))))
+
+(def
+ #^{:arglists '([coll])
+ :doc "Sequence. Returns a new ISeq on the collection. If the
+ collection is empty, returns nil. (seq nil) returns nil. seq also
+ works on Strings, native Java arrays (of reference types) and any
+ objects that implement Iterable."
+ :tag clojure.lang.ISeq}
+ seq (fn seq [coll] (. clojure.lang.RT (seq coll))))
+
+(def
+ #^{:arglists '([#^Class c x])
+ :doc "Evaluates x and tests if it is an instance of the class
+ c. Returns true or false"}
+ instance? (fn instance? [#^Class c x] (. c (isInstance x))))
+
+(def
+ #^{:arglists '([x])
+ :doc "Return true if x implements ISeq"}
+ seq? (fn seq? [x] (instance? clojure.lang.ISeq x)))
+
+(def
+ #^{:arglists '([x])
+ :doc "Return true if x is a String"}
+ string? (fn string? [x] (instance? String x)))
+
+(def
+ #^{:arglists '([x])
+ :doc "Return true if x implements IPersistentMap"}
+ map? (fn map? [x] (instance? clojure.lang.IPersistentMap x)))
+
+(def
+ #^{:arglists '([x])
+ :doc "Return true if x implements IPersistentVector "}
+ vector? (fn vector? [x] (instance? clojure.lang.IPersistentVector x)))
+
+(def
+ #^{:private true}
+ sigs
+ (fn [fdecl]
+ (if (seq? (first fdecl))
+ (loop [ret [] fdecl fdecl]
+ (if fdecl
+ (recur (conj ret (first (first fdecl))) (rest fdecl))
+ (seq ret)))
+ (list (first fdecl)))))
+
+(def
+ #^{:arglists '([map key val] [map key val & kvs])
+ :doc "assoc[iate]. When applied to a map, returns a new map of the
+ same (hashed/sorted) type, that contains the mapping of key(s) to
+ val(s). When applied to a vector, returns a new vector that
+ contains val at index. Note - index must be <= (count vector)."}
+ assoc
+ (fn assoc
+ ([map key val] (. clojure.lang.RT (assoc map key val)))
+ ([map key val & kvs]
+ (let [ret (assoc map key val)]
+ (if kvs
+ (recur ret (first kvs) (second kvs) (rrest kvs))
+ ret)))))
+
+;;;;;;;;;;;;;;;;; metadata ;;;;;;;;;;;;;;;;;;;;;;;;;;;
+(def
+ #^{:arglists '([obj])
+ :doc "Returns the metadata of obj, returns nil if there is no metadata."}
+ meta (fn meta [x]
+ (if (instance? clojure.lang.IObj x)
+ (. #^clojure.lang.IObj x (meta)))))
+
+(def
+ #^{:arglists '([#^clojure.lang.IObj obj m])
+ :doc "Returns an object of the same type and value as obj, with
+ map m as its metadata."}
+ with-meta (fn with-meta [#^clojure.lang.IObj x m]
+ (. x (withMeta m))))
+
+(def
+ #^{:arglists '([coll])
+ :doc "Return the last item in coll, in linear time"}
+ last (fn last [s]
+ (if (rest s)
+ (recur (rest s))
+ (first s))))
+
+(def
+ #^{:arglists '([coll])
+ :doc "Return a sequence of all but the last item in coll, in linear time"}
+ butlast (fn butlast [s]
+ (loop [ret [] s s]
+ (if (rest s)
+ (recur (conj ret (first s)) (rest s))
+ (seq ret)))))
+
+(def
+
+ #^{:doc "Same as (def name (fn [params* ] exprs*)) or (def
+ name (fn ([params* ] exprs*)+)) with any doc-string or attrs added
+ to the var metadata"
+ :arglists '([name doc-string? attr-map? [params*] body]
+ [name doc-string? attr-map? ([params*] body)+ attr-map?])}
+ defn (fn defn [name & fdecl]
+ (let [m (if (string? (first fdecl))
+ {:doc (first fdecl)}
+ {})
+ fdecl (if (string? (first fdecl))
+ (rest fdecl)
+ fdecl)
+ m (if (map? (first fdecl))
+ (conj m (first fdecl))
+ m)
+ fdecl (if (map? (first fdecl))
+ (rest fdecl)
+ fdecl)
+ fdecl (if (vector? (first fdecl))
+ (list fdecl)
+ fdecl)
+ m (if (map? (last fdecl))
+ (conj m (last fdecl))
+ m)
+ fdecl (if (map? (last fdecl))
+ (butlast fdecl)
+ fdecl)
+ m (conj {:arglists (list 'quote (sigs fdecl))} m)]
+ (list 'def (with-meta name (conj (if (meta name) (meta name) {}) m))
+ (cons `fn fdecl)))))
+
+(. (var defn) (setMacro))
+
+(defn cast
+ "Throws a ClassCastException if x is not a c, else returns x."
+ [#^Class c x]
+ (. c (cast x)))
+
+(defn to-array
+ "Returns an array of Objects containing the contents of coll, which
+ can be any Collection. Maps to java.util.Collection.toArray()."
+ [coll] (. clojure.lang.RT (toArray coll)))
+
+(defn vector
+ "Creates a new vector containing the args."
+ ([] [])
+ ([& args]
+ (. clojure.lang.LazilyPersistentVector (create args))))
+
+(defn vec
+ "Creates a new vector containing the contents of coll."
+ ([coll]
+ (. clojure.lang.LazilyPersistentVector (createOwning (to-array coll)))))
+
+(defn hash-map
+ "keyval => key val
+ Returns a new hash map with supplied mappings."
+ ([] {})
+ ([& keyvals]
+ (. clojure.lang.PersistentHashMap (create keyvals))))
+
+(defn hash-set
+ "Returns a new hash set with supplied keys."
+ ([] #{})
+ ([& keys]
+ (. clojure.lang.PersistentHashSet (create keys))))
+
+(defn sorted-map
+ "keyval => key val
+ Returns a new sorted map with supplied mappings."
+ ([& keyvals]
+ (. clojure.lang.PersistentTreeMap (create keyvals))))
+
+(defn sorted-set
+ "Returns a new sorted set with supplied keys."
+ ([& keys]
+ (. clojure.lang.PersistentTreeSet (create keys))))
+
+(defn sorted-map-by
+ "keyval => key val
+ Returns a new sorted map with supplied mappings, using the supplied comparator."
+ ([comparator & keyvals]
+ (. clojure.lang.PersistentTreeMap (create comparator keyvals))))
+
+;;;;;;;;;;;;;;;;;;;;
+(def
+
+ #^{:doc "Like defn, but the resulting function name is declared as a
+ macro and will be used as a macro by the compiler when it is
+ called."
+ :arglists '([name doc-string? attr-map? [params*] body]
+ [name doc-string? attr-map? ([params*] body)+ attr-map?])}
+ defmacro (fn [name & args]
+ (list 'do
+ (cons `defn (cons name args))
+ (list '. (list 'var name) '(setMacro)))))
+
+(. (var defmacro) (setMacro))
+
+(defmacro when
+ "Evaluates test. If logical true, evaluates body in an implicit do."
+ [test & body]
+ (list 'if test (cons 'do body)))
+
+(defmacro when-not
+ "Evaluates test. If logical false, evaluates body in an implicit do."
+ [test & body]
+ (list 'if test nil (cons 'do body)))
+
+(defn nil?
+ "Returns true if x is nil, false otherwise."
+ {:tag Boolean}
+ [x] (identical? x nil))
+
+(defn false?
+ "Returns true if x is the value false, false otherwise."
+ {:tag Boolean}
+ [x] (identical? x false))
+
+(defn true?
+ "Returns true if x is the value true, false otherwise."
+ {:tag Boolean}
+ [x] (identical? x true))
+
+(defn not
+ "Returns true if x is logical false, false otherwise."
+ {:tag Boolean}
+ [x] (if x false true))
+
+(defn str
+ "With no args, returns the empty string. With one arg x, returns
+ x.toString(). (str nil) returns the empty string. With more than
+ one arg, returns the concatenation of the str values of the args."
+ {:tag String}
+ ([] "")
+ ([#^Object x]
+ (if (nil? x) "" (. x (toString))))
+ ([x & ys]
+ (loop [sb (new StringBuilder #^String (str x)) more ys]
+ (if more
+ (recur (. sb (append (str (first more)))) (rest more))
+ (str sb)))))
+
+(defn symbol
+ "Returns a Symbol with the given namespace and name."
+ ([name] (. clojure.lang.Symbol (intern name)))
+ ([ns name] (. clojure.lang.Symbol (intern ns name))))
+
+(defn keyword
+ "Returns a Keyword with the given namespace and name. Do not use :
+ in the keyword strings, it will be added automatically."
+ ([name] (. clojure.lang.Keyword (intern nil name)))
+ ([ns name] (. clojure.lang.Keyword (intern ns name))))
+
+(defn gensym
+ "Returns a new symbol with a unique name. If a prefix string is
+ supplied, the name is prefix# where # is some unique number. If
+ prefix is not supplied, the prefix is 'G'."
+ ([] (gensym "G__"))
+ ([prefix-string] (. clojure.lang.Symbol (intern (str prefix-string (str (. clojure.lang.RT (nextID))))))))
+
+(defmacro cond
+ "Takes a set of test/expr pairs. It evaluates each test one at a
+ time. If a test returns logical true, cond evaluates and returns
+ the value of the corresponding expr and doesn't evaluate any of the
+ other tests or exprs. (cond) returns nil."
+ [& clauses]
+ (when clauses
+ (list 'if (first clauses)
+ (second clauses)
+ (cons 'cond (rest (rest clauses))))))
+
+(defn spread
+ {:private true}
+ [arglist]
+ (cond
+ (nil? arglist) nil
+ (nil? (rest arglist)) (seq (first arglist))
+ :else (cons (first arglist) (spread (rest arglist)))))
+
+(defn apply
+ "Applies fn f to the argument list formed by prepending args to argseq."
+ {:arglists '([f args* argseq])}
+ [#^clojure.lang.IFn f & args]
+ (. f (applyTo (spread args))))
+
+(defn list*
+ "Creates a new list containing the item prepended to more."
+ [item & more]
+ (spread (cons item more)))
+
+(defmacro delay
+ "Takes a body of expressions and yields a function than will invoke
+ the body only the first time it is called, and will cache the result
+ and return it on all calls"
+ [& body]
+ (list 'new 'clojure.lang.Delay (list* `fn [] body)))
+
+(defn fnseq
+ "Returns a seq object whose first is first and whose rest is the
+ value produced by calling restfn with no arguments. restfn will be
+ called at most once per step in the sequence, e.g. calling rest
+ repeatedly on the head of the seq calls restfn once - the value it
+ yields is cached."
+ [first restfn]
+ (new clojure.lang.FnSeq first restfn))
+
+(defmacro lazy-cons
+ "Expands to code which produces a seq object whose first is
+ first-expr and whose rest is rest-expr, neither of which is
+ evaluated until first/rest is called. Each expr will be evaluated at most
+ once per step in the sequence, e.g. calling first/rest repeatedly on the
+ same node of the seq evaluates first/rest-expr once - the values they yield are
+ cached."
+ [first-expr & rest-expr]
+ (list 'new 'clojure.lang.LazySeq (list `fn [] first-expr) (list* `fn [] rest-expr)))
+
+(defn concat
+ "Returns a lazy seq representing the concatenation of the elements in x + xs."
+ ([] nil)
+ ([x & xs]
+ (cond
+ (nil? xs) (seq x)
+ (nil? (seq x)) (recur (first xs) (rest xs))
+ :else (lazy-cons (first x) (apply concat (rest x) xs)))))
+
+;;;;;;;;;;;;;;;;at this point all the support for syntax-quote exists;;;;;;;;;;;;;;;;;;;;;;
+(defn =
+ "Equality. Returns true if obj1 equals obj2, false if not. Same as
+ Java obj1.equals(obj2) except it also works for nil, and compares
+ numbers in a type-independent manner. Clojure's immutable data
+ structures define equals() (and thus =) as a value, not an identity,
+ comparison."
+ {:tag Boolean
+ :inline (fn [x y] `(. clojure.lang.Util equal ~x ~y))}
+ [x y] (. clojure.lang.Util (equal x y)))
+
+(defn not=
+ "Same as (not (= obj1 obj2))"
+ {:tag Boolean}
+ [x y] (not (= x y)))
+
+(defn compare
+ "Comparator. Returns 0 if x equals y, -1 if x is logically 'less
+ than' y, else 1. Same as Java x.compareTo(y) except it also works
+ for nil, and compares numbers in a type-independent manner. x must
+ implement Comparable"
+ {:tag Integer
+ :inline (fn [x y] `(. clojure.lang.Util compare ~x ~y))}
+ [x y] (. clojure.lang.Util (compare x y)))
+
+(defmacro and
+ "Evaluates exprs one at a time, from left to right. If a form
+ returns logical false (nil or false), and returns that value and
+ doesn't evaluate any of the other expressions, otherwise it returns
+ the value of the last expr. (and) returns true."
+ ([] true)
+ ([x] x)
+ ([x & rest]
+ `(let [and# ~x]
+ (if and# (and ~@rest) and#))))
+
+(defmacro or
+ "Evaluates exprs one at a time, from left to right. If a form
+ returns a logical true value, or returns that value and doesn't
+ evaluate any of the other expressions, otherwise it returns the
+ value of the last expression. (or) returns nil."
+ ([] nil)
+ ([x] x)
+ ([x & rest]
+ `(let [or# ~x]
+ (if or# or# (or ~@rest)))))
+
+;;;;;;;;;;;;;;;;;;; sequence fns ;;;;;;;;;;;;;;;;;;;;;;;
+(defn reduce
+ "f should be a function of 2 arguments. If val is not supplied,
+ returns the result of applying f to the first 2 items in coll, then
+ applying f to that result and the 3rd item, etc. If coll contains no
+ items, f must accept no arguments as well, and reduce returns the
+ result of calling f with no arguments. If coll has only 1 item, it
+ is returned and f is not called. If val is supplied, returns the
+ result of applying f to val and the first item in coll, then
+ applying f to that result and the 2nd item, etc. If coll contains no
+ items, returns val and f is not called."
+ ([f coll]
+ (let [s (seq coll)]
+ (if s
+ (if (instance? clojure.lang.IReduce s)
+ (. #^clojure.lang.IReduce s (reduce f))
+ (reduce f (first s) (rest s)))
+ (f))))
+ ([f val coll]
+ (let [s (seq coll)]
+ (if (instance? clojure.lang.IReduce s)
+ (. #^clojure.lang.IReduce s (reduce f val))
+ ((fn [f val s]
+ (if s
+ (recur f (f val (first s)) (rest s))
+ val)) f val s)))))
+
+(defn reverse
+ "Returns a seq of the items in coll in reverse order. Not lazy."
+ [coll]
+ (reduce conj nil coll))
+
+;;math stuff
+(defn +
+ "Returns the sum of nums. (+) returns 0."
+ {:inline (fn [x y] `(. clojure.lang.Numbers (add ~x ~y)))
+ :inline-arities #{2}}
+ ([] 0)
+ ([x] (cast Number x))
+ ([x y] (. clojure.lang.Numbers (add x y)))
+ ([x y & more]
+ (reduce + (+ x y) more)))
+
+(defn *
+ "Returns the product of nums. (*) returns 1."
+ {:inline (fn [x y] `(. clojure.lang.Numbers (multiply ~x ~y)))
+ :inline-arities #{2}}
+ ([] 1)
+ ([x] (cast Number x))
+ ([x y] (. clojure.lang.Numbers (multiply x y)))
+ ([x y & more]
+ (reduce * (* x y) more)))
+
+(defn /
+ "If no denominators are supplied, returns 1/numerator,
+ else returns numerator divided by all of the denominators."
+ {:inline (fn [x y] `(. clojure.lang.Numbers (divide ~x ~y)))
+ :inline-arities #{2}}
+ ([x] (/ 1 x))
+ ([x y] (. clojure.lang.Numbers (divide x y)))
+ ([x y & more]
+ (reduce / (/ x y) more)))
+
+(defn -
+ "If no ys are supplied, returns the negation of x, else subtracts
+ the ys from x and returns the result."
+ {:inline (fn [& args] `(. clojure.lang.Numbers (minus ~@args)))
+ :inline-arities #{1 2}}
+ ([x] (. clojure.lang.Numbers (minus x)))
+ ([x y] (. clojure.lang.Numbers (minus x y)))
+ ([x y & more]
+ (reduce - (- x y) more)))
+
+(defn <
+ "Returns non-nil if nums are in monotonically increasing order,
+ otherwise false."
+ {:inline (fn [x y] `(. clojure.lang.Numbers (lt ~x ~y)))
+ :inline-arities #{2}}
+ ([x] true)
+ ([x y] (. clojure.lang.Numbers (lt x y)))
+ ([x y & more]
+ (if (< x y)
+ (if (rest more)
+ (recur y (first more) (rest more))
+ (< y (first more)))
+ false)))
+
+(defn <=
+ "Returns non-nil if nums are in monotonically non-decreasing order,
+ otherwise false."
+ {:inline (fn [x y] `(. clojure.lang.Numbers (lte ~x ~y)))
+ :inline-arities #{2}}
+ ([x] true)
+ ([x y] (. clojure.lang.Numbers (lte x y)))
+ ([x y & more]
+ (if (<= x y)
+ (if (rest more)
+ (recur y (first more) (rest more))
+ (<= y (first more)))
+ false)))
+
+(defn >
+ "Returns non-nil if nums are in monotonically decreasing order,
+ otherwise false."
+ {:inline (fn [x y] `(. clojure.lang.Numbers (gt ~x ~y)))
+ :inline-arities #{2}}
+ ([x] true)
+ ([x y] (. clojure.lang.Numbers (gt x y)))
+ ([x y & more]
+ (if (> x y)
+ (if (rest more)
+ (recur y (first more) (rest more))
+ (> y (first more)))
+ false)))
+
+(defn >=
+ "Returns non-nil if nums are in monotonically non-increasing order,
+ otherwise false."
+ {:inline (fn [x y] `(. clojure.lang.Numbers (gte ~x ~y)))
+ :inline-arities #{2}}
+ ([x] true)
+ ([x y] (. clojure.lang.Numbers (gte x y)))
+ ([x y & more]
+ (if (>= x y)
+ (if (rest more)
+ (recur y (first more) (rest more))
+ (>= y (first more)))
+ false)))
+
+(defn ==
+ "Returns non-nil if nums all have the same value, otherwise false"
+ {:inline (fn [x y] `(. clojure.lang.Numbers (equiv ~x ~y)))
+ :inline-arities #{2}}
+ ([x] true)
+ ([x y] (. clojure.lang.Numbers (equiv x y)))
+ ([x y & more]
+ (if (== x y)
+ (if (rest more)
+ (recur y (first more) (rest more))
+ (== y (first more)))
+ false)))
+
+(defn max
+ "Returns the greatest of the nums."
+ ([x] x)
+ ([x y] (if (> x y) x y))
+ ([x y & more]
+ (reduce max (max x y) more)))
+
+(defn min
+ "Returns the least of the nums."
+ ([x] x)
+ ([x y] (if (< x y) x y))
+ ([x y & more]
+ (reduce min (min x y) more)))
+
+(defn inc
+ "Returns a number one greater than num."
+ {:inline (fn [x] `(. clojure.lang.Numbers (inc ~x)))}
+ [x] (. clojure.lang.Numbers (inc x)))
+
+(defn dec
+ "Returns a number one less than num."
+ {:inline (fn [x] `(. clojure.lang.Numbers (dec ~x)))}
+ [x] (. clojure.lang.Numbers (dec x)))
+
+(defn unchecked-inc
+ "Returns a number one greater than x, an int or long.
+ Note - uses a primitive operator subject to overflow."
+ {:inline (fn [x] `(. clojure.lang.Numbers (unchecked_inc ~x)))}
+ [x] (. clojure.lang.Numbers (unchecked_inc x)))
+
+(defn unchecked-dec
+ "Returns a number one less than x, an int or long.
+ Note - uses a primitive operator subject to overflow."
+ {:inline (fn [x] `(. clojure.lang.Numbers (unchecked_dec ~x)))}
+ [x] (. clojure.lang.Numbers (unchecked_dec x)))
+
+(defn unchecked-negate
+ "Returns the negation of x, an int or long.
+ Note - uses a primitive operator subject to overflow."
+ {:inline (fn [x] `(. clojure.lang.Numbers (unchecked_negate ~x)))}
+ [x] (. clojure.lang.Numbers (unchecked_negate x)))
+
+(defn unchecked-add
+ "Returns the sum of x and y, both int or long.
+ Note - uses a primitive operator subject to overflow."
+ {:inline (fn [x y] `(. clojure.lang.Numbers (unchecked_add ~x ~y)))}
+ [x y] (. clojure.lang.Numbers (unchecked_add x y)))
+
+(defn unchecked-subtract
+ "Returns the difference of x and y, both int or long.
+ Note - uses a primitive operator subject to overflow."
+ {:inline (fn [x y] `(. clojure.lang.Numbers (unchecked_subtract ~x ~y)))}
+ [x y] (. clojure.lang.Numbers (unchecked_subtract x y)))
+
+(defn unchecked-multiply
+ "Returns the product of x and y, both int or long.
+ Note - uses a primitive operator subject to overflow."
+ {:inline (fn [x y] `(. clojure.lang.Numbers (unchecked_multiply ~x ~y)))}
+ [x y] (. clojure.lang.Numbers (unchecked_multiply x y)))
+
+(defn unchecked-divide
+ "Returns the division of x by y, both int or long.
+ Note - uses a primitive operator subject to truncation."
+ {:inline (fn [x y] `(. clojure.lang.Numbers (unchecked_divide ~x ~y)))}
+ [x y] (. clojure.lang.Numbers (unchecked_divide x y)))
+
+(defn pos?
+ "Returns true if num is greater than zero, else false"
+ {:tag Boolean
+ :inline (fn [x] `(. clojure.lang.Numbers (isPos ~x)))}
+ [x] (. clojure.lang.Numbers (isPos x)))
+
+(defn neg?
+ "Returns true if num is less than zero, else false"
+ {:tag Boolean
+ :inline (fn [x] `(. clojure.lang.Numbers (isNeg ~x)))}
+ [x] (. clojure.lang.Numbers (isNeg x)))
+
+(defn zero?
+ "Returns true if num is zero, else false"
+ {:tag Boolean
+ :inline (fn [x] `(. clojure.lang.Numbers (isZero ~x)))}
+ [x] (. clojure.lang.Numbers (isZero x)))
+
+(defn quot
+ "quot[ient] of dividing numerator by denominator."
+ [num div]
+ (. clojure.lang.Numbers (quotient num div)))
+
+(defn rem
+ "rem[ainder] of dividing numerator by denominator."
+ [num div]
+ (. clojure.lang.Numbers (remainder num div)))
+
+(defn rationalize
+ "returns the rational value of num"
+ [num]
+ (. clojure.lang.Numbers (rationalize num)))
+
+;;Bit ops
+
+(defn bit-not
+ "Bitwise complement"
+ [x] (. clojure.lang.Numbers not x))
+
+
+(defn bit-and
+ "Bitwise and"
+ [x y] (. clojure.lang.Numbers and x y))
+
+(defn bit-or
+ "Bitwise or"
+ [x y] (. clojure.lang.Numbers or x y))
+
+(defn bit-xor
+ "Bitwise exclusive or"
+ [x y] (. clojure.lang.Numbers xor x y))
+
+(defn bit-and-not
+ "Bitwise and with complement"
+ [x y] (. clojure.lang.Numbers andNot x y))
+
+
+(defn bit-clear
+ "Clear bit at index n"
+ [x n] (. clojure.lang.Numbers clearBit x n))
+
+(defn bit-set
+ "Set bit at index n"
+ [x n] (. clojure.lang.Numbers setBit x n))
+
+(defn bit-flip
+ "Flip bit at index n"
+ [x n] (. clojure.lang.Numbers flipBit x n))
+
+(defn bit-test
+ "Test bit at index n"
+ [x n] (. clojure.lang.Numbers testBit x n))
+
+
+(defn bit-shift-left
+ "Bitwise shift left"
+ [x n] (. clojure.lang.Numbers shiftLeft x n))
+
+(defn bit-shift-right
+ "Bitwise shift right"
+ [x n] (. clojure.lang.Numbers shiftRight x n))
+
+;;
+
+(defn complement
+ "Takes a fn f and returns a fn that takes the same arguments as f,
+ has the same effects, if any, and returns the opposite truth value."
+ [f] (fn [& args]
+ (not (apply f args))))
+
+(defn constantly
+ "Returns a function that takes any number of arguments and returns x."
+ [x] (fn [& args] x))
+
+(defn identity
+ "Returns its argument."
+ [x] x)
+
+;;Collection stuff
+
+
+
+(defn count
+ "Returns the number of items in the collection. (count nil) returns
+ 0. Also works on strings, arrays, and Java Collections and Maps"
+ [coll] (. clojure.lang.RT (count coll)))
+
+;;list stuff
+(defn peek
+ "For a list or queue, same as first, for a vector, same as, but much
+ more efficient than, last. If the collection is empty, returns nil."
+ [coll] (. clojure.lang.RT (peek coll)))
+
+(defn pop
+ "For a list or queue, returns a new list/queue without the first
+ item, for a vector, returns a new vector without the last item. If
+ the collection is empty, throws an exception. Note - not the same
+ as rest/butlast."
+ [coll] (. clojure.lang.RT (pop coll)))
+
+(defn nth
+ "Returns the value at the index. get returns nil if index out of
+ bounds, nth throws an exception unless not-found is supplied. nth
+ also works for strings, Java arrays, regex Matchers and Lists, and,
+ in O(n) time, for sequences."
+ ([coll index] (. clojure.lang.RT (nth coll index)))
+ ([coll index not-found] (. clojure.lang.RT (nth coll index not-found))))
+
+;;map stuff
+
+(defn contains?
+ "Returns true if key is present, else false."
+ [map key] (. clojure.lang.RT (contains map key)))
+
+(defn get
+ "Returns the value mapped to key, not-found or nil if key not present."
+ ([map key]
+ (. clojure.lang.RT (get map key)))
+ ([map key not-found]
+ (. clojure.lang.RT (get map key not-found))))
+
+(defn dissoc
+ "dissoc[iate]. Returns a new map of the same (hashed/sorted) type,
+ that does not contain a mapping for key(s)."
+ ([map] map)
+ ([map key]
+ (. clojure.lang.RT (dissoc map key)))
+ ([map key & ks]
+ (let [ret (dissoc map key)]
+ (if ks
+ (recur ret (first ks) (rest ks))
+ ret))))
+
+(defn disj
+ "disj[oin]. Returns a new set of the same (hashed/sorted) type, that
+ does not contain key(s)."
+ ([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 find
+ "Returns the map entry for key, or nil if key not present."
+ [map key] (. clojure.lang.RT (find map key)))
+
+(defn select-keys
+ "Returns a map containing only those entries in map whose key is in keys"
+ [map keyseq]
+ (loop [ret {} keys (seq keyseq)]
+ (if keys
+ (let [entry (. clojure.lang.RT (find map (first keys)))]
+ (recur
+ (if entry
+ (conj ret entry)
+ ret)
+ (rest keys)))
+ ret)))
+
+(defn keys
+ "Returns a sequence of the map's keys."
+ [map] (. clojure.lang.RT (keys map)))
+
+(defn vals
+ "Returns a sequence of the map's values."
+ [map] (. clojure.lang.RT (vals map)))
+
+(defn key
+ "Returns the key of the map entry."
+ [#^java.util.Map$Entry e]
+ (. e (getKey)))
+
+(defn val
+ "Returns the value in the map entry."
+ [#^java.util.Map$Entry e]
+ (. e (getValue)))
+
+(defn rseq
+ "Returns, in constant time, a sequence of the items in rev (which
+ can be a vector or sorted-map), in reverse order."
+ [#^clojure.lang.Reversible rev]
+ (. rev (rseq)))
+
+(defn name
+ "Returns the name String of a symbol or keyword."
+ [#^clojure.lang.Named x]
+ (. x (getName)))
+
+(defn namespace
+ "Returns the namespace String of a symbol or keyword, or nil if not present."
+ [#^clojure.lang.Named x]
+ (. x (getNamespace)))
+
+(defmacro locking
+ "Executes exprs in an implicit do, while holding the monitor of x.
+ Will release the monitor of x in all circumstances."
+ [x & body]
+ `(let [lockee# ~x]
+ (try
+ (monitor-enter lockee#)
+ ~@body
+ (finally
+ (monitor-exit lockee#)))))
+
+(defmacro ..
+ "form => fieldName-symbol or (instanceMethodName-symbol args*)
+
+ Expands into a member access (.) of the first member on the first
+ argument, followed by the next member on the result, etc. For
+ instance:
+
+ (.. System (getProperties) (get \"os.name\"))
+
+ expands to:
+
+ (. (. System (getProperties)) (get \"os.name\"))
+
+ but is easier to write, read, and understand."
+ ([x form] `(. ~x ~form))
+ ([x form & more] `(.. (. ~x ~form) ~@more)))
+
+(defmacro ->
+ "Macro. Threads the expr through the forms. Inserts x as the
+ second item in the first form, making a list of it if it is not a
+ list already. If there are more forms, inserts the first form as the
+ second item in second form, etc."
+ ([x form] (if (seq? form)
+ `(~(first form) ~x ~@(rest form))
+ (list form x)))
+ ([x form & more] `(-> (-> ~x ~form) ~@more)))
+
+;;multimethods
+(defmacro defmulti
+ "Creates a new multimethod with the associated dispatch function. If
+ default-dispatch-val is supplied it becomes the default dispatch
+ value of the multimethod, otherwise the default dispatch value
+ is :default."
+ ([name dispatch-fn] `(defmulti ~name ~dispatch-fn :default))
+ ([name dispatch-fn default-val]
+ `(def ~name (new clojure.lang.MultiFn ~dispatch-fn ~default-val))))
+
+(defmacro defmethod
+ "Creates and installs a new method of multimethod associated with dispatch-value. "
+ [multifn dispatch-val & fn-tail]
+ `(let [pvar# (var ~multifn)]
+ (. pvar# (commuteRoot (fn [#^clojure.lang.MultiFn mf#]
+ (. mf# (assoc ~dispatch-val (fn ~@fn-tail))))))))
+
+(defmacro remove-method
+ "Removes the method of multimethod associated with dispatch-value."
+ [multifn dispatch-val]
+ `(let [pvar# (var ~multifn)]
+ (. pvar# (commuteRoot (fn [#^clojure.lang.MultiFn mf#]
+ (. mf# (dissoc ~dispatch-val)))))))
+
+;;;;;;;;; var stuff
+
+(defmacro binding
+ "binding => var-symbol init-expr
+
+ Creates new bindings for the (already-existing) vars, with the
+ supplied initial values, executes the exprs in an implicit do, then
+ re-establishes the bindings that existed before."
+ [bindings & body]
+ (let [var-ize (fn [var-vals]
+ (loop [ret [] vvs (seq var-vals)]
+ (if vvs
+ (recur (conj (conj ret `(var ~(first vvs))) (second vvs))
+ (rest (rest vvs)))
+ (seq ret))))]
+ `(do
+ (. clojure.lang.Var (pushThreadBindings (hash-map ~@(var-ize bindings))))
+ (try
+ ~@body
+ (finally
+ (. clojure.lang.Var (popThreadBindings)))))))
+
+(defn find-var
+ "Returns the global var named by the namespace-qualified symbol, or
+ nil if no var with that name."
+ [sym] (. clojure.lang.Var (find sym)))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Refs ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+(defn agent
+ "Creates and returns an agent with an initial value of state."
+ [state] (new clojure.lang.Agent state))
+
+(defn ! [& args] (throw (new Exception "! is now send. See also send-off")))
+
+(defn send
+ "Dispatch an action to an agent. Returns the agent immediately.
+ Subsequently, in a thread from a thread pool, the state of the agent
+ will be set to the value of:
+
+ (apply action-fn state-of-agent args)"
+ [#^clojure.lang.Agent a f & args]
+ (. a (dispatch f args false)))
+
+(defn send-off
+ "Dispatch a potentially blocking action to an agent. Returns the
+ agent immediately. Subsequently, in a separate thread, the state of
+ the agent will be set to the value of:
+
+ (apply action-fn state-of-agent args)"
+ [#^clojure.lang.Agent a f & args]
+ (. a (dispatch f args true)))
+
+(defn agent-errors
+ "Returns a sequence of the exceptions thrown during asynchronous
+ actions of the agent."
+ [#^clojure.lang.Agent a] (. a (getErrors)))
+
+(defn clear-agent-errors
+ "Clears any exceptions thrown during asynchronous actions of the
+ agent, allowing subsequent actions to occur."
+ [#^clojure.lang.Agent a] (. a (clearErrors)))
+
+(defn ref
+ "Creates and returns a Ref with an initial value of x."
+ [x] (new clojure.lang.Ref x))
+
+(defn deref
+ "Also reader macro: @ref/@agent Within a transaction, returns the
+ in-transaction-value of ref, else returns the
+ most-recently-committed value of ref. When applied to an agent,
+ returns its current state."
+ [#^clojure.lang.IRef ref] (. ref (get)))
+
+
+(defn commute
+ "Must be called in a transaction. Sets the in-transaction-value of
+ ref to:
+
+ (apply fun in-transaction-value-of-ref args)
+
+ and returns the in-transaction-value of ref.
+
+ At the commit point of the transaction, sets the value of ref to be:
+
+ (apply fun most-recently-committed-value-of-ref args)
+
+ Thus fun should be commutative, or, failing that, you must accept
+ last-one-in-wins behavior. commute allows for more concurrency than
+ ref-set."
+
+ [#^clojure.lang.Ref ref fun & args]
+ (. ref (commute fun args)))
+
+(defn alter
+ "Must be called in a transaction. Sets the in-transaction-value of
+ ref to:
+
+ (apply fun in-transaction-value-of-ref args)
+
+ and returns the in-transaction-value of ref."
+ [#^clojure.lang.Ref ref fun & args]
+ (. ref (alter fun args)))
+
+(defn ref-set
+ "Must be called in a transaction. Sets the value of ref.
+ Returns val."
+ [#^clojure.lang.Ref ref val]
+ (. ref (set val)))
+
+(defn ensure
+ "Must be called in a transaction. Protects the ref from modification
+ by other transactions. Returns the in-transaction-value of
+ ref. Allows for more concurrency than (ref-set ref @ref)"
+ [#^clojure.lang.Ref ref]
+ (. ref (touch))
+ (. ref (get)))
+
+(defmacro sync
+ "transaction-flags => TBD, pass nil for now
+
+ Runs the exprs (in an implicit do) in a transaction that encompasses
+ exprs and any nested calls. Starts a transaction if none is already
+ running on this thread. Any uncaught exception will abort the
+ transaction and flow out of sync. The exprs may be run more than
+ once, but any effects on Refs will be atomic."
+ [flags-ignored-for-now & body]
+ `(. clojure.lang.LockingTransaction
+ (runInTransaction (fn [] ~@body))))
+
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; fn stuff ;;;;;;;;;;;;;;;;
+
+
+(defn comp
+ "Takes a set of functions and returns a fn that is the composition
+ of those fns. The returned fn takes a variable number of args,
+ applies the rightmost of fns to the args, the next
+ fn (right-to-left) to the result, etc."
+ [& fs]
+ (let [fs (reverse fs)]
+ (fn [& args]
+ (loop [ret (apply (first fs) args) fs (rest fs)]
+ (if fs
+ (recur ((first fs) ret) (rest fs))
+ ret)))))
+
+(defn partial
+ "Takes a function f and fewer than the normal arguments to f, and
+ returns a fn that takes a variable number of additional args. When
+ called, the returned function calls f with args + additional args."
+ ([f arg1]
+ (fn [& args] (apply f arg1 args)))
+ ([f arg1 arg2]
+ (fn [& args] (apply f arg1 arg2 args)))
+ ([f arg1 arg2 arg3]
+ (fn [& args] (apply f arg1 arg2 arg3 args)))
+ ([f arg1 arg2 arg3 & more]
+ (fn [& args] (apply f arg1 arg2 arg3 (concat more args)))))
+
+;;;;;;;;;;;;;;;;;;; sequence fns ;;;;;;;;;;;;;;;;;;;;;;;
+
+(defn every?
+ "Returns true if (pred x) is logical true for every x in coll, else
+ false."
+ {:tag Boolean}
+ [pred coll]
+ (if (seq coll)
+ (and (pred (first coll))
+ (recur pred (rest coll)))
+ true))
+
+(def
+ #^{:tag Boolean
+ :doc "Returns false if (pred x) is logical true for every x in
+ coll, else true."
+ :arglists '([pred coll])}
+not-every? (comp not every?))
+
+(defn some
+ "Returns the first logical true value of (pred x) for any x in coll,
+ else nil."
+ [pred coll]
+ (when (seq coll)
+ (or (pred (first coll)) (recur pred (rest coll)))))
+
+(def
+ #^{:tag Boolean
+ :doc "Returns false if (pred x) is logical true for any x in coll,
+ else true."
+ :arglists '([pred coll])}
+ not-any? (comp not some))
+
+(defn map
+ "Returns a lazy seq consisting of the result of applying f to the
+ set of first items of each coll, followed by applying f to the set
+ of second items in each coll, until any one of the colls is
+ exhausted. Any remaining items in other colls are ignored. Function
+ f should accept number-of-colls arguments."
+ ([f coll]
+ (when (seq coll)
+ (lazy-cons (f (first coll)) (map f (rest coll)))))
+ ([f coll & colls]
+ (when (and (seq coll) (every? seq colls))
+ (lazy-cons (apply f (first coll) (map first colls))
+ (apply map f (rest coll) (map rest colls))))))
+
+(defn mapcat
+ "Returns the result of applying concat to the result of applying map
+ to f and colls. Thus function f should return a collection."
+ [f & colls]
+ (apply concat (apply map f colls)))
+
+(defn filter
+ "Returns a lazy seq of the items in coll for which
+ (pred item) returns true."
+ [pred coll]
+ (when (seq coll)
+ (if (pred (first coll))
+ (lazy-cons (first coll) (filter pred (rest coll)))
+ (recur pred (rest coll)))))
+
+(defn take
+ "Returns a lazy seq of the first n items in coll, or all items if
+ there are fewer than n."
+ [n coll]
+ (when (and (pos? n) (seq coll))
+ (lazy-cons (first coll) (take (dec n) (rest coll)))))
+
+(defn take-while
+ "Returns a lazy seq of successive items from coll while
+ (pred item) returns true."
+ [pred coll]
+ (when (and (seq coll) (pred (first coll)))
+ (lazy-cons (first coll) (take-while pred (rest coll)))))
+
+(defn drop
+ "Returns a lazy seq of all but the first n items in coll."
+ [n coll]
+ (if (and (pos? n) (seq coll))
+ (recur (dec n) (rest coll))
+ (seq coll)))
+
+(defn drop-last
+ "Return a lazy seq of all but the last n (default 1) items in coll"
+ ([s] (drop-last 1 s))
+ ([n s] (map (fn [x _] x) (seq s) (drop n s))))
+
+(defn drop-while
+ "Returns a lazy seq of the items in coll starting from the first
+ item for which (pred item) returns nil."
+ [pred coll]
+ (if (and (seq coll) (pred (first coll)))
+ (recur pred (rest coll))
+ (seq coll)))
+
+(defn cycle
+ "Returns a lazy (infinite!) seq of repetitions of the items in
+ coll."
+ [coll]
+ (when (seq coll)
+ (let [rep (fn thisfn [xs]
+ (if xs
+ (lazy-cons (first xs) (thisfn (rest xs)))
+ (recur (seq coll))))]
+ (rep (seq coll)))))
+
+(defn split-at
+ "Returns a vector of [(take n coll) (drop n coll)]"
+ [n coll]
+ [(take n coll) (drop n coll)])
+
+(defn split-with
+ "Returns a vector of [(take-while pred coll) (drop-while pred coll)]"
+ [pred coll]
+ [(take-while pred coll) (drop-while pred coll)])
+
+(defn repeat
+ "Returns a lazy (infinite!) seq of xs."
+ [x] (lazy-cons x (repeat x)))
+
+(defn replicate
+ "Returns a lazy seq of n xs."
+ [n x] (take n (repeat x)))
+
+(defn iterate
+ "Returns a lazy seq of x, (f x), (f (f x)) etc."
+ [f x] (lazy-cons x (iterate f (f x))))
+
+(defn range
+ "Returns a lazy seq of nums from start (inclusive) to end
+ (exclusive), by step, where start defaults to 0 and step to 1."
+ ([end] (if (and (> end 0) (< end (. Integer MAX_VALUE)))
+ (new clojure.lang.Range 0 end)
+ (take end (iterate inc 0))))
+ ([start end] (if (and (< start end) (< end (. Integer MAX_VALUE)))
+ (new clojure.lang.Range start end)
+ (take (- end start) (iterate inc start))))
+ ([start end step]
+ (take-while (partial (if (pos? step) > <) end) (iterate (partial + step) start))))
+
+(defn merge
+ "Returns a map that consists of the rest of the maps conj-ed onto
+ the first. If a key occurs in more than one map, the mapping from
+ the latter (left-to-right) will be the mapping in the result."
+ [& maps] (reduce conj maps))
+
+(defn merge-with
+ "Returns a map that consists of the rest of the maps conj-ed onto
+ the first. If a key occurs in more than one map, the mapping(s)
+ from the latter (left-to-right) will be combined with the mapping in
+ the result by calling (f val-in-result val-in-latter)."
+ [f & maps]
+ (let [merge-entry (fn [m e]
+ (let [k (key e) v (val e)]
+ (if (contains? m k)
+ (assoc m k (f (m k) v))
+ (assoc m k v))))
+ merge2 (fn [m1 m2]
+ (reduce merge-entry m1 (seq m2)))]
+ (reduce merge2 maps)))
+
+
+
+(defn zipmap
+ "Returns a map with the keys mapped to the corresponding vals."
+ [keys vals]
+ (loop [map {}
+ ks (seq keys)
+ vs (seq vals)]
+ (if (and ks vs)
+ (recur (assoc map (first ks) (first vs))
+ (rest ks)
+ (rest vs))
+ map)))
+
+(defn line-seq
+ "Returns the lines of text from rdr as a lazy sequence of strings.
+ rdr must implement java.io.BufferedReader."
+ [#^java.io.BufferedReader rdr]
+ (let [line (. rdr (readLine))]
+ (when line
+ (lazy-cons line (line-seq rdr)))))
+
+(defn comparator
+ "Returns an implementation of java.util.Comparator based upon pred."
+ [pred]
+ (fn [x y]
+ (cond (pred x y) -1 (pred y x) 1 :else 0)))
+
+(defn sort
+ "Returns a sorted sequence of the items in coll. If no comparator is
+ supplied, uses compare. comparator must
+ implement java.util.Comparator."
+ ([#^java.util.Collection coll]
+ (sort compare coll))
+ ([#^java.util.Comparator comp #^java.util.Collection coll]
+ (when (and coll (not (. coll (isEmpty))))
+ (let [a (. coll (toArray))]
+ (. java.util.Arrays (sort a comp))
+ (seq a)))))
+
+(defn sort-by
+ "Returns a sorted sequence of the items in coll, where the sort
+ order is determined by comparing (keyfn item). If no comparator is
+ supplied, uses compare. comparator must
+ implement java.util.Comparator."
+ ([keyfn coll]
+ (sort-by keyfn compare coll))
+ ([keyfn #^java.util.Comparator comp coll]
+ (sort (fn [x y] (. comp (compare (keyfn x) (keyfn y)))) coll)))
+
+;; evaluation
+
+(defn eval
+ "Evaluates the form data structure (not text!) and returns the result."
+ [form] (. clojure.lang.Compiler (eval form)))
+
+;(defn defimports [& imports-maps]
+; (def *imports* (apply merge imports-maps)))
+
+(defmacro doseq
+ "Repeatedly executes body (presumably for side-effects) with
+ binding-form bound to successive items from coll. Does not retain
+ the head of the sequence. Returns nil."
+ [item list & body]
+ `(loop [list# (seq ~list)]
+ (when list#
+ (let [~item (first list#)]
+ ~@body)
+ (recur (rest list#)))))
+
+(defn scan [& args] (throw (new Exception "scan is now called dorun")))
+(defn touch [& args] (throw (new Exception "touch is now called doall")))
+
+(defn dorun
+ "When lazy sequences are produced via functions that have side
+ effects, any effects other than those needed to produce the first
+ element in the seq do not occur until the seq is consumed. dorun can
+ be used to force any effects. Walks through the successive rests of
+ the seq, does not retain the head and returns nil."
+ ([coll]
+ (when (seq coll)
+ (recur (rest coll))))
+ ([n coll]
+ (when (and (seq coll) (pos? n))
+ (recur (dec n) (rest coll)))))
+
+(defn doall
+ "When lazy sequences are produced via functions that have side
+ effects, any effects other than those needed to produce the first
+ element in the seq do not occur until the seq is consumed. doall can
+ be used to force any effects. Walks through the successive rests of
+ the seq, retains the head and returns it, thus causing the entire
+ seq to reside in memory at one time."
+ ([coll]
+ (dorun coll)
+ coll)
+ ([n coll]
+ (dorun n coll)
+ coll))
+
+(defn await
+ "Blocks the current thread (indefinitely!) until all actions
+ dispatched thus far, from this thread or agent, to the agent(s) have
+ occurred."
+ [& agents]
+ (when *agent*
+ (throw (new Exception "Can't await in agent action")))
+ (let [latch (new java.util.concurrent.CountDownLatch (count agents))
+ count-down (fn [agent] (. latch (countDown)) agent)]
+ (doseq agent agents
+ (send agent count-down))
+ (. latch (await))))
+
+(defn await1 [#^clojure.lang.Agent a]
+ (when (pos? (.getQueueCount a))
+ (await a))
+ a)
+
+(defn await-for
+ "Blocks the current thread until all actions dispatched thus
+ far (from this thread or agent) to the agents have occurred, or the
+ timeout (in milliseconds) has elapsed. Returns nil if returning due
+ to timeout, non-nil otherwise."
+ [timeout-ms & agents]
+ (when *agent*
+ (throw (new Exception "Can't await in agent action")))
+ (let [latch (new java.util.concurrent.CountDownLatch (count agents))
+ count-down (fn [agent] (. latch (countDown)) agent)]
+ (doseq agent agents
+ (send agent count-down))
+ (. latch (await timeout-ms (. java.util.concurrent.TimeUnit MILLISECONDS)))))
+
+(defmacro dotimes
+ "Repeatedly executes body (presumably for side-effects) with name
+ bound to integers from 0 through n-1."
+ [i n & body]
+ `(let [n# (int ~n)]
+ (loop [~i (int 0)]
+ (when (< ~i n#)
+ ~@body
+ (recur (unchecked-inc ~i))))))
+
+(defn import
+ "import-list => (package-symbol class-name-symbols*)
+
+ For each name in class-name-symbols, adds a mapping from name to the
+ class named by package.name to the current namespace."
+ [& import-lists]
+ (when import-lists
+ (let [#^clojure.lang.Namespace ns *ns*
+ pkg (ffirst import-lists)
+ classes (rfirst import-lists)]
+ (doseq c classes
+ (. ns (importClass c (. Class (forName (str pkg "." c)))))) )
+ (apply import (rest import-lists))))
+
+(defn into-array
+ "Returns an array of the type of the first element in coll,
+ containing the contents of coll, which must be of a compatible
+ type."
+ [aseq]
+ (. clojure.lang.RT (seqToTypedArray (seq aseq))))
+
+(defn into
+ "Returns a new coll consisting of to-coll with all of the items of
+ from-coll conjoined."
+ [to from]
+ (let [ret to items (seq from)]
+ (if items
+ (recur (conj ret (first items)) (rest items))
+ ret)))
+
+(defn #^{:private true}
+ array [& items]
+ (into-array items))
+
+(defn pr
+ "Prints the object(s) to the output stream that is the current value
+ of *out*. Prints the object(s), separated by spaces if there is
+ more than one. By default, pr and prn print in a way that objects
+ can be read by the reader"
+ ([] nil)
+ ([x]
+ (. clojure.lang.RT (print x *out*))
+ nil)
+ ([x & more]
+ (pr x)
+ (. *out* (append \space))
+ (apply pr more)))
+
+(defn newline
+ "Writes a newline to the output stream that is the current value of
+ *out*"
+ []
+ (. *out* (append \newline))
+ nil)
+
+(defn flush
+ "Flushes the output stream that is the current value of
+ *out*"
+ []
+ (. *out* (flush))
+ nil)
+
+(defn prn
+ "Same as pr followed by (newline). Observes *flush-on-newline*"
+ [& more]
+ (apply pr more)
+ (newline)
+ (when *flush-on-newline*
+ (flush)))
+
+(defn print
+ "Prints the object(s) to the output stream that is the current value
+ of *out*. print and println produce output for human consumption."
+ [& more]
+ (binding [*print-readably* nil]
+ (apply pr more)))
+
+(defn println
+ "Same as print followed by (newline)"
+ [& more]
+ (binding [*print-readably* nil]
+ (apply prn more)))
+
+
+(defn read
+ "Reads the next object from stream, which must be an instance of
+ java.io.PushbackReader or some derivee. stream defaults to the
+ current value of *in* ."
+ ([]
+ (read *in*))
+ ([stream]
+ (read stream true nil))
+ ([stream eof-error? eof-value]
+ (read stream eof-error? eof-value false))
+ ([stream eof-error? eof-value recursive?]
+ (. clojure.lang.LispReader (read stream eof-error? eof-value recursive?))))
+
+(defn read-line
+ "Reads the next line from stream that is the current value of *in* ."
+ [] (. *in* (readLine)))
+
+(defmacro with-open
+ "Evaluates body in a try expression with name bound to the value of
+ init, and a finally clause that calls (. name (close))."
+ [name init & body]
+ `(let [~name ~init]
+ (try
+ ~@body
+ (finally
+ (. ~name (close))))))
+
+(defmacro doto
+ "Evaluates x then calls all of the methods with the supplied
+ arguments in succession on the resulting object, returning it.
+
+ (doto (new java.util.HashMap) (put \"a\" 1) (put \"b\" 2))"
+ [x & members]
+ (let [gx (gensym)]
+ `(let [~gx ~x]
+ (do
+ ~@(map (fn [m] (list '. gx m))
+ members))
+ ~gx)))
+
+(defmacro memfn
+ "Expands into code that creates a fn that expects to be passed an
+ object and any args and calls the named instance method on the
+ object passing the args. Use when you want to treat a Java method as
+ a first-class fn."
+ [name & args]
+ `(fn [target# ~@args]
+ (. target# (~name ~@args))))
+
+(defmacro time
+ "Evaluates expr and prints the time it took. Returns the value of
+ expr."
+ [expr]
+ `(let [start# (. System (nanoTime))
+ ret# ~expr]
+ (prn (str "Elapsed time: " (/ (double (- (. System (nanoTime)) start#)) 1000000.0) " msecs"))
+ ret#))
+
+(defn num
+ "Coerce to Number"
+ {:tag Number
+ :inline (fn [x] `(. clojure.lang.Numbers (num ~x)))}
+ [x] (. clojure.lang.Numbers (num x)))
+
+(defn int
+ "Coerce to int"
+ {:tag Integer
+ :inline (fn [x] `(. clojure.lang.RT (intCast ~x)))}
+ [x] (. clojure.lang.RT (intCast x)))
+
+(defn long
+ "Coerce to long"
+ {:tag Long
+ :inline (fn [x] `(. clojure.lang.RT (longCast ~x)))}
+ [#^Number x] (. x (longValue)))
+
+(defn float
+ "Coerce to float"
+ {:tag Float
+ :inline (fn [x] `(. clojure.lang.RT (floatCast ~x)))}
+ [#^Number x] (. x (floatValue)))
+
+(defn double
+ "Coerce to double"
+ {:tag Double
+ :inline (fn [x] `(. clojure.lang.RT (doubleCast ~x)))}
+ [#^Number x] (. x (doubleValue)))
+
+(defn short
+ "Coerce to short"
+ {:tag Short}
+ [#^Number x] (. x (shortValue)))
+
+(defn byte
+ "Coerce to byte"
+ {:tag Byte}
+ [#^Number x] (. x (byteValue)))
+
+(defn char
+ "Coerce to char"
+ {:tag Character}
+ [x] (. clojure.lang.RT (charCast x)))
+
+(defn boolean
+ "Coerce to boolean"
+ {:tag Boolean}
+ [x] (if x true false))
+
+(defn bigint
+ "Coerce to BigInteger"
+ {:tag BigInteger}
+ [x] (. BigInteger valueOf x))
+
+(defn bigdec
+ "Coerce to BigDecimal"
+ {:tag BigDecimal}
+ [x] (. BigDecimal valueOf x))
+
+(import '(java.lang.reflect Array))
+
+(defn alength
+ "Returns the length of the Java array. Works on arrays of all
+ types."
+ {:inline (fn [a] `(. clojure.lang.RT (alength ~a)))}
+ [array] (. clojure.lang.RT (alength array)))
+
+(defn aclone
+ "Returns a clone of the Java array. Works on arrays of known
+ types."
+ {:inline (fn [a] `(. clojure.lang.RT (aclone ~a)))}
+ [array] (. clojure.lang.RT (aclone array)))
+
+(defn aget
+ "Returns the value at the index/indices. Works on Java arrays of all
+ types."
+ {:inline (fn [a i] `(. clojure.lang.RT (aget ~a ~i)))
+ :inline-arities #{2}}
+ ([array idx]
+ (. Array (get array idx)))
+ ([array idx & idxs]
+ (apply aget (aget array idx) idxs)))
+
+(defn aset
+ "Sets the value at the index/indices. Works on Java arrays of
+ reference types. Returns val."
+ {:inline (fn [a i v] `(. clojure.lang.RT (aset ~a ~i ~v)))
+ :inline-arities #{3}}
+ ([array idx val]
+ (. Array (set array idx val))
+ val)
+ ([array idx idx2 & idxv]
+ (apply aset (aget array idx) idx2 idxv)))
+
+(defmacro
+ #^{:private true}
+ def-aset [name method coerce]
+ `(defn ~name
+ {:arglists '([~'array ~'idx ~'val] [~'array ~'idx ~'idx2 & ~'idxv])}
+ ([array# idx# val#]
+ (. Array (~method array# idx# (~coerce val#)))
+ val#)
+ ([array# idx# idx2# & idxv#]
+ (apply ~name (aget array# idx#) idx2# idxv#))))
+
+(def-aset
+ #^{:doc "Sets the value at the index/indices. Works on arrays of int. Returns val."}
+ aset-int setInt int)
+
+(def-aset
+ #^{:doc "Sets the value at the index/indices. Works on arrays of long. Returns val."}
+ aset-long setLong long)
+
+(def-aset
+ #^{:doc "Sets the value at the index/indices. Works on arrays of boolean. Returns val."}
+ aset-boolean setBoolean boolean)
+
+(def-aset
+ #^{:doc "Sets the value at the index/indices. Works on arrays of float. Returns val."}
+ aset-float setFloat float)
+
+(def-aset
+ #^{:doc "Sets the value at the index/indices. Works on arrays of double. Returns val."}
+ aset-double setDouble double)
+
+(def-aset
+ #^{:doc "Sets the value at the index/indices. Works on arrays of short. Returns val."}
+ aset-short setShort short)
+
+(def-aset
+ #^{:doc "Sets the value at the index/indices. Works on arrays of byte. Returns val."}
+ aset-byte setByte byte)
+
+(def-aset
+ #^{:doc "Sets the value at the index/indices. Works on arrays of char. Returns val."}
+ aset-char setChar char)
+
+(defn make-array
+ "Creates and returns an array of instances of the specified class of
+ the specified dimension(s). Note that a class object is required.
+ Class objects can be obtained by using their imported or
+ fully-qualified name. Class objects for the primitive types can be
+ obtained using, e.g., (. Integer TYPE)."
+ ([#^Class type len]
+ (. Array (newInstance type (int len))))
+ ([#^Class type dim & more-dims]
+ (let [dims (cons dim more-dims)
+ #^"[I" dimarray (make-array (. Integer TYPE) (count dims))]
+ (dotimes i (alength dimarray)
+ (aset-int dimarray i (nth dims i)))
+ (. Array (newInstance type dimarray)))))
+
+(defn to-array-2d
+ "Returns a (potentially-ragged) 2-dimensional array of Objects
+ containing the contents of coll, which can be any Collection of any
+ Collection."
+ [#^java.util.Collection coll]
+ (let [ret (make-array (. Class (forName "[Ljava.lang.Object;")) (. coll (size)))]
+ (loop [i 0 xs (seq coll)]
+ (when xs
+ (aset ret i (to-array (first xs)))
+ (recur (inc i) (rest xs))))
+ ret))
+
+(import '(java.util.concurrent Executors LinkedBlockingQueue))
+
+(defn pmap
+ ([f coll]
+ (let [nthreads (.. Runtime (getRuntime) (availableProcessors))
+ exec (. Executors (newFixedThreadPool nthreads))
+ todo (ref (seq coll))
+ out (ref 0)
+ q (new LinkedBlockingQueue)
+ produce (fn []
+ (let [job (sync nil
+ (when @todo
+ (let [item (first @todo)]
+ (alter todo rest)
+ (commute out inc)
+ (list item))))]
+ (when job
+ (. q (put (f (first job))))
+ (recur))))
+ tasks (doseq dnu (map (fn [task]
+ (. exec (submit #^java.util.concurrent.Callable task)))
+ (replicate nthreads produce)))
+ consume (fn thisfn []
+ (if (sync nil (and (or @todo (pos? @out))
+ (commute out dec)))
+ (fnseq (. q (take)) thisfn)
+ (do
+ (. exec (shutdown))
+ (doseq x tasks)
+ nil)))]
+ (consume)))
+ ([f coll & colls]
+ (pmap (fn [items] (apply f items))
+ (let [encl-fn (fn thisfn [collseq]
+ (when (every? seq collseq)
+ (lazy-cons (map first collseq)
+ (thisfn (map rest collseq)))))]
+ (encl-fn (cons coll colls))))))
+
+(defn macroexpand-1
+ "If form represents a macro form, returns its expansion,
+ else returns form."
+ [form]
+ (. clojure.lang.Compiler (macroexpand1 form)))
+
+(defn macroexpand
+ "Repeatedly calls macroexpand-1 on form until it no longer
+ represents a macro form, then returns it. Note neither
+ macroexpand-1 nor macroexpand expand macros in subforms."
+ [form]
+ (let [ex (macroexpand-1 form)]
+ (if (identical? ex form)
+ form
+ (macroexpand ex))))
+
+(defn create-struct
+ "Returns a structure basis object."
+ [& keys]
+ (. clojure.lang.PersistentStructMap (createSlotMap keys)))
+
+(defmacro defstruct
+ "Same as (def name (create-struct keys...))"
+ [name & keys]
+ `(def ~name (create-struct ~@keys)))
+
+(defn struct-map
+ "Returns a new structmap instance with the keys of the
+ structure-basis. keyvals may contain all, some or none of the basis
+ keys - where values are not supplied they will default to nil.
+ keyvals can also contain keys not in the basis."
+ [s & inits]
+ (. clojure.lang.PersistentStructMap (create s inits)))
+
+(defn struct
+ "Returns a new structmap instance with the keys of the
+ structure-basis. vals must be supplied for basis keys in order -
+ where values are not supplied they will default to nil."
+ [s & vals]
+ (. clojure.lang.PersistentStructMap (construct s vals)))
+
+(defn accessor
+ "Returns a fn that, given an instance of a structmap with the basis,
+ returns the value at the key. The key must be in the basis. The
+ returned function should be (slightly) more efficient than using
+ get, but such use of accessors should be limited to known
+ performance-critical areas."
+ [s key]
+ (. clojure.lang.PersistentStructMap (getAccessor s key)))
+
+(defn subvec
+ "Returns a persistent vector of the items in vector from
+ start (inclusive) to end (exclusive). If end is not supplied,
+ defaults to (count vector). This operation is O(1) and very fast, as
+ the resulting vector shares structure with the original and no
+ trimming is done."
+ ([v start]
+ (subvec v start (count v)))
+ ([v start end]
+ (. clojure.lang.RT (subvec v start end))))
+
+(defn load
+ "Sequentially read and evaluate the set of forms contained in the
+ stream/file"
+ [rdr] (. clojure.lang.Compiler (load rdr)))
+
+(defn resultset-seq
+ "Creates and returns a lazy sequence of structmaps corresponding to
+ the rows in the java.sql.ResultSet rs"
+ [#^java.sql.ResultSet rs]
+ (let [rsmeta (. rs (getMetaData))
+ idxs (range 1 (inc (. rsmeta (getColumnCount))))
+ keys (map (comp keyword (memfn toLowerCase))
+ (map (fn [i] (. rsmeta (getColumnName i))) idxs))
+ row-struct (apply create-struct keys)
+ row-values (fn [] (map (fn [#^Integer i] (. rs (getObject i))) idxs))
+ rows (fn thisfn []
+ (when (. rs (next))
+ (lazy-cons (apply struct row-struct (row-values)) (thisfn))))]
+ (rows)))
+
+(defn set
+ "Returns a set of the distinct elements of coll."
+ [coll] (apply hash-set coll))
+
+(defn #^{:private true}
+ filter-key [keyfn pred amap]
+ (loop [ret {} es (seq amap)]
+ (if es
+ (if (pred (keyfn (first es)))
+ (recur (assoc ret (key (first es)) (val (first es))) (rest es))
+ (recur ret (rest es)))
+ ret)))
+
+(defn find-ns
+ "Returns the namespace named by the symbol or nil if it doesn't exist."
+ [sym] (. clojure.lang.Namespace (find sym)))
+
+(defn create-ns
+ "Create a new namespace named by the symbol if one doesn't already
+ exist, returns it or the already-existing namespace of the same
+ name."
+ [sym] (. clojure.lang.Namespace (findOrCreate sym)))
+
+(defn remove-ns
+ "Removes the namespace named by the symbol. Use with caution.
+ Cannot be used to remove the clojure namespace."
+ [sym] (. clojure.lang.Namespace (remove sym)))
+
+(defn all-ns
+ "Returns a sequence of all namespaces."
+ [] (. clojure.lang.Namespace (all)))
+
+(defn ns-name
+ "Returns the name of the namespace, a symbol."
+ [#^clojure.lang.Namespace ns]
+ (. ns (getName)))
+
+(defn ns-map
+ "Returns a map of all the mappings for the namespace."
+ [#^clojure.lang.Namespace ns]
+ (. ns (getMappings)))
+
+(defn ns-unmap
+ "Removes the mappings for the symbol from the namespace."
+ [#^clojure.lang.Namespace ns sym]
+ (. ns (unmap sym)))
+
+;(defn export [syms]
+; (doseq sym syms
+; (.. *ns* (intern sym) (setExported true))))
+
+(defn ns-publics
+ "Returns a map of the public intern mappings for the namespace."
+ [#^clojure.lang.Namespace ns]
+ (filter-key val (fn [#^clojure.lang.Var v] (and (instance? clojure.lang.Var v)
+ (= ns (. v ns))
+ (. v (isPublic))))
+ (ns-map ns)))
+
+(defn ns-imports
+ "Returns a map of the import mappings for the namespace."
+ [#^clojure.lang.Namespace ns]
+ (filter-key val (partial instance? Class) (ns-map ns)))
+
+(defn refer
+ "refers to all public vars of ns, subject to filters.
+ filters can include at most one each of:
+
+ :exclude list-of-symbols
+ :only list-of-symbols
+ :rename map-of-fromsymbol-tosymbol
+
+ For each public interned var in the namespace named by the symbol,
+ adds a mapping from the name of the var to the var to the current
+ namespace. Throws an exception if name is already mapped to
+ something else in the current namespace. Filters can be used to
+ select a subset, via inclusion or exclusion, or to provide a mapping
+ to a symbol different from the var's name, in order to prevent
+ clashes."
+ [ns-sym & filters]
+ (let [ns (or (find-ns ns-sym) (throw (new Exception (str "No namespace: " ns-sym))))
+ fs (apply hash-map filters)
+ nspublics (ns-publics ns)
+ rename (or (:rename fs) {})
+ exclude (set (:exclude fs))
+ to-do (or (:only fs) (keys nspublics))]
+ (doseq sym to-do
+ (when-not (exclude sym)
+ (let [v (nspublics sym)]
+ (when-not v
+ (throw (new java.lang.IllegalAccessError (str sym " is not public"))))
+ (. *ns* (refer (or (rename sym) sym) v)))))))
+
+(defn ns-refers
+ "Returns a map of the refer mappings for the namespace."
+ [#^clojure.lang.Namespace ns]
+ (filter-key val (fn [#^clojure.lang.Var v] (and (instance? clojure.lang.Var v)
+ (not= ns (. v ns))))
+ (ns-map ns)))
+
+(defn ns-interns
+ "Returns a map of the intern mappings for the namespace."
+ [#^clojure.lang.Namespace ns]
+ (filter-key val (fn [#^clojure.lang.Var v] (and (instance? clojure.lang.Var v)
+ (= ns (. v ns))))
+ (ns-map ns)))
+
+(defn take-nth
+ "Returns a lazy seq of every nth item in coll."
+ [n coll]
+ (when (seq coll)
+ (lazy-cons (first coll) (take-nth n (drop n coll)))))
+
+(defn interleave
+ "Returns a lazy seq of the first item in each coll, then the second
+ etc."
+ [& colls]
+ (apply concat (apply map list colls)))
+
+(defn var-get
+ "Gets the value in the var object"
+ [#^clojure.lang.Var x] (. x (get)))
+
+(defn var-set
+ "Sets the value in the var object to val. The var must be
+ thread-locally bound."
+ [#^clojure.lang.Var x val] (. x (set val)))
+
+(defmacro with-local-vars
+ "varbinding=> symbol init-expr
+
+ Executes the exprs in a context in which the symbols are bound to
+ vars with per-thread bindings to the init-exprs. The symbols refer
+ to the var objects themselves, and must be accessed with var-get and
+ var-set"
+ [name-vals-vec & body]
+ `(let [~@(interleave (take-nth 2 name-vals-vec)
+ (repeat '(. clojure.lang.Var (create))))]
+ (. clojure.lang.Var (pushThreadBindings (hash-map ~@name-vals-vec)))
+ (try
+ ~@body
+ (finally (. clojure.lang.Var (popThreadBindings))))))
+
+(defn ns-resolve
+ "Returns the var or Class to which a symbol will be resolved in the
+ namespace, else nil. Note that if the symbol is fully qualified,
+ the var/Class to which it resolves need not be present in the
+ namespace."
+ [ns sym]
+ (. clojure.lang.Compiler (maybeResolveIn ns sym)))
+
+(defn resolve
+ "same as (ns-resolve *ns* symbol)"
+ [sym] (ns-resolve *ns* sym))
+
+(defn array-map
+ "Constructs an array-map."
+ ([] (. clojure.lang.PersistentArrayMap EMPTY))
+ ([& keyvals] (new clojure.lang.PersistentArrayMap (to-array keyvals))))
+
+(defn nthrest
+ "Returns the nth rest of coll, (seq coll) when n is 0."
+ [coll n]
+ (loop [n n xs (seq coll)]
+ (if (and xs (pos? n))
+ (recur (dec n) (rest xs))
+ xs)))
+
+(defn symbol?
+ "Return true if x is a Symbol"
+ [x] (instance? clojure.lang.Symbol x))
+
+(defn keyword?
+ "Return true if x is a Keyword"
+ [x] (instance? clojure.lang.Keyword x))
+
+;redefine let and loop with destructuring
+(defn destructure [bindings]
+ (let [bmap (apply array-map bindings)
+ pb (fn pb [bvec b v]
+ (let [pvec
+ (fn [bvec b val]
+ (let [gvec (gensym "vec__")]
+ (loop [ret (-> bvec (conj gvec) (conj val))
+ n 0
+ bs b
+ seen-rest? false]
+ (if bs
+ (let [firstb (first bs)]
+ (cond
+ (= firstb '&) (recur (pb ret (second bs) (list `nthrest gvec n))
+ n
+ (rrest bs)
+ true)
+ (= firstb :as) (pb ret (second bs) gvec)
+ :else (if seen-rest?
+ (throw (new Exception "Unsupported binding form, only :as can follow & parameter"))
+ (recur (pb ret firstb (list `nth gvec n nil))
+ (inc n)
+ (rest bs)
+ seen-rest?))))
+ ret))))
+ pmap
+ (fn [bvec b v]
+ (let [gmap (or (:as b) (gensym "map__"))
+ defaults (:or b)]
+ (loop [ret (-> bvec (conj gmap) (conj v))
+ bes (reduce
+ (fn [bes entry]
+ (reduce #(assoc %1 %2 ((val entry) %2))
+ (dissoc bes (key entry))
+ ((key entry) bes)))
+ (dissoc b :as :or)
+ {:keys #(keyword (str %)), :strs str, :syms #(list `quote %)})]
+ (if bes
+ (let [bb (key (first bes))
+ bk (val (first bes))
+ has-default (contains? defaults bb)]
+ (recur (pb ret bb (if has-default
+ (list `get gmap bk (defaults bb))
+ (list `get gmap bk)))
+ (rest bes)))
+ ret))))]
+ (cond
+ (symbol? b) (-> bvec (conj b) (conj v))
+ (vector? b) (pvec bvec b v)
+ (map? b) (pmap bvec b v)
+ :else (throw (new Exception (str "Unsupported binding form: " b))))))
+ process-entry (fn [bvec b] (pb bvec (key b) (val b)))]
+ (if (every? symbol? (keys bmap))
+ bindings
+ (reduce process-entry [] bmap))))
+
+(defmacro let
+ "Evaluates the exprs in a lexical context in which the symbols in
+ the binding-forms are bound to their respective init-exprs or parts
+ therein."
+ [bindings & body]
+ `(let* ~(destructure bindings) ~@body))
+
+;redefine fn with destructuring
+(defmacro fn
+ "(fn name? [params* ] exprs*)
+ (fn name? ([params* ] exprs*)+)
+
+ params => positional-params* , or positional-params* & rest-param
+ positional-param => binding-form
+ rest-param => binding-form
+ name => symbol
+
+ Defines a function"
+ [& sigs]
+ (let [name (if (symbol? (first sigs)) (first sigs) nil)
+ sigs (if name (rest sigs) sigs)
+ sigs (if (vector? (first sigs)) (list sigs) sigs)
+ psig (fn [sig]
+ (let [[params & body] sig]
+ (if (every? symbol? params)
+ sig
+ (loop [params params
+ new-params []
+ lets []]
+ (if params
+ (if (symbol? (first params))
+ (recur (rest params) (conj new-params (first params)) lets)
+ (let [gparam (gensym "p__")]
+ (recur (rest params) (conj new-params gparam)
+ (-> lets (conj (first params)) (conj gparam)))))
+ `(~new-params
+ (let ~lets
+ ~@body)))))))
+ new-sigs (map psig sigs)]
+ (with-meta
+ (if name
+ (list* 'fn* name new-sigs)
+ (cons 'fn* new-sigs))
+ *macro-meta*)))
+
+(defmacro loop
+ "Evaluates the exprs in a lexical context in which the symbols in
+ the binding-forms are bound to their respective init-exprs or parts
+ therein. Acts as a recur target."
+ [bindings & body]
+ (let [db (destructure bindings)]
+ (if (= db bindings)
+ `(loop* ~bindings ~@body)
+ (let [vs (take-nth 2 (drop 1 bindings))
+ bs (take-nth 2 bindings)
+ gs (map (fn [b] (if (symbol? b) b (gensym))) bs)
+ bfs (reduce (fn [ret [b v g]]
+ (if (symbol? b)
+ (conj ret g v)
+ (conj ret g v b g)))
+ [] (map vector bs vs gs))]
+ `(let ~bfs
+ (loop* ~(vec (interleave gs gs))
+ (let ~(vec (interleave bs gs))
+ ~@body)))))))
+
+(defmacro when-first
+ "Same as (when (seq xs) (let [x (first xs)] body))"
+ [x xs & body]
+ `(when (seq ~xs)
+ (let [~x (first ~xs)]
+ ~@body)))
+
+(defmacro lazy-cat
+ "Expands to code which yields a lazy sequence of the concatenation
+ of the supplied colls. Each coll expr is not evaluated until it is
+ needed."
+ ([coll] `(seq ~coll))
+ ([coll & colls]
+ `(let [iter# (fn iter# [coll#]
+ (if (seq coll#)
+ (lazy-cons (first coll#) (iter# (rest coll#)))
+ (lazy-cat ~@colls)))]
+ (iter# ~coll))))
+
+
+
+(defmacro for
+ "List comprehension. Takes a vector of one or more
+ binding-form/collection-expr pairs, each followed by an optional filtering
+ :when/:while expression (:when test or :while test), and yields a
+ lazy sequence of evaluations of expr. Collections are iterated in a
+ nested fashion, rightmost fastest, and nested coll-exprs can refer to
+ bindings created in prior binding-forms.
+
+ (take 100 (for [x (range 100000000) y (range 1000000) :while (< y x)] [x y]))"
+ ([seq-exprs expr]
+ (let [pargs (fn [xs]
+ (loop [ret []
+ [b e & [w f & wr :as r] :as xs] (seq xs)]
+ (if xs
+ (cond
+ (= w :when) (recur (conj ret {:b b :e e :f f :w :when}) wr)
+ (= w :while) (recur (conj ret {:b b :e e :f f :w :while}) wr)
+ :else (recur (conj ret {:b b :e e :f true :w :while}) r))
+ (seq ret))))
+ emit (fn emit [[{b :b f :f w :w} & [{ys :e} :as rses]]]
+ (let [giter (gensym "iter__") gxs (gensym "s__")]
+ `(fn ~giter [~gxs]
+ (when-first ~b ~gxs
+ (if ~f
+ ~(if rses
+ `(let [iterys# ~(emit rses)]
+ (lazy-cat (iterys# ~ys)
+ (~giter (rest ~gxs))))
+ `(lazy-cons ~expr (~giter (rest ~gxs))))
+ ~(if (= w :when)
+ `(recur (rest ~gxs))
+ nil))))))]
+ `(let [iter# ~(emit (pargs seq-exprs))]
+ (iter# ~(second seq-exprs))))))
+
+(defmacro comment
+ "Ignores body, yields nil"
+ [& body])
+
+(defmacro with-out-str
+ "Evaluates exprs in a context in which *out* is bound to a fresh
+ StringWriter. Returns the string created by any nested printing
+ calls."
+ [& body]
+ `(let [s# (new java.io.StringWriter)]
+ (binding [*out* s#]
+ ~@body
+ (str s#))))
+
+(defn pr-str
+ "pr to a string, returning it"
+ [& xs]
+ (with-out-str
+ (apply pr xs)))
+
+(defn prn-str
+ "prn to a string, returning it"
+ [& xs]
+ (with-out-str
+ (apply prn xs)))
+
+(defn print-str
+ "print to a string, returning it"
+ [& xs]
+ (with-out-str
+ (apply print xs)))
+
+(defn println-str
+ "println to a string, returning it"
+ [& xs]
+ (with-out-str
+ (apply println xs)))
+
+(defmacro assert
+ "Evaluates expr and throws an exception if it does not evaluate to
+ logical true."
+ [x]
+ `(when-not ~x
+ (throw (new Exception (str "Assert failed: " (pr-str '~x))))))
+
+(defn test
+ "test [v] finds fn at key :test in var metadata and calls it,
+ presuming failure will throw exception"
+ [v]
+ (let [f (:test ^v)]
+ (if f
+ (do (f) :ok)
+ :no-test)))
+
+(defn re-pattern
+ "Returns an instance of java.util.regex.Pattern, for use, e.g. in
+ re-matcher."
+ {:tag java.util.regex.Pattern}
+ [s] (. java.util.regex.Pattern (compile s)))
+
+(defn re-matcher
+ "Returns an instance of java.util.regex.Matcher, for use, e.g. in
+ re-find."
+ {:tag java.util.regex.Matcher}
+ [#^java.util.regex.Pattern re s]
+ (. re (matcher s)))
+
+(defn re-groups
+ "Returns the groups from the most recent match/find. If there are no
+ nested groups, returns a string of the entire match. If there are
+ nested groups, returns a vector of the groups, the first element
+ being the entire match."
+ [#^java.util.regex.Matcher m]
+ (let [gc (. m (groupCount))]
+ (if (zero? gc)
+ (. m (group))
+ (loop [ret [] c 0]
+ (if (<= c gc)
+ (recur (conj ret (. m (group c))) (inc c))
+ ret)))))
+
+(defn re-seq
+ "Returns a lazy sequence of successive matches of pattern in string,
+ using java.util.regex.Matcher.find(), each such match processed with
+ re-groups."
+ [#^java.util.regex.Pattern re s]
+ (let [m (re-matcher re s)]
+ ((fn step []
+ (when (. m (find))
+ (lazy-cons (re-groups m) (step)))))))
+
+(defn re-matches
+ "Returns the match, if any, of string to pattern, using
+ java.util.regex.Matcher.matches(). Uses re-groups to return the
+ groups."
+ [#^java.util.regex.Pattern re s]
+ (let [m (re-matcher re s)]
+ (when (. m (matches))
+ (re-groups m))))
+
+
+(defn re-find
+ "Returns the next regex match, if any, of string to pattern, using
+ java.util.regex.Matcher.find(). Uses re-groups to return the
+ groups."
+ ([#^java.util.regex.Matcher m]
+ (when (. m (find))
+ (re-groups m)))
+ ([#^java.util.regex.Pattern re s]
+ (let [m (re-matcher re s)]
+ (re-find m))))
+
+(defn rand
+ "Returns a random floating point number between 0 (inclusive) and
+ 1 (exclusive)."
+ ([] (. Math (random)))
+ ([n] (* n (rand))))
+
+(defn rand-int
+ "Returns a random integer between 0 (inclusive) and n (exclusive)."
+ [n] (int (rand n)))
+
+(defmacro defn-
+ "same as defn, yielding non-public def"
+ [name & decls]
+ (list* `defn (with-meta name (assoc (meta name) :private true)) decls))
+
+(defn print-doc [v]
+ (println "-------------------------")
+ (println (str (ns-name (:ns ^v)) "/" (:name ^v)))
+ (prn (:arglists ^v))
+ (when (:macro ^v)
+ (println "Macro"))
+ (println " " (:doc ^v)))
+
+(defn find-doc
+ "Prints documentation for any var whose documentation or name
+ contains a match for re-string"
+ [re-string]
+ (let [re (re-pattern re-string)]
+ (dorun (for [ns (all-ns)
+ v (sort-by (comp :name meta) (vals (ns-interns ns)))
+ :when (and (:doc ^v)
+ (or (re-find (re-matcher re (:doc ^v)))
+ (re-find (re-matcher re (str (:name ^v))))))]
+ (print-doc v)))))
+
+(defmacro doc
+ "Prints documentation for the var named by varname"
+ [varname]
+ `(print-doc (var ~varname)))
+
+(defn tree-seq
+ "returns a lazy sequence of the nodes in a tree, via a depth-first walk.
+ branch? must be a fn of one arg that returns true if passed a node
+ that can have children (but may not). children must be a fn of one
+ arg that returns a sequence of the children. Will only be called on
+ nodes for which branch? returns true. Root is the root node of the
+ tree, must be a branch."
+ [branch? children root]
+ (let [walk (fn walk [nodes]
+ (when-first node nodes
+ (lazy-cons
+ node
+ (if (branch? node)
+ (lazy-cat (walk (children node))
+ (walk (rest nodes)))
+ (walk (rest nodes))))))]
+ (lazy-cons root (walk (children root)))))
+
+(defn file-seq
+ "A tree seq on java.io.Files"
+ [dir]
+ (tree-seq
+ (fn [#^java.io.File f] (. f (isDirectory)))
+ (fn [#^java.io.File d] (seq (. d (listFiles))))
+ dir))
+
+(defn xml-seq
+ "A tree seq on the xml elements as per xml/parse"
+ [root]
+ (tree-seq
+ (complement string?)
+ (comp seq :content)
+ root))
+
+(defn special-symbol?
+ "Returns true if s names a special form"
+ [s]
+ (contains? (. clojure.lang.Compiler specials) s))
+
+(defn var?
+ "Returns true if v is of type clojure.lang.Var"
+ [v] (instance? clojure.lang.Var v))
+
+(defn class
+ "Returns the Class of x"
+ [#^Object x] (. x (getClass)))
+
+(defn slurp
+ "Reads the file named by f into a string and returns it."
+ [#^String f]
+ (with-open r (new java.io.BufferedReader (new java.io.FileReader f))
+ (let [sb (new StringBuilder)]
+ (loop [c (. r (read))]
+ (if (neg? c)
+ (str sb)
+ (do
+ (. sb (append (char c)))
+ (recur (. r (read)))))))))
+
+(defn subs
+ "Returns the substring of s beginning at start inclusive, and ending
+ at end (defaults to length of string), exclusive."
+ ([#^String s start] (. s (substring start)))
+ ([#^String s start end] (. s (substring start end))))
+
+(defn max-key
+ "Returns the x for which (k x), a number, is greatest."
+ ([k x] x)
+ ([k x y] (if (> (k x) (k y)) x y))
+ ([k x y & more]
+ (reduce #(max-key k %1 %2) (max-key k x y) more)))
+
+(defn min-key
+ "Returns the x for which (k x), a number, is least."
+ ([k x] x)
+ ([k x y] (if (< (k x) (k y)) x y))
+ ([k x y & more]
+ (reduce #(min-key k %1 %2) (min-key k x y) more)))
+
+(defn distinct
+ "Returns a lazy sequence of the elements of coll with duplicates removed"
+ [coll]
+ (let [step (fn step [[f & r :as xs] seen]
+ (when xs
+ (if (seen f) (recur r seen)
+ (lazy-cons f (step r (conj seen f))))))]
+ (step (seq coll) #{})))
+
+(defmacro if-let
+ "if test is true, evaluates then with binding-form bound to the value of test, if not, yields else"
+ ([binding-form test then]
+ `(if-let ~binding-form ~test ~then nil))
+ ([binding-form test then else]
+ `(let [temp# ~test]
+ (if temp#
+ (let [~binding-form temp#]
+ ~then)
+ ~else))))
+
+(defmacro when-let
+ "when test is true, evaluates body with binding-form bound to the value of test"
+ [binding-form test & body]
+ `(let [temp# ~test]
+ (when temp#
+ (let [~binding-form temp#]
+ ~@body))))
+
+(defn replace
+ "Given a map of replacement pairs and a vector/collection, returns a
+ vector/seq with any elements = a key in smap replaced with the
+ corresponding val in smap"
+ [smap coll]
+ (if (vector? coll)
+ (reduce (fn [v i]
+ (if-let e (find smap (nth v i))
+ (assoc v i (val e))
+ v))
+ coll (range (count coll)))
+ (map #(if-let e (find smap %) (val e) %) coll)))
+
+(defmacro dosync
+ "Runs the exprs (in an implicit do) in a transaction that encompasses
+ exprs and any nested calls. Starts a transaction if none is already
+ running on this thread. Any uncaught exception will abort the
+ transaction and flow out of dosync. The exprs may be run more than
+ once, but any effects on Refs will be atomic."
+ [& exprs]
+ `(sync nil ~@exprs))
+
+(defmacro with-precision
+ "Sets the precision and rounding mode to be used for BigDecimal operations.
+
+ Usage: (with-precision 10 (/ 1M 3))
+ or: (with-precision 10 :rounding HALF_DOWN (/ 1M 3))
+
+ The rounding mode is one of CEILING, FLOOR, HALF_UP, HALF_DOWN,
+ HALF_EVEN, UP, DOWN and UNNECESSARY; it defaults to HALF_UP."
+ [precision & exprs]
+ (let [[body rm] (if (= (first exprs) :rounding)
+ [(rest (rest exprs))
+ `((. java.math.RoundingMode ~(second exprs)))]
+ [exprs nil])]
+ `(binding [*math-context* (java.math.MathContext. ~precision ~@rm)]
+ ~@body)))
+
+(defn bound-fn
+ {:private true}
+ [#^clojure.lang.Sorted sc test key]
+ (fn [e]
+ (test (.. sc comparator (compare (. sc entryKey e) key)) 0)))
+
+(defn subseq
+ "sc must be a sorted collection, test(s) one of <, <=, > or
+ >=. Returns a seq of those entries with keys ek for
+ which (test (.. sc comparator (compare ek key)) 0) is true"
+ ([#^clojure.lang.Sorted sc test key]
+ (let [include (bound-fn sc test key)]
+ (if (#{> >=} test)
+ (when-let [e :as s] (. sc seqFrom key true)
+ (if (include e) s (rest s)))
+ (take-while include (. sc seq true)))))
+ ([#^clojure.lang.Sorted sc start-test start-key end-test end-key]
+ (when-let [e :as s] (. sc seqFrom start-key true)
+ (take-while (bound-fn sc end-test end-key)
+ (if ((bound-fn sc start-test start-key) e) s (rest s))))))
+
+(defn rsubseq
+ "sc must be a sorted collection, test(s) one of <, <=, > or
+ >=. Returns a reverse seq of those entries with keys ek for
+ which (test (.. sc comparator (compare ek key)) 0) is true"
+ ([#^clojure.lang.Sorted sc test key]
+ (let [include (bound-fn sc test key)]
+ (if (#{< <=} test)
+ (when-let [e :as s] (. sc seqFrom key false)
+ (if (include e) s (rest s)))
+ (take-while include (. sc seq false)))))
+ ([#^clojure.lang.Sorted sc start-test start-key end-test end-key]
+ (when-let [e :as s] (. sc seqFrom end-key false)
+ (take-while (bound-fn sc start-test start-key)
+ (if ((bound-fn sc end-test end-key) e) s (rest s))))))
+
+(defn repeatedly
+ "Takes a function of no args, presumably with side effects, and returns an infinite
+ lazy sequence of calls to it"
+ [f] (lazy-cons (f) (repeatedly f)))
+
+(defn add-classpath
+ "Adds the url (String or URL object) to the classpath per URLClassLoader.addURL"
+ [url] (. clojure.lang.RT addURL url))
+
+
+
+(defn hash
+ "Returns the hash code of its argument"
+ [x] (. clojure.lang.Util (hash x)))
+
+(defn interpose
+ "Returns a lazy seq of the elements of coll separated by sep"
+ [sep coll] (drop 1 (interleave (repeat sep) coll)))
+
+(defn partition
+ "Returns a lazy sequence of lists of n items each, at offsets step
+ apart. If step is not supplied, defaults to n, i.e. the partitions
+ do not overlap."
+ ([n coll]
+ (partition n n coll))
+ ([n step coll]
+ (when (seq coll)
+ (let [p (take n coll)]
+ (when (= n (count p))
+ (lazy-cons p (partition n step (drop step coll))))))))
+
+(defmacro definline
+ "Experimental - like defmacro, except defines a named function whose
+ body is the expansion, calls to which may be expanded inline as if
+ it were a macro"
+ [name & decl]
+ (let [[args expr] (drop-while (comp not vector?) decl)
+ inline (eval (list 'fn args expr))]
+ `(do
+ (defn ~name ~args ~(apply inline args))
+ (let [v# (var ~name)]
+ (.setMeta v# (assoc ^v# :inline ~inline))))))
+
+(defn empty
+ "Returns an empty collection of the same category as coll, or nil"
+ [#^clojure.lang.IPersistentCollection coll]
+ (.empty coll))
+
+(defmacro amap
+ "Maps an expression across an array a, using an index named idx, and
+ return value named ret, initialized to a clone of a, then setting each element of
+ ret to the evaluation of expr, returning the new array ret."
+ [a idx ret expr]
+ `(let [a# ~a
+ ~ret (aclone a#)]
+ (loop [~idx (int 0)]
+ (if (< ~idx (alength a#))
+ (do
+ (aset ~ret ~idx ~expr)
+ (recur (unchecked-inc ~idx)))
+ ~ret))))
+
+(defmacro areduce
+ "Reduces an expression across an array a, using an index named idx,
+ and return value named ret, initialized to init, setting ret to the evaluation of expr at
+ each step, returning ret."
+ [a idx ret init expr]
+ `(let [a# ~a]
+ (loop [~idx (int 0) ~ret ~init]
+ (if (< ~idx (alength a#))
+ (recur (unchecked-inc ~idx) ~expr)
+ ~ret))))
+
+(defn float-array
+ "Creates an array of floats"
+ {:inline (fn [& args] `(. clojure.lang.Numbers float_array ~@args))
+ :inline-arities #{1 2}}
+ ([size-or-seq] (. clojure.lang.Numbers float_array size-or-seq))
+ ([size init-val-or-seq] (. clojure.lang.Numbers float_array size init-val-or-seq)))
+
+(defn double-array
+ "Creates an array of doubles"
+ {:inline (fn [& args] `(. clojure.lang.Numbers double_array ~@args))
+ :inline-arities #{1 2}}
+ ([size-or-seq] (. clojure.lang.Numbers double_array size-or-seq))
+ ([size init-val-or-seq] (. clojure.lang.Numbers double_array size init-val-or-seq)))
+
+(defn int-array
+ "Creates an array of ints"
+ {:inline (fn [& args] `(. clojure.lang.Numbers int_array ~@args))
+ :inline-arities #{1 2}}
+ ([size-or-seq] (. clojure.lang.Numbers int_array size-or-seq))
+ ([size init-val-or-seq] (. clojure.lang.Numbers int_array size init-val-or-seq)))
+
+(defn long-array
+ "Creates an array of ints"
+ {:inline (fn [& args] `(. clojure.lang.Numbers long_array ~@args))
+ :inline-arities #{1 2}}
+ ([size-or-seq] (. clojure.lang.Numbers long_array size-or-seq))
+ ([size init-val-or-seq] (. clojure.lang.Numbers long_array size init-val-or-seq)))
+
+(definline floats
+ "Casts to float[]"
+ [xs] `(. clojure.lang.Numbers floats ~xs))
+
+(definline ints
+ "Casts to int[]"
+ [xs] `(. clojure.lang.Numbers ints ~xs))
+
+(definline doubles
+ "Casts to double[]"
+ [xs] `(. clojure.lang.Numbers doubles ~xs))
+
+(definline longs
+ "Casts to long[]"
+ [xs] `(. clojure.lang.Numbers longs ~xs))
+
+(import '(java.util.concurrent BlockingQueue LinkedBlockingQueue))
+
+(defn seque
+ "Creates a queued seq on another (presumably lazy) seq s. The queued
+ seq will produce a concrete seq in the background, and can get up to
+ n items ahead of the consumer. n-or-q can be an integer n buffer
+ size, or an instance of java.util.concurrent BlockingQueue. Note
+ that reading from a seque can block if the reader gets ahead of the
+ producer."
+ ([s] (seque 100 s))
+ ([n-or-q s]
+ (let [#^BlockingQueue q (if (instance? BlockingQueue n-or-q)
+ n-or-q
+ (LinkedBlockingQueue. (int n-or-q)))
+ NIL (Object.) ;nil sentinel since LBQ doesn't support nils
+ agt (agent (seq s))
+ fill (fn [s]
+ (try
+ (loop [[x & xs :as s] s]
+ (if s
+ (if (.offer q (if (nil? x) NIL x))
+ (recur xs)
+ s)
+ (.put q q))) ; q itself is eos sentinel
+ (catch Exception e
+ (.put q q)
+ (throw e))))
+ drain (fn drain []
+ (let [x (.take q)]
+ (if (identical? x q) ;q itself is eos sentinel
+ @agt ;will be nil - touch agent just to propagate errors
+ (do
+ (send-off agt fill)
+ (lazy-cons (if (identical? x NIL) nil x) (drain))))))]
+ (send-off agt fill)
+ (drain)))) \ No newline at end of file
diff --git a/src/clojure/genclass.clj b/src/clojure/genclass.clj
new file mode 100644
index 00000000..cdc09845
--- /dev/null
+++ b/src/clojure/genclass.clj
@@ -0,0 +1,517 @@
+; 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.
+
+(in-ns 'clojure)
+
+(import '(java.lang.reflect Modifier Constructor)
+ '(clojure.asm ClassWriter ClassVisitor Opcodes Type)
+ '(clojure.asm.commons Method GeneratorAdapter)
+ '(clojure.lang IPersistentMap))
+
+;(defn method-sig [#^java.lang.reflect.Method meth]
+; [(. meth (getName)) (seq (. meth (getParameterTypes)))])
+
+(defn- non-private-methods [#^Class c]
+ (loop [mm {}
+ considered #{}
+ c c]
+ (if c
+ (let [[mm considered]
+ (loop [mm mm
+ considered considered
+ meths (concat
+ (seq (. c (getDeclaredMethods)))
+ (seq (. c (getMethods))))]
+ (if meths
+ (let [#^java.lang.reflect.Method meth (first meths)
+ mods (. meth (getModifiers))
+ mk (method-sig meth)]
+ (if (or (considered mk)
+ (. Modifier (isPrivate mods))
+ (. Modifier (isStatic mods))
+ (. Modifier (isFinal mods))
+ (= "finalize" (.getName meth)))
+ (recur mm (conj considered mk) (rest meths))
+ (recur (assoc mm mk meth) (conj considered mk) (rest meths))))
+ [mm considered]))]
+ (recur mm considered (. c (getSuperclass))))
+ mm)))
+
+(defn- ctor-sigs [super]
+ (for [#^Constructor ctor (. super (getDeclaredConstructors))
+ :when (not (. Modifier (isPrivate (. ctor (getModifiers)))))]
+ (apply vector (. ctor (getParameterTypes)))))
+
+(defn- escape-class-name [c]
+ (.. (.getSimpleName c)
+ (replace "[]" "<>")))
+
+(defn- overload-name [mname pclasses]
+ (if (seq pclasses)
+ (apply str mname (interleave (repeat \-)
+ (map escape-class-name pclasses)))
+ (str mname "-void")))
+
+;(distinct (map first(keys (mapcat non-private-methods [Object IPersistentMap]))))
+
+(defn gen-class
+ "Generates compiled bytecode for a class with the given
+ package-qualified cname (which, as all names in these parameters, can
+ be a string or symbol). The gen-class construct contains no
+ implementation, as the implementation will be dynamically sought by
+ the generated class in functions in a corresponding Clojure
+ namespace. Given a generated class org.mydomain.MyClass, methods
+ will be implemented that look for same-named functions in a Clojure
+ namespace called org.domain.MyClass. The init and main
+ functions (see below) will be found similarly. The static
+ initializer for the generated class will attempt to load the Clojure
+ support code for the class as a resource from the claspath, e.g. in
+ the example case, org/mydomain/MyClass.clj
+
+ Returns a map containing :name and :bytecode. Most uses will be
+ satisfied by the higher-level gen-and-load-class and
+ gen-and-store-class functions, which generate and immediately load,
+ or generate and store to disk, respectively.
+
+ Options should be a set of key/value pairs, all of which are optional:
+
+ :extends aclass
+
+ Specifies the superclass, the non-private methods of which will be
+ overridden by the class. If not provided, defaults to Object.
+
+ :implements [interface ...]
+
+ One or more interfaces, the methods of which will be implemented by the class.
+
+ :init name
+
+ If supplied, names a function that will be called with the arguments
+ to the constructor. Must return [ [superclass-constructor-args] state]
+ If not supplied, the constructor args are passed directly to
+ the superclass constructor and the state will be nil
+
+ :constructors {[param-types] [super-param-types], ...}
+
+ By default, constructors are created for the generated class which
+ match the signature(s) of the constructors for the superclass. This
+ parameter may be used to explicitly specify constructors, each entry
+ providing a mapping from a constructor signature to a superclass
+ constructor signature. When you supply this, you must supply an :init
+ specifier.
+
+ :methods [ [name [param-types] return-type], ...]
+
+ The generated class automatically defines all of the non-private
+ methods of its superclasses/interfaces. This parameter can be used
+ to specify the signatures of additional methods of the generated
+ class. Static methods can be specified with #^{:static true} in the
+ signature's metadata. Do not repeat superclass/interface signatures
+ here.
+
+ :main boolean
+
+ If supplied and true, a static public main function will be
+ generated. It will pass each string of the String[] argument as a
+ separate argument to a function called 'main.
+
+ :factory name
+
+ If supplied, a (set of) public static factory function(s) will be
+ created with the given name, and the same signature(s) as the
+ constructor(s).
+
+ :state name
+
+ If supplied, a public final instance field with the given name will be
+ created. You must supply an :init function in order to provide a
+ value for the state. Note that, though final, the state can be a ref
+ or agent, supporting the creation of Java objects with transactional
+ or asynchronous mutation semantics.
+
+ :exposes {protected-field-name {:get name :set name}, ...}
+
+ Since the implementations of the methods of the generated class
+ occur in Clojure functions, they have no access to the inherited
+ protected fields of the superclass. This parameter can be used to
+ generate public getter/setter methods exposing the protected field(s)
+ for use in the implementation."
+
+ [cname & options]
+ (let [name (str cname)
+ {:keys [extends implements constructors methods main factory state init exposes]} (apply hash-map options)
+ super (or extends Object)
+ interfaces implements
+ supers (cons super (seq interfaces))
+ ctor-sig-map (or constructors (zipmap (ctor-sigs super) (ctor-sigs super)))
+ cv (new ClassWriter (. ClassWriter COMPUTE_MAXS))
+ cname (. name (replace "." "/"))
+ ctype (. Type (getObjectType cname))
+ iname (fn [c] (.. Type (getType c) (getInternalName)))
+ totype (fn [c] (. Type (getType c)))
+ to-types (fn [cs] (if (pos? (count cs))
+ (into-array (map totype cs))
+ (make-array Type 0)))
+ obj-type (totype Object)
+ arg-types (fn [n] (if (pos? n)
+ (into-array (replicate n obj-type))
+ (make-array Type 0)))
+ super-type (totype super)
+ init-name (str init)
+ factory-name (str factory)
+ state-name (str state)
+ main-name "main"
+ var-name (fn [s] (str s "__var"))
+ rt-type (totype clojure.lang.RT)
+ var-type (totype clojure.lang.Var)
+ ifn-type (totype clojure.lang.IFn)
+ iseq-type (totype clojure.lang.ISeq)
+ ex-type (totype java.lang.UnsupportedOperationException)
+ all-sigs (distinct (concat (map #(let[[m p] (key %)] {m [p]}) (mapcat non-private-methods supers))
+ (map (fn [[m p]] {(str m) [p]}) methods)))
+ sigs-by-name (apply merge-with concat {} all-sigs)
+ overloads (into {} (filter (fn [[m s]] (rest s)) sigs-by-name))
+ var-fields (concat (and init [init-name])
+ (and main [main-name])
+ (distinct (concat (keys sigs-by-name)
+ (mapcat (fn [[m s]] (map #(overload-name m %) s)) overloads)
+ (mapcat (comp (partial map str) vals val) exposes))))
+ emit-get-var (fn [gen v]
+ (let [false-label (. gen newLabel)
+ end-label (. gen newLabel)]
+ (. gen getStatic ctype (var-name v) var-type)
+ (. gen dup)
+ (. gen invokeVirtual var-type (. Method (getMethod "boolean isBound()")))
+ (. gen ifZCmp (. GeneratorAdapter EQ) false-label)
+ (. gen invokeVirtual var-type (. Method (getMethod "Object get()")))
+ (. gen goTo end-label)
+ (. gen mark false-label)
+ (. gen pop)
+ (. gen visitInsn (. Opcodes ACONST_NULL))
+ (. gen mark end-label)))
+ emit-forwarding-method
+ (fn [mname pclasses rclass as-static else-gen]
+ (let [ptypes (to-types pclasses)
+ rtype (totype rclass)
+ m (new Method mname rtype ptypes)
+ is-overload (overloads mname)
+ gen (new GeneratorAdapter (+ (. Opcodes ACC_PUBLIC) (if as-static (. Opcodes ACC_STATIC) 0))
+ m nil nil cv)
+ found-label (. gen (newLabel))
+ else-label (. gen (newLabel))
+ end-label (. gen (newLabel))]
+ (. gen (visitCode))
+ (when is-overload
+ (emit-get-var gen (overload-name mname pclasses))
+ (. gen (dup))
+ (. gen (ifNonNull found-label))
+ (. gen (pop)))
+ (emit-get-var gen mname)
+ (. gen (dup))
+ (. gen (ifNull else-label))
+ (when is-overload
+ (. gen (mark found-label)))
+ ;if found
+ (when-not as-static
+ (. gen (loadThis)))
+ ;box args
+ (dotimes i (count ptypes)
+ (. gen (loadArg i))
+ (. clojure.lang.Compiler$HostExpr (emitBoxReturn nil gen (nth pclasses i))))
+ ;call fn
+ (. gen (invokeInterface ifn-type (new Method "invoke" obj-type
+ (to-types (replicate (+ (count ptypes)
+ (if as-static 0 1))
+ Object)))))
+ ;(into-array (cons obj-type
+ ; (replicate (count ptypes) obj-type))))))
+ ;unbox return
+ (. gen (unbox rtype))
+ (when (= (. rtype (getSort)) (. Type VOID))
+ (. gen (pop)))
+ (. gen (goTo end-label))
+
+ ;else call supplied alternative generator
+ (. gen (mark else-label))
+ (. gen (pop))
+
+ (else-gen gen m)
+
+ (. gen (mark end-label))
+ (. gen (returnValue))
+ (. gen (endMethod))))
+ ]
+ ;start class definition
+ (. cv (visit (. Opcodes V1_5) (+ (. Opcodes ACC_PUBLIC) (. Opcodes ACC_SUPER))
+ cname nil (iname super)
+ (when interfaces
+ (into-array (map iname interfaces)))))
+
+ ;static fields for vars
+ (doseq v var-fields
+ (. cv (visitField (+ (. Opcodes ACC_PUBLIC) (. Opcodes ACC_FINAL) (. Opcodes ACC_STATIC))
+ (var-name v)
+ (. var-type getDescriptor)
+ nil nil)))
+
+ ;instance field for state
+ (when state
+ (. cv (visitField (+ (. Opcodes ACC_PUBLIC) (. Opcodes ACC_FINAL))
+ state-name
+ (. obj-type getDescriptor)
+ nil nil)))
+
+ ;static init to set up var fields and load clj
+ (let [gen (new GeneratorAdapter (+ (. Opcodes ACC_PUBLIC) (. Opcodes ACC_STATIC))
+ (. Method getMethod "void <clinit> ()")
+ nil nil cv)]
+ (. gen (visitCode))
+ (doseq v var-fields
+ (. gen push name)
+ (. gen push v)
+ (. gen (invokeStatic rt-type (. Method (getMethod "clojure.lang.Var var(String,String)"))))
+ (. gen putStatic ctype (var-name v) var-type))
+
+ (. gen push ctype)
+ (. gen push (str (. name replace \. (. java.io.File separatorChar)) ".clj"))
+ (. gen (invokeStatic rt-type (. Method (getMethod "void loadResourceScript(Class,String)"))))
+
+ (. gen (returnValue))
+ (. gen (endMethod)))
+
+ ;ctors
+ (doseq [pclasses super-pclasses] ctor-sig-map
+ (let [ptypes (to-types pclasses)
+ super-ptypes (to-types super-pclasses)
+ m (new Method "<init>" (. Type VOID_TYPE) ptypes)
+ super-m (new Method "<init>" (. Type VOID_TYPE) super-ptypes)
+ gen (new GeneratorAdapter (. Opcodes ACC_PUBLIC) m nil nil cv)
+ no-init-label (. gen newLabel)
+ end-label (. gen newLabel)
+ nth-method (. Method (getMethod "Object nth(Object,int)"))
+ local (. gen newLocal obj-type)]
+ (. gen (visitCode))
+
+ (if init
+ (do
+ (emit-get-var gen init-name)
+ (. gen dup)
+ (. gen ifNull no-init-label)
+ ;box init args
+ (dotimes i (count pclasses)
+ (. gen (loadArg i))
+ (. clojure.lang.Compiler$HostExpr (emitBoxReturn nil gen (nth pclasses i))))
+ ;call init fn
+ (. gen (invokeInterface ifn-type (new Method "invoke" obj-type
+ (arg-types (count ptypes)))))
+ ;expecting [[super-ctor-args] state] returned
+ (. gen dup)
+ (. gen push 0)
+ (. gen (invokeStatic rt-type nth-method))
+ (. gen storeLocal local)
+
+ (. gen (loadThis))
+ (. gen dupX1)
+ (dotimes i (count super-pclasses)
+ (. gen loadLocal local)
+ (. gen push i)
+ (. gen (invokeStatic rt-type nth-method))
+ (. clojure.lang.Compiler$HostExpr (emitUnboxArg nil gen (nth super-pclasses i))))
+ (. gen (invokeConstructor super-type super-m))
+
+ (if state
+ (do
+ (. gen push 1)
+ (. gen (invokeStatic rt-type nth-method))
+ (. gen (putField ctype state-name obj-type)))
+ (. gen pop))
+
+ (. gen goTo end-label)
+ ;no init found
+ (. gen mark no-init-label)
+ (. gen (throwException ex-type (str init-name " not defined")))
+ (. gen mark end-label))
+ (if (= pclasses super-pclasses)
+ (do
+ (. gen (loadThis))
+ (. gen (loadArgs))
+ (. gen (invokeConstructor super-type super-m)))
+ (throw (new Exception ":init not specified, but ctor and super ctor args differ"))))
+
+ (. gen (returnValue))
+ (. gen (endMethod))
+ ;factory
+ (when factory
+ (let [fm (new Method factory-name ctype ptypes)
+ gen (new GeneratorAdapter (+ (. Opcodes ACC_PUBLIC) (. Opcodes ACC_STATIC))
+ fm nil nil cv)]
+ (. gen (visitCode))
+ (. gen newInstance ctype)
+ (. gen dup)
+ (. gen (loadArgs))
+ (. gen (invokeConstructor ctype m))
+ (. gen (returnValue))
+ (. gen (endMethod))))))
+
+ ;add methods matching supers', if no fn -> call super
+ (let [mm (non-private-methods super)]
+ (doseq #^java.lang.reflect.Method meth (vals mm)
+ (emit-forwarding-method (.getName meth) (.getParameterTypes meth) (.getReturnType meth) false
+ (fn [gen m]
+ (. gen (loadThis))
+ ;push args
+ (. gen (loadArgs))
+ ;call super
+ (. gen (visitMethodInsn (. Opcodes INVOKESPECIAL)
+ (. super-type (getInternalName))
+ (. m (getName))
+ (. m (getDescriptor)))))))
+ ;add methods matching interfaces', if no fn -> throw
+ (doseq #^Class iface interfaces
+ (doseq #^java.lang.reflect.Method meth (. iface (getMethods))
+ (when-not (contains? mm (method-sig meth))
+ (emit-forwarding-method (.getName meth) (.getParameterTypes meth) (.getReturnType meth) false
+ (fn [gen m]
+ (. gen (throwException ex-type (. m (getName)))))))))
+ ;extra methods
+ (doseq [mname pclasses rclass :as msig] methods
+ (emit-forwarding-method (str mname) pclasses rclass (:static ^msig)
+ (fn [gen m]
+ (. gen (throwException ex-type (. m (getName))))))))
+
+ ;main
+ (when main
+ (let [m (. Method getMethod "void main (String[])")
+ gen (new GeneratorAdapter (+ (. Opcodes ACC_PUBLIC) (. Opcodes ACC_STATIC))
+ m nil nil cv)
+ no-main-label (. gen newLabel)
+ end-label (. gen newLabel)]
+ (. gen (visitCode))
+
+ (emit-get-var gen main-name)
+ (. gen dup)
+ (. gen ifNull no-main-label)
+ (. gen loadArgs)
+ (. gen (invokeStatic rt-type (. Method (getMethod "clojure.lang.ISeq seq(Object)"))))
+ (. gen (invokeInterface ifn-type (new Method "applyTo" obj-type
+ (into-array [iseq-type]))))
+ (. gen pop)
+ (. gen goTo end-label)
+ ;no main found
+ (. gen mark no-main-label)
+ (. gen (throwException ex-type (str main-name " not defined")))
+ (. gen mark end-label)
+ (. gen (returnValue))
+ (. gen (endMethod))))
+ ;field exposers
+ (doseq [f {getter :get setter :set}] exposes
+ (let [fld (.getField super (str f))
+ ftype (totype (.getType fld))]
+ (when getter
+ (let [m (new Method (str getter) ftype (to-types []))
+ gen (new GeneratorAdapter (. Opcodes ACC_PUBLIC) m nil nil cv)]
+ (. gen (visitCode))
+ (. gen loadThis)
+ (. gen getField ctype (str f) ftype)
+ (. gen (returnValue))
+ (. gen (endMethod))))
+ (when setter
+ (let [m (new Method (str setter) (. Type VOID_TYPE) (into-array [ftype]))
+ gen (new GeneratorAdapter (. Opcodes ACC_PUBLIC) m nil nil cv)]
+ (. gen (visitCode))
+ (. gen loadThis)
+ (. gen loadArgs)
+ (. gen putField ctype (str f) ftype)
+ (. gen (returnValue))
+ (. gen (endMethod))))))
+ ;finish class def
+ (. cv (visitEnd))
+ {:name name :bytecode (. cv (toByteArray))}))
+
+(defn gen-and-load-class
+ "Generates and immediately loads the bytecode for the specified
+ class. Note that a class generated this way can be loaded only once
+ - the JVM supports only one class with a given name per
+ classloader. Subsequent to generation you can import it into any
+ desired namespaces just like any other class. See gen-class for a
+ description of the options."
+
+ [name & options]
+ (let [{:keys [name bytecode]}
+ (apply gen-class (str name) options)]
+ (.. clojure.lang.RT ROOT_CLASSLOADER (defineClass (str name) bytecode))))
+
+(defn gen-and-save-class
+ "Generates the bytecode for the named class and stores in a .class
+ file in a subpath of the supplied path, the directories for which
+ must already exist. See gen-class for a description of the options"
+
+ [path name & options]
+ (let [{:keys [name bytecode]} (apply gen-class (str name) options)
+ file (java.io.File. path (str (. name replace \. (. java.io.File separatorChar)) ".class"))]
+ (.createNewFile file)
+ (with-open f (java.io.FileOutputStream. file)
+ (.write f bytecode))))
+
+(comment
+;usage
+(gen-class
+ package-qualified-name
+ ;all below are optional
+ :extends aclass
+ :implements [interface ...]
+ :constructors {[param-types] [super-param-types], }
+ :methods [[name [param-types] return-type], ]
+ :main boolean
+ :factory name
+ :state name
+ :init name
+ :exposes {protected-field {:get name :set name}, })
+
+(gen-and-load-class
+;(clojure/gen-and-save-class
+; "/Users/rich/Downloads"
+ 'fred.lucy.Ethel
+ :extends clojure.lang.Box ;APersistentMap
+ :implements [clojure.lang.IPersistentMap]
+ :state 'state
+ ;:constructors {[Object] [Object]}
+ ;:init 'init
+ :main true
+ :factory 'create
+ :methods [#^{:static true} ['foo [Object] Object]
+ ['bar [] Object]]
+ :exposes {'val {:get 'getVal :set 'setVal}})
+
+(in-ns 'fred.lucy.Ethel)
+(clojure/refer 'clojure :exclude '(assoc seq count cons empty))
+(defn init [n] [[] n])
+(defn foo
+ ([x] x))
+(defn main [x y] (println x y))
+(in-ns 'user)
+(def ethel (new fred.lucy.Ethel__2276 42))
+(def ethel (fred.lucy.Ethel__2276.create 21))
+(fred.lucy.Ethel__2276.main (into-array ["lucy" "ricky"]))
+(.state ethel)
+(.foo ethel 7)
+(.foo ethel)
+(.getVal ethel)
+(.setVal ethel 12)
+
+(gen-class org.clojure.MyComparator :implements [Comparator])
+(in-ns 'org.clojure.MyComparator)
+(defn compare [this x y] ...)
+
+(load-file "/Users/rich/dev/clojure/src/genclass.clj")
+
+(clojure/gen-and-save-class "/Users/rich/dev/clojure/gen/"
+ 'org.clojure.ClojureServlet
+ :extends javax.servlet.http.HttpServlet)
+
+)
diff --git a/src/clojure/inspector/inspector.clj b/src/clojure/inspector/inspector.clj
new file mode 100644
index 00000000..ad5a374e
--- /dev/null
+++ b/src/clojure/inspector/inspector.clj
@@ -0,0 +1,110 @@
+; 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.
+
+(in-ns 'clojure.inspector)
+(clojure/refer 'clojure)
+
+(import '(javax.swing.tree TreeModel)
+ '(javax.swing.table TableModel)
+ '(javax.swing JTree JTable JScrollPane JFrame))
+
+(defn atom? [x]
+ (not (instance? clojure.lang.IPersistentCollection x)))
+
+(defn collection-tag [x]
+ (cond
+ (instance? java.util.Map$Entry x) :entry
+ (instance? clojure.lang.IPersistentMap x) :map
+ (instance? java.util.Map x) :map
+ (instance? clojure.lang.Sequential x) :seq
+ :else :atom))
+
+(defmulti is-leaf collection-tag)
+(defmulti get-child (fn [parent index] (collection-tag parent)))
+(defmulti get-child-count collection-tag)
+
+(defmethod is-leaf :default [node]
+ (atom? node))
+(defmethod get-child :default [parent index]
+ (nth parent index))
+(defmethod get-child-count :default [parent]
+ (count parent))
+
+(defmethod is-leaf :entry [e]
+ (is-leaf (val e)))
+(defmethod get-child :entry [e index]
+ (get-child (val e) index))
+(defmethod get-child-count :entry [e]
+ (count (val e)))
+
+(defmethod is-leaf :map [m]
+ false)
+(defmethod get-child :map [m index]
+ (nth (seq m) index))
+
+(defn tree-model [data]
+ (proxy [TreeModel] []
+ (getRoot [] data)
+ (addTreeModelListener [treeModelListener])
+ (getChild [parent index]
+ (get-child parent index))
+ (getChildCount [parent]
+ (get-child-count parent))
+ (isLeaf [node]
+ (is-leaf node))
+ (valueForPathChanged [path newValue])
+ (getIndexOfChild [parent child]
+ -1)
+ (removeTreeModelListener [treeModelListener])))
+
+
+(defn table-model [data]
+ (let [row1 (first data)
+ colcnt (count row1)
+ cnt (count data)
+ vals (if (instance? clojure.lang.IPersistentMap row1) vals identity)]
+ (proxy [TableModel] []
+ (addTableModelListener [tableModelListener])
+ (getColumnClass [columnIndex] Object)
+ (getColumnCount [] colcnt)
+ (getColumnName [columnIndex]
+ (if (instance? clojure.lang.IPersistentMap row1)
+ (name (nth (keys row1) columnIndex))
+ (str columnIndex)))
+ (getRowCount [] cnt)
+ (getValueAt [rowIndex columnIndex]
+ (nth (vals (nth data rowIndex)) columnIndex))
+ (isCellEditable [rowIndex columnIndex] false)
+ (removeTableModelListener [tableModelListener]))))
+
+(defn inspect-tree
+ "creates a graphical (Swing) inspector on the supplied hierarchical data"
+ [data]
+ (doto (new JFrame "Clojure Inspector")
+ (add (new JScrollPane (new JTree (tree-model data))))
+ (setSize 400 600)
+ (setVisible true)))
+
+(defn inspect-table
+ "creates a graphical (Swing) inspector on the supplied regular
+ data, which must be a sequential data structure of data structures
+ of equal length"
+ [data]
+ (doto (new JFrame "Clojure Inspector")
+ (add (new JScrollPane (new JTable (table-model data))))
+ (setSize 400 600)
+ (setVisible true)))
+
+(comment
+
+(load-file "src/inspector.clj")
+(refer 'inspector)
+(inspect-tree {:a 1 :b 2 :c [1 2 3 {:d 4 :e 5 :f [6 7 8]}]})
+(inspect-table [[1 2 3][4 5 6][7 8 9][10 11 12]])
+
+) \ No newline at end of file
diff --git a/src/clojure/parallel/parallel.clj b/src/clojure/parallel/parallel.clj
new file mode 100644
index 00000000..a9959b3a
--- /dev/null
+++ b/src/clojure/parallel/parallel.clj
@@ -0,0 +1,248 @@
+; 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.
+
+(in-ns 'clojure.parallel)
+(clojure/refer 'clojure)
+
+(comment "
+The parallel library wraps the ForkJoin library scheduled for inclusion in JDK 7:
+
+http://gee.cs.oswego.edu/dl/concurrency-interest/index.html
+
+You'll need jsr166y.jar in your classpath in order to use this
+library. The basic idea is that Clojure collections, and most
+efficiently vectors, can be turned into parallel arrays for use by
+this library with the function par, although most of the functions
+take collections and will call par if needed, so normally you will
+only need to call par explicitly in order to attach bound/filter/map
+ops. Parallel arrays support the attachment of bounds, filters and
+mapping functions prior to realization/calculation, which happens as
+the result of any of several operations on the
+array (pvec/psort/pfilter-nils/pfilter-dupes). Rather than perform
+composite operations in steps, as would normally be done with
+sequences, maps and filters are instead attached and thus composed by
+providing ops to par. Note that there is an order sensitivity to the
+attachments - bounds precede filters precede mappings. All operations
+then happen in parallel, using multiple threads and a sophisticated
+work-stealing system supported by fork-join, either when the array is
+realized, or to perform aggregate operations like preduce/pmin/pmax
+etc. A parallel array can be realized into a Clojure vector using
+pvec.
+")
+
+(import '(jsr166y.forkjoin ParallelArray ParallelArrayWithBounds ParallelArrayWithFilter
+ ParallelArrayWithMapping
+ Ops$Op Ops$BinaryOp Ops$Reducer Ops$Predicate Ops$BinaryPredicate
+ Ops$IntAndObjectPredicate Ops$IntAndObjectToObject))
+
+(defn- op [f]
+ (proxy [Ops$Op] []
+ (op [x] (f x))))
+
+(defn- binary-op [f]
+ (proxy [Ops$BinaryOp] []
+ (op [x y] (f x y))))
+
+(defn- int-and-object-to-object [f]
+ (proxy [Ops$IntAndObjectToObject] []
+ (op [i x] (f x i))))
+
+(defn- reducer [f]
+ (proxy [Ops$Reducer] []
+ (op [x y] (f x y))))
+
+(defn- predicate [f]
+ (proxy [Ops$Predicate] []
+ (op [x] (boolean (f x)))))
+
+(defn- binary-predicate [f]
+ (proxy [Ops$BinaryPredicate] []
+ (op [x y] (boolean (f x y)))))
+
+(defn- int-and-object-predicate [f]
+ (proxy [Ops$IntAndObjectPredicate] []
+ (op [i x] (boolean (f x i)))))
+
+(defn par
+ "Creates a parallel array from coll. ops, if supplied, perform
+ on-the-fly filtering or transformations during parallel realization
+ or calculation. ops form a chain, and bounds must precede filters,
+ must precede maps. ops must be a set of keyword value pairs of the
+ following forms:
+
+ :bound [start end]
+
+ Only elements from start (inclusive) to end (exclusive) will be
+ processed when the array is realized.
+
+ :filter pred
+
+ Filter preds remove elements from processing when the array is realized. pred
+ must be a function of one argument whose return will be processed
+ via boolean.
+
+ :filter-index pred2
+
+ pred2 must be a function of two arguments, which will be an element
+ of the collection and the corresponding index, whose return will be
+ processed via boolean.
+
+ :filter-with [pred2 coll2]
+
+ pred2 must be a function of two arguments, which will be
+ corresponding elements of the 2 collections.
+
+ :map f
+
+ Map fns will be used to transform elements when the array is
+ realized. f must be a function of one argument.
+
+ :map-index f2
+
+ f2 must be a function of two arguments, which will be an element of
+ the collection and the corresponding index.
+
+ :map-with [f2 coll2]
+
+ f2 must be a function of two arguments, which will be corresponding
+ elements of the 2 collections."
+
+ ([coll]
+ (if (instance? ParallelArrayWithMapping coll)
+ coll
+ (. ParallelArray createUsingHandoff
+ (to-array coll)
+ (. ParallelArray defaultExecutor))))
+ ([coll & ops]
+ (reduce (fn [pa [op args]]
+ (cond
+ (= op :bound) (. pa withBounds (args 0) (args 1))
+ (= op :filter) (. pa withFilter (predicate args))
+ (= op :filter-with) (. pa withFilter (binary-predicate (args 0)) (par (args 1)))
+ (= op :filter-index) (. pa withIndexedFilter (int-and-object-predicate args))
+ (= op :map) (. pa withMapping (parallel/op args))
+ (= op :map-with) (. pa withMapping (binary-op (args 0)) (par (args 1)))
+ (= op :map-index) (. pa withIndexedMapping (int-and-object-to-object args))
+ :else (throw (Exception. (str "Unsupported par op: " op)))))
+ (par coll)
+ (partition 2 ops))))
+
+;;;;;;;;;;;;;;;;;;;;; aggregate operations ;;;;;;;;;;;;;;;;;;;;;;
+(defn pany
+ "Returns some (random) element of the coll if it satisfies the bound/filter/map"
+ [coll]
+ (. (par coll) any))
+
+(defn pmax
+ "Returns the maximum element, presuming Comparable elements, unless
+ a Comparator comp is supplied"
+ ([coll] (. (par coll) max))
+ ([coll comp] (. (par coll) max comp)))
+
+(defn pmin
+ "Returns the minimum element, presuming Comparable elements, unless
+ a Comparator comp is supplied"
+ ([coll] (. (par coll) min))
+ ([coll comp] (. (par coll) min comp)))
+
+(defn- summary-map [s]
+ {:min (.min s) :max (.max s) :size (.size s) :min-index (.indexOfMin s) :max-index (.indexOfMax s)})
+
+(defn psummary
+ "Returns a map of summary statistics (min. max, size, min-index, max-index,
+ presuming Comparable elements, unless a Comparator comp is supplied"
+ ([coll] (summary-map (. (par coll) summary)))
+ ([coll comp] (summary-map (. (par coll) summary comp))))
+
+(defn preduce
+ "Returns the reduction of the realized elements of coll
+ using function f. Note f will not necessarily be called
+ consecutively, and so must be commutative. Also note that
+ (f base an-element) might be performed many times, i.e. base is not
+ an initial value as with sequential reduce."
+ [f base coll]
+ (. (par coll) (reduce (reducer f) base)))
+
+;;;;;;;;;;;;;;;;;;;;; collection-producing operations ;;;;;;;;;;;;;;;;;;;;;;
+
+(defn- pa-to-vec [pa]
+ (vec (. pa getArray)))
+
+(defn- pall
+ "Realizes a copy of the coll as a parallel array, with any bounds/filters/maps applied"
+ [coll]
+ (if (instance? ParallelArrayWithMapping coll)
+ (. coll all)
+ (par coll)))
+
+(defn pvec
+ "Returns the realized contents of the parallel array pa as a Clojure vector"
+ [pa] (pa-to-vec (pall pa)))
+
+(defn pdistinct
+ "Returns a parallel array of the distinct elements of coll"
+ [coll]
+ (pa-to-vec (. (pall coll) allUniqueElements)))
+
+;this doesn't work, passes null to reducer?
+(defn- pcumulate [coll f init]
+ (.. (pall coll) (precumulate (reducer f) init)))
+
+(defn psort
+ "Returns a new vector consisting of the realized items in coll, sorted,
+ presuming Comparable elements, unless a Comparator comp is supplied"
+ ([coll] (pa-to-vec (. (pall coll) sort)))
+ ([coll comp] (pa-to-vec (. (pall coll) sort comp))))
+
+(defn pfilter-nils
+ "Returns a vector containing the non-nil (realized) elements of coll"
+ [coll]
+ (pa-to-vec (. (pall coll) removeNulls)))
+
+(defn pfilter-dupes
+ "Returns a vector containing the (realized) elements of coll,
+ without any consecutive duplicates"
+ [coll]
+ (pa-to-vec (. (pall coll) removeConsecutiveDuplicates)))
+
+
+(comment
+(load-file "src/parallel.clj")
+(refer 'parallel)
+(pdistinct [1 2 3 2 1])
+;(pcumulate [1 2 3 2 1] + 0) ;broken, not exposed
+(def a (make-array Object 1000000))
+(dotimes i (count a)
+ (aset a i (rand-int i)))
+(time (reduce + 0 a))
+(time (preduce + 0 a))
+(time (count (distinct a)))
+(time (count (pdistinct a)))
+
+(preduce + 0 [1 2 3 2 1])
+(preduce + 0 (psort a))
+(pvec (par [11 2 3 2] :filter-index (fn [x i] (> i x))))
+(pvec (par [11 2 3 2] :filter-with [(fn [x y] (> y x)) [110 2 33 2]]))
+
+(psummary ;or pvec/pmax etc
+ (par [11 2 3 2]
+ :filter-with [(fn [x y] (> y x))
+ [110 2 33 2]]
+ :map #(* % 2)))
+
+(preduce + 0
+ (par [11 2 3 2]
+ :filter-with [< [110 2 33 2]]))
+
+(time (reduce + 0 (map #(* % %) (range 1000000))))
+(time (preduce + 0 (par (range 1000000) :map-index *)))
+(def v (range 1000000))
+(time (preduce + 0 (par v :map-index *)))
+(time (preduce + 0 (par v :map #(* % %))))
+(time (reduce + 0 (map #(* % %) v)))
+) \ No newline at end of file
diff --git a/src/clojure/proxy.clj b/src/clojure/proxy.clj
new file mode 100644
index 00000000..f72111a4
--- /dev/null
+++ b/src/clojure/proxy.clj
@@ -0,0 +1,307 @@
+; 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.
+
+(in-ns 'clojure)
+
+(import
+ '(clojure.asm ClassWriter ClassVisitor Opcodes Type)
+ '(java.lang.reflect Modifier Constructor)
+ '(clojure.asm.commons Method GeneratorAdapter)
+ '(clojure.lang IProxy Reflector DynamicClassLoader IPersistentMap PersistentHashMap RT))
+
+(def *proxy-classes* (ref {}))
+
+(defn method-sig [#^java.lang.reflect.Method meth]
+ [(. meth (getName)) (seq (. meth (getParameterTypes))) (. meth getReturnType)])
+
+(defn get-proxy-class
+ "Takes an optional single class followed by zero or more
+ interfaces. If not supplied class defaults to Object. Creates an
+ returns an instance of a proxy class derived from the supplied
+ classes. The resulting value is cached and used for any subsequent
+ requests for the same class set. Returns a Class object."
+ [& bases]
+ (let [bases (if (. (first bases) (isInterface))
+ (cons Object bases)
+ bases)
+ [super & interfaces] bases]
+ (or (get @*proxy-classes* bases)
+ (let [cv (new ClassWriter (. ClassWriter COMPUTE_MAXS))
+ cname (str "clojure/lang/" (gensym "Proxy__"))
+ ctype (. Type (getObjectType cname))
+ iname (fn [c] (.. Type (getType c) (getInternalName)))
+ fmap "__clojureFnMap"
+ totype (fn [c] (. Type (getType c)))
+ to-types (fn [cs] (if (pos? (count cs))
+ (into-array (map totype cs))
+ (make-array Type 0)))
+ super-type (totype super)
+ map-type (totype PersistentHashMap)
+ ifn-type (totype clojure.lang.IFn)
+ obj-type (totype Object)
+ sym-type (totype clojure.lang.Symbol)
+ rt-type (totype clojure.lang.RT)
+ ex-type (totype java.lang.UnsupportedOperationException)
+ gen-method
+ (fn [#^java.lang.reflect.Method meth else-gen]
+ (let [pclasses (. meth (getParameterTypes))
+ ptypes (to-types pclasses)
+ rtype (totype (. meth (getReturnType)))
+ m (new Method (. meth (getName)) rtype ptypes)
+ gen (new GeneratorAdapter (. Opcodes ACC_PUBLIC) m nil nil cv)
+ else-label (. gen (newLabel))
+ end-label (. gen (newLabel))
+ decl-type (. Type (getType (. meth (getDeclaringClass))))]
+ (. gen (visitCode))
+ (. gen (loadThis))
+ (. gen (getField ctype fmap map-type))
+ ;get symbol corresponding to name
+ (. gen (push (. meth (getName))))
+ (. gen (invokeStatic sym-type (. Method (getMethod "clojure.lang.Symbol create(String)"))))
+ ;lookup fn in map
+ (. gen (invokeStatic rt-type (. Method (getMethod "Object get(Object, Object)"))))
+ (. gen (dup))
+ (. gen (ifNull else-label))
+ ;if found
+ (. gen (loadThis))
+ ;box args
+ (dotimes i (count ptypes)
+ (. gen (loadArg i))
+ (. clojure.lang.Compiler$HostExpr (emitBoxReturn nil gen (nth pclasses i))))
+ ;call fn
+ (. gen (invokeInterface ifn-type (new Method "invoke" obj-type
+ (into-array (cons obj-type
+ (replicate (count ptypes) obj-type))))))
+ ;unbox return
+ (. gen (unbox rtype))
+ (when (= (. rtype (getSort)) (. Type VOID))
+ (. gen (pop)))
+ (. gen (goTo end-label))
+
+ ;else call supplied alternative generator
+ (. gen (mark else-label))
+ (. gen (pop))
+
+ (else-gen gen m)
+
+ (. gen (mark end-label))
+ (. gen (returnValue))
+ (. gen (endMethod))))]
+
+ ;start class definition
+ (. cv (visit (. Opcodes V1_5) (+ (. Opcodes ACC_PUBLIC) (. Opcodes ACC_SUPER))
+ cname nil (iname super)
+ (into-array (map iname (cons IProxy interfaces)))))
+ ;add field for fn mappings
+ (. cv (visitField (+ (. Opcodes ACC_PRIVATE) (. Opcodes ACC_VOLATILE))
+ fmap (. map-type (getDescriptor)) nil nil))
+ ;add ctors matching/calling super's
+ (doseq #^Constructor ctor (. super (getDeclaredConstructors))
+ (when-not (. Modifier (isPrivate (. ctor (getModifiers))))
+ (let [ptypes (to-types (. ctor (getParameterTypes)))
+ m (new Method "<init>" (. Type VOID_TYPE) ptypes)
+ gen (new GeneratorAdapter (. Opcodes ACC_PUBLIC) m nil nil cv)]
+ (. gen (visitCode))
+ ;call super ctor
+ (. gen (loadThis))
+ (. gen (dup))
+ (. gen (loadArgs))
+ (. gen (invokeConstructor super-type m))
+ ;init fmap
+ (. gen (getStatic map-type "EMPTY" map-type))
+ (. gen (putField ctype fmap map-type))
+
+ (. gen (returnValue))
+ (. gen (endMethod)))))
+ ;add IProxy methods
+ (let [m (. Method (getMethod "void __updateClojureFnMappings(clojure.lang.IPersistentMap)"))
+ gen (new GeneratorAdapter (. Opcodes ACC_PUBLIC) m nil nil cv)]
+ (. gen (visitCode))
+ (. gen (loadThis))
+ (. gen (dup))
+ (. gen (getField ctype fmap map-type))
+ (. gen (loadArgs))
+ (. gen (invokeInterface (totype clojure.lang.IPersistentCollection)
+ (. Method (getMethod "clojure.lang.IPersistentCollection cons(Object)"))))
+ (. gen (checkCast map-type))
+ (. gen (putField ctype fmap map-type))
+
+ (. gen (returnValue))
+ (. gen (endMethod)))
+ (let [m (. Method (getMethod "clojure.lang.IPersistentMap __getClojureFnMappings()"))
+ gen (new GeneratorAdapter (. Opcodes ACC_PUBLIC) m nil nil cv)]
+ (. gen (visitCode))
+ (. gen (loadThis))
+ (. gen (getField ctype fmap map-type))
+ (. gen (returnValue))
+ (. gen (endMethod)))
+
+ ;calc set of supers' non-private instance methods
+ (let [mm (loop [mm {} considered #{} c super]
+ (if c
+ (let [[mm considered]
+ (loop [mm mm
+ considered considered
+ meths (concat
+ (seq (. c (getDeclaredMethods)))
+ (seq (. c (getMethods))))]
+ (if meths
+ (let [#^java.lang.reflect.Method meth (first meths)
+ mods (. meth (getModifiers))
+ mk (method-sig meth)]
+ (if (or (considered mk)
+ (. Modifier (isPrivate mods))
+ (. Modifier (isStatic mods))
+ (. Modifier (isFinal mods))
+ (= "finalize" (.getName meth)))
+ (recur mm (conj considered mk) (rest meths))
+ (recur (assoc mm mk meth) (conj considered mk) (rest meths))))
+ [mm considered]))]
+ (recur mm considered (. c (getSuperclass))))
+ mm))]
+ ;add methods matching supers', if no mapping -> call super
+ (doseq #^java.lang.reflect.Method meth (vals mm)
+ (gen-method meth
+ (fn [gen m]
+ (. gen (loadThis))
+ ;push args
+ (. gen (loadArgs))
+ ;call super
+ (. gen (visitMethodInsn (. Opcodes INVOKESPECIAL)
+ (. super-type (getInternalName))
+ (. m (getName))
+ (. m (getDescriptor)))))))
+
+ ;add methods matching interfaces', if no mapping -> throw
+ (doseq #^Class iface interfaces
+ (doseq #^java.lang.reflect.Method meth (. iface (getMethods))
+ (when-not (contains? mm (method-sig meth))
+ (gen-method meth
+ (fn [gen m]
+ (. gen (throwException ex-type (. m (getName))))))))))
+
+ ;finish class def
+ (. cv (visitEnd))
+ ;generate, cache and return class object
+ (let [loader (. RT ROOT_CLASSLOADER)
+ c (. loader (defineClass (. cname (replace "/" "."))
+ (. cv (toByteArray))))]
+ (sync nil (commute *proxy-classes* assoc bases c))
+ c)))))
+
+(defn construct-proxy
+ "Takes a proxy class and any arguments for its superclass ctor and
+ creates and returns an instance of the proxy."
+ [c & ctor-args]
+ (. Reflector (invokeConstructor c (to-array ctor-args))))
+
+(defn update-proxy
+ "Takes a proxy instance and a map of symbols (whose names must
+ correspond to methods of the proxy superclass/superinterfaces) to
+ fns (which must take arguments matching the corresponding method,
+ plus an additional (explicit) first arg corresponding to this, and
+ updates (via assoc) the proxy's fn map. nil can be passed instead of
+ a fn, in which case the corresponding method will revert to the
+ default behavior. Note that this function can be used to update the
+ behavior of an existing instance without changing its identity."
+ [#^IProxy proxy mappings]
+ (. proxy (__updateClojureFnMappings mappings)))
+
+(defn proxy-mappings
+ "Takes a proxy instance and returns the proxy's fn map."
+ [#^IProxy proxy]
+ (. proxy (__getClojureFnMappings)))
+
+(defmacro proxy
+ "class-and-interfaces - a vector of class names
+
+ args - a (possibly empty) vector of arguments to the superclass
+ constructor.
+
+ f => (name [params*] body) or
+ (name ([params*] body) ([params+] body) ...)
+
+ Expands to code which creates a instance of a proxy class that
+ implements the named class/interface(s) by calling the supplied
+ fns. A single class, if provided, must be first. If not provided it
+ defaults to Object.
+
+ The interfaces names must be valid interface types. If a method fn
+ is not provided for a class method, the superclass methd will be
+ called. If a method fn is not provided for an interface method, an
+ UnsupportedOperationException will be thrown should it be
+ called. Method fns are closures and can capture the environment in
+ which proxy is called. Each method fn takes an additional implicit
+ first arg, which is bound to 'this. Note that while method fns can
+ be provided to override protected methods, they have no other access
+ to protected members, nor to super, as these capabilities cannot be
+ proxied."
+ [class-and-interfaces args & fs]
+ `(let [pc# (get-proxy-class ~@class-and-interfaces)
+ p# (construct-proxy pc# ~@args)]
+ (update-proxy p#
+ ~(loop [fmap {} fs fs]
+ (if fs
+ (let [[sym & meths] (first fs)
+ meths (if (vector? (first meths))
+ (list meths)
+ meths)
+ meths (map (fn [[params & body]]
+ (cons (apply vector 'this params) body))
+ meths)]
+ (recur (assoc fmap (list `quote (symbol (name sym))) (cons `fn meths)) (rest fs)))
+ fmap)))
+ p#))
+
+(defn proxy-call-with-super [call this meth]
+ (let [m (proxy-mappings this)]
+ (update-proxy this (assoc m meth nil))
+ (let [ret (call)]
+ (update-proxy this m)
+ ret)))
+
+(defmacro proxy-super
+ "Use to call a superclass method in the body of a proxy method.
+ Note, expansion captures 'this"
+ [meth & args]
+ `(proxy-call-with-super (fn [] (. ~'this ~meth ~@args)) ~'this '~(symbol (name meth))))
+
+(defn bean
+ "Takes a Java object and returns a read-only implementation of the
+ map abstraction based upon its JavaBean properties."
+ [#^Object x]
+ (let [c (. x (getClass))
+ pmap (reduce (fn [m #^java.beans.PropertyDescriptor pd]
+ (let [name (. pd (getName))
+ method (. pd (getReadMethod))]
+ (if (and method (zero? (alength (. method (getParameterTypes)))))
+ (assoc m (keyword name) (fn [] (. method (invoke x nil))))
+ m)))
+ {}
+ (seq (.. java.beans.Introspector
+ (getBeanInfo c)
+ (getPropertyDescriptors))))
+ v (fn [k] ((pmap k)))
+ snapshot (fn []
+ (reduce (fn [m e]
+ (assoc m (key e) ((val e))))
+ {} (seq pmap)))]
+ (proxy [clojure.lang.APersistentMap]
+ []
+ (containsKey [k] (contains? pmap k))
+ (entryAt [k] (when (contains? pmap k) (new clojure.lang.MapEntry k (v k))))
+ (valAt ([k] (v k))
+ ([k default] (if (contains? pmap k) (v k) default)))
+ (cons [m] (conj (snapshot) m))
+ (count [] (count pmap))
+ (assoc [k v] (assoc (snapshot) k v))
+ (without [k] (dissoc (snapshot) k))
+ (seq [] ((fn thisfn [pseq]
+ (when pseq
+ (lazy-cons (new clojure.lang.MapEntry (first pseq) (v (first pseq)))
+ (thisfn (rest pseq))))) (keys pmap))))))
diff --git a/src/clojure/set/set.clj b/src/clojure/set/set.clj
new file mode 100644
index 00000000..668de4b4
--- /dev/null
+++ b/src/clojure/set/set.clj
@@ -0,0 +1,116 @@
+; 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.
+
+(in-ns 'clojure.set)
+(clojure/refer 'clojure)
+
+(defn union
+ "Returns a set that is the union of the two sets."
+ [xset yset]
+ (reduce conj xset yset))
+
+(defn difference
+ "Returns a set that is xset without the elements of yset."
+ [xset yset]
+ (reduce disj xset yset))
+
+(defn intersection
+ "Returns a set of the elements present in both xset and yset."
+ [xset yset]
+ (difference xset (difference xset yset)))
+
+(defn select
+ "Returns a set of the elements for which pred is true"
+ [pred xset]
+ (reduce (fn [s k] (if (pred k) s (disj s k)))
+ xset xset))
+
+(defn project
+ "Returns a rel of the elements of xrel with only the keys in ks"
+ [xrel ks]
+ (set (map #(select-keys % ks) xrel)))
+
+(defn rename-keys
+ "Returns the map with the keys in kmap renamed to the vals in kmap"
+ [map kmap]
+ (reduce
+ (fn [m [old new]]
+ (if (not= old new)
+ (-> m (assoc new (m old)) (dissoc old))
+ m))
+ map kmap))
+
+(defn rename
+ "Returns a rel of the maps in xrel with the keys in kmap renamed to the vals in kmap"
+ [xrel kmap]
+ (set (map #(rename-keys % kmap) xrel)))
+
+(defn index
+ "Returns a map of the distinct values of ks in the xrel mapped to a
+ set of the maps in xrel with the corresponding values of ks."
+ [xrel ks]
+ (reduce
+ (fn [m x]
+ (let [ik (select-keys x ks)]
+ (assoc m ik (conj (get m ik #{}) x))))
+ {} xrel))
+
+(defn map-invert
+ "Returns the map with the vals mapped to the keys."
+ [m] (reduce (fn [m [k v]] (assoc m v k)) {} m))
+
+(defn join
+ "When passed 2 rels, returns the rel corresponding to the natural
+ join. When passed an additional keymap, joins on the corresponding
+ keys."
+ ([xrel yrel] ;natural join
+ (if (and (seq xrel) (seq yrel))
+ (let [ks (intersection (set (keys (first xrel))) (set (keys (first yrel))))
+ [r s] (if (<= (count xrel) (count yrel))
+ [xrel yrel]
+ [yrel xrel])
+ idx (index r ks)]
+ (reduce (fn [ret x]
+ (let [found (idx (select-keys x ks))]
+ (if found
+ (reduce #(conj %1 (merge %2 x)) ret found)
+ ret)))
+ #{} s))
+ #{}))
+ ([xrel yrel km] ;arbitrary key mapping
+ (let [[r s k] (if (<= (count xrel) (count yrel))
+ [xrel yrel (map-invert km)]
+ [yrel xrel km])
+ idx (index r (vals k))]
+ (reduce (fn [ret x]
+ (let [found (idx (rename-keys (select-keys x (keys k)) k))]
+ (if found
+ (reduce #(conj %1 (merge %2 x)) ret found)
+ ret)))
+ #{} s))))
+
+(comment
+(refer 'set)
+(def xs #{{:a 11 :b 1 :c 1 :d 4}
+ {:a 2 :b 12 :c 2 :d 6}
+ {:a 3 :b 3 :c 3 :d 8 :f 42}})
+
+(def ys #{{:a 11 :b 11 :c 11 :e 5}
+ {:a 12 :b 11 :c 12 :e 3}
+ {:a 3 :b 3 :c 3 :e 7 }})
+
+(join xs ys)
+(join xs (rename ys {:b :yb :c :yc}) {:a :a})
+
+(union #{:a :b :c} #{:c :d :e })
+(difference #{:a :b :c} #{:c :d :e})
+(intersection #{:a :b :c} #{:c :d :e})
+
+(index ys [:b])
+)
+
diff --git a/src/clojure/xml/xml.clj b/src/clojure/xml/xml.clj
new file mode 100644
index 00000000..55a8f140
--- /dev/null
+++ b/src/clojure/xml/xml.clj
@@ -0,0 +1,117 @@
+; 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.
+
+(in-ns 'clojure.xml)
+(clojure/refer 'clojure)
+
+(import '(org.xml.sax ContentHandler Attributes SAXException)
+ '(javax.xml.parsers SAXParser SAXParserFactory))
+
+(def *stack*)
+(def *current*)
+(def *state*) ; :element :chars :between
+(def *sb*)
+
+(defstruct element :tag :attrs :content)
+
+(def tag (accessor element :tag))
+(def attrs (accessor element :attrs))
+(def content (accessor element :content))
+
+(def content-handler
+ (let [push-content (fn [e c]
+ (assoc e :content (conj (or (:content e) []) c)))
+ push-chars (fn []
+ (when (and (= *state* :chars)
+ (some (complement #(. Character (isWhitespace %))) (str *sb*)))
+ (set! *current* (push-content *current* (str *sb*)))))]
+ (new clojure.lang.XMLHandler
+ (proxy [ContentHandler] []
+ (startElement [uri local-name q-name #^Attributes atts]
+ (let [attrs (fn [ret i]
+ (if (neg? i)
+ ret
+ (recur (assoc ret
+ (. clojure.lang.Keyword (intern (symbol (. atts (getQName i)))))
+ (. atts (getValue i)))
+ (dec i))))
+ e (struct element
+ (. clojure.lang.Keyword (intern (symbol q-name)))
+ (when (pos? (. atts (getLength)))
+ (attrs {} (dec (. atts (getLength))))))]
+ (push-chars)
+ (set! *stack* (conj *stack* *current*))
+ (set! *current* e)
+ (set! *state* :element))
+ nil)
+ (endElement [uri local-name q-name]
+ (push-chars)
+ (set! *current* (push-content (peek *stack*) *current*))
+ (set! *stack* (pop *stack*))
+ (set! *state* :between)
+ nil)
+ (characters [ch start length]
+ (when-not (= *state* :chars)
+ (set! *sb* (new StringBuilder)))
+ (let [#^StringBuilder sb *sb*]
+ (. sb (append ch start length))
+ (set! *state* :chars))
+ nil)
+ (setDocumentLocator [locator])
+ (startDocument [])
+ (endDocument [])
+ (startPrefixMapping [prefix uri])
+ (endPrefixMapping [prefix])
+ (ignorableWhitespace [ch start length])
+ (processingInstruction [target data])
+ (skippedEntity [name])
+ ))))
+
+(defn startparse-sax [s ch]
+ (.. SAXParserFactory (newInstance) (newSAXParser) (parse s ch)))
+
+(defn parse
+ "Parses and loads the source s, which can be a File, InputStream or
+ String naming a URI. Returns a tree of the xml/element struct-map,
+ which has the keys :tag, :attrs, and :content. and accessor fns tag,
+ attrs, and content. Other parsers can be supplied by passing
+ startparse, a fn taking a source and a ContentHandler and returning
+ a parser"
+ ([s] (parse s startparse-sax))
+ ([s startparse]
+ (binding [*stack* nil
+ *current* (struct element)
+ *state* :between
+ *sb* nil]
+ (startparse s content-handler)
+ ((:content *current*) 0))))
+
+(defn emit-element [e]
+ (if (instance? String e)
+ (println e)
+ (do
+ (print (str "<" (name (:tag e))))
+ (when (:attrs e)
+ (doseq attr (:attrs e)
+ (print (str " " (name (key attr)) "='" (val attr)"'"))))
+ (if (:content e)
+ (do
+ (println ">")
+ (doseq c (:content e)
+ (emit-element c))
+ (println (str "</" (name (:tag e)) ">")))
+ (println "/>")))))
+
+(defn emit [x]
+ (println "<?xml version='1.0' encoding='UTF-8'?>")
+ (emit-element x))
+
+;(export '(tag attrs content parse element emit emit-element))
+
+;(load-file "/Users/rich/dev/clojure/src/xml.clj")
+;(def x (xml/parse "http://arstechnica.com/journals.rssx"))
diff --git a/src/clojure/zip/zip.clj b/src/clojure/zip/zip.clj
new file mode 100644
index 00000000..40c765e5
--- /dev/null
+++ b/src/clojure/zip/zip.clj
@@ -0,0 +1,248 @@
+; 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.
+
+;functional hierarchical zipper, with navigation, editing and enumeration
+;see Huet
+
+(in-ns 'clojure.zip)
+(clojure/refer 'clojure :exclude '(replace))
+
+(defn zipper
+ "Creates a new zipper structure.
+
+ branch? is a fn that, given a node, returns true if can have
+ children, even if it currently doesn't.
+
+ children is a fn that, given a branch node, returns a seq of its
+ children.
+
+ make-node is a fn that, given an existing node and a seq of
+ children, returns a new branch node with the supplied children.
+ root is the root node."
+ [branch? children make-node root]
+ #^{:zip/branch? branch? :zip/children children :zip/make-node make-node}
+ [root nil])
+
+(defn seq-zip
+ "Returns a zipper for nested sequences, given a root sequence"
+ [root]
+ (zipper seq? identity (fn [node children] children) root))
+
+(defn vector-zip
+ "Returns a zipper for nested vectors, given a root vector"
+ [root]
+ (zipper vector? seq (fn [node children] (apply vector children)) root))
+
+(defn xml-zip
+ "Returns a zipper for xml elements (as from xml/parse),
+ given a root element"
+ [root]
+ (zipper (complement string?)
+ (comp seq :content)
+ (fn [node children]
+ (assoc node :content (and children (apply vector children))))
+ root))
+
+(defn node
+ "Returns the node at loc"
+ [loc] (loc 0))
+
+(defn branch?
+ "Returns true if the node at loc is a branch"
+ [loc]
+ ((:zip/branch? ^loc) (node loc)))
+
+(defn children
+ "Returns a seq of the children of node at loc, which must be a branch"
+ [loc]
+ ((:zip/children ^loc) (node loc)))
+
+(defn make-node
+ "Returns a new branch node, given an existing node and new
+ children. The loc is only used to supply the constructor."
+ [loc node children]
+ ((:zip/make-node ^loc) node children))
+
+(defn path
+ "Returns a seq of nodes leading to this loc"
+ [loc]
+ (:pnodes (loc 1)))
+
+(defn lefts
+ "Returns a seq of the left siblings of this loc"
+ [loc]
+ (seq (:l (loc 1))))
+
+(defn rights
+ "Returns a seq of the right siblings of this loc"
+ [loc]
+ (:r (loc 1)))
+
+
+(defn down
+ "Returns the loc of the leftmost child of the node at this loc, or
+ nil if no children"
+ [loc]
+ (let [[node path] loc
+ [c & crest :as cs] (children loc)]
+ (when cs
+ (with-meta [c {:l []
+ :pnodes (if path (conj (:pnodes path) node) [node])
+ :ppath path
+ :r crest}] ^loc))))
+
+(defn up
+ "Returns the loc of the parent of the node at this loc, or nil if at
+ the top"
+ [loc]
+ (let [[node {l :l, ppath :ppath, pnodes :pnodes r :r, changed? :changed?, :as path}] loc]
+ (when path
+ (let [pnode (peek pnodes)]
+ (with-meta (if changed?
+ [(make-node loc pnode (concat l (cons node r)))
+ (and ppath (assoc ppath :changed? true))]
+ [pnode ppath])
+ ^loc)))))
+
+(defn root
+ "zips all the way up and returns the root node, reflecting any
+ changes."
+ [loc]
+ (if (= :end (loc 1))
+ (node loc)
+ (let [p (up loc)]
+ (if p
+ (recur p)
+ (node loc)))))
+
+(defn right
+ "Returns the loc of the right sibling of the node at this loc, or nil"
+ [loc]
+ (let [[node {l :l [r & rrest :as rs] :r :as path}] loc]
+ (when (and path rs)
+ (with-meta [r (assoc path :l (conj l node) :r rrest)] ^loc))))
+
+(defn left
+ "Returns the loc of the left sibling of the node at this loc, or nil"
+ [loc]
+ (let [[node {l :l r :r :as path}] loc]
+ (when (and path (seq l))
+ (with-meta [(peek l) (assoc path :l (pop l) :r (cons node r))] ^loc))))
+
+(defn insert-left
+ "Inserts the item as the left sibling of the node at this loc,
+ without moving"
+ [loc item]
+ (let [[node {l :l :as path}] loc]
+ (if (nil? path)
+ (throw (new Exception "Insert at top"))
+ (with-meta [node (assoc path :l (conj l item) :changed? true)] ^loc))))
+
+(defn insert-right
+ "Inserts the item as the right sibling of the node at this loc,
+ without moving"
+ [loc item]
+ (let [[node {r :r :as path}] loc]
+ (if (nil? path)
+ (throw (new Exception "Insert at top"))
+ (with-meta [node (assoc path :r (cons item r) :changed? true)] ^loc))))
+
+(defn replace
+ "Replaces the node at this loc, without moving"
+ [loc node]
+ (let [[_ path] loc]
+ (with-meta [node (assoc path :changed? true)] ^loc)))
+
+(defn edit
+ "Replaces the node at this loc with the value of (f node args)"
+ [loc f & args]
+ (replace loc (apply f (node loc) args)))
+
+(defn insert-child
+ "Inserts the item as the leftmost child of the node at this loc,
+ without moving"
+ [loc item]
+ (replace loc (make-node loc (node loc) (cons item (children loc)))))
+
+(defn append-child
+ "Inserts the item as the rightmost child of the node at this loc,
+ without moving"
+ [loc item]
+ (replace loc (make-node loc (node loc) (concat (children loc) [item]))))
+
+(defn next
+ "Moves to the next loc in the hierarchy, depth-first. When reaching
+ the end, returns a distinguished loc detectable via end?. If already
+ at the end, stays there."
+ [loc]
+ (if (= :end (loc 1))
+ loc
+ (or
+ (and (branch? loc) (down loc))
+ (right loc)
+ (loop [p loc]
+ (if (up p)
+ (or (right (up p)) (recur (up p)))
+ [(node p) :end])))))
+
+(defn end?
+ "Returns true if loc represents the end of a depth-first walk"
+ [loc]
+ (= :end (loc 1)))
+
+(defn remove
+ "Removes the node at loc, returning the loc that would have preceded
+ it in a depth-first walk."
+ [loc]
+ (let [[node {l :l, ppath :ppath, pnodes :pnodes, rs :r, :as path}] loc]
+ (if (nil? path)
+ (throw (new Exception "Remove at top"))
+ (if (pos? (count l))
+ (with-meta [(peek l) (assoc path :l (pop l) :changed? true)] ^loc)
+ (with-meta [(make-node loc (peek pnodes) rs)
+ (and ppath (assoc ppath :changed? true))]
+ ^loc)))))
+
+(comment
+
+(load-file "/Users/rich/dev/clojure/src/zip.clj")
+(refer 'zip)
+(def data '[[a * b] + [c * d]])
+(def dz (vector-zip data))
+
+(right (down (right (right (down dz)))))
+(lefts (right (down (right (right (down dz))))))
+(rights (right (down (right (right (down dz))))))
+(up (up (right (down (right (right (down dz)))))))
+(path (right (down (right (right (down dz))))))
+
+(-> dz down right right down right)
+(-> dz down right right down right (replace '/) root)
+(-> dz next next (edit str) next next next (replace '/) root)
+(-> dz next next next next next next next next next remove root)
+(-> dz next next next next next next next next next remove (insert-right 'e) root)
+(-> dz next next next next next next next next next remove up (append-child 'e) root)
+
+(end? (-> dz next next next next next next next next next remove next))
+
+(-> dz next remove next remove root)
+
+(loop [loc dz]
+ (if (end? loc)
+ (root loc)
+ (recur (next (if (= '* (node loc))
+ (replace loc '/)
+ loc)))))
+
+(loop [loc dz]
+ (if (end? loc)
+ (root loc)
+ (recur (next (if (= '* (node loc))
+ (remove loc)
+ loc)))))
+)
diff --git a/src/jvm/clojure/lang/Compiler.java b/src/jvm/clojure/lang/Compiler.java
index 7bacaecb..700116c3 100644
--- a/src/jvm/clojure/lang/Compiler.java
+++ b/src/jvm/clojure/lang/Compiler.java
@@ -2286,7 +2286,7 @@ static class IfExpr implements Expr{
static final public IPersistentMap CHAR_MAP =
PersistentHashMap.create('-', "_",
- '.', "_DOT_",
+// '.', "_DOT_",
':', "_COLON_",
'+', "_PLUS_",
'>', "_GT_",
@@ -2683,7 +2683,8 @@ static public class FnExpr implements Expr{
//fn.thisName = name;
String basename = enclosingMethod != null ?
(enclosingMethod.fn.name + "$")
- : "clojure.fns." + (munge(currentNS().name.name) + ".");
+ : //"clojure.fns." +
+ (munge(currentNS().name.name) + ".");
if(RT.second(form) instanceof Symbol)
name = ((Symbol) RT.second(form)).name;
fn.simpleName = ((name != null ?
@@ -3827,9 +3828,11 @@ public static Object eval(Object form) throws Exception{
}
try
{
- if(form instanceof IPersistentCollection)
+ if(form instanceof IPersistentCollection
+ && !(RT.first(form) instanceof Symbol
+ && ((Symbol)RT.first(form)).name.startsWith("def")))
{
- FnExpr fexpr = (FnExpr) analyze(C.EXPRESSION, RT.list(FN, PersistentVector.EMPTY, form), "repl");
+ FnExpr fexpr = (FnExpr) analyze(C.EXPRESSION, RT.list(FN, PersistentVector.EMPTY, form), "eval");
IFn fn = (IFn) fexpr.eval();
return fn.invoke();
}
diff --git a/src/jvm/clojure/lang/RT.java b/src/jvm/clojure/lang/RT.java
index cba00ec0..23261e75 100644
--- a/src/jvm/clojure/lang/RT.java
+++ b/src/jvm/clojure/lang/RT.java
@@ -289,11 +289,12 @@ static public void init() throws Exception{
}
static void doInit() throws Exception{
- loadResourceScript(RT.class, "boot.clj");
- loadResourceScript(RT.class, "proxy.clj");
- loadResourceScript(RT.class, "zip.clj");
- loadResourceScript(RT.class, "xml.clj");
- loadResourceScript(RT.class, "set.clj");
+ loadResourceScript(RT.class, "clojure/boot.clj");
+ loadResourceScript(RT.class, "clojure/proxy.clj");
+ loadResourceScript(RT.class, "clojure/genclass.clj");
+ loadResourceScript(RT.class, "clojure/zip/zip.clj");
+ loadResourceScript(RT.class, "clojure/xml/xml.clj");
+ loadResourceScript(RT.class, "clojure/set/set.clj");
Var.pushThreadBindings(
RT.map(CURRENT_NS, CURRENT_NS.get(),
diff --git a/src/jvm/clojure/lang/Reflector.java b/src/jvm/clojure/lang/Reflector.java
index da9edf5f..d5b14edc 100644
--- a/src/jvm/clojure/lang/Reflector.java
+++ b/src/jvm/clojure/lang/Reflector.java
@@ -36,7 +36,7 @@ public static Object invokeInstanceMethod(Object target, String methodName, Obje
}
static Object invokeMatchingMethod(String methodName, List methods, Object target, Object[] args)
- throws IllegalAccessException, InvocationTargetException, NoSuchMethodException{
+ throws Exception{
Method m = null;
Object[] boxedArgs = null;
if(methods.isEmpty())
@@ -77,7 +77,16 @@ static Object invokeMatchingMethod(String methodName, List methods, Object targe
}
if(m == null)
throw new IllegalArgumentException("No matching method found: " + methodName);
+ try{
return prepRet(m.getReturnType(), m.invoke(target, boxedArgs));
+ }
+ catch(InvocationTargetException e)
+ {
+ if(e.getCause() instanceof Exception)
+ throw (Exception) e.getCause();
+ throw e;
+ }
+
}
public static Method getAsMethodOfPublicBase(Class c, Method m){