diff options
author | Rich Hickey <richhickey@gmail.com> | 2008-02-16 03:23:08 +0000 |
---|---|---|
committer | Rich Hickey <richhickey@gmail.com> | 2008-02-16 03:23:08 +0000 |
commit | 30675ba730f58f0ba5b5e66485caa862d0ee8cfd (patch) | |
tree | cce9ef8ca1b6db87c6e6b29941f25e6750a06d1a /src | |
parent | 64ab2668075a2ccf082501853348316c17580e7d (diff) |
more docs, doc macro
Diffstat (limited to 'src')
-rw-r--r-- | src/boot.clj | 436 |
1 files changed, 341 insertions, 95 deletions
diff --git a/src/boot.clj b/src/boot.clj index 6f3ebe33..a1d65834 100644 --- a/src/boot.clj +++ b/src/boot.clj @@ -8,7 +8,10 @@ (in-ns 'clojure) -(def #^{:arglists '([& args])} list (. clojure.lang.PersistentList creator)) +(def #^{:arglists '([& args]) +:doc "Creates a new list containing the items."} +list (. clojure.lang.PersistentList creator)) + (def #^{:arglists '([x seq])} cons (fn* [x seq] (. clojure.lang.RT (cons x seq)))) ;during bootstrap we don't have destructuring let or fn, will redefine later @@ -18,12 +21,24 @@ (def #^{:macro true} fn (fn* [& decl] (cons 'fn* decl))) -(def #^{:arglists '([coll x])} conj (fn [coll x] (. clojure.lang.RT (conj coll x)))) +(def #^{:arglists '([coll x]) +:doc "conj[oin]. Returns a new collection with the item 'added'. (conj nil item) returns (item). +The 'addition' may happen at different 'places' depending on the concrete type."} +conj (fn [coll x] (. clojure.lang.RT (conj coll x)))) + (def #^{:arglists '([x])} first (fn [x] (. clojure.lang.RT (first x)))) (def #^{:arglists '([x])} rest (fn [x] (. clojure.lang.RT (rest x)))) -(def #^{:arglists '([coll])} seq (fn [coll] (. clojure.lang.RT (seq coll)))) + +(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."} +seq (fn [coll] (. clojure.lang.RT (seq coll)))) + (def #^{:arglists '([#^Class c x])} instance? (fn [#^Class c x] (. c (isInstance x)))) -(def #^{:arglists '([x])} seq? (fn [x] (instance? clojure.lang.ISeq x))) + +(def #^{:arglists '([x]) +:doc "Return true if x implements ISeq"} +seq? (fn [x] (instance? clojure.lang.ISeq x))) (def #^{:private true} sigs (fn [fdecl] @@ -33,7 +48,12 @@ (recur (conj ret (first (first fdecl))) (rest fdecl)) (seq ret))) (list (first fdecl))))) -(def #^{:arglists '([map key val])} assoc (fn [map key val] (. clojure.lang.RT (assoc map key val)))) + +(def #^{:arglists '([map key val]) +:doc "assoc[iate]. When applied to a map, returns a new map of the same (hashed/sorted) type, +that contains the mapping of key to val. when applied to a vector, returns a new vector that contains val at index. +Note - index must be <= (count vector)."} +assoc (fn [map key val] (. clojure.lang.RT (assoc map key val)))) ;;;;;;;;;;;;;;;;; metadata ;;;;;;;;;;;;;;;;;;;;;;;;;;; (def #^{:arglists '([x])} meta (fn [x] @@ -44,14 +64,18 @@ (. x (withMeta m)))) -(def defn (fn [name & fdecl] +(def +#^{:doc "Same as (def name (fn [params* ] exprs*)) or (def name (fn ([params* ] exprs*)+))"} +defn (fn [name & fdecl] (list 'def (with-meta name (assoc (meta name) :arglists (list 'quote (sigs fdecl)))) (cons `fn (cons name fdecl))))) (. (var defn) (setMacro)) -(defn vector +(defn +#^{:doc "Creates a new vector containing the args."} +vector ([] []) ([& args] (. clojure.lang.PersistentVector (create args)))) @@ -72,7 +96,10 @@ ;;;;;;;;;;;;;;;;;;;; -(def defmacro (fn [name & args] +(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."} +defmacro (fn [name & args] (list 'do (cons `defn (cons name args)) (list '. (list 'var name) '(setMacro))))) @@ -84,16 +111,28 @@ when [test & body] (list 'if test (cons 'do body))) -(defmacro when-not [test & body] +(defmacro +#^{:doc "Evaluates test. If logical false, evaluates body in an implicit do."} +when-not [test & body] (list 'if test nil (cons 'do body))) -(defn #^Boolean nil? [x] (identical? x nil)) -(defn #^Boolean false? [x] (identical? x false)) -(defn #^Boolean true? [x] (identical? x true)) +(defn +#^{:tag Boolean :doc "Returns true if x is nil, false otherwise."} +nil? [x] (identical? x nil)) + +(defn +#^{:tag Boolean :doc "Returns true if x is the value false, false otherwise."} +false? [x] (identical? x false)) + +(defn +#^{:tag Boolean :doc "Returns true if x is the value true, false otherwise."} +true? [x] (identical? x true)) -(defn not [x] (if x false true)) +(defn +#^{:tag Boolean :doc "Returns true if x is logical false, false otherwise."} +not [x] (if x false true)) (defn second [x] (. clojure.lang.RT (second x))) @@ -103,10 +142,23 @@ when [test & body] (defn frest [x] (first (rest x))) (defn rrest [x] (rest (rest x))) -(defn #^Boolean = [x y] (. clojure.lang.RT (equal x y))) -(defn #^Boolean not= [x y] (not (= x y))) +(defn +#^{:tag Boolean + :doc "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."} += [x y] (. clojure.lang.RT (equal x y))) + +(defn +#^{:tag Boolean + :doc "Same as (not (= obj1 obj2))"} +not= [x y] (not (= x y))) -(defn #^String str +(defn +#^{:tag String + :doc "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."} +str ([] "") ([#^Object x] (if x (. x (toString)) "")) @@ -116,19 +168,31 @@ when [test & body] (recur (. sb (append (str (first more)))) (rest more)) (str sb))))) -(defn symbol +(defn +#^{:doc "Returns a Symbol with the given namespace and name."} +symbol ([name] (. clojure.lang.Symbol (intern name))) ([ns name] (. clojure.lang.Symbol (intern ns name)))) -(defn keyword +(defn +#^{:doc "Returns a Keyword with the given namespace and name. +Do not use : in the keyword strings, it will be added automatically."} +keyword ([name] (. clojure.lang.Keyword (intern nil name))) ([ns name] (. clojure.lang.Keyword (intern ns name)))) -(defn gensym +(defn +#^{:doc "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 ([] (gensym "G__")) ([prefix-string] (. clojure.lang.Symbol (intern (str prefix-string (str (. clojure.lang.RT (nextID)))))))) -(defmacro cond [& clauses] +(defmacro +#^{:doc "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."} +cond [& clauses] (when clauses (list 'if (first clauses) (second clauses) @@ -140,11 +204,15 @@ when [test & body] (nil? (rest arglist)) (seq (first arglist)) :else (cons (first arglist) (spread (rest arglist))))) -(defn apply [#^clojure.lang.IFn f & args] +(defn +#^{:doc "Applies fn f to the argument list formed by prepending args to argseq."} +apply [#^clojure.lang.IFn f & args] (. f (applyTo (spread args)))) -(defn list* [arg & args] - (spread (cons arg args))) +(defn +#^{:doc "Creates a new list containing the item prepended to more."} +list* [item & more] + (spread (cons item more))) (defmacro delay [& body] (list 'new 'clojure.lang.Delay (list* `fn [] body))) @@ -205,33 +273,44 @@ or (reduce conj nil coll)) ;;math stuff -(defn + +(defn +#^{:doc "Returns the sum of nums. (+) returns 0."} ++ ([] 0) ([x] x) ([x y] (. clojure.lang.Num (add x y))) ([x y & more] (reduce + (+ x y) more))) -(defn * +(defn +#^{:doc "Returns the product of nums. (*) returns 1."} +* ([] 1) ([x] x) ([x y] (. clojure.lang.Num (multiply x y))) ([x y & more] (reduce * (* x y) more))) -(defn / +(defn +#^{:doc "If no denominators are supplied, returns 1/numerator, +else returns numerator divided by all of the denominators."} +/ ([x] (/ 1 x)) ([x y] (. clojure.lang.Num (divide x y))) ([x y & more] (reduce / (/ x y) more))) -(defn - +(defn +#^{:doc "If no ys are supplied, returns the negation of x, else subtracts the ys from x and returns the result."} +- ([x] (. clojure.lang.Num (negate x))) ([x y] (. clojure.lang.Num (subtract x y))) ([x y & more] (reduce - (- x y) more))) -(defn < +(defn +#^{:doc "Returns non-nil if nums are in monotonically increasing order, otherwise nil."} +< ([x] true) ([x y] (. clojure.lang.Num (lt x y))) ([x y & more] @@ -240,7 +319,9 @@ or (recur y (first more) (rest more)) (< y (first more)))))) -(defn <= +(defn +#^{:doc "Returns non-nil if nums are in monotonically non-decreasing order, otherwise nil."} +<= ([x] true) ([x y] (. clojure.lang.Num (lte x y))) ([x y & more] @@ -249,7 +330,9 @@ or (recur y (first more) (rest more)) (<= y (first more)))))) -(defn > +(defn +#^{:doc "Returns non-nil if nums are in monotonically decreasing order, otherwise nil."} +> ([x] true) ([x y] (. clojure.lang.Num (gt x y))) ([x y & more] @@ -258,7 +341,9 @@ or (recur y (first more) (rest more)) (> y (first more)))))) -(defn >= +(defn +#^{:doc "Returns non-nil if nums are in monotonically non-increasing order, otherwise nil."} +>= ([x] true) ([x y] (. clojure.lang.Num (gte x y))) ([x y & more] @@ -267,7 +352,9 @@ or (recur y (first more) (rest more)) (>= y (first more)))))) -(defn == +(defn +#^{:doc "Returns non-nil if nums all have the same value, otherwise nil"} +== ([x] true) ([x y] (. clojure.lang.Num (equiv x y))) ([x y & more] @@ -276,37 +363,58 @@ or (recur y (first more) (rest more)) (== y (first more)))))) -(defn max +(defn +#^{:doc "Returns the greatest of the nums."} +max ([x] x) ([x y] (if (> x y) x y)) ([x y & more] (reduce max (max x y) more))) -(defn min +(defn +#^{:doc "Returns the least of the nums."} +min ([x] x) ([x y] (if (< x y) x y)) ([x y & more] (reduce min (min x y) more))) -(defn inc [x] +(defn +#^{:doc "Returns a number one greater than num."} +inc [x] (. clojure.lang.Num (inc x))) -(defn dec [x] +(defn +#^{:doc "Returns a number one less than num."} +dec [x] (. clojure.lang.Num (dec x))) -(defn #^Boolean pos? [x] +(defn +#^{:tag Boolean +:doc "Returns true if num is greater than zero, else false"} +pos? [x] (. clojure.lang.Num (posPred x))) -(defn #^Boolean neg? [x] +(defn +#^{:tag Boolean +:doc "Returns true if num is less than zero, else false"} +neg? [x] (. clojure.lang.Num (negPred x))) -(defn #^Boolean zero? [x] +(defn +#^{:tag Boolean +:doc "Returns true if num is zero, else false"} +zero? [x] (. clojure.lang.Num (zeroPred x))) -(defn quot [num div] +(defn +#^{:doc "quot[ient] of dividing numerator by denominator."} +quot [num div] (. clojure.lang.Num (quotient num div))) -(defn rem [num div] +(defn +#^{:doc "rem[ainder] of dividing numerator by denominator."} +rem [num div] (. clojure.lang.Num (remainder num div))) ;;Bit ops @@ -329,27 +437,42 @@ or (defn bit-not [x] (. clojure.lang.IntegerNum (bitNot x))) -(defn complement [f] +(defn +#^{:doc "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."} +complement [f] (fn [& args] (not (apply f args)))) -(defn constantly [x] +(defn +#^{:doc "Returns a function that takes any number of arguments and returns x."} +constantly [x] (fn [& args] x)) -(defn identity [x] x) +(defn +#^{:doc "Returns its argument."} +identity [x] x) ;;Collection stuff -(defn count [coll] +(defn +#^{:doc "Returns the number of items in the collection. (count nil) returns 0. +Also works on strings, arrays, and Java Collections and Maps"} +count [coll] (. clojure.lang.RT (count coll))) ;;list stuff -(defn peek [list] +(defn +#^{:doc "Same as first. Returns the first item in the list. If the list is empty, returns nil."} +peek [list] (. clojure.lang.RT (peek list))) -(defn pop [list] +(defn +#^{:doc "Returns a new list without the first item. If the list is empty, throws an exception. +Note - not the same as rest."} +pop [list] (. clojure.lang.RT (pop list))) (defn nth [coll index] @@ -357,10 +480,14 @@ or ;;map stuff -(defn contains? [map key] +(defn +#^{:doc "Returns true if key is present, else false."} +contains? [map key] (. clojure.lang.RT (contains map key))) -(defn get +(defn +#^{:doc "Returns the value mapped to key, not-found or nil if key not present."} +get ([map key] (. clojure.lang.RT (get map key))) ([map key not-found] @@ -368,13 +495,19 @@ or -(defn dissoc [map key] +(defn +#^{:doc "dissoc[iate]. Returns a new map of the same (hashed/sorted) type, that does not contain a mapping for key."} +dissoc [map key] (. clojure.lang.RT (dissoc map key))) -(defn find [map key] +(defn +#^{:doc "Returns the map entry for key, or nil if key not present."} +find [map key] (. clojure.lang.RT (find map key))) -(defn select [map keyseq] +(defn +#^{:doc "Returns a map containing only those entries in map whose key is in keys"} +select [map keyseq] (loop [ret {} keys (seq keyseq)] (if keys (let [entry (. clojure.lang.RT (find map (first keys)))] @@ -385,16 +518,24 @@ or (rest keys))) ret))) -(defn keys [map] +(defn +#^{:doc "Returns a sequence of the map's keys."} +keys [map] (. clojure.lang.RT (keys map))) -(defn vals [map] +(defn +#^{:doc "Returns a sequence of the map's values."} +vals [map] (. clojure.lang.RT (vals map))) -(defn key [#^java.util.Map$Entry e] +(defn +#^{:doc "Returns the key of the map entry."} +key [#^java.util.Map$Entry e] (. e (getKey))) -(defn val [#^java.util.Map$Entry e] +(defn +#^{:doc "Returns the value in the map entry."} +val [#^java.util.Map$Entry e] (. e (getValue))) (defn rseq [#^clojure.lang.Reversible rev] @@ -417,7 +558,10 @@ or (or (first args) (recur (rest args))))) -(defmacro locking [x & body] +(defmacro +#^{:doc "Executes exprs in an implicit do, while holding the monitor of x. +Will release the monitor of x in all circumstances."} +locking [x & body] `(let [lockee# ~x] (try (monitor-enter lockee#) @@ -429,7 +573,10 @@ or ([x form] `(. ~x ~form)) ([x form & more] `(.. (. ~x ~form) ~@more))) -(defmacro -> +(defmacro +#^{:doc "Macro. Threads the expr through the forms. Inserts expr as the second item in the first form. +If there are more forms, inserts the first form as the second item in second form, etc."} +-> ([x form] `(~(first form) ~x ~@(rest form))) ([x form & more] `(-> (-> ~x ~form) ~@more))) @@ -509,7 +656,11 @@ or ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; fn stuff ;;;;;;;;;;;;;;;; -(defn comp [& fs] +(defn +#^{:doc "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."} +comp [& fs] (let [fs (reverse fs)] (fn [& args] (loop [ret (apply (first fs) args) fs (rest fs)] @@ -517,7 +668,10 @@ or (recur ((first fs) ret) (rest fs)) ret))))) -(defn partial +(defn +#^{:doc "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."} +partial ([f arg1] (fn [& args] (apply f arg1 args))) ([f arg1 arg2] @@ -610,10 +764,17 @@ or ([start end step] (take-while (partial (if (pos? step) > <) end) (iterate (partial + step) start)))) -(defn merge [& maps] +(defn +#^{:doc "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."} +merge [& maps] (reduce conj maps)) -(defn merge-with [f & maps] +(defn +#^{:doc "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)."} +merge-with [f & maps] (let [merge-entry (fn [m e] (let [k (key e) v (val e)] (if (contains? m k) @@ -635,12 +796,16 @@ or (rest vs)) map))) -(defn line-seq [#^java.io.BufferedReader rdr] +(defn +#^{:doc "Returns the lines of text from rdr as a lazy sequence of strings. rdr must implement java.io.BufferedReader."} +line-seq [#^java.io.BufferedReader rdr] (let [line (. rdr (readLine))] (when line (lazy-cons line (line-seq rdr))))) -(defn comparator [pred] +(defn +#^{:doc "Returns an implementation of java.util.Comparator based upon pred."} +comparator [pred] (fn [x y] (cond (pred x y) -1 (pred y x) 1 :else 0))) (defn sort @@ -708,7 +873,9 @@ eval [form] (! agent count-down)) (. latch (await timeout-ms (. java.util.concurrent.TimeUnit MILLISECONDS))))) -(defmacro dotimes [i n & body] +(defmacro +#^{:doc "Repeatedly executes body (presumably for side-effects) with name bound to integers from 0 through n-1."} +dotimes [i n & body] `(loop [~i 0 n# ~n] (when (< ~i n#) ~@body @@ -751,7 +918,11 @@ eval [form] (rest fs)) fmap)))) -(defn pr +(defn +#^{:doc "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"} +pr ([] nil) ([x] (. clojure.lang.RT (print x *out*)) @@ -765,15 +936,22 @@ eval [form] (. *out* (append \newline)) nil) -(defn prn [& more] +(defn +#^{:doc "Same as pr followed by (newline)"} +prn [& more] (apply pr more) (newline)) -(defn print [& more] +(defn +#^{:doc "Prints the object(s) to the output stream that is the current value of *out*. + print and println produce output for human consumption."} +print [& more] (binding [*print-readably* nil] (apply pr more))) -(defn println [& more] +(defn +#^{:doc "Same as print followed by (newline)"} +println [& more] (binding [*print-readably* nil] (apply prn more))) @@ -810,7 +988,9 @@ read `(fn [target# ~@args] (. target# (~name ~@args)))) -(defmacro time [expr] +(defmacro +#^{:doc "Evaluates expr and prints the time it took. Returns the value of expr."} +time [expr] `(let [start# (. System (nanoTime)) ret# ~expr] (prn (str "Elapsed time: " (/ (- (. System (nanoTime)) start#) 1000000.0) " msecs")) @@ -936,32 +1116,52 @@ read (this (map rest collseq)))))] (encl-fn (cons coll colls)))))) -(defn macroexpand-1 [form] +(defn +#^{:doc "If form represents a macro form, returns its expansion, else returns form."} +macroexpand-1 [form] (let [v (. clojure.lang.Compiler (isMacro (first form)))] (if v (apply @v (rest form)) form))) -(defn macroexpand [form] +(defn +#^{:doc "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."} +macroexpand [form] (let [ex (macroexpand-1 form) v (. clojure.lang.Compiler (isMacro (first ex)))] (if v (macroexpand ex) ex))) -(defn create-struct [& keys] +(defn +#^{:doc "Returns a structure basis object."} +create-struct [& keys] (. clojure.lang.PersistentStructMap (createSlotMap keys))) -(defmacro defstruct [name & keys] +(defmacro +#^{:doc "Same as (def name (create-struct keys...))"} +defstruct [name & keys] `(def ~name (create-struct ~@keys))) -(defn struct-map [s & inits] +(defn +#^{:doc "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."} +struct-map [s & inits] (. clojure.lang.PersistentStructMap (create s inits))) -(defn struct [s & vals] +(defn +#^{:doc "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."} +struct [s & vals] (. clojure.lang.PersistentStructMap (construct s vals))) -(defn accessor [s key] +(defn +#^{:doc "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."} +accessor [s key] (. clojure.lang.PersistentStructMap (getAccessor s key))) (defn subvec @@ -1092,9 +1292,11 @@ load [rdr] (defn resolve [sym] (ns-resolve *ns* sym)) -(defn array-map +(defn +#^{:doc "Constructs an array-map."} +array-map ([] (. clojure.lang.PersistentArrayMap EMPTY)) - ([& args] (new clojure.lang.PersistentArrayMap (to-array args)))) + ([& keyvals] (new clojure.lang.PersistentArrayMap (to-array keyvals)))) (defn nthrest [coll n] (loop [n n xs (seq coll)] @@ -1102,22 +1304,31 @@ load [rdr] (recur (dec n) (rest xs)) xs))) -(defn string? [x] +(defn +#^{:doc "Return true if x is a String"} +string? [x] (instance? String x)) -(defn symbol? [x] +(defn +#^{:doc "Return true if x is a Symbol"} +symbol? [x] (instance? clojure.lang.Symbol x)) -(defn map? [x] +(defn +#^{:doc "Return true if x implements IPersistentMap"} +map? [x] (instance? clojure.lang.IPersistentMap x)) -(defn vector? [x] +(defn +#^{:doc "Return true if x implements IPersistentVector "} +vector? [x] (instance? clojure.lang.IPersistentVector x)) ;redefine let with destructuring (defmacro -#^{:doc "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."} +#^{:doc "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."} let [bindings & body] (let [bmap (apply array-map bindings) pb (fn pb [bvec b v] @@ -1258,29 +1469,42 @@ let [bindings & body] (defmacro comment [& body]) -(defmacro with-out-str [& body] +(defmacro +#^{:doc "Evaluates exprs in a context in which *out* is bound to a fresh StringWriter. +Returns the string created by any nested printing calls."} +with-out-str [& body] `(let [s# (new java.io.StringWriter)] (binding [*out* s#] ~@body (str s#)))) -(defn pr-str [& xs] +(defn +#^{:doc "pr to a string, returning it"} +pr-str [& xs] (with-out-str (apply pr xs))) -(defn prn-str [& xs] +(defn +#^{:doc "prn to a string, returning it"} +prn-str [& xs] (with-out-str (apply prn xs))) -(defn print-str [& xs] +(defn +#^{:doc "print to a string, returning it"} +print-str [& xs] (with-out-str (apply print xs))) -(defn println-str [& xs] +(defn +#^{:doc "println to a string, returning it"} +println-str [& xs] (with-out-str (apply println xs))) -(defmacro assert [x] +(defmacro +#^{:doc "Evaluates expr and throws an exception if it does not evaluate to logical true."} +assert [x] `(when-not ~x (throw (new Exception (str "Assert failed: " (pr-str '~x)))))) @@ -1292,10 +1516,17 @@ test [v] (do (f) :ok) :no-test))) -(defn #^java.util.regex.Matcher re-matcher [#^java.util.regex.Pattern re s] +(defn +#^{:tag java.util.regex.Matcher +:doc "Returns an instance of java.util.regex.Matcher, for use, e.g. in re-find."} +re-matcher [#^java.util.regex.Pattern re s] (. re (matcher s))) -(defn re-groups [#^java.util.regex.Matcher m] +(defn +#^{:doc "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."} +re-groups [#^java.util.regex.Matcher m] (let [gc (. m (groupCount))] (if (zero? gc) (. m (group)) @@ -1304,19 +1535,28 @@ test [v] (recur (conj ret (. m (group c))) (inc c)) ret))))) -(defn re-seq [#^java.util.regex.Pattern re s] +(defn +#^{:doc "Returns a lazy sequence of successive matches of pattern in string, using java.util.regex.Matcher.find(), +each such match processed with re-groups."} +re-seq [#^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 [#^java.util.regex.Pattern re s] +(defn +#^{:doc "Returns the match, if any, of string to pattern, using java.util.regex.Matcher.matches(). +Uses re-groups to return the groups."} +re-matches [#^java.util.regex.Pattern re s] (let [m (re-matcher re s)] (when (. m (matches)) (re-groups m)))) -(defn re-find +(defn +#^{:doc "Returns the next regex match, if any, of string to pattern, using java.util.regex.Matcher.find(). +Uses re-groups to return the groups."} +re-find ([#^java.util.regex.Matcher m] (when (. m (find)) (re-groups m))) @@ -1333,3 +1573,9 @@ test [v] (defmacro defn- [name & decls] (list* `defn (with-meta name (assoc (meta name) :private true)) decls)) + +(defmacro doc [varname] + `(do + (prn (var ~varname)) + (prn (:arglists (meta (var ~varname)))) + (println (:doc (meta (var ~varname)))))) |