From 57f7c6ea164271d92cec5a12d22043c7029e3de2 Mon Sep 17 00:00:00 2001
From: "Hudson @ build.clojure.org" This method attempts to find resue the given array as the basis for an array map as quickly as possible. If a trailing element exists in the array or it contains duplicate keys then it delegates to the complex path.
It will reallocate a smaller init array if duplicate keys are found.
+ * + *If a trailing element is found then will attempt to add it to the resulting map as if by conj.
+ *No guarantees about the order of the keys in the trailing element are made.
+ **/ +private static PersistentArrayMap createAsIfByAssocComplexPath(Object[] init, boolean hasTrailing){ + if(hasTrailing) + { + IPersistentCollection trailing = PersistentArrayMap.EMPTY.cons(init[init.length-1]); + init = growSeedArray(init, trailing); + } + // If this looks like it is doing busy-work, it is because it // is achieving these goals: O(n^2) run time like // createWithCheck(), never modify init arg, and only diff --git a/test/clojure/test_clojure/data_structures.clj b/test/clojure/test_clojure/data_structures.clj index 69baf137c6..854560466b 100644 --- a/test/clojure/test_clojure/data_structures.clj +++ b/test/clojure/test_clojure/data_structures.clj @@ -1330,3 +1330,34 @@ (is (= (hash (->Rec 1 1)) (hash (assoc r :a 1)))) (is (= (hash (->Rec 1 1)) (hash (dissoc r2 :c)))) (is (= (hash (->Rec 1 1)) (hash (dissoc (assoc r :c 1) :c)))))) + +(deftest singleton-map-in-destructure-context + (let [sample-map {:a 1 :b 2} + {:keys [a] :as m1} (list sample-map)] + (is (= m1 sample-map)) + (is (= a 1)))) + +(deftest trailing-map-destructuring + (let [sample-map {:a 1 :b 2} + add (fn [& {:keys [a b]}] (+ a b)) + addn (fn [n & {:keys [a b]}] (+ n a b))] + (testing "that kwargs are applied properly given a map in place of the key/val pairs" + (is (= 3 (add :a 1 :b 2))) + (is (= 3 (add {:a 1 :b 2}))) + (is (= 13 (addn 10 :a 1 :b 2))) + (is (= 13 (addn 10 {:a 1 :b 2}))) + (is (= 103 ((partial addn 100) :a 1 {:b 2}))) + (is (= 103 ((partial addn 100 :a 1) {:b 2}))) + (is (= 107 ((partial addn 100 :a 1) {:a 5 :b 2})))) + (testing "built maps" + (let [{:as m1} (list :a 1 :b 2) + {:as m2} (list :a 1 :b 2 {:c 3}) + {:as m3} (list :a 1 :b 2 {:a 0}) + {:keys [a4] :as m4} (list nil)] + (= m1 {:a 1 :b 2}) + (= m2 {:a 1 :b 2 :c 3}) + (= m3 {:a 0 :b 2}) + (= m1 (seq-to-map-for-destructuring (list :a 1 :b 2))) + (= m2 (seq-to-map-for-destructuring (list :a 1 :b 2 {:c 3}))) + (= m3 (seq-to-map-for-destructuring (list :a 1 :b 2 {:a 0}))) + (= a4 nil))))) From 9249412dbd7e761670c4f05b399a10460230707d Mon Sep 17 00:00:00 2001 From: Alex MillerIFn
s can be passed to higher order functions, e.g. the
- * example below passes plus
to read
:
inc
to map
:
*
* * IFn map = Clojure.var("clojure.core", "map"); diff --git a/src/jvm/clojure/java/api/package.html b/src/jvm/clojure/java/api/package.html index 6536c33ab5..a24d3c9b79 100644 --- a/src/jvm/clojure/java/api/package.html +++ b/src/jvm/clojure/java/api/package.html @@ -57,7 +57,7 @@
IFn
s can be passed to higher order functions, e.g. the - example below passesplus
toread
: + example below passesinc
tomap
:IFn map = Clojure.var("clojure.core", "map"); IFn inc = Clojure.var("clojure.core", "inc"); From ade22645ba5dbf4c0d8115b19938af96d6fb4cd5 Mon Sep 17 00:00:00 2001 From: Alex MillerDate: Thu, 18 Nov 2021 09:47:56 -0600 Subject: [PATCH 29/78] CLJ-1360 Update clojure.string/split docstring regarding trailing empty parts Signed-off-by: Alex Miller --- src/clj/clojure/string.clj | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/clj/clojure/string.clj b/src/clj/clojure/string.clj index 35e0650f65..38f0d6d91d 100644 --- a/src/clj/clojure/string.clj +++ b/src/clj/clojure/string.clj @@ -218,7 +218,8 @@ Design notes for clojure.string: (defn split "Splits string on a regular expression. Optional argument limit is - the maximum number of splits. Not lazy. Returns vector of the splits." + the maximum number of parts. Not lazy. Returns vector of the parts. + Trailing empty strings are not returned - pass limit of -1 to return all." {:added "1.2"} ([^CharSequence s ^Pattern re] (LazilyPersistentVector/createOwning (.split re s))) @@ -226,7 +227,7 @@ Design notes for clojure.string: (LazilyPersistentVector/createOwning (.split re s limit)))) (defn split-lines - "Splits s on \\n or \\r\\n." + "Splits s on \\n or \\r\\n. Trailing empty lines are not returned." {:added "1.2"} [^CharSequence s] (split s #"\r?\n")) From 554090e7fd5f33fc3c1c962bb34af53a01332a75 Mon Sep 17 00:00:00 2001 From: Arne Brasseur Date: Thu, 18 Nov 2021 09:41:29 -0600 Subject: [PATCH 30/78] CLJ-2249 Clarify clojure.core/get docstring regarding sets, strings, arrays, ILookup Signed-off-by: Alex Miller --- src/clj/clojure/core.clj | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/clj/clojure/core.clj b/src/clj/clojure/core.clj index a3a32522b4..9f3cdf371f 100644 --- a/src/clj/clojure/core.clj +++ b/src/clj/clojure/core.clj @@ -1494,7 +1494,8 @@ [coll key] (. clojure.lang.RT (contains coll key))) (defn get - "Returns the value mapped to key, not-found or nil if key not present." + "Returns the value mapped to key, not-found or nil if key not present + in associative collection, set, string, array, or ILookup instance." {:inline (fn [m k & nf] `(. clojure.lang.RT (get ~m ~k ~@nf))) :inline-arities #{2 3} :added "1.0"} From e1220832d900745727cf5a1b69f4a6cd664f1443 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Tue, 5 Oct 2021 10:32:45 -0500 Subject: [PATCH 31/78] CLJ-2488 Add definition to reify docstring Signed-off-by: Alex Miller --- src/clj/clojure/core_deftype.clj | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/clj/clojure/core_deftype.clj b/src/clj/clojure/core_deftype.clj index 786f0d4b53..7906ccbe35 100644 --- a/src/clj/clojure/core_deftype.clj +++ b/src/clj/clojure/core_deftype.clj @@ -67,8 +67,9 @@ (throw (IllegalArgumentException. (apply print-str "Unsupported option(s) -" bad-opts)))) [interfaces methods opts])) -(defmacro reify - "reify is a macro with the following structure: +(defmacro reify + "reify creates an object implementing a protocol or interface. + reify is a macro with the following structure: (reify options* specs*) From 631c46ed98ed3bfefdb8a15080e004ab470b0bf4 Mon Sep 17 00:00:00 2001 From: Nikita Prokopov Date: Sun, 30 Aug 2015 18:56:04 +0600 Subject: [PATCH 32/78] CLJ-1808 map-invert should use reduce-kv and transient Signed-off-by: Alex Miller --- src/clj/clojure/set.clj | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/clj/clojure/set.clj b/src/clj/clojure/set.clj index b63a004475..9ffb72900a 100644 --- a/src/clj/clojure/set.clj +++ b/src/clj/clojure/set.clj @@ -106,7 +106,11 @@ (defn map-invert "Returns the map with the vals mapped to the keys." {:added "1.0"} - [m] (reduce (fn [m [k v]] (assoc m v k)) {} m)) + [m] + (persistent! + (reduce-kv (fn [m k v] (assoc! m v k)) + (transient {}) + m))) (defn join "When passed 2 rels, returns the rel corresponding to the natural From d004e799364e29815dc1b080dbf9e8bd9858c321 Mon Sep 17 00:00:00 2001 From: Steve Miner Date: Tue, 5 Oct 2021 09:48:39 -0500 Subject: [PATCH 33/78] CLJ-2065 Support IKVReduce on SubVector Signed-off-by: Alex Miller --- src/jvm/clojure/lang/APersistentVector.java | 12 +++++++++++- test/clojure/test_clojure/vectors.clj | 4 ++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/jvm/clojure/lang/APersistentVector.java b/src/jvm/clojure/lang/APersistentVector.java index c9f15cdd3f..de8a09ea68 100644 --- a/src/jvm/clojure/lang/APersistentVector.java +++ b/src/jvm/clojure/lang/APersistentVector.java @@ -544,7 +544,7 @@ public APersistentVector.RSeq withMeta(IPersistentMap meta){ } } -public static class SubVector extends APersistentVector implements IObj{ +public static class SubVector extends APersistentVector implements IObj, IKVReduce{ public final IPersistentVector v; public final int start; public final int end; @@ -574,6 +574,16 @@ public Iterator iterator(){ return super.iterator(); } + public Object kvreduce(IFn f, Object init){ + int cnt = count(); + for (int i=0; i = end) || (i < 0)) throw new IndexOutOfBoundsException(); diff --git a/test/clojure/test_clojure/vectors.clj b/test/clojure/test_clojure/vectors.clj index 0bea3ff4b8..0be0bf14e8 100644 --- a/test/clojure/test_clojure/vectors.clj +++ b/test/clojure/test_clojure/vectors.clj @@ -416,3 +416,7 @@ (is (= [0 1 2 3] (vec (reify clojure.lang.IReduceInit (reduce [_ f start] (reduce f start (range 4)))))))) + +(deftest test-reduce-kv-vectors + (is (= 25 (reduce-kv + 10 [2 4 6]))) + (is (= 25 (reduce-kv + 10 (subvec [0 2 4 6] 1))))) From e21bbfe1d1b06ae703e939951e6c8f199969d70b Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Tue, 23 Nov 2021 12:47:24 -0600 Subject: [PATCH 34/78] CLJ-2326 Add :direct-linking to *compiler-options* docstring and remove Alpha marking Signed-off-by: Alex Miller --- src/clj/clojure/core.clj | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/clj/clojure/core.clj b/src/clj/clojure/core.clj index 9f3cdf371f..0dba6fcd97 100644 --- a/src/clj/clojure/core.clj +++ b/src/clj/clojure/core.clj @@ -6473,7 +6473,10 @@ fails, attempts to require sym's namespace and retries." Supported options: :elide-meta - a collection of metadata keys to elide during compilation. :disable-locals-clearing - set to true to disable clearing, useful for using a debugger - Alpha, subject to change." + :direct-linking - set to true to use direct static invocation of functions, rather than vars + Note that call sites compiled with direct linking will not be affected by var redefinition. + Use ^:redef (or ^:dynamic) on a var to prevent direct linking and allow redefinition. + See https://clojure.org/reference/compilation for more information." {:added "1.4"}) (add-doc-and-meta *ns* From 8ebad0ab3f912932d94874120cad89493f2aa22e Mon Sep 17 00:00:00 2001 From: "Hudson @ build.clojure.org" Date: Tue, 23 Nov 2021 13:25:56 -0600 Subject: [PATCH 35/78] [maven-release-plugin] prepare release clojure-1.11.0-alpha3 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 71c4378068..d9ae7e5f14 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar -1.11.0-master-SNAPSHOT +1.11.0-alpha3 http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git -HEAD +clojure-1.11.0-alpha3 From 7697d5da77a319077e71343f76fa204327881de4 Mon Sep 17 00:00:00 2001 From: "Hudson @ build.clojure.org" Date: Tue, 23 Nov 2021 13:25:56 -0600 Subject: [PATCH 36/78] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index d9ae7e5f14..71c4378068 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar -1.11.0-alpha3 +1.11.0-master-SNAPSHOT http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git -clojure-1.11.0-alpha3 +HEAD From abe19832c0294fec4c9c55430c9262c4b6d2f8b1 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Tue, 30 Nov 2021 10:45:25 -0600 Subject: [PATCH 37/78] Remove/ignore project files --- .gitignore | 1 + ...ven__org_clojure_data_generators_0_1_2.xml | 13 ----------- ...ven__org_clojure_test_generative_0_4_0.xml | 13 ----------- clojure.iml | 23 ------------------- 4 files changed, 1 insertion(+), 49 deletions(-) delete mode 100644 .idea/libraries/Maven__org_clojure_data_generators_0_1_2.xml delete mode 100644 .idea/libraries/Maven__org_clojure_test_generative_0_4_0.xml delete mode 100644 clojure.iml diff --git a/.gitignore b/.gitignore index 5376efaf3f..18cf4cc05c 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ nbproject/private/ maven-classpath maven-classpath.properties .idea/ +*.iml diff --git a/.idea/libraries/Maven__org_clojure_data_generators_0_1_2.xml b/.idea/libraries/Maven__org_clojure_data_generators_0_1_2.xml deleted file mode 100644 index 78f485eeb9..0000000000 --- a/.idea/libraries/Maven__org_clojure_data_generators_0_1_2.xml +++ /dev/null @@ -1,13 +0,0 @@ - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_clojure_test_generative_0_4_0.xml b/.idea/libraries/Maven__org_clojure_test_generative_0_4_0.xml deleted file mode 100644 index 78fac6dfd0..0000000000 --- a/.idea/libraries/Maven__org_clojure_test_generative_0_4_0.xml +++ /dev/null @@ -1,13 +0,0 @@ -- -- -- - -- - -- - \ No newline at end of file diff --git a/clojure.iml b/clojure.iml deleted file mode 100644 index c1c8a6a84a..0000000000 --- a/clojure.iml +++ /dev/null @@ -1,23 +0,0 @@ - -- -- -- - -- - -- - \ No newline at end of file From f5e5a4a7b8e0785436f0bbb9b91b6de9f754aa33 Mon Sep 17 00:00:00 2001 From: Alex Miller- - -- - -- - - - - - - - - - - - - - Date: Thu, 13 Jan 2022 11:57:31 -0600 Subject: [PATCH 38/78] CLJ-2684 Update contrib deps Signed-off-by: Alex Miller --- pom.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 71c4378068..59159805a1 100644 --- a/pom.xml +++ b/pom.xml @@ -41,7 +41,7 @@ org.clojure spec.alpha -0.3.214 +0.3.218 org.clojure @@ -51,7 +51,7 @@org.clojure test.generative -0.5.2 +1.0.0 test @@ -63,7 +63,7 @@ org.clojure test.check -0.9.0 +1.1.1 test From b32e35ae89d291882dbdb662c4193ecfa9a593e8 Mon Sep 17 00:00:00 2001 From: Alexander Yakushev Date: Thu, 13 Jan 2022 11:29:09 -0600 Subject: [PATCH 39/78] CLJ-2621: Make InstanceMethodExpr.emit discard unused primitive returns without boxing Signed-off-by: Alex Miller --- src/jvm/clojure/lang/Compiler.java | 16 ++++++++++++---- test/clojure/test_clojure/java_interop.clj | 18 +++++++++++++++++- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/src/jvm/clojure/lang/Compiler.java b/src/jvm/clojure/lang/Compiler.java index 041786e888..ce16f85a21 100644 --- a/src/jvm/clojure/lang/Compiler.java +++ b/src/jvm/clojure/lang/Compiler.java @@ -1612,8 +1612,16 @@ public void emit(C context, ObjExpr objx, GeneratorAdapter gen){ gen.invokeInterface(type, m); else gen.invokeVirtual(type, m); - //if(context != C.STATEMENT || method.getReturnType() == Void.TYPE) - HostExpr.emitBoxReturn(objx, gen, method.getReturnType()); + Class retClass = method.getReturnType(); + if(context == C.STATEMENT) + { + if(retClass == long.class || retClass == double.class) + gen.pop2(); + else if(retClass != void.class) + gen.pop(); + } + else + HostExpr.emitBoxReturn(objx, gen, retClass); } else { @@ -1627,9 +1635,9 @@ public void emit(C context, ObjExpr objx, GeneratorAdapter gen){ method.emitClearLocals(gen); } gen.invokeStatic(REFLECTOR_TYPE, invokeInstanceMethodMethod); + if(context == C.STATEMENT) + gen.pop(); } - if(context == C.STATEMENT) - gen.pop(); } public boolean hasJavaClass(){ diff --git a/test/clojure/test_clojure/java_interop.clj b/test/clojure/test_clojure/java_interop.clj index 30fab56e56..cb21064b25 100644 --- a/test/clojure/test_clojure/java_interop.clj +++ b/test/clojure/test_clojure/java_interop.clj @@ -13,7 +13,8 @@ (:use clojure.test) (:require [clojure.inspector] [clojure.set :as set]) - (:import java.util.Base64)) + (:import java.util.Base64 + (java.util.concurrent.atomic AtomicLong AtomicInteger))) ; http://clojure.org/java_interop ; http://clojure.org/compilation @@ -589,3 +590,18 @@ (is (= (char \a) \a))) ;; Note: More coercions in numbers.clj + +; Test that primitive boxing elision in statement context works +; correctly (CLJ-2621) + +(defn inc-atomic-int [^AtomicInteger l] + (.incrementAndGet l) + nil) + +(defn inc-atomic-long [^AtomicLong l] + (.incrementAndGet l) + nil) + +(deftest test-boxing-prevention-when-compiling-statements + (is (= 1 (.get (doto (AtomicInteger. 0) inc-atomic-int)))) + (is (= 1 (.get (doto (AtomicLong. 0) inc-atomic-long))))) From b30a99014814f2fe68833622a567c80133b0c417 Mon Sep 17 00:00:00 2001 From: Fogus Date: Thu, 13 Jan 2022 11:37:08 -0500 Subject: [PATCH 40/78] CLJ-2663: Added a guard in APVector#doEquiv so that List operands that do not respond to #size are not checked. Also, added count short-circuit logic to ASeq#equiv in an attempt to leverage fast-count benefit, but the guard is more strict such that this and the operand should bouth be Counted. Signed-off-by: Alex Miller --- src/jvm/clojure/lang/APersistentVector.java | 13 ++++++++----- src/jvm/clojure/lang/ASeq.java | 5 +++++ test/clojure/test_clojure/vectors.clj | 8 ++++++++ 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/src/jvm/clojure/lang/APersistentVector.java b/src/jvm/clojure/lang/APersistentVector.java index de8a09ea68..3e88d14dbf 100644 --- a/src/jvm/clojure/lang/APersistentVector.java +++ b/src/jvm/clojure/lang/APersistentVector.java @@ -98,15 +98,18 @@ static boolean doEquiv(IPersistentVector v, Object obj){ else if(obj instanceof List) { Collection ma = (Collection) obj; - if(ma.size() != v.count()) + + if((!(ma instanceof IPersistentCollection) || (ma instanceof Counted)) && (ma.size() != v.count())) return false; - for(Iterator i1 = ((List) v).iterator(), i2 = ma.iterator(); - i1.hasNext();) + + Iterator i2 = ma.iterator(); + + for(Iterator i1 = ((List) v).iterator(); i1.hasNext();) { - if(!Util.equiv(i1.next(), i2.next())) + if(!i2.hasNext() || !Util.equiv(i1.next(), i2.next())) return false; } - return true; + return !i2.hasNext(); } else { diff --git a/src/jvm/clojure/lang/ASeq.java b/src/jvm/clojure/lang/ASeq.java index 325aa27c24..f0f8e5d447 100644 --- a/src/jvm/clojure/lang/ASeq.java +++ b/src/jvm/clojure/lang/ASeq.java @@ -37,6 +37,11 @@ public boolean equiv(Object obj){ if(!(obj instanceof Sequential || obj instanceof List)) return false; + + if(this instanceof Counted && obj instanceof Counted && + ((Counted)this).count() != ((Counted)obj).count()) + return false; + ISeq ms = RT.seq(obj); for(ISeq s = seq(); s != null; s = s.next(), ms = ms.next()) { diff --git a/test/clojure/test_clojure/vectors.clj b/test/clojure/test_clojure/vectors.clj index 0be0bf14e8..ea2b8e77d5 100644 --- a/test/clojure/test_clojure/vectors.clj +++ b/test/clojure/test_clojure/vectors.clj @@ -420,3 +420,11 @@ (deftest test-reduce-kv-vectors (is (= 25 (reduce-kv + 10 [2 4 6]))) (is (= 25 (reduce-kv + 10 (subvec [0 2 4 6] 1))))) + +(deftest test-vector-eqv-to-non-counted-types + (is (not= (range) [0 1 2])) + (is (not= [0 1 2] (range))) + (is (= [0 1 2] (take 3 (range)))) + (is (= [0 1 2] (new java.util.ArrayList [0 1 2]))) + (is (not= [1 2] (take 1 (cycle [1 2])))) + (is (= [1 2 3 nil 4 5 6 nil] (eduction cat [[1 2 3 nil] [4 5 6 nil]])))) From 304d7c6a81bd7d8511e9ef3d89dc199b1464afaa Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Wed, 12 Jan 2022 16:03:23 -0600 Subject: [PATCH 41/78] CLJ-2677 In clojure.math inline methods, use coercion functions to resolve to single overload Signed-off-by: Alex Miller --- build.xml | 2 +- codegen/gen_math.clj | 263 +++++++++++++++++++++++ src/clj/clojure/{java => }/math.clj | 141 +++++------- test/clojure/test_clojure/math.clj | 320 ++++++++++++++++++++++++++++ 4 files changed, 638 insertions(+), 88 deletions(-) create mode 100644 codegen/gen_math.clj rename src/clj/clojure/{java => }/math.clj (83%) create mode 100644 test/clojure/test_clojure/math.clj diff --git a/build.xml b/build.xml index 444b5d9603..6796b3d986 100644 --- a/build.xml +++ b/build.xml @@ -76,7 +76,6 @@ - @@ -86,6 +85,7 @@ + diff --git a/codegen/gen_math.clj b/codegen/gen_math.clj new file mode 100644 index 0000000000..484649d3d3 --- /dev/null +++ b/codegen/gen_math.clj @@ -0,0 +1,263 @@ +;; This code was used to generate the clojure.math namespace in +;; Clojure 1.11 to wrap Java 1.8 java.lang.Math methods. There are +;; many small tweaks in this to get exactly the output that was +;; desired and it was not intended to be reused in any way, it is +;; included here for future reference. + +(ns gen-math + (:require + [clojure.reflect :as reflect] + [clojure.set :as set] + [clojure.string :as str]) + (:import + [java.io StringWriter Writer])) + +;; manually created +(declare HEADER) +(declare FNS) +(declare DOCS) +(declare ARGS) +(declare ARGTYPES) + +(def const-template + "(def + ^{:doc %s + :added %s + :const true + :tag %s} + %s + %s)\n\n") + +(defn- emit-constant + [^Writer writer {:keys [cname name added type]}] + (let [sym (symbol (str cname) (str name)) + doc (str "\"" (get DOCS (symbol name)) "\"") + tag (str "'" type)] + (.write writer + (format const-template doc (pr-str added) tag name sym)))) + +(def fn-template + "(defn %s + {:doc %s + :inline-arities %s + :inline %s + :added %s} + %s%s + %s)\n\n") + +(defn- clojurize + [sym] + (or + (get '{IEEEremainder IEEE-remainder} sym) + (let [s (name sym)] + (symbol + (str + (reduce + (fn [^StringBuilder b ^Character c] + (if (Character/isUpperCase c) + (.. b (append "-") (append (Character/toLowerCase c))) + (.append b c))) + (StringBuilder.) + s)))))) + +(defn- inline-body + [params param-types] + (str/join " " + (map (fn [p pt] (format "(%s ~%s)" pt p)) + params param-types))) + +(defn- body + [params param-types on-types] + (map (fn [p pt] (if (contains? on-types pt) `(~pt ~p) p)) + params param-types)) + +(defn- emit-fn + [^Writer writer {:keys [cname fname sigs]}] + (let [sym (symbol (str cname) (str fname)) + arities (group-by #(-> % :parameter-types count) sigs) + arity (-> arities keys first) ;; NOTE: ignore multiple arities, none in Math + arity-sigs (get arities arity) + cname (clojurize fname) + doc (str "\"" (get DOCS cname) "\"") + sig (if (= 1 (count arity-sigs)) (first arity-sigs) (get ARGTYPES cname)) + {pts :parameter-types, rt :return-type} sig + ps (get ARGS cname) + ;; coerce all args in inline body + inline-body (format "(fn %s `(%s%s))" (pr-str ps) (if (< 0 (count ps)) (str sym " ") sym) (inline-body ps pts)) + ;; ps are hinted, so coerce only ps that can't be hinted - int type + body `(~sym ~@(body ps pts #{'int})) + rts (if (#{'long 'double} rt) (str "^" rt " ") "") + hints (map #(if (#{'long 'double} %) (symbol (str "^" %)) nil) pts) + pst (vec (remove nil? (interleave hints ps)))] + (.write writer + (format fn-template cname doc #{arity} inline-body (pr-str "1.11") rts pst body)))) + +(defn gen-static-wrappers + [csym] + (let [added "1.11" + members (:members (reflect/type-reflect (resolve csym))) + statics (filter #(set/subset? #{:public :static} (:flags %)) members) + {fs false, ms true} (group-by #(contains? % :return-type) statics) + methods (->> ms (filter (fn [m] + (or (= 'scalb (:name m)) + (empty? (set/intersection #{'int 'float} (set (:parameter-types m)))))))) + by-name (group-by :name methods) + writer (StringWriter.)] + (.write writer HEADER) + (doseq [f fs] + (emit-constant writer (merge f {:cname csym, :added added}))) + (doseq [n FNS] + (emit-fn writer {:cname csym, :fname n, :added added, :sigs (get by-name n)})) + (spit "src/clj/clojure/math.clj" (str writer)))) + +(comment + (gen-static-wrappers 'Math) + ) + +;;;; Manually provided info used during the generator + +(def ^String HEADER + "; Copyright (c) Rich Hickey. All rights reserved. +; The use and distribution terms for this software are covered by the +; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) +; which can be found in the file epl-v10.html 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. + +(ns + ^{:author \"Alex Miller\", + :doc \"Clojure wrapper functions for java.lang.Math static methods. + + Function calls are inlined for performance, and type hinted for primitive + long or double parameters where appropriate. In general, Math methods are + optimized for performance and have bounds for error tolerance. If + greater precision is needed, use java.lang.StrictMath directly instead. + + For more complete information, see: + https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html\"} + clojure.math) + +(set! *warn-on-reflection* true) + +") + +;; fns + +;; omitted: toIntExact +;; omitted but include in core w/polymorphic impl: abs, min, max +(def FNS + '[sin cos tan asin acos atan toRadians toDegrees exp log log10 + sqrt cbrt IEEEremainder ceil floor rint atan2 pow round random + addExact subtractExact multiplyExact incrementExact decrementExact negateExact + floorDiv floorMod ulp signum sinh cosh tanh hypot expm1 log1p copySign getExponent + nextAfter nextUp nextDown scalb]) + +;; docstrings to use +(def DOCS + '{ + E "Constant for e, the base for natural logarithms.\n See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#E" + PI "Constant for pi, the ratio of the circumference of a circle to its diameter.\n See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#PI" + sin "Returns the sine of an angle.\n If a is ##NaN, ##-Inf, ##Inf => ##NaN\n If a is zero => zero with the same sign as a\n See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#sin-double-" + cos "Returns the cosine of an angle.\n If a is ##NaN, ##-Inf, ##Inf => ##NaN\n See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#cos-double-" + tan "Returns the tangent of an angle.\n If a is ##NaN, ##-Inf, ##Inf => ##NaN\n If a is zero => zero with the same sign as a\n See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#tan-double-" + asin "Returns the arc sine of an angle, in the range -pi/2 to pi/2.\n If a is ##NaN or |a|>1 => ##NaN\n If a is zero => zero with the same sign as a\n See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#asin-double-" + acos "Returns the arc cosine of a, in the range 0.0 to pi.\n If a is ##NaN or |a|>1 => ##NaN\n See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#acos-double-" + atan "Returns the arc tangent of a, in the range of -pi/2 to pi/2.\n If a is ##NaN => ##NaN\n If a is zero => zero with the same sign as a\n See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#atan-double-" + to-radians "Converts an angle in degrees to an approximate equivalent angle in radians.\n See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#toRadians-double-" + to-degrees "Converts an angle in radians to an approximate equivalent angle in degrees.\n See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#toDegrees-double-" + exp "Returns Euler's number e raised to the power of a.\n If a is ##NaN => ##NaN\n If a is ##Inf => ##Inf\n If a is ##-Inf => +0.0\n See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#exp-double-" + log "Returns the natural logarithm (base e) of a.\n If a is ##NaN or negative => ##NaN\n If a is ##Inf => ##Inf\n If a is zero => ##-Inf\n See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#log-double-" + log10 "Returns the logarithm (base 10) of a.\n If a is ##NaN or negative => ##NaN\n If a is ##Inf => ##Inf\n If a is zero => ##-Inf\n See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#log10-double-" + sqrt "Returns the positive square root of a.\n If a is ##NaN or negative => ##NaN\n If a is ##Inf => ##Inf\n If a is zero => a\n See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#sqrt-double-" + cbrt "Returns the cube root of a.\n If a is ##NaN => ##NaN\n If a is ##Inf or ##-Inf => a\n If a is zero => zero with sign matching a\n See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#cbrt-double-" + IEEE-remainder "Returns the remainder per IEEE 754 such that\n remainder = dividend - divisor * n\n where n is the integer closest to the exact value of dividend / divisor.\n If two integers are equally close, then n is the even one.\n If the remainder is zero, sign will match dividend.\n If dividend or divisor is ##NaN, or dividend is ##Inf or ##-Inf, or divisor is zero => ##NaN\n If dividend is finite and divisor is infinite => dividend\n See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#IEEEremainder-double-double-" + ceil "Returns the smallest double greater than or equal to a, and equal to a\n mathematical integer.\n If a is ##NaN or ##Inf or ##-Inf or already equal to an integer => a\n See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#ceil-double-" + floor "Returns the largest double less than or equal to a, and equal to a\n mathematical integer.\n If a is ##NaN or ##Inf or ##-Inf or already equal to an integer => a\n If a is less than zero but greater than -1.0 => -0.0\n See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#floor-double-" + rint "Returns the double closest to a and equal to a mathematical integer.\n If two values are equally close, return the even one.\n If a is ##NaN or ##Inf or ##-Inf or zero => a\n See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#rint-double-" + atan2 "Returns the angle theta from the conversion of rectangular coordinates (x, y) to polar coordinates (r, theta).\n Computes the phase theta by computing an arc tangent of y/x in the range of -pi to pi.\n For more details on special cases, see:\n https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#atan2-double-double-" + pow "Returns the value of a raised to the power of b.\n For more details on special cases, see:\n https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#pow-double-double-" + round "Returns the closest long to a. If equally close to two values, return the one\n closer to ##Inf.\n If a is ##NaN => 0\n If a is ##-Inf or < Long/MIN_VALUE => Long/MIN_VALUE\n If a is ##Inf or > Long/MAX_VALUE => Long/MAX_VALUE\n See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#round-double-" + random "Returns a positive double between 0.0 and 1.0, chosen pseudorandomly with\n approximately random distribution.\n See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#random--" + add-exact "Returns the sum of x and y, throws ArithmeticException on overflow.\n See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#addExact-long-long-" + subtract-exact "Returns the difference of x and y, throws ArithmeticException on overflow.\n See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#subtractExact-long-long-" + multiply-exact "Returns the product of x and y, throws ArithmeticException on overflow.\n See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#multiplyExact-long-long-" + increment-exact "Returns a incremented by 1, throws ArithmeticException on overflow.\n See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#incrementExact-long-" + decrement-exact "Returns a decremented by 1, throws ArithmeticException on overflow.\n See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#decrementExact-long-" + negate-exact "Returns the negation of a, throws ArithmeticException on overflow.\n See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#negateExact-long-" + floor-div "Integer division that rounds to negative infinity (as opposed to zero).\n The special case (floorDiv Long/MIN_VALUE -1) overflows and returns Long/MIN_VALUE.\n See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#floorDiv-long-long-" + floor-mod "Integer modulus x - (floorDiv(x, y) * y). Sign matches y and is in the\n range -|y| < r < |y|.\n See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#floorMod-long-long-" + ulp "Returns the size of an ulp (unit in last place) for d.\n If d is ##NaN => ##NaN\n If d is ##Inf or ##-Inf => ##Inf\n If d is zero => Double/MIN_VALUE\n If d is +/- Double/MAX_VALUE => 2^971\n See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#ulp-double-" + signum "Returns the signum function of d - zero for zero, 1.0 if >0, -1.0 if <0.\n If d is ##NaN => ##NaN\n See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#signum-double-" + sinh "Returns the hyperbolic sine of x, (e^x - e^-x)/2.\n If x is ##NaN => ##NaN\n If x is ##Inf or ##-Inf or zero => x\n See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#sinh-double-" + cosh "Returns the hyperbolic cosine of x, (e^x + e^-x)/2.\n If x is ##NaN => ##NaN\n If x is ##Inf or ##-Inf => ##Inf\n If x is zero => 1.0\n See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#cosh-double-" + tanh "Returns the hyperbolic tangent of x, sinh(x)/cosh(x).\n If x is ##NaN => ##NaN\n If x is zero => zero, with same sign\n If x is ##Inf => +1.0\n If x is ##-Inf => -1.0\n See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#tanh-double-" + hypot "Returns sqrt(x^2 + y^2) without intermediate underflow or overflow.\n If x or y is ##Inf or ##-Inf => ##Inf\n If x or y is ##NaN and neither is ##Inf or ##-Inf => ##NaN\n See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#hypot-double-double-" + expm1 "Returns e^x - 1. Near 0, expm1(x)+1 is more accurate to e^x than exp(x).\n If x is ##NaN => ##NaN\n If x is ##Inf => #Inf\n If x is ##-Inf => -1.0\n If x is zero => x\n See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#expm1-double-" + log1p "Returns ln(1+x). For small values of x, log1p(x) is more accurate than\n log(1.0+x).\n If x is ##NaN or < -1 => ##NaN\n If x is ##Inf => ##Inf\n If x is -1 => ##-Inf\n If x is 0 => 0 with sign matching x\n See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#log1p-double-" + copy-sign "Returns a double with the magnitude of the first argument and the sign of\n the second.\n See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#copySign-double-double-" + get-exponent "Returns the exponent of d.\n If d is ##NaN, ##Inf, ##-Inf => Double/MAX_EXPONENT + 1\n If d is zero or subnormal => Double/MIN_EXPONENT - 1\n See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#getExponent-double-" + next-after "Returns the adjacent floating point number to start in the direction of\n the second argument. If the arguments are equal, the second is returned.\n If either arg is #NaN => #NaN\n If both arguments are signed zeros => direction\n If start is +-Double/MIN_VALUE and direction would cause a smaller magnitude\n => zero with sign matching start\n If start is ##Inf or ##-Inf and direction would cause a smaller magnitude\n => Double/MAX_VALUE with same sign as start\n If start is equal to +=Double/MAX_VALUE and direction would cause a larger magnitude\n => ##Inf or ##-Inf with sign matching start\n See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#nextAfter-double-double-" + next-up "Returns the adjacent double of d in the direction of ##Inf.\n If d is ##NaN => ##NaN\n If d is ##Inf => ##Inf\n If d is zero => Double/MIN_VALUE\n See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#nextUp-double-" + next-down "Returns the adjacent double of d in the direction of ##-Inf.\n If d is ##NaN => ##NaN\n If d is ##-Inf => ##-Inf\n If d is zero => -Double/MIN_VALUE\n See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#nextDown-double-" + scalb "Returns d * 2^scaleFactor, scaling by a factor of 2. If the exponent\n is between Double/MIN_EXPONENT and Double/MAX_EXPONENT, the answer is exact.\n If d is ##NaN => ##NaN\n If d is ##Inf or ##-Inf => ##Inf or ##-Inf respectively\n If d is zero => zero of same sign as d\n See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#nextDown-double-" + }) + +(def FNS + '[sin cos tan asin acos atan toRadians toDegrees exp log log10 + sqrt cbrt IEEEremainder ceil floor rint atan2 pow round random + addExact subtractExact multiplyExact incrementExact decrementExact negateExact + floorDiv floorMod ulp signum sinh cosh tanh hypot expm1 log1p copySign getExponent + nextAfter nextUp nextDown scalb]) + +;; arg names to use (match java.lang.Math signatures) +(def ARGS + '{ + sin [a] + cos [a] + tan [a] + asin [a] + acos [a] + atan [a] + to-radians [deg] + to-degrees [r] + exp [a] + log [a] + log10 [a] + sqrt [a] + cbrt [a] + IEEE-remainder [dividend divisor] + ceil [a] + floor [a] + rint [a] + atan2 [y x] + pow [a b] + round [a] + random [] + add-exact [x y] + subtract-exact [x y] + multiply-exact [x y] + increment-exact [a] + decrement-exact [a] + negate-exact [a] + floor-div [x y] + floor-mod [x y] + ulp [d] + signum [d] + sinh [x] + cosh [x] + tanh [x] + hypot [x y] + expm1 [x] + log1p [x] + copy-sign [magnitude sign] + get-exponent [d] + next-after [start direction] + next-up [d] + next-down [d] + scalb [d scaleFactor] + }) + +;; type signature to use (otherwise automatically determined) +(def ARGTYPES + '{scalb {:parameter-types [double int] :return-type double}}) diff --git a/src/clj/clojure/java/math.clj b/src/clj/clojure/math.clj similarity index 83% rename from src/clj/clojure/java/math.clj rename to src/clj/clojure/math.clj index 2d54fb52d7..c5b67b1f1c 100644 --- a/src/clj/clojure/java/math.clj +++ b/src/clj/clojure/math.clj @@ -17,8 +17,9 @@ For more complete information, see: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html"} - clojure.java.math - (:refer-clojure :exclude [min max])) + clojure.math) + +(set! *warn-on-reflection* true) (def ^{:doc "Constant for e, the base for natural logarithms. @@ -44,7 +45,7 @@ If a is zero => zero with the same sign as a See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#sin-double-" :inline-arities #{1} - :inline (fn [a] `(Math/sin ~a)) + :inline (fn [a] `(Math/sin (double ~a))) :added "1.11"} ^double [^double a] (Math/sin a)) @@ -54,7 +55,7 @@ If a is ##NaN, ##-Inf, ##Inf => ##NaN See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#cos-double-" :inline-arities #{1} - :inline (fn [a] `(Math/cos ~a)) + :inline (fn [a] `(Math/cos (double ~a))) :added "1.11"} ^double [^double a] (Math/cos a)) @@ -65,7 +66,7 @@ If a is zero => zero with the same sign as a See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#tan-double-" :inline-arities #{1} - :inline (fn [a] `(Math/tan ~a)) + :inline (fn [a] `(Math/tan (double ~a))) :added "1.11"} ^double [^double a] (Math/tan a)) @@ -76,7 +77,7 @@ If a is zero => zero with the same sign as a See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#asin-double-" :inline-arities #{1} - :inline (fn [a] `(Math/asin ~a)) + :inline (fn [a] `(Math/asin (double ~a))) :added "1.11"} ^double [^double a] (Math/asin a)) @@ -86,7 +87,7 @@ If a is ##NaN or |a|>1 => ##NaN See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#acos-double-" :inline-arities #{1} - :inline (fn [a] `(Math/acos ~a)) + :inline (fn [a] `(Math/acos (double ~a))) :added "1.11"} ^double [^double a] (Math/acos a)) @@ -97,7 +98,7 @@ If a is zero => zero with the same sign as a See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#atan-double-" :inline-arities #{1} - :inline (fn [a] `(Math/atan ~a)) + :inline (fn [a] `(Math/atan (double ~a))) :added "1.11"} ^double [^double a] (Math/atan a)) @@ -106,7 +107,7 @@ {:doc "Converts an angle in degrees to an approximate equivalent angle in radians. See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#toRadians-double-" :inline-arities #{1} - :inline (fn [deg] `(Math/toRadians ~deg)) + :inline (fn [deg] `(Math/toRadians (double ~deg))) :added "1.11"} ^double [^double deg] (Math/toRadians deg)) @@ -115,7 +116,7 @@ {:doc "Converts an angle in radians to an approximate equivalent angle in degrees. See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#toDegrees-double-" :inline-arities #{1} - :inline (fn [r] `(Math/toDegrees ~r)) + :inline (fn [r] `(Math/toDegrees (double ~r))) :added "1.11"} ^double [^double r] (Math/toDegrees r)) @@ -127,7 +128,7 @@ If a is ##-Inf => +0.0 See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#exp-double-" :inline-arities #{1} - :inline (fn [a] `(Math/exp ~a)) + :inline (fn [a] `(Math/exp (double ~a))) :added "1.11"} ^double [^double a] (Math/exp a)) @@ -139,7 +140,7 @@ If a is zero => ##-Inf See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#log-double-" :inline-arities #{1} - :inline (fn [a] `(Math/log ~a)) + :inline (fn [a] `(Math/log (double ~a))) :added "1.11"} ^double [^double a] (Math/log a)) @@ -151,7 +152,7 @@ If a is zero => ##-Inf See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#log10-double-" :inline-arities #{1} - :inline (fn [a] `(Math/log10 ~a)) + :inline (fn [a] `(Math/log10 (double ~a))) :added "1.11"} ^double [^double a] (Math/log10 a)) @@ -163,7 +164,7 @@ If a is zero => a See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#sqrt-double-" :inline-arities #{1} - :inline (fn [a] `(Math/sqrt ~a)) + :inline (fn [a] `(Math/sqrt (double ~a))) :added "1.11"} ^double [^double a] (Math/sqrt a)) @@ -175,7 +176,7 @@ If a is zero => zero with sign matching a See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#cbrt-double-" :inline-arities #{1} - :inline (fn [a] `(Math/cbrt ~a)) + :inline (fn [a] `(Math/cbrt (double ~a))) :added "1.11"} ^double [^double a] (Math/cbrt a)) @@ -190,7 +191,7 @@ If dividend is finite and divisor is infinite => dividend See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#IEEEremainder-double-double-" :inline-arities #{2} - :inline (fn [dividend divisor] `(Math/IEEEremainder ~dividend ~divisor)) + :inline (fn [dividend divisor] `(Math/IEEEremainder (double ~dividend) (double ~divisor))) :added "1.11"} ^double [^double dividend ^double divisor] (Math/IEEEremainder dividend divisor)) @@ -201,7 +202,7 @@ If a is ##NaN or ##Inf or ##-Inf or already equal to an integer => a See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#ceil-double-" :inline-arities #{1} - :inline (fn [a] `(Math/ceil ~a)) + :inline (fn [a] `(Math/ceil (double ~a))) :added "1.11"} ^double [^double a] (Math/ceil a)) @@ -213,7 +214,7 @@ If a is less than zero but greater than -1.0 => -0.0 See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#floor-double-" :inline-arities #{1} - :inline (fn [a] `(Math/floor ~a)) + :inline (fn [a] `(Math/floor (double ~a))) :added "1.11"} ^double [^double a] (Math/floor a)) @@ -224,7 +225,7 @@ If a is ##NaN or ##Inf or ##-Inf or zero => a See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#rint-double-" :inline-arities #{1} - :inline (fn [a] `(Math/rint ~a)) + :inline (fn [a] `(Math/rint (double ~a))) :added "1.11"} ^double [^double a] (Math/rint a)) @@ -235,7 +236,7 @@ For more details on special cases, see: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#atan2-double-double-" :inline-arities #{2} - :inline (fn [y x] `(Math/atan2 ~y ~x)) + :inline (fn [y x] `(Math/atan2 (double ~y) (double ~x))) :added "1.11"} ^double [^double y ^double x] (Math/atan2 y x)) @@ -245,7 +246,7 @@ For more details on special cases, see: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#pow-double-double-" :inline-arities #{2} - :inline (fn [a b] `(Math/pow ~a ~b)) + :inline (fn [a b] `(Math/pow (double ~a) (double ~b))) :added "1.11"} ^double [^double a ^double b] (Math/pow a b)) @@ -258,7 +259,7 @@ If a is ##Inf or > Long/MAX_VALUE => Long/MAX_VALUE See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#round-double-" :inline-arities #{1} - :inline (fn [a] `(Math/round ~a)) + :inline (fn [a] `(Math/round (double ~a))) :added "1.11"} ^long [^double a] (Math/round a)) @@ -277,7 +278,7 @@ {:doc "Returns the sum of x and y, throws ArithmeticException on overflow. See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#addExact-long-long-" :inline-arities #{2} - :inline (fn [x y] `(Math/addExact ~x ~y)) + :inline (fn [x y] `(Math/addExact (long ~x) (long ~y))) :added "1.11"} ^long [^long x ^long y] (Math/addExact x y)) @@ -286,7 +287,7 @@ {:doc "Returns the difference of x and y, throws ArithmeticException on overflow. See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#subtractExact-long-long-" :inline-arities #{2} - :inline (fn [x y] `(Math/subtractExact ~x ~y)) + :inline (fn [x y] `(Math/subtractExact (long ~x) (long ~y))) :added "1.11"} ^long [^long x ^long y] (Math/subtractExact x y)) @@ -295,7 +296,7 @@ {:doc "Returns the product of x and y, throws ArithmeticException on overflow. See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#multiplyExact-long-long-" :inline-arities #{2} - :inline (fn [x y] `(Math/multiplyExact ~x ~y)) + :inline (fn [x y] `(Math/multiplyExact (long ~x) (long ~y))) :added "1.11"} ^long [^long x ^long y] (Math/multiplyExact x y)) @@ -304,7 +305,7 @@ {:doc "Returns a incremented by 1, throws ArithmeticException on overflow. See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#incrementExact-long-" :inline-arities #{1} - :inline (fn [a] `(Math/incrementExact ~a)) + :inline (fn [a] `(Math/incrementExact (long ~a))) :added "1.11"} ^long [^long a] (Math/incrementExact a)) @@ -313,16 +314,16 @@ {:doc "Returns a decremented by 1, throws ArithmeticException on overflow. See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#decrementExact-long-" :inline-arities #{1} - :inline (fn [a] `(Math/decrementExact ~a)) + :inline (fn [a] `(Math/decrementExact (long ~a))) :added "1.11"} ^long [^long a] (Math/decrementExact a)) -(defn negative-exact +(defn negate-exact {:doc "Returns the negation of a, throws ArithmeticException on overflow. See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#negateExact-long-" :inline-arities #{1} - :inline (fn [a] `(Math/negateExact ~a)) + :inline (fn [a] `(Math/negateExact (long ~a))) :added "1.11"} ^long [^long a] (Math/negateExact a)) @@ -332,7 +333,7 @@ The special case (floorDiv Long/MIN_VALUE -1) overflows and returns Long/MIN_VALUE. See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#floorDiv-long-long-" :inline-arities #{2} - :inline (fn [x y] `(Math/floorDiv ~x ~y)) + :inline (fn [x y] `(Math/floorDiv (long ~x) (long ~y))) :added "1.11"} ^long [^long x ^long y] (Math/floorDiv x y)) @@ -342,47 +343,11 @@ range -|y| < r < |y|. See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#floorMod-long-long-" :inline-arities #{2} - :inline (fn [x y] `(Math/floorMod ~x ~y)) + :inline (fn [x y] `(Math/floorMod (long ~x) (long ~y))) :added "1.11"} ^long [^long x ^long y] (Math/floorMod x y)) -(defn abs - {:doc "Returns the absolute value of a (long or double). - If not negative, a is returned, else negation of a is returned. - If a is Long/MIN_VALUE => Long/MIN_VALUE - If a is a double and zero => +0.0 - If a is a double and ##Inf or ##-Inf => ##Inf - If a is a double and ##NaN => ##NaN - See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#abs-long-" - :inline-arities #{1} - :inline (fn [a] `(Math/abs ~a)) - :added "1.11"} - [a] - (Math/abs a)) - -(defn max - {:doc "Returns the greater of a or b. - If doubles and a or b is ##NaN => ##NaN - If doubles and one is negative zero, other positive zero => positive zero - See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#max-long-long-" - :inline-arities #{2} - :inline (fn [a b] `(Math/max ~a ~b)) - :added "1.11"} - [a b] - (Math/max a b)) - -(defn min - {:doc "Returns the lesser of a or b. - If doubles and a or b is ##NaN => ##NaN - If doubles and one is negative zero, other positive zero => negative zero - See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#min-double-double-" - :inline-arities #{2} - :inline (fn [p0 p1] `(Math/min ~p0 ~p1)) - :added "1.11"} - [p0 p1] - (Math/min p0 p1)) - (defn ulp {:doc "Returns the size of an ulp (unit in last place) for d. If d is ##NaN => ##NaN @@ -391,7 +356,7 @@ If d is +/- Double/MAX_VALUE => 2^971 See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#ulp-double-" :inline-arities #{1} - :inline (fn [d] `(Math/ulp ~d)) + :inline (fn [d] `(Math/ulp (double ~d))) :added "1.11"} ^double [^double d] (Math/ulp d)) @@ -399,10 +364,9 @@ (defn signum {:doc "Returns the signum function of d - zero for zero, 1.0 if >0, -1.0 if <0. If d is ##NaN => ##NaN - If d is ##Inf or ##-Inf => d See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#signum-double-" :inline-arities #{1} - :inline (fn [d] `(Math/signum ~d)) + :inline (fn [d] `(Math/signum (double ~d))) :added "1.11"} ^double [^double d] (Math/signum d)) @@ -413,7 +377,7 @@ If x is ##Inf or ##-Inf or zero => x See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#sinh-double-" :inline-arities #{1} - :inline (fn [x] `(Math/sinh ~x)) + :inline (fn [x] `(Math/sinh (double ~x))) :added "1.11"} ^double [^double x] (Math/sinh x)) @@ -425,7 +389,7 @@ If x is zero => 1.0 See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#cosh-double-" :inline-arities #{1} - :inline (fn [x] `(Math/cosh ~x)) + :inline (fn [x] `(Math/cosh (double ~x))) :added "1.11"} ^double [^double x] (Math/cosh x)) @@ -438,7 +402,7 @@ If x is ##-Inf => -1.0 See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#tanh-double-" :inline-arities #{1} - :inline (fn [x] `(Math/tanh ~x)) + :inline (fn [x] `(Math/tanh (double ~x))) :added "1.11"} ^double [^double x] (Math/tanh x)) @@ -449,7 +413,7 @@ If x or y is ##NaN and neither is ##Inf or ##-Inf => ##NaN See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#hypot-double-double-" :inline-arities #{2} - :inline (fn [x y] `(Math/hypot ~x ~y)) + :inline (fn [x y] `(Math/hypot (double ~x) (double ~y))) :added "1.11"} ^double [^double x ^double y] (Math/hypot x y)) @@ -462,7 +426,7 @@ If x is zero => x See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#expm1-double-" :inline-arities #{1} - :inline (fn [x] `(Math/expm1 ~x)) + :inline (fn [x] `(Math/expm1 (double ~x))) :added "1.11"} ^double [^double x] (Math/expm1 x)) @@ -471,10 +435,12 @@ {:doc "Returns ln(1+x). For small values of x, log1p(x) is more accurate than log(1.0+x). If x is ##NaN or < -1 => ##NaN - If x is ##Inf or ##-Inf or x => x + If x is ##Inf => ##Inf + If x is -1 => ##-Inf + If x is 0 => 0 with sign matching x See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#log1p-double-" :inline-arities #{1} - :inline (fn [x] `(Math/log1p ~x)) + :inline (fn [x] `(Math/log1p (double ~x))) :added "1.11"} ^double [^double x] (Math/log1p x)) @@ -484,7 +450,7 @@ the second. See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#copySign-double-double-" :inline-arities #{2} - :inline (fn [magnitude sign] `(Math/copySign ~magnitude ~sign)) + :inline (fn [magnitude sign] `(Math/copySign (double ~magnitude) (double ~sign))) :added "1.11"} ^double [^double magnitude ^double sign] (Math/copySign magnitude sign)) @@ -495,7 +461,7 @@ If d is zero or subnormal => Double/MIN_EXPONENT - 1 See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#getExponent-double-" :inline-arities #{1} - :inline (fn [d] `(Math/getExponent ~d)) + :inline (fn [d] `(Math/getExponent (double ~d))) :added "1.11"} [^double d] (Math/getExponent d)) @@ -513,7 +479,7 @@ => ##Inf or ##-Inf with sign matching start See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#nextAfter-double-double-" :inline-arities #{2} - :inline (fn [start direction] `(Math/nextAfter ~start ~direction)) + :inline (fn [start direction] `(Math/nextAfter (double ~start) (double ~direction))) :added "1.11"} ^double [^double start ^double direction] (Math/nextAfter start direction)) @@ -525,7 +491,7 @@ If d is zero => Double/MIN_VALUE See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#nextUp-double-" :inline-arities #{1} - :inline (fn [d] `(Math/nextUp ~d)) + :inline (fn [d] `(Math/nextUp (double ~d))) :added "1.11"} ^double [^double d] (Math/nextUp d)) @@ -533,11 +499,11 @@ (defn next-down {:doc "Returns the adjacent double of d in the direction of ##-Inf. If d is ##NaN => ##NaN - If d is ##Inf => ##-Inf - If d is zero => Double/MIN_VALUE + If d is ##-Inf => ##-Inf + If d is zero => -Double/MIN_VALUE See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#nextDown-double-" :inline-arities #{1} - :inline (fn [d] `(Math/nextDown ~d)) + :inline (fn [d] `(Math/nextDown (double ~d))) :added "1.11"} ^double [^double d] (Math/nextDown d)) @@ -549,8 +515,9 @@ If d is ##Inf or ##-Inf => ##Inf or ##-Inf respectively If d is zero => zero of same sign as d See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#nextDown-double-" - :inline-arities #{1} - :inline (fn [d scaleFactor] `(Math/scalb ~d ~scaleFactor)) + :inline-arities #{2} + :inline (fn [d scaleFactor] `(Math/scalb (double ~d) (int ~scaleFactor))) :added "1.11"} ^double [^double d scaleFactor] - (Math/scalb d scaleFactor)) \ No newline at end of file + (Math/scalb d (int scaleFactor))) + diff --git a/test/clojure/test_clojure/math.clj b/test/clojure/test_clojure/math.clj new file mode 100644 index 0000000000..63975e7505 --- /dev/null +++ b/test/clojure/test_clojure/math.clj @@ -0,0 +1,320 @@ +; Copyright (c) Rich Hickey. All rights reserved. +; The use and distribution terms for this software are covered by the +; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) +; which can be found in the file epl-v10.html 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. + +(ns clojure.test-clojure.math + (:require + [clojure.test :refer :all] + [clojure.math :as m])) + +(set! *warn-on-reflection* true) + +(defn neg-zero? + [^double d] + (and (zero? d) (< (Double/compare d 0.0) 0))) + +(defn pos-zero? + [^double d] + (and (zero? d) (not (< (Double/compare d 0.0) 0)))) + +(deftest test-sin + (is (NaN? (m/sin ##NaN))) + (is (NaN? (m/sin ##-Inf))) + (is (NaN? (m/sin ##Inf))) + (is (pos-zero? (m/sin 0.0))) + (is (neg-zero? (m/sin -0.0))) + (is (= (m/sin m/PI) (- (m/sin (- m/PI)))))) + +(deftest test-cos + (is (NaN? (m/cos ##NaN))) + (is (NaN? (m/cos ##-Inf))) + (is (NaN? (m/cos ##Inf))) + (is (= 1.0 (m/cos 0.0) (m/cos -0.0))) + (is (= (m/cos m/PI) (m/cos (- m/PI))))) + +(deftest test-tan + (is (NaN? (m/tan ##NaN))) + (is (NaN? (m/tan ##-Inf))) + (is (NaN? (m/tan ##Inf))) + (is (pos-zero? (m/tan 0.0))) + (is (neg-zero? (m/tan -0.0))) + (is (= (- (m/tan m/PI)) (m/tan (- m/PI))))) + +(deftest test-asin + (is (NaN? (m/asin ##NaN))) + (is (NaN? (m/asin 2.0))) + (is (NaN? (m/asin -2.0))) + (is (zero? (m/asin -0.0)))) + +(deftest test-acos + (is (NaN? (m/acos ##NaN))) + (is (NaN? (m/acos -2.0))) + (is (NaN? (m/acos 2.0))) + (is (= m/PI (* 2 (m/acos 0.0))))) + +(deftest test-atan + (is (NaN? (m/atan ##NaN))) + (is (pos-zero? (m/atan 0.0))) + (is (neg-zero? (m/atan -0.0))) + (is (= 0.7853981633974483 (m/atan 1)))) + +(deftest test-radians-degrees-roundtrip + (doseq [d (range 0.0 360.0 5.0)] + (is (= (m/round d) (m/round (-> d m/to-radians m/to-degrees)))))) + +(deftest test-exp + (is (NaN? (m/exp ##NaN))) + (is (= ##Inf (m/exp ##Inf))) + (is (pos-zero? (m/exp ##-Inf))) + (is (= 1.0 (m/exp 0.0))) + (is (= m/E (m/exp 1)))) + +(deftest test-log + (is (NaN? (m/log ##NaN))) + (is (NaN? (m/log -1.0))) + (is (= ##Inf (m/log ##Inf))) + (is (= ##-Inf (m/log 0.0))) + (is (= 1.0 (m/log m/E)))) + +(deftest test-log10 + (is (NaN? (m/log10 ##NaN))) + (is (NaN? (m/log10 -1.0))) + (is (= ##Inf (m/log10 ##Inf))) + (is (= ##-Inf (m/log10 0.0))) + (is (= 1.0 (m/log10 10)))) + +(deftest test-sqrt + (is (NaN? (m/sqrt ##NaN))) + (is (NaN? (m/sqrt -1.0))) + (is (= ##Inf (m/sqrt ##Inf))) + (is (pos-zero? (m/sqrt 0))) + (is (= 2.0 (m/sqrt 4.0)))) + +(deftest test-cbrt + (is (NaN? (m/cbrt ##NaN))) + (is (= ##-Inf (m/cbrt ##-Inf))) + (is (= ##Inf (m/cbrt ##Inf))) + (is (pos-zero? (m/cbrt 0))) + (is (= 2.0 (m/cbrt 8.0)))) + +(deftest test-IEEE-remainder + (is (NaN? (m/IEEE-remainder ##NaN 1.0))) + (is (NaN? (m/IEEE-remainder 1.0 ##NaN))) + (is (NaN? (m/IEEE-remainder ##Inf 2.0))) + (is (NaN? (m/IEEE-remainder ##-Inf 2.0))) + (is (NaN? (m/IEEE-remainder 2 0.0))) + (is (= 1.0 (m/IEEE-remainder 5.0 4.0)))) + +(deftest test-ceil + (is (NaN? (m/ceil ##NaN))) + (is (= ##Inf (m/ceil ##Inf))) + (is (= ##-Inf (m/ceil ##-Inf))) + (is (= 4.0 (m/ceil m/PI)))) + +(deftest test-floor + (is (NaN? (m/floor ##NaN))) + (is (= ##Inf (m/floor ##Inf))) + (is (= ##-Inf (m/floor ##-Inf))) + (is (= 3.0 (m/floor m/PI)))) + +(deftest test-rint + (is (NaN? (m/rint ##NaN))) + (is (= ##Inf (m/rint ##Inf))) + (is (= ##-Inf (m/rint ##-Inf))) + (is (= 1.0 (m/rint 1.2))) + (is (neg-zero? (m/rint -0.01)))) + +(deftest test-atan2 + (is (NaN? (m/atan2 ##NaN 1.0))) + (is (NaN? (m/atan2 1.0 ##NaN))) + (is (pos-zero? (m/atan2 0.0 1.0))) + (is (neg-zero? (m/atan2 -0.0 1.0))) + (is (= m/PI (m/atan2 0.0 -1.0))) + (is (= (- m/PI) (m/atan2 -0.0 -1.0))) + (is (= m/PI (* 2.0 (m/atan2 1.0 0.0)))) + (is (= m/PI (* -2.0 (m/atan2 -1.0 0.0)))) + (is (= m/PI (* 4.0 (m/atan2 ##Inf ##Inf)))) + (is (= m/PI (/ (* 4.0 (m/atan2 ##Inf ##-Inf)) 3.0))) + (is (= m/PI (* -4.0 (m/atan2 ##-Inf ##Inf)))) + (is (= m/PI (/ (* -4.0 (m/atan2 ##-Inf ##-Inf)) 3.0)))) + +(deftest test-pow + (is (= 1.0 (m/pow 4.0 0.0))) + (is (= 1.0 (m/pow 4.0 -0.0))) + (is (= 4.2 (m/pow 4.2 1.0))) + (is (NaN? (m/pow 4.2 ##NaN))) + (is (NaN? (m/pow ##NaN 2.0))) + (is (= ##Inf (m/pow 2.0 ##Inf))) + (is (= ##Inf (m/pow 0.5 ##-Inf))) + (is (= 0.0 (m/pow 2.0 ##-Inf))) + (is (= 0.0 (m/pow 0.5 ##Inf))) + (is (NaN? (m/pow 1.0 ##Inf))) + (is (pos-zero? (m/pow 0.0 1.5))) + (is (pos-zero? (m/pow ##Inf -2.0))) + (is (= ##Inf (m/pow 0.0 -2.0))) + (is (= ##Inf (m/pow ##Inf 2.0))) + (is (pos-zero? (m/pow -0.0 1.5))) + (is (pos-zero? (m/pow ##-Inf -1.5))) + (is (neg-zero? (m/pow -0.0 3.0))) + (is (neg-zero? (m/pow ##-Inf -3.0))) + (is (= ##Inf (m/pow -0.0 -1.5))) + (is (= ##Inf (m/pow ##-Inf 2.5))) + (is (= ##-Inf (m/pow -0.0 -3.0))) + (is (= ##-Inf (m/pow ##-Inf 3.0))) + (is (= 4.0 (m/pow -2.0 2.0))) + (is (= -8.0 (m/pow -2.0 3.0))) + (is (= 8.0 (m/pow 2.0 3.0)))) + +(deftest test-round + (is (= 0 (m/round ##NaN))) + (is (= Long/MIN_VALUE (m/round ##-Inf))) + (is (= Long/MIN_VALUE (m/round (- Long/MIN_VALUE 2.0)))) + (is (= Long/MAX_VALUE (m/round ##Inf))) + (is (= Long/MAX_VALUE (m/round (+ Long/MAX_VALUE 2.0)))) + (is (= 4 (m/round 3.5)))) + +(deftest test-add-exact + (try + (m/add-exact Long/MAX_VALUE 1) + (is false) + (catch ArithmeticException _ + (is true)))) + +(deftest test-subtract-exact + (try + (m/subtract-exact Long/MIN_VALUE 1) + (is false) + (catch ArithmeticException _ + (is true)))) + +(deftest test-multiply-exact + (try + (m/multiply-exact Long/MAX_VALUE 2) + (is false) + (catch ArithmeticException _ + (is true)))) + +(deftest test-increment-exact + (try + (m/increment-exact Long/MAX_VALUE) + (is false) + (catch ArithmeticException _ + (is true)))) + +(deftest test-decrement-exact + (try + (m/decrement-exact Long/MIN_VALUE) + (is false) + (catch ArithmeticException _ + (is true)))) + +(deftest test-negate-exact + (is (= (inc Long/MIN_VALUE) (m/negate-exact Long/MAX_VALUE))) + (try + (m/negate-exact Long/MIN_VALUE) + (is false) + (catch ArithmeticException _ + (is true)))) + +(deftest test-floor-div + (is (= Long/MIN_VALUE (m/floor-div Long/MIN_VALUE -1))) + (is (= -1 (m/floor-div -2 5)))) + +(deftest test-floor-mod + (is (= 3 (m/floor-mod -2 5)))) + +(deftest test-ulp + (is (NaN? (m/ulp ##NaN))) + (is (= ##Inf (m/ulp ##Inf))) + (is (= ##Inf (m/ulp ##-Inf))) + (is (= Double/MIN_VALUE (m/ulp 0.0))) + (is (= (m/pow 2 971) (m/ulp Double/MAX_VALUE))) + (is (= (m/pow 2 971) (m/ulp (- Double/MAX_VALUE))))) + +(deftest test-signum + (is (NaN? (m/signum ##NaN))) + (is (zero? (m/signum 0.0))) + (is (zero? (m/signum -0.0))) + (is (= 1.0 (m/signum 42.0))) + (is (= -1.0 (m/signum -42.0)))) + +(deftest test-sinh + (is (NaN? (m/sinh ##NaN))) + (is (= ##Inf (m/sinh ##Inf))) + (is (= ##-Inf (m/sinh ##-Inf))) + (is (= 0.0 (m/sinh 0.0)))) + +(deftest test-cosh + (is (NaN? (m/cosh ##NaN))) + (is (= ##Inf (m/cosh ##Inf))) + (is (= ##Inf (m/cosh ##-Inf))) + (is (= 1.0 (m/cosh 0.0)))) + +(deftest test-tanh + (is (NaN? (m/tanh ##NaN))) + (is (= 1.0 (m/tanh ##Inf))) + (is (= -1.0 (m/tanh ##-Inf))) + (is (= 0.0 (m/tanh 0.0)))) + +(deftest test-hypot + (is (= ##Inf (m/hypot 1.0 ##Inf))) + (is (= ##Inf (m/hypot ##Inf 1.0))) + (is (NaN? (m/hypot ##NaN 1.0))) + (is (NaN? (m/hypot 1.0 ##NaN))) + (is (= 13.0 (m/hypot 5.0 12.0)))) + +(deftest test-expm1 + (is (NaN? (m/expm1 ##NaN))) + (is (= ##Inf (m/expm1 ##Inf))) + (is (= -1.0 (m/expm1 ##-Inf))) + (is (= 0.0 (m/expm1 0.0)))) + +(deftest test-log1p + (is (NaN? (m/log1p ##NaN))) + (is (= ##Inf (m/log1p ##Inf))) + (is (= ##-Inf (m/log1p -1.0))) + (is (pos-zero? (m/log1p 0.0))) + (is (neg-zero? (m/log1p -0.0)))) + +(deftest test-copy-sign + (is (= 1.0 (m/copy-sign 1.0 42.0))) + (is (= -1.0 (m/copy-sign 1.0 -42.0))) + (is (= -1.0 (m/copy-sign 1.0 ##-Inf)))) + +(deftest test-get-exponent + (is (= (inc Double/MAX_EXPONENT) (m/get-exponent ##NaN))) + (is (= (inc Double/MAX_EXPONENT) (m/get-exponent ##Inf))) + (is (= (inc Double/MAX_EXPONENT) (m/get-exponent ##-Inf))) + (is (= (dec Double/MIN_EXPONENT) (m/get-exponent 0.0))) + (is (= 0 (m/get-exponent 1.0))) + (is (= 13 (m/get-exponent 12345.678)))) + +(deftest test-next-after + (is (NaN? (m/next-after ##NaN 1))) + (is (NaN? (m/next-after 1 ##NaN))) + (is (pos-zero? (m/next-after 0.0 0.0))) + (is (neg-zero? (m/next-after -0.0 -0.0))) + (is (= Double/MAX_VALUE (m/next-after ##Inf 1.0))) + (is (pos-zero? (m/next-after Double/MIN_VALUE -1.0)))) + +(deftest test-next-up + (is (NaN? (m/next-up ##NaN))) + (is (= ##Inf (m/next-up ##Inf))) + (is (= Double/MIN_VALUE (m/next-up 0.0)))) + +(deftest test-next-down + (is (NaN? (m/next-down ##NaN))) + (is (= ##-Inf (m/next-down ##-Inf))) + (is (= (- Double/MIN_VALUE) (m/next-down 0.0)))) + +(deftest test-scalb + (is (NaN? (m/scalb ##NaN 1))) + (is (= ##Inf (m/scalb ##Inf 1))) + (is (= ##-Inf (m/scalb ##-Inf 1))) + (is (pos-zero? (m/scalb 0.0 2))) + (is (neg-zero? (m/scalb -0.0 2))) + (is (= 32.0 (m/scalb 2.0 4)))) From ff61321179a0b0f7d2c17a394ade80465ac15c28 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Mon, 10 Jan 2022 13:52:31 -0600 Subject: [PATCH 42/78] CLJ-2673 Implement abs/min/max in clojure.core with polymorphic numeric support Signed-off-by: Alex Miller --- src/clj/clojure/core.clj | 12 +++++++ src/jvm/clojure/lang/Numbers.java | 51 +++++++++++++++++++++------ test/clojure/test_clojure/numbers.clj | 14 ++++++++ 3 files changed, 67 insertions(+), 10 deletions(-) diff --git a/src/clj/clojure/core.clj b/src/clj/clojure/core.clj index 0dba6fcd97..7c8cb1804a 100644 --- a/src/clj/clojure/core.clj +++ b/src/clj/clojure/core.clj @@ -1134,6 +1134,18 @@ ([x y & more] (reduce1 min (min x y) more))) +(defn abs + {:doc "Returns the absolute value of a. + If a is Long/MIN_VALUE => Long/MIN_VALUE + If a is a double and zero => +0.0 + If a is a double and ##Inf or ##-Inf => ##Inf + If a is a double and ##NaN => ##NaN" + :inline-arities #{1} + :inline (fn [a] `(clojure.lang.Numbers/abs ~a)) + :added "1.11"} + [a] + (clojure.lang.Numbers/abs a)) + (defn dec' "Returns a number one less than num. Supports arbitrary precision. See also: dec" diff --git a/src/jvm/clojure/lang/Numbers.java b/src/jvm/clojure/lang/Numbers.java index fa13cba62c..6405bc2193 100644 --- a/src/jvm/clojure/lang/Numbers.java +++ b/src/jvm/clojure/lang/Numbers.java @@ -68,6 +68,8 @@ static interface Ops{ public Number dec(Number x); public Number decP(Number x); public Number unchecked_dec(Number x); + + public Number abs(Number x); } static abstract class OpsP implements Ops{ @@ -619,6 +621,10 @@ public Number unchecked_dec(Number x){ long val = x.longValue(); return num(Numbers.unchecked_dec(val)); } + + public Number abs(Number x){ + return num(Math.abs(x.longValue())); + } } final static class DoubleOps extends OpsP{ @@ -706,6 +712,10 @@ public Number inc(Number x){ public Number dec(Number x){ return Double.valueOf(x.doubleValue() - 1); } + + public Number abs(Number x) { + return num(Math.abs(x.doubleValue())); + } } final static class RatioOps extends OpsP{ @@ -837,6 +847,11 @@ public Number dec(Number x){ return Numbers.add(x, -1); } + public Number abs(Number x) { + Ratio r = (Ratio) x; + return new Ratio(r.numerator.abs(), r.denominator); + } + } final static class BigIntOps extends OpsP{ @@ -935,6 +950,10 @@ public Number dec(Number x){ BigInteger bx = toBigInteger(x); return BigInt.fromBigInteger(bx.subtract(BigInteger.ONE)); } + + public Number abs(Number x) { + return BigInt.fromBigInteger(toBigInteger(x).abs()); + } } @@ -1054,6 +1073,14 @@ public Number dec(Number x){ ? bx.subtract(BigDecimal.ONE) : bx.subtract(BigDecimal.ONE, mc); } + + public Number abs(Number x) { + MathContext mc = (MathContext) MATH_CONTEXT.deref(); + BigDecimal bx = (BigDecimal) x; + return mc == null + ? ((BigDecimal) x).abs() + : ((BigDecimal) x).abs(mc); + } } static final LongOps LONG_OPS = new LongOps(); @@ -4068,11 +4095,7 @@ static public Object max(long x, double y){ static public long max(long x, long y){ - if(x > y) { - return x; - } else { - return y; - } + return Math.max(x, y); } @@ -4166,11 +4189,7 @@ static public Object min(long x, double y){ static public long min(long x, long y){ - if(x < y) { - return x; - } else { - return y; - } + return Math.min(x, y); } static public Object min(long x, Object y){ @@ -4221,4 +4240,16 @@ static public Object min(Object x, Object y){ } } +static public long abs(long x){ + return Math.abs(x); +} + +static public double abs(double x){ + return Math.abs(x); +} + +static public Number abs(Object x) { + return ops(x).abs((Number)x); +} + } diff --git a/test/clojure/test_clojure/numbers.clj b/test/clojure/test_clojure/numbers.clj index 26140a7c29..cc62a63c89 100644 --- a/test/clojure/test_clojure/numbers.clj +++ b/test/clojure/test_clojure/numbers.clj @@ -644,6 +644,20 @@ Math/pow overflows to Infinity." (is (= java.lang.Long (class (min 1.0 2.0 -10)))) (is (= java.lang.Double (class (min 1 2 -10.0 3 4 5)))))) +(deftest test-abs + (are [in ex] (= ex (abs in)) + -1 1 + 1 1 + Long/MIN_VALUE Long/MIN_VALUE ;; special case! + -1.0 1.0 + -0.0 0.0 + ##-Inf ##Inf + ##Inf ##Inf + -123.456M 123.456M + -123N 123N + -1/5 1/5) + (is (NaN? (abs ##NaN)))) + (deftest clj-868 (testing "min/max: NaN is contagious" (letfn [(fnan? [^Float x] (Float/isNaN x)) From bf0c0e23a0e05509c785598be19b01c2b8e80bb5 Mon Sep 17 00:00:00 2001 From: Paula Gearon Date: Tue, 14 Dec 2021 10:44:30 -0500 Subject: [PATCH 43/78] CLJ-2679 quoting condition values that are generated for case-hash collisions Signed-off-by: Alex Miller --- src/clj/clojure/core.clj | 2 +- test/clojure/test_clojure/control.clj | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/clj/clojure/core.clj b/src/clj/clojure/core.clj index 7c8cb1804a..72a4548eb3 100644 --- a/src/clj/clojure/core.clj +++ b/src/clj/clojure/core.clj @@ -6702,7 +6702,7 @@ fails, attempts to require sym's namespace and retries." (next ks) (next vs)) m)) assoc-multi (fn [m h bucket] - (let [testexprs (apply concat bucket) + (let [testexprs (mapcat (fn [kv] [(list 'quote (first kv)) (second kv)]) bucket) expr `(condp = ~expr-sym ~@testexprs ~default)] (assoc m h expr))) hmap (reduce1 diff --git a/test/clojure/test_clojure/control.clj b/test/clojure/test_clojure/control.clj index 92846ad38d..f3fe436b45 100644 --- a/test/clojure/test_clojure/control.clj +++ b/test/clojure/test_clojure/control.clj @@ -421,7 +421,14 @@ :b 1 :c -2 :d 4294967296 - :d 3)) + :d 3) + (are [result input] (= result (case input + #{a} :set + :foo :keyword + a :symbol)) + :symbol 'a + :keyword :foo + :set '#{a})) (testing "test warn for hash collision" (should-print-err-message #"Performance warning, .*:\d+ - hash collision of some case test constants; if selected, those entries will be tested sequentially..*\r?\n" From 0cbf655d181c2de8cd30bf234e40488fc94dbdfa Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Tue, 30 Nov 2021 08:19:41 -0600 Subject: [PATCH 44/78] CLJ-2670 - Use Math exact methods where possible for perf Signed-off-by: Alex Miller --- src/jvm/clojure/lang/Numbers.java | 29 ++++++--------------------- src/jvm/clojure/lang/RT.java | 5 +---- test/clojure/test_clojure/numbers.clj | 2 +- 3 files changed, 8 insertions(+), 28 deletions(-) diff --git a/src/jvm/clojure/lang/Numbers.java b/src/jvm/clojure/lang/Numbers.java index 6405bc2193..82d8e6914c 100644 --- a/src/jvm/clojure/lang/Numbers.java +++ b/src/jvm/clojure/lang/Numbers.java @@ -1915,10 +1915,7 @@ static public Number unchecked_dec(Object x){ static public double remainder(long x, double y){return remainder((double)x,y);} static public long add(long x, long y){ - long ret = x + y; - if ((ret ^ x) < 0 && (ret ^ y) < 0) - return throwIntOverflow(); - return ret; + return Math.addExact(x, y); } static public Number addP(long x, long y){ @@ -1929,10 +1926,7 @@ static public Number addP(long x, long y){ } static public long minus(long x, long y){ - long ret = x - y; - if (((ret ^ x) < 0 && (ret ^ ~y) < 0)) - return throwIntOverflow(); - return ret; + return Math.subtractExact(x, y); } static public Number minusP(long x, long y){ @@ -1943,9 +1937,7 @@ static public Number minusP(long x, long y){ } static public long minus(long x){ - if(x == Long.MIN_VALUE) - return throwIntOverflow(); - return -x; + return Math.negateExact(x); } static public Number minusP(long x){ @@ -1955,9 +1947,7 @@ static public Number minusP(long x){ } static public long inc(long x){ - if(x == Long.MAX_VALUE) - return throwIntOverflow(); - return x + 1; + return Math.incrementExact(x); } static public Number incP(long x){ @@ -1967,9 +1957,7 @@ static public Number incP(long x){ } static public long dec(long x){ - if(x == Long.MIN_VALUE) - return throwIntOverflow(); - return x - 1; + return Math.decrementExact(x); } static public Number decP(long x){ @@ -1980,12 +1968,7 @@ static public Number decP(long x){ static public long multiply(long x, long y){ - if (x == Long.MIN_VALUE && y < 0) - return throwIntOverflow(); - long ret = x * y; - if (y != 0 && ret/y != x) - return throwIntOverflow(); - return ret; + return Math.multiplyExact(x, y); } static public Number multiplyP(long x, long y){ diff --git a/src/jvm/clojure/lang/RT.java b/src/jvm/clojure/lang/RT.java index 74399cf15f..5d20ef4964 100644 --- a/src/jvm/clojure/lang/RT.java +++ b/src/jvm/clojure/lang/RT.java @@ -1244,10 +1244,7 @@ static public int intCast(float x){ } static public int intCast(long x){ - int i = (int) x; - if(i != x) - throw new IllegalArgumentException("Value out of range for int: " + x); - return i; + return Math.toIntExact(x); } static public int intCast(double x){ diff --git a/test/clojure/test_clojure/numbers.clj b/test/clojure/test_clojure/numbers.clj index cc62a63c89..a6b61605ea 100644 --- a/test/clojure/test_clojure/numbers.clj +++ b/test/clojure/test_clojure/numbers.clj @@ -181,7 +181,7 @@ (let [wrapped (fn [x] (try (f x) - (catch IllegalArgumentException e :error)))] + (catch RuntimeException e :error)))] (is (= vals (map wrapped inputs))))))) ;; *** Functions *** From 4b9eadccce2aaf97e64bcc8e35c05c529df8fdd2 Mon Sep 17 00:00:00 2001 From: Hugo Duncan Date: Wed, 12 Mar 2014 14:38:38 -0400 Subject: [PATCH 45/78] Fix quoting in assert-predicate Signed-off-by: Alex Miller --- src/clj/clojure/test.clj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/clj/clojure/test.clj b/src/clj/clojure/test.clj index 0ab20a75a3..fc3536d7f3 100644 --- a/src/clj/clojure/test.clj +++ b/src/clj/clojure/test.clj @@ -447,7 +447,7 @@ result# (apply ~pred values#)] (if result# (do-report {:type :pass, :message ~msg, - :expected '~form, :actual (cons ~pred values#)}) + :expected '~form, :actual (cons '~pred values#)}) (do-report {:type :fail, :message ~msg, :expected '~form, :actual (list '~'not (cons '~pred values#))})) result#))) From f08a81ba946cb7afaea859822bba1f52004326ec Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Mon, 20 Sep 2021 15:06:45 -0500 Subject: [PATCH 46/78] CLJ-2234 - Use explicit multimethod hierarchy in preference checks Signed-off-by: Alex Miller --- src/jvm/clojure/lang/MultiFn.java | 26 +++++++-------- test/clojure/test_clojure/multimethods.clj | 37 ++++++++++++++++++++++ 2 files changed, 50 insertions(+), 13 deletions(-) diff --git a/src/jvm/clojure/lang/MultiFn.java b/src/jvm/clojure/lang/MultiFn.java index fd37e2a085..44ac1ce1c0 100644 --- a/src/jvm/clojure/lang/MultiFn.java +++ b/src/jvm/clojure/lang/MultiFn.java @@ -85,7 +85,7 @@ public MultiFn preferMethod(Object dispatchValX, Object dispatchValY) { rw.writeLock().lock(); try { - if(prefers(dispatchValY, dispatchValX)) + if(prefers(hierarchy.deref(), dispatchValY, dispatchValX)) throw new IllegalStateException( String.format("Preference conflict in multimethod '%s': %s is already preferred to %s", name, dispatchValY, dispatchValX)); @@ -102,29 +102,29 @@ public MultiFn preferMethod(Object dispatchValX, Object dispatchValY) { } } -private boolean prefers(Object x, Object y) { +private boolean prefers(Object hierarchy, Object x, Object y) { IPersistentSet xprefs = (IPersistentSet) getPreferTable().valAt(x); if(xprefs != null && xprefs.contains(y)) return true; - for(ISeq ps = RT.seq(parents.invoke(y)); ps != null; ps = ps.next()) + for(ISeq ps = RT.seq(parents.invoke(hierarchy, y)); ps != null; ps = ps.next()) { - if(prefers(x, ps.first())) + if(prefers(hierarchy, x, ps.first())) return true; } - for(ISeq ps = RT.seq(parents.invoke(x)); ps != null; ps = ps.next()) + for(ISeq ps = RT.seq(parents.invoke(hierarchy, x)); ps != null; ps = ps.next()) { - if(prefers(ps.first(), y)) + if(prefers(hierarchy, ps.first(), y)) return true; } return false; } -private boolean isA(Object x, Object y) { - return RT.booleanCast(isa.invoke(hierarchy.deref(), x, y)); +private boolean isA(Object hierarchy, Object x, Object y) { + return RT.booleanCast(isa.invoke(hierarchy, x, y)); } -private boolean dominates(Object x, Object y) { - return prefers(x, y) || isA(x, y); +private boolean dominates(Object hierarchy, Object x, Object y) { + return prefers(hierarchy, x, y) || isA(hierarchy, x, y); } private IPersistentMap resetCache() { @@ -170,11 +170,11 @@ private IFn findAndCacheBestMethod(Object dispatchVal) { for(Object o : getMethodTable()) { Map.Entry e = (Map.Entry) o; - if(isA(dispatchVal, e.getKey())) + if(isA(ch, dispatchVal, e.getKey())) { - if(bestEntry == null || dominates(e.getKey(), bestEntry.getKey())) + if(bestEntry == null || dominates(ch, e.getKey(), bestEntry.getKey())) bestEntry = e; - if(!dominates(bestEntry.getKey(), e.getKey())) + if(!dominates(ch, bestEntry.getKey(), e.getKey())) throw new IllegalArgumentException( String.format( "Multiple methods in multimethod '%s' match dispatch value: %s -> %s and %s, and neither is preferred", diff --git a/test/clojure/test_clojure/multimethods.clj b/test/clojure/test_clojure/multimethods.clj index 924b0bcbeb..435f0f64a5 100644 --- a/test/clojure/test_clojure/multimethods.clj +++ b/test/clojure/test_clojure/multimethods.clj @@ -203,6 +203,43 @@ (testing "The prefers method now returns the correct table" (is (= {[::rect ::shape] #{[::shape ::rect]}} (prefers bar))))) +(deftest indirect-preferences-mulitmethod-test + (testing "Using global hierarchy" + (derive ::parent-1 ::grandparent-1) + (derive ::parent-2 ::grandparent-2) + (derive ::child ::parent-1) + (derive ::child ::parent-2) + (testing "x should be preferred over y if x is preferred over an ancestor of y" + (defmulti indirect-1 keyword) + (prefer-method indirect-1 ::parent-1 ::grandparent-2) + (defmethod indirect-1 ::parent-1 [_] ::parent-1) + (defmethod indirect-1 ::parent-2 [_] ::parent-2) + (is (= ::parent-1 (indirect-1 ::child)))) + (testing "x should be preferred over y if an ancestor of x is preferred over y" + (defmulti indirect-2 keyword) + (prefer-method indirect-2 ::grandparent-1 ::parent-2) + (defmethod indirect-2 ::parent-1 [_] ::parent-1) + (defmethod indirect-2 ::parent-2 [_] ::parent-2) + (is (= ::parent-1 (indirect-2 ::child))))) + (testing "Using custom hierarchy" + (def local-h (-> (make-hierarchy) + (derive :parent-1 :grandparent-1) + (derive :parent-2 :grandparent-2) + (derive :child :parent-1) + (derive :child :parent-2))) + (testing "x should be preferred over y if x is preferred over an ancestor of y" + (defmulti indirect-3 keyword :hierarchy #'local-h) + (prefer-method indirect-3 :parent-1 :grandparent-2) + (defmethod indirect-3 :parent-1 [_] :parent-1) + (defmethod indirect-3 :parent-2 [_] :parent-2) + (is (= :parent-1 (indirect-3 :child)))) + (testing "x should be preferred over y if an ancestor of x is preferred over y" + (defmulti indirect-4 keyword :hierarchy #'local-h) + (prefer-method indirect-4 :grandparent-1 :parent-2) + (defmethod indirect-4 :parent-1 [_] :parent-1) + (defmethod indirect-4 :parent-2 [_] :parent-2) + (is (= :parent-1 (indirect-4 :child)))))) + (deftest remove-all-methods-test (testing "Core function remove-all-methods works" (defmulti simple1 identity) From c33a5abca7828843b7018a8aa28e63dd40310f86 Mon Sep 17 00:00:00 2001 From: Jonathan D Johnston Date: Thu, 21 Mar 2019 20:59:30 -0400 Subject: [PATCH 47/78] CLJ-2493: Prevent browse-url from hanging when using xdg-open (updated) Signed-off-by: Alex Miller --- src/clj/clojure/java/browse.clj | 2 +- src/clj/clojure/java/shell.clj | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/clj/clojure/java/browse.clj b/src/clj/clojure/java/browse.clj index 6fcc650756..c416e53832 100644 --- a/src/clj/clojure/java/browse.clj +++ b/src/clj/clojure/java/browse.clj @@ -71,6 +71,6 @@ script (if (= :uninitialized script) (reset! *open-url-script* (open-url-script-val)) script)] - (or (when script (sh/sh script (str url)) true) + (or (when script (sh/launch script (str url)) true) (open-url-in-browser url) (open-url-in-swing url)))) diff --git a/src/clj/clojure/java/shell.clj b/src/clj/clojure/java/shell.clj index cb3f90a276..8f167086df 100644 --- a/src/clj/clojure/java/shell.clj +++ b/src/clj/clojure/java/shell.clj @@ -127,6 +127,21 @@ collecting its stdout"} exit-code (.waitFor proc)] {:exit exit-code :out @out :err @err})))) +(defn launch + "Same as sh except the I/O channels of the sub-process are ignored. + + Use when you want the sub-process to take an action, but do not want to wait + for the I/O channels to close. Example: Launching a browser with xdg-open. + " + {:added "1.11"} + [& args] + (let [[cmd opts] (parse-args args) + proc (.exec (Runtime/getRuntime) + ^"[Ljava.lang.String;" (into-array cmd) + (as-env-strings (:env opts)) + (as-file (:dir opts)))] + {:exit (.waitFor proc)})) + (comment (println (sh "ls" "-l")) @@ -139,4 +154,9 @@ collecting its stdout"} (println (sh "cat" "myimage.png" :out-enc :bytes)) ; reads binary file into bytes[] (println (sh "cmd" "/c dir 1>&2")) +(println (launch "touch" "my-test-file")) +(println (sh "ls" "-l" "my-test-file")) +(println (launch "rm" "my-test-file")) +(println (sh "ls" "-l" "my-test-file")) + ) From b962791cbb201e91c29003f2ae1f7cd7a908971f Mon Sep 17 00:00:00 2001 From: Ghadi Shayban Date: Fri, 16 Oct 2020 16:13:10 -0400 Subject: [PATCH 48/78] CLJ-2556 complete into's process consistently Signed-off-by: Alex Miller --- src/clj/clojure/core.clj | 6 +++++- test/clojure/test_clojure/transducers.clj | 10 ++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/clj/clojure/core.clj b/src/clj/clojure/core.clj index 72a4548eb3..30500de3e9 100644 --- a/src/clj/clojure/core.clj +++ b/src/clj/clojure/core.clj @@ -6961,7 +6961,11 @@ fails, attempts to require sym's namespace and retries." (reduce conj to from))) ([to xform from] (if (instance? clojure.lang.IEditableCollection to) - (with-meta (persistent! (transduce xform conj! (transient to) from)) (meta to)) + (let [tm (meta to) + rf (fn + ([coll] (-> (persistent! coll) (with-meta tm))) + ([coll v] (conj! coll v)))] + (transduce xform rf (transient to) from)) (transduce xform conj to from)))) (defn mapv diff --git a/test/clojure/test_clojure/transducers.clj b/test/clojure/test_clojure/transducers.clj index 76a0e978a3..b7a9c665e2 100644 --- a/test/clojure/test_clojure/transducers.clj +++ b/test/clojure/test_clojure/transducers.clj @@ -398,3 +398,13 @@ (sequence (map-indexed vector) []))) (is (= [[0 1] [1 2] [2 3] [3 4]] (sequence (map-indexed vector) (range 1 5))))) + +(deftest test-into+halt-when + (is (= :anomaly (into [] (comp (filter some?) (halt-when #{:anomaly})) + [1 2 3 :anomaly 4]))) + (is (= {:anomaly :oh-no!, + :partial-results [1 2]} + (into [] + (halt-when :anomaly #(assoc %2 :partial-results %1)) + [1 2 {:anomaly :oh-no!} 3 4])))) + From c01f10bd8c68bd16c657fe352b206573f9306168 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Thu, 21 Oct 2021 22:40:07 -0500 Subject: [PATCH 49/78] CLJ-2665 Modify change for :as-alias to load if :as or :use also included Signed-off-by: Alex Miller --- src/clj/clojure/core.clj | 31 +++++++++++++-------------- test/clojure/test_clojure/ns_libs.clj | 12 ++++++----- 2 files changed, 22 insertions(+), 21 deletions(-) diff --git a/src/clj/clojure/core.clj b/src/clj/clojure/core.clj index 30500de3e9..055050b530 100644 --- a/src/clj/clojure/core.clj +++ b/src/clj/clojure/core.clj @@ -5960,26 +5960,25 @@ opts (apply hash-map options) {:keys [as reload reload-all require use verbose as-alias]} opts loaded (contains? @*loaded-libs* lib) - load (cond reload-all - load-all - (or reload (not require) (not loaded)) - load-one) need-ns (or as use) + load (cond reload-all load-all + reload load-one + (not loaded) (cond need-ns load-one + as-alias (fn [lib _need _require] (create-ns lib)) + :else load-one)) + filter-opts (select-keys opts '(:exclude :only :rename :refer)) undefined-on-entry (not (find-ns lib))] (binding [*loading-verbosely* (or *loading-verbosely* verbose)] - (if as-alias - (when (not (find-ns lib)) - (create-ns lib)) - (if load - (try - (load lib need-ns require) - (catch Exception e - (when undefined-on-entry - (remove-ns lib)) - (throw e))) - (throw-if (and need-ns (not (find-ns lib))) - "namespace '%s' not found" lib))) + (if load + (try + (load lib need-ns require) + (catch Exception e + (when undefined-on-entry + (remove-ns lib)) + (throw e))) + (throw-if (and need-ns (not (find-ns lib))) + "namespace '%s' not found" lib)) (when (and need-ns *loading-verbosely*) (printf "(clojure.core/in-ns '%s)\n" (ns-name *ns*))) (when as diff --git a/test/clojure/test_clojure/ns_libs.clj b/test/clojure/test_clojure/ns_libs.clj index a9f4f97f71..256f99ae87 100644 --- a/test/clojure/test_clojure/ns_libs.clj +++ b/test/clojure/test_clojure/ns_libs.clj @@ -116,16 +116,18 @@ (is (= :not.a.real.ns.foo/baz (read-string "::foo/baz"))) - ;; can use :as-alias in use - (use '[dummy.example1 :as-alias e1]) - (let [aliases (ns-aliases *ns*)] - (is (= 'dummy.example1 (ns-name (get aliases 'e1))))) + ;; can use :as-alias in use, but load will occur + (use '[clojure.walk :as-alias e1]) + (is (= 'clojure.walk (ns-name (get (ns-aliases *ns*) 'e1)))) + (is (= :clojure.walk/walk (read-string "::e1/walk"))) ;; can use both :as and :as-alias (require '[clojure.set :as n1 :as-alias n2]) (let [aliases (ns-aliases *ns*)] (is (= 'clojure.set (ns-name (get aliases 'n1)))) - (is (= 'clojure.set (ns-name (get aliases 'n2)))))) + (is (= 'clojure.set (ns-name (get aliases 'n2)))) + (is (= (resolve 'n1/union) #'clojure.set/union)) + (is (= (resolve 'n2/union) #'clojure.set/union)))) (deftest require-as-alias-then-load-later ;; alias but don't load From 4a4a6e7717d411679820c4a3ce735a77aef45cc3 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Thu, 2 Dec 2021 13:37:05 -0600 Subject: [PATCH 50/78] CLJ-2611 Disallow XXE by default in clojure.xml/parse Signed-off-by: Alex Miller --- src/clj/clojure/xml.clj | 40 ++++++++++++++++++++--- test/clojure/test_clojure/clojure_xml.clj | 13 ++++++-- 2 files changed, 47 insertions(+), 6 deletions(-) diff --git a/src/clj/clojure/xml.clj b/src/clj/clojure/xml.clj index 4e4220f265..d892e19279 100644 --- a/src/clj/clojure/xml.clj +++ b/src/clj/clojure/xml.clj @@ -72,8 +72,36 @@ (skippedEntity [name]) )))) -(defn startparse-sax [s ch] - (.. SAXParserFactory (newInstance) (newSAXParser) (parse s ch))) +(defn sax-parser + "Create a new SAXParser" + {:added "1.11"} + ^SAXParser [] + (.newSAXParser (SAXParserFactory/newInstance))) + +(defn disable-external-entities + "Modifies a SAXParser to disable external entity resolution to prevent XXE attacks" + {:added "1.11"} + ^SAXParser [^SAXParser parser] + (let [reader (.getXMLReader parser)] + ;; as per https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html + (.setFeature reader "http://apache.org/xml/features/nonvalidating/load-external-dtd" false) + (.setFeature reader "http://xml.org/sax/features/external-general-entities", false) + (.setFeature reader "http://xml.org/sax/features/external-parameter-entities" false) + parser)) + +(defn startparse-sax + "A startparse function suitable for use with clojure.xml/parse. + Note that this function is open to XXE entity attacks, see startparse-sax-safe." + {:added "1.0"} + [s ch] + (.parse (sax-parser) s ch)) + +(defn startparse-sax-safe + "A startparse function suitable for use with clojure.xml/parse. + External entity resolution is disabled to prevent XXE entity attacks." + {:added "1.11"} + [s ch] + (.parse (disable-external-entities (sax-parser)) s ch)) (defn parse "Parses and loads the source s, which can be a File, InputStream or @@ -81,9 +109,13 @@ 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" + a parser. + + Prior to 1.11, used startparse-sax by default. As of 1.11, uses + startparse-sax-safe, which disables XXE (XML External Entity) + processing. Pass startparse-sax to revert to prior behavior." {:added "1.0"} - ([s] (parse s startparse-sax)) + ([s] (parse s startparse-sax-safe)) ([s startparse] (binding [*stack* nil *current* (struct element) diff --git a/test/clojure/test_clojure/clojure_xml.clj b/test/clojure/test_clojure/clojure_xml.clj index cf7eb9508d..d37962f361 100644 --- a/test/clojure/test_clojure/clojure_xml.clj +++ b/test/clojure/test_clojure/clojure_xml.clj @@ -11,9 +11,18 @@ (ns clojure.test-clojure.clojure-xml (:use clojure.test) - (:require [clojure.xml :as xml])) - + (:require [clojure.xml :as xml]) + (:import [java.io ByteArrayInputStream])) +(deftest CLJ-2611-avoid-XXE + (let [xml-str " + + ]> + &xxe; "] + (is (= {:tag :foo, :attrs nil, :content nil} + (with-open [input (ByteArrayInputStream. (.getBytes xml-str))] + (xml/parse input)))))) ; parse ; emit-element From e45e47882597359aa2adce9f244ecdba730e6c76 Mon Sep 17 00:00:00 2001 From: Ghadi ShaybanDate: Thu, 13 Jan 2022 14:27:57 -0600 Subject: [PATCH 51/78] CLJ-2555: clojure.core/iteration Subsumes CLJ-1906 Signed-off-by: Alex Miller --- src/clj/clojure/core.clj | 43 +++++++++++++ test/clojure/test_clojure/sequences.clj | 85 +++++++++++++++++++++++++ 2 files changed, 128 insertions(+) diff --git a/src/clj/clojure/core.clj b/src/clj/clojure/core.clj index 055050b530..4db32604a6 100644 --- a/src/clj/clojure/core.clj +++ b/src/clj/clojure/core.clj @@ -7783,6 +7783,49 @@ fails, attempts to require sym's namespace and retries." (reduce #(proc %2) nil coll) nil) +(defn iteration + "creates a seqable/reducible given step!, + a function of some (opaque continuation data) k + + step! - fn of k/nil to (opaque) 'ret' + + :some? - fn of ret -> truthy, indicating there is a value + will not call vf/kf nor continue when false + :vf - fn of ret -> v, the values produced by the iteration + :kf - fn of ret -> next-k or nil (will not continue) + :initk - the first value passed to step! + + vf, kf default to identity, some? defaults to some?, initk defaults to nil + + it is presumed that step! with non-initk is unreproducible/non-idempotent + if step! with initk is unreproducible, it is on the consumer to not consume twice" + {:added "1.11"} + [step! & {:keys [vf kf some? initk] + :or {vf identity + kf identity + some? some? + initk nil}}] + (reify + clojure.lang.Seqable + (seq [_] + ((fn next [ret] + (when (some? ret) + (cons (vf ret) + (when-some [k (kf ret)] + (lazy-seq (next (step! k))))))) + (step! initk))) + clojure.lang.IReduceInit + (reduce [_ rf init] + (loop [acc init + ret (step! initk)] + (if (some? ret) + (let [acc (rf acc (vf ret))] + (if (reduced? acc) + @acc + (if-some [k (kf ret)] + (recur acc (step! k)) + acc))) + acc))))) (defn tagged-literal? "Return true if the value is the data representation of a tagged literal" diff --git a/test/clojure/test_clojure/sequences.clj b/test/clojure/test_clojure/sequences.clj index 54d640f72d..96e6775bdd 100644 --- a/test/clojure/test_clojure/sequences.clj +++ b/test/clojure/test_clojure/sequences.clj @@ -1384,3 +1384,88 @@ (when (reversible? coll) (is (= true (instance? clojure.lang.IMeta (rseq coll)))) (is (= {:a true} (meta (with-meta (rseq coll) {:a true}))))))) + +(deftest test-iteration-opts + (let [genstep (fn [steps] + (fn [k] (swap! steps inc) (inc k))) + test (fn [expect & iteropts] + (is (= expect + (let [nsteps (atom 0) + iter (apply iteration (genstep nsteps) iteropts) + ret (doall (seq iter))] + {:ret ret :steps @nsteps}) + (let [nsteps (atom 0) + iter (apply iteration (genstep nsteps) iteropts) + ret (into [] iter)] + {:ret ret :steps @nsteps}))))] + (test {:ret [1 2 3 4] + :steps 5} + :initk 0 :some? #(< % 5)) + (test {:ret [1 2 3 4 5] + :steps 5} + :initk 0 :kf (fn [ret] (when (< ret 5) ret))) + (test {:ret ["1"] + :steps 2} + :initk 0 :some? #(< % 2) :vf str)) + + ;; kf does not stop on false + (let [iter #(iteration (fn [k] + (if (boolean? k) + [10 :boolean] + [k k])) + :vf second + :kf (fn [[k v]] + (cond + (= k 3) false + (< k 14) (inc k))) + :initk 0)] + (is (= [0 1 2 3 :boolean 11 12 13 14] + (into [] (iter)) + (seq (iter)))))) + +(deftest test-iteration + ;; equivalence to line-seq + (let [readme #(java.nio.file.Files/newBufferedReader (.toPath (java.io.File. "readme.txt")))] + (is (= (with-open [r (readme)] + (vec (iteration (fn [_] (.readLine r))))) + (with-open [r (readme)] + (doall (line-seq r)))))) + + ;; paginated API + (let [items 12 pgsize 5 + src (vec (repeatedly items #(java.util.UUID/randomUUID))) + api (fn [tok] + (let [tok (or tok 0)] + (when (< tok items) + {:tok (+ tok pgsize) + :ret (subvec src tok (min (+ tok pgsize) items))})))] + (is (= src + (mapcat identity (iteration api :kf :tok :vf :ret)) + (into [] cat (iteration api :kf :tok :vf :ret))))) + + (let [src [:a :b :c :d :e] + api (fn [k] + (let [k (or k 0)] + (if (< k (count src)) + {:item (nth src k) + :k (inc k)})))] + (is (= [:a :b :c] + (vec (iteration api + :some? (comp #{:a :b :c} :item) + :kf :k + :vf :item)) + (vec (iteration api + :kf #(some-> % :k #{0 1 2}) + :vf :item)))))) + +(defspec iteration-seq-equals-reduce 100 + (prop/for-all [initk gen/int + seed gen/int] + (let [src (fn [] + (let [rng (java.util.Random. seed)] + (iteration #(unchecked-add % (.nextLong rng)) + :some? (complement #(zero? (mod % 1000))) + :vf str + :initk initk)))] + (= (into [] (src)) + (seq (src)))))) \ No newline at end of file From 5451cee06b9e31513a19e596e4e155d1f08d2a8d Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Thu, 13 Jan 2022 14:38:37 -0600 Subject: [PATCH 52/78] CLJ-2680 Primitive local bindings can have matching type hint Signed-off-by: Alex Miller --- src/jvm/clojure/lang/Compiler.java | 9 +++++++-- test/clojure/test_clojure/numbers.clj | 3 +++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/jvm/clojure/lang/Compiler.java b/src/jvm/clojure/lang/Compiler.java index ce16f85a21..cacaeb0f0e 100644 --- a/src/jvm/clojure/lang/Compiler.java +++ b/src/jvm/clojure/lang/Compiler.java @@ -6024,9 +6024,14 @@ public static class LocalBindingExpr implements Expr, MaybePrimitiveExpr, Assign public LocalBindingExpr(LocalBinding b, Symbol tag) { if(b.getPrimitiveType() != null && tag != null) - throw new UnsupportedOperationException("Can't type hint a primitive local"); + if(! b.getPrimitiveType().equals(tagClass(tag))) + throw new UnsupportedOperationException("Can't type hint a primitive local with a different type"); + else + this.tag = null; + else + this.tag = tag; + this.b = b; - this.tag = tag; this.clearPath = (PathNode)CLEAR_PATH.get(); this.clearRoot = (PathNode)CLEAR_ROOT.get(); diff --git a/test/clojure/test_clojure/numbers.clj b/test/clojure/test_clojure/numbers.clj index a6b61605ea..bf822cc947 100644 --- a/test/clojure/test_clojure/numbers.clj +++ b/test/clojure/test_clojure/numbers.clj @@ -184,6 +184,9 @@ (catch RuntimeException e :error)))] (is (= vals (map wrapped inputs))))))) +(deftest test-prim-with-matching-hint + (is (= 1 (let [x 1.2] (Math/round ^double x))))) + ;; *** Functions *** (defonce DELTA 1e-12) From 2b3ba822815981e7f76907a3b75e9ecc428f7656 Mon Sep 17 00:00:00 2001 From: Ghadi Shayban Date: Thu, 20 Jan 2022 10:54:35 -0600 Subject: [PATCH 53/78] CLJ-2690 Clarify iteration docstring, rename args Signed-off-by: Alex Miller --- src/clj/clojure/core.clj | 41 +++++++++++++------------ test/clojure/test_clojure/sequences.clj | 8 ++--- 2 files changed, 26 insertions(+), 23 deletions(-) diff --git a/src/clj/clojure/core.clj b/src/clj/clojure/core.clj index 4db32604a6..42abb7f00a 100644 --- a/src/clj/clojure/core.clj +++ b/src/clj/clojure/core.clj @@ -7784,46 +7784,49 @@ fails, attempts to require sym's namespace and retries." nil) (defn iteration - "creates a seqable/reducible given step!, - a function of some (opaque continuation data) k + "Creates a seqable/reducible via repeated calls to step, + a function of some (continuation token) 'k'. The first call to step + will be passed initk, returning 'ret'. Iff (somef ret) is true, + (vf ret) will be included in the iteration, else iteration will + terminate and vf/kf will not be called. If (kf ret) is non-nil it + will be passed to the next step call, else iteration will terminate. - step! - fn of k/nil to (opaque) 'ret' + This can be used e.g. to consume APIs that return paginated or batched data. - :some? - fn of ret -> truthy, indicating there is a value - will not call vf/kf nor continue when false - :vf - fn of ret -> v, the values produced by the iteration - :kf - fn of ret -> next-k or nil (will not continue) - :initk - the first value passed to step! + step - (possibly impure) fn of 'k' -> 'ret' - vf, kf default to identity, some? defaults to some?, initk defaults to nil + :somef - fn of 'ret' -> logical true/false, default 'some?' + :vf - fn of 'ret' -> 'v', a value produced by the iteration, default 'identity' + :kf - fn of 'ret' -> 'next-k' or nil (signaling 'do not continue'), default 'identity' + :initk - the first value passed to step, default 'nil' - it is presumed that step! with non-initk is unreproducible/non-idempotent - if step! with initk is unreproducible, it is on the consumer to not consume twice" + It is presumed that step with non-initk is unreproducible/non-idempotent. + If step with initk is unreproducible it is on the consumer to not consume twice." {:added "1.11"} - [step! & {:keys [vf kf some? initk] + [step & {:keys [somef vf kf initk] :or {vf identity kf identity - some? some? + somef some? initk nil}}] (reify clojure.lang.Seqable (seq [_] ((fn next [ret] - (when (some? ret) + (when (somef ret) (cons (vf ret) (when-some [k (kf ret)] - (lazy-seq (next (step! k))))))) - (step! initk))) + (lazy-seq (next (step k))))))) + (step initk))) clojure.lang.IReduceInit (reduce [_ rf init] (loop [acc init - ret (step! initk)] - (if (some? ret) + ret (step initk)] + (if (somef ret) (let [acc (rf acc (vf ret))] (if (reduced? acc) @acc (if-some [k (kf ret)] - (recur acc (step! k)) + (recur acc (step k)) acc))) acc))))) diff --git a/test/clojure/test_clojure/sequences.clj b/test/clojure/test_clojure/sequences.clj index 96e6775bdd..1fc93cd8ce 100644 --- a/test/clojure/test_clojure/sequences.clj +++ b/test/clojure/test_clojure/sequences.clj @@ -1400,13 +1400,13 @@ {:ret ret :steps @nsteps}))))] (test {:ret [1 2 3 4] :steps 5} - :initk 0 :some? #(< % 5)) + :initk 0 :somef #(< % 5)) (test {:ret [1 2 3 4 5] :steps 5} :initk 0 :kf (fn [ret] (when (< ret 5) ret))) (test {:ret ["1"] :steps 2} - :initk 0 :some? #(< % 2) :vf str)) + :initk 0 :somef #(< % 2) :vf str)) ;; kf does not stop on false (let [iter #(iteration (fn [k] @@ -1451,7 +1451,7 @@ :k (inc k)})))] (is (= [:a :b :c] (vec (iteration api - :some? (comp #{:a :b :c} :item) + :somef (comp #{:a :b :c} :item) :kf :k :vf :item)) (vec (iteration api @@ -1464,7 +1464,7 @@ (let [src (fn [] (let [rng (java.util.Random. seed)] (iteration #(unchecked-add % (.nextLong rng)) - :some? (complement #(zero? (mod % 1000))) + :somef (complement #(zero? (mod % 1000))) :vf str :initk initk)))] (= (into [] (src)) From 326366d11923620f6815cfd149300bb48da01593 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Wed, 19 Jan 2022 12:55:12 -0600 Subject: [PATCH 54/78] CLJ-2689 Provide more tolerance for inexact floating point math tests Signed-off-by: Alex Miller --- test/clojure/test_clojure/math.clj | 44 +++++++++++++++++------------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/test/clojure/test_clojure/math.clj b/test/clojure/test_clojure/math.clj index 63975e7505..4520b41b2b 100644 --- a/test/clojure/test_clojure/math.clj +++ b/test/clojure/test_clojure/math.clj @@ -21,20 +21,26 @@ [^double d] (and (zero? d) (not (< (Double/compare d 0.0) 0)))) +(defn ulp= + "Tests that y = x +/- m*ulp(x)" + [x y ^double m] + (let [mu (* (m/ulp x) m)] + (<= (- x mu) y (+ x mu)))) + (deftest test-sin (is (NaN? (m/sin ##NaN))) (is (NaN? (m/sin ##-Inf))) (is (NaN? (m/sin ##Inf))) (is (pos-zero? (m/sin 0.0))) (is (neg-zero? (m/sin -0.0))) - (is (= (m/sin m/PI) (- (m/sin (- m/PI)))))) + (is (ulp= (m/sin m/PI) (- (m/sin (- m/PI))) 1))) (deftest test-cos (is (NaN? (m/cos ##NaN))) (is (NaN? (m/cos ##-Inf))) (is (NaN? (m/cos ##Inf))) (is (= 1.0 (m/cos 0.0) (m/cos -0.0))) - (is (= (m/cos m/PI) (m/cos (- m/PI))))) + (is (ulp= (m/cos m/PI) (m/cos (- m/PI)) 1))) (deftest test-tan (is (NaN? (m/tan ##NaN))) @@ -42,7 +48,7 @@ (is (NaN? (m/tan ##Inf))) (is (pos-zero? (m/tan 0.0))) (is (neg-zero? (m/tan -0.0))) - (is (= (- (m/tan m/PI)) (m/tan (- m/PI))))) + (is (ulp= (- (m/tan m/PI)) (m/tan (- m/PI)) 1))) (deftest test-asin (is (NaN? (m/asin ##NaN))) @@ -54,45 +60,45 @@ (is (NaN? (m/acos ##NaN))) (is (NaN? (m/acos -2.0))) (is (NaN? (m/acos 2.0))) - (is (= m/PI (* 2 (m/acos 0.0))))) + (is (ulp= (* 2 (m/acos 0.0)) m/PI 1))) (deftest test-atan (is (NaN? (m/atan ##NaN))) (is (pos-zero? (m/atan 0.0))) (is (neg-zero? (m/atan -0.0))) - (is (= 0.7853981633974483 (m/atan 1)))) + (is (ulp= (m/atan 1) 0.7853981633974483 1))) (deftest test-radians-degrees-roundtrip (doseq [d (range 0.0 360.0 5.0)] - (is (= (m/round d) (m/round (-> d m/to-radians m/to-degrees)))))) + (is (ulp= (m/round d) (m/round (-> d m/to-radians m/to-degrees)) 1)))) (deftest test-exp (is (NaN? (m/exp ##NaN))) (is (= ##Inf (m/exp ##Inf))) (is (pos-zero? (m/exp ##-Inf))) - (is (= 1.0 (m/exp 0.0))) - (is (= m/E (m/exp 1)))) + (is (ulp= (m/exp 0.0) 1.0 1)) + (is (ulp= (m/exp 1) m/E 1))) (deftest test-log (is (NaN? (m/log ##NaN))) (is (NaN? (m/log -1.0))) (is (= ##Inf (m/log ##Inf))) (is (= ##-Inf (m/log 0.0))) - (is (= 1.0 (m/log m/E)))) + (is (ulp= (m/log m/E) 1.0 1))) (deftest test-log10 (is (NaN? (m/log10 ##NaN))) (is (NaN? (m/log10 -1.0))) (is (= ##Inf (m/log10 ##Inf))) (is (= ##-Inf (m/log10 0.0))) - (is (= 1.0 (m/log10 10)))) + (is (ulp= (m/log10 10) 1.0 1))) (deftest test-sqrt (is (NaN? (m/sqrt ##NaN))) (is (NaN? (m/sqrt -1.0))) (is (= ##Inf (m/sqrt ##Inf))) (is (pos-zero? (m/sqrt 0))) - (is (= 2.0 (m/sqrt 4.0)))) + (is (= (m/sqrt 4.0) 2.0))) (deftest test-cbrt (is (NaN? (m/cbrt ##NaN))) @@ -133,14 +139,14 @@ (is (NaN? (m/atan2 1.0 ##NaN))) (is (pos-zero? (m/atan2 0.0 1.0))) (is (neg-zero? (m/atan2 -0.0 1.0))) - (is (= m/PI (m/atan2 0.0 -1.0))) - (is (= (- m/PI) (m/atan2 -0.0 -1.0))) - (is (= m/PI (* 2.0 (m/atan2 1.0 0.0)))) - (is (= m/PI (* -2.0 (m/atan2 -1.0 0.0)))) - (is (= m/PI (* 4.0 (m/atan2 ##Inf ##Inf)))) - (is (= m/PI (/ (* 4.0 (m/atan2 ##Inf ##-Inf)) 3.0))) - (is (= m/PI (* -4.0 (m/atan2 ##-Inf ##Inf)))) - (is (= m/PI (/ (* -4.0 (m/atan2 ##-Inf ##-Inf)) 3.0)))) + (is (ulp= (m/atan2 0.0 -1.0) m/PI 2)) + (is (ulp= (m/atan2 -0.0 -1.0) (- m/PI) 2)) + (is (ulp= (* 2.0 (m/atan2 1.0 0.0)) m/PI 2)) + (is (ulp= (* -2.0 (m/atan2 -1.0 0.0)) m/PI 2)) + (is (ulp= (* 4.0 (m/atan2 ##Inf ##Inf)) m/PI 2)) + (is (ulp= (/ (* 4.0 (m/atan2 ##Inf ##-Inf)) 3.0) m/PI 2)) + (is (ulp= (* -4.0 (m/atan2 ##-Inf ##Inf)) m/PI 2)) + (is (ulp= (/ (* -4.0 (m/atan2 ##-Inf ##-Inf)) 3.0) m/PI 2))) (deftest test-pow (is (= 1.0 (m/pow 4.0 0.0))) From da0b9574017918deede6d2a15f386a7cc1b70a2c Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Thu, 20 Jan 2022 16:13:26 -0600 Subject: [PATCH 55/78] CLJ-2685 Fix iteration generative test comparison Signed-off-by: Alex Miller --- test/clojure/test_clojure/sequences.clj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/clojure/test_clojure/sequences.clj b/test/clojure/test_clojure/sequences.clj index 1fc93cd8ce..4eb99e7860 100644 --- a/test/clojure/test_clojure/sequences.clj +++ b/test/clojure/test_clojure/sequences.clj @@ -988,7 +988,7 @@ {} {:a 1 :b 2} #{} #{1 2} )) -(defspec longrange-equals-range 100 +(defspec longrange-equals-range 1000 (prop/for-all [start gen/int end gen/int step gen/s-pos-int] @@ -1458,7 +1458,7 @@ :kf #(some-> % :k #{0 1 2}) :vf :item)))))) -(defspec iteration-seq-equals-reduce 100 +(defspec iteration-seq-equals-reduce 1000 (prop/for-all [initk gen/int seed gen/int] (let [src (fn [] @@ -1468,4 +1468,4 @@ :vf str :initk initk)))] (= (into [] (src)) - (seq (src)))))) \ No newline at end of file + (into [] (seq (src))))))) From 027d8ff2859442b222bf9cfa4c1be45567b788eb Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Wed, 2 Feb 2022 14:43:41 -0600 Subject: [PATCH 56/78] Revert "CLJ-2493: Prevent browse-url from hanging when using xdg-open (updated)" This reverts commit c33a5abca7828843b7018a8aa28e63dd40310f86. --- src/clj/clojure/java/browse.clj | 2 +- src/clj/clojure/java/shell.clj | 20 -------------------- 2 files changed, 1 insertion(+), 21 deletions(-) diff --git a/src/clj/clojure/java/browse.clj b/src/clj/clojure/java/browse.clj index c416e53832..6fcc650756 100644 --- a/src/clj/clojure/java/browse.clj +++ b/src/clj/clojure/java/browse.clj @@ -71,6 +71,6 @@ script (if (= :uninitialized script) (reset! *open-url-script* (open-url-script-val)) script)] - (or (when script (sh/launch script (str url)) true) + (or (when script (sh/sh script (str url)) true) (open-url-in-browser url) (open-url-in-swing url)))) diff --git a/src/clj/clojure/java/shell.clj b/src/clj/clojure/java/shell.clj index 8f167086df..cb3f90a276 100644 --- a/src/clj/clojure/java/shell.clj +++ b/src/clj/clojure/java/shell.clj @@ -127,21 +127,6 @@ collecting its stdout"} exit-code (.waitFor proc)] {:exit exit-code :out @out :err @err})))) -(defn launch - "Same as sh except the I/O channels of the sub-process are ignored. - - Use when you want the sub-process to take an action, but do not want to wait - for the I/O channels to close. Example: Launching a browser with xdg-open. - " - {:added "1.11"} - [& args] - (let [[cmd opts] (parse-args args) - proc (.exec (Runtime/getRuntime) - ^"[Ljava.lang.String;" (into-array cmd) - (as-env-strings (:env opts)) - (as-file (:dir opts)))] - {:exit (.waitFor proc)})) - (comment (println (sh "ls" "-l")) @@ -154,9 +139,4 @@ collecting its stdout"} (println (sh "cat" "myimage.png" :out-enc :bytes)) ; reads binary file into bytes[] (println (sh "cmd" "/c dir 1>&2")) -(println (launch "touch" "my-test-file")) -(println (sh "ls" "-l" "my-test-file")) -(println (launch "rm" "my-test-file")) -(println (sh "ls" "-l" "my-test-file")) - ) From 19e3a2708def5ffb7f2be030d8e8e895464ce2d2 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Tue, 25 Jan 2022 12:02:09 -0600 Subject: [PATCH 57/78] CLJ-2493 - Prevent browse-url from hanging when using xdg-open Signed-off-by: Alex Miller --- src/clj/clojure/java/browse.clj | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/clj/clojure/java/browse.clj b/src/clj/clojure/java/browse.clj index 6fcc650756..6a16ce37db 100644 --- a/src/clj/clojure/java/browse.clj +++ b/src/clj/clojure/java/browse.clj @@ -12,7 +12,9 @@ clojure.java.browse (:require [clojure.java.shell :as sh] [clojure.string :as str]) - (:import (java.net URI))) + (:import (java.io File) + (java.net URI) + (java.lang ProcessBuilder ProcessBuilder$Redirect))) (defn- macosx? [] (-> "os.name" System/getProperty .toLowerCase @@ -71,6 +73,16 @@ script (if (= :uninitialized script) (reset! *open-url-script* (open-url-script-val)) script)] - (or (when script (sh/sh script (str url)) true) + (or (when script + (try + (let [command [script (str url)] + null-file (File. (if (.startsWith (System/getProperty "os.name") "Windows") "NUL" "/dev/null")) + pb (doto (ProcessBuilder. ^java.util.List command) + ;; emulate ProcessBuilder.Redirect.DISCARD added in Java 9 + (.redirectOutput null-file) + (.redirectError null-file))] + (.start pb) ;; do not wait for the process + true) + (catch Throwable _ false))) (open-url-in-browser url) (open-url-in-swing url)))) From 4a9ce390519c41eae100954378937eb220a81dc0 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Tue, 25 Jan 2022 21:03:58 -0600 Subject: [PATCH 58/78] CLJ-2529 Set exception phase for runtime exceptions caught in Compiler.load() Signed-off-by: Alex Miller --- src/jvm/clojure/lang/Compiler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jvm/clojure/lang/Compiler.java b/src/jvm/clojure/lang/Compiler.java index cacaeb0f0e..12cf1e5623 100644 --- a/src/jvm/clojure/lang/Compiler.java +++ b/src/jvm/clojure/lang/Compiler.java @@ -7662,7 +7662,7 @@ public static Object load(Reader rdr, String sourcePath, String sourceName) { catch(Throwable e) { if(!(e instanceof CompilerException)) - throw new CompilerException(sourcePath, (Integer) LINE_BEFORE.deref(), (Integer) COLUMN_BEFORE.deref(), e); + throw new CompilerException(sourcePath, (Integer) LINE_BEFORE.deref(), (Integer) COLUMN_BEFORE.deref(), null, CompilerException.PHASE_EXECUTION, e); else throw (CompilerException) e; } From fc98f92c76254c5a6306debaf0f9df28c3bb3646 Mon Sep 17 00:00:00 2001 From: Fogus Date: Tue, 1 Feb 2022 11:34:18 -0500 Subject: [PATCH 59/78] CLJ-2620: io-prepl now calls valf on exeception data in the case where an exception occurs in the :print-eval-result phase Signed-off-by: Alex Miller --- src/clj/clojure/core/server.clj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/clj/clojure/core/server.clj b/src/clj/clojure/core/server.clj index 48377d4127..3cda4d1f74 100644 --- a/src/clj/clojure/core/server.clj +++ b/src/clj/clojure/core/server.clj @@ -288,7 +288,7 @@ (try (assoc m :val (valf (:val m))) (catch Throwable ex - (assoc m :val (ex->data ex :print-eval-result) + (assoc m :val (valf (ex->data ex :print-eval-result)) :exception true))) m)))))))) From 8957a93099fc506c3b24ed5739bf9e2fc1811bef Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Thu, 20 Jan 2022 21:18:39 -0600 Subject: [PATCH 60/78] CLJ-1180 Resolve classname for tag metadata on defprotocol Signed-off-by: Alex Miller --- src/clj/clojure/core_deftype.clj | 10 +++++- test/clojure/test_clojure/protocols.clj | 35 +++++++++++++++---- .../test_clojure/protocols/examples.clj | 2 ++ 3 files changed, 40 insertions(+), 7 deletions(-) diff --git a/src/clj/clojure/core_deftype.clj b/src/clj/clojure/core_deftype.clj index 7906ccbe35..c2babab291 100644 --- a/src/clj/clojure/core_deftype.clj +++ b/src/clj/clojure/core_deftype.clj @@ -652,7 +652,15 @@ [opts sigs])) sigs (when sigs (reduce1 (fn [m s] - (let [name-meta (meta (first s)) + (let [tag-to-class (fn [tag] + (if-let [c (and (instance? clojure.lang.Symbol tag) + (= (.indexOf (.getName ^clojure.lang.Symbol tag) ".") -1) + (not (contains? '#{int long float double char short byte boolean void + ints longs floats doubles chars shorts bytes booleans objects} tag)) + (resolve tag))] + (symbol (.getName c)) + tag)) + name-meta (update-in (meta (first s)) [:tag] tag-to-class) mname (with-meta (first s) nil) [arglists doc] (loop [as [] rs (rest s)] diff --git a/test/clojure/test_clojure/protocols.clj b/test/clojure/test_clojure/protocols.clj index ff556dcaed..4e951449bb 100644 --- a/test/clojure/test_clojure/protocols.clj +++ b/test/clojure/test_clojure/protocols.clj @@ -47,13 +47,13 @@ (deftest protocols-test (testing "protocol fns have useful metadata" (let [common-meta {:ns (find-ns 'clojure.test-clojure.protocols.examples) - :protocol #'ExampleProtocol}] - (are [m f] (= (merge (quote m) common-meta) + :protocol #'ExampleProtocol :tag nil}] + (are [m f] (= (merge common-meta m) (meta (var f))) - {:name foo :arglists ([a]) :doc "method with one arg"} foo - {:name bar :arglists ([a b]) :doc "method with two args"} bar - {:name baz :arglists ([a] [a b]) :doc "method with multiple arities" :tag String} baz - {:name with-quux :arglists ([a]) :doc "method name with a hyphen"} with-quux))) + {:name 'foo :arglists '([a]) :doc "method with one arg"} foo + {:name 'bar :arglists '([a b]) :doc "method with two args"} bar + {:name 'baz :arglists '([a] [a b]) :doc "method with multiple arities" :tag 'java.lang.String} baz + {:name 'with-quux :arglists '([a]) :doc "method name with a hyphen"} with-quux))) (testing "protocol fns throw IllegalArgumentException if no impl matches" (is (thrown-with-msg? IllegalArgumentException @@ -682,3 +682,26 @@ (reduce-kv #(assoc %1 %3 %2) {} (seq {:a 1 :b 2}))))) + +(defn aget-long-hinted ^long [x] (aget (longs-hinted x) 0)) + +(deftest test-longs-hinted-proto + (is (= 1 + (aget-long-hinted + (reify LongsHintedProto + (longs-hinted [_] (long-array [1]))))))) + +;; CLJ-1180 - resolve type hints in protocol methods + +(import 'clojure.lang.ISeq) +(defprotocol P + (^ISeq f [_])) +(ns clojure.test-clojure.protocols.other + (:use clojure.test)) +(defn cf [val] + (let [aseq (clojure.test-clojure.protocols/f val)] + (count aseq))) +(extend-protocol clojure.test-clojure.protocols/P String + (f [s] (seq s))) +(deftest test-resolve-type-hints-in-protocol-methods + (is (= 4 (clojure.test-clojure.protocols/f "test")))) diff --git a/test/clojure/test_clojure/protocols/examples.clj b/test/clojure/test_clojure/protocols/examples.clj index 9d962d5651..0c247eab04 100644 --- a/test/clojure/test_clojure/protocols/examples.clj +++ b/test/clojure/test_clojure/protocols/examples.clj @@ -17,3 +17,5 @@ (hinted [^int i]) (hinted [^String s])) +(defprotocol LongsHintedProto + (^longs longs-hinted [_])) From 658693f6cf97e6ab0ff789e096c9eb6654e4d3ab Mon Sep 17 00:00:00 2001 From: Ambrose Bonnaire-Sergeant Date: Tue, 25 Jan 2022 12:34:24 -0600 Subject: [PATCH 61/78] CLJ-1973: sort proxy methods for reproducibility Comparator sorts methods by arity then name/param-types/return-types on clashes. Signed-off-by: Alex Miller --- build.xml | 1 + src/clj/clojure/core_proxy.clj | 15 +++++--- test/clojure/test_clojure/java_interop.clj | 38 ++++++++++++++++++-- test/clojure/test_clojure/proxy/examples.clj | 30 ++++++++++++++++ 4 files changed, 77 insertions(+), 7 deletions(-) create mode 100644 test/clojure/test_clojure/proxy/examples.clj diff --git a/build.xml b/build.xml index 6796b3d986..34fd65b2c6 100644 --- a/build.xml +++ b/build.xml @@ -105,6 +105,7 @@ + diff --git a/src/clj/clojure/core_proxy.clj b/src/clj/clojure/core_proxy.clj index c7f35774e6..46f7b4b868 100644 --- a/src/clj/clojure/core_proxy.clj +++ b/src/clj/clojure/core_proxy.clj @@ -241,12 +241,17 @@ mb (map #(vector (%1 %2) (vals (dissoc %1 %2))) mgroups rtypes) bridge? (reduce1 into1 #{} (map second mb)) ifaces-meths (remove bridge? (vals ifaces-meths)) - mm (remove bridge? (vals mm))] + mm (remove bridge? (vals mm)) + reflect-Method-keyfn (fn [meth] + (let [[name param-types ^Class return-type] (method-sig meth)] + (-> [name] + (into1 (map #(.getName ^Class %) param-types)) + (conj (.getName return-type)))))] ;add methods matching supers', if no mapping -> call super - (doseq [[^java.lang.reflect.Method dest bridges] mb - ^java.lang.reflect.Method meth bridges] + (doseq [[^java.lang.reflect.Method dest bridges] (sort-by (comp reflect-Method-keyfn first) mb) + ^java.lang.reflect.Method meth (sort-by reflect-Method-keyfn bridges)] (gen-bridge meth dest)) - (doseq [^java.lang.reflect.Method meth mm] + (doseq [^java.lang.reflect.Method meth (sort-by reflect-Method-keyfn mm)] (gen-method meth (fn [^GeneratorAdapter gen ^Method m] (. gen (loadThis)) @@ -259,7 +264,7 @@ (. m (getDescriptor))))))) ;add methods matching interfaces', if no mapping -> throw - (doseq [^java.lang.reflect.Method meth ifaces-meths] + (doseq [^java.lang.reflect.Method meth (sort-by reflect-Method-keyfn ifaces-meths)] (gen-method meth (fn [^GeneratorAdapter gen ^Method m] (. gen (throwException ex-type (. m (getName)))))))) diff --git a/test/clojure/test_clojure/java_interop.clj b/test/clojure/test_clojure/java_interop.clj index cb21064b25..4925284cc2 100644 --- a/test/clojure/test_clojure/java_interop.clj +++ b/test/clojure/test_clojure/java_interop.clj @@ -11,8 +11,11 @@ (ns clojure.test-clojure.java-interop (:use clojure.test) - (:require [clojure.inspector] - [clojure.set :as set]) + (:require [clojure.data :as data] + [clojure.inspector] + [clojure.pprint :as pp] + [clojure.set :as set] + [clojure.test-clojure.proxy.examples :as proxy-examples]) (:import java.util.Base64 (java.util.concurrent.atomic AtomicLong AtomicInteger))) @@ -176,6 +179,37 @@ str) "chain chain chain"))) +;https://clojure.atlassian.net/browse/CLJ-1973 +(deftest test-proxy-method-order + (let [class-reader (clojure.asm.ClassReader. proxy-examples/proxy1-class-name) + method-order (atom []) + method-visitor (proxy [clojure.asm.ClassVisitor] [clojure.asm.Opcodes/ASM4 nil] + (visitMethod [access name descriptor signature exceptions] + (swap! method-order conj {:name name :descriptor descriptor}) + nil)) + _ (.accept class-reader method-visitor 0) + expected [{:name " ", :descriptor "()V"} + {:name "__initClojureFnMappings", :descriptor "(Lclojure/lang/IPersistentMap;)V"} + {:name "__updateClojureFnMappings", :descriptor "(Lclojure/lang/IPersistentMap;)V"} + {:name "__getClojureFnMappings", :descriptor "()Lclojure/lang/IPersistentMap;"} + {:name "clone", :descriptor "()Ljava/lang/Object;"} + {:name "hashCode", :descriptor "()I"} + {:name "toString", :descriptor "()Ljava/lang/String;"} + {:name "equals", :descriptor "(Ljava/lang/Object;)Z"} + {:name "a", :descriptor "(Ljava/io/File;)Z"} + {:name "a", :descriptor "(Ljava/lang/Boolean;)Ljava/lang/Object;"} + {:name "a", :descriptor "(Ljava/lang/Runnable;)Z"} + {:name "a", :descriptor "(Ljava/lang/String;)I"} + {:name "b", :descriptor "(Ljava/lang/String;)Ljava/lang/Object;"} + {:name "c", :descriptor "(Ljava/lang/String;)Ljava/lang/Object;"} + {:name "d", :descriptor "(Ljava/lang/String;)Ljava/lang/Object;"} + {:name "a", :descriptor "(Ljava/lang/Boolean;Ljava/lang/String;)I"} + {:name "a", :descriptor "(Ljava/lang/String;Ljava/io/File;)Z"} + {:name "a", :descriptor "(Ljava/lang/String;Ljava/lang/Runnable;)Z"} + {:name "a", :descriptor "(Ljava/lang/String;Ljava/lang/String;)I"}] + actual @method-order] + (is (= expected actual) + (with-out-str (pp/pprint (data/diff expected actual)))))) ;; serialized-proxy can be regenerated using a modified version of ;; Clojure with the proxy serialization prohibition disabled and the diff --git a/test/clojure/test_clojure/proxy/examples.clj b/test/clojure/test_clojure/proxy/examples.clj new file mode 100644 index 0000000000..b98042320f --- /dev/null +++ b/test/clojure/test_clojure/proxy/examples.clj @@ -0,0 +1,30 @@ +; Copyright (c) Rich Hickey. All rights reserved. +; The use and distribution terms for this software are covered by the +; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) +; which can be found in the file epl-v10.html 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. + +(ns ^{:doc "Test proxy classes that are AOT-compiled for the tests in + clojure.test-clojure.java-interop." + :author "Ambrose Bonnaire-Sergeant"} + clojure.test-clojure.proxy.examples) + +(definterface A + (^int a [^String x]) + (^boolean a [^java.io.File x]) + (^boolean a [^Runnable x]) + (a [^Boolean x]) + (^int a [^Boolean x ^String y]) + (^int a [^String x ^String y]) + (^boolean a [^String x ^java.io.File y]) + (^boolean a [^String x ^Runnable y]) + (b [^String x]) + (c [^String x]) + (d [^String x])) + +(def ^String proxy1-class-name + (-> (proxy [A] []) + class + .getName)) From 16c91f256fd843687be99b4e3fe2e9af12f5428a Mon Sep 17 00:00:00 2001 From: Clojure Build Date: Wed, 2 Feb 2022 15:07:32 -0600 Subject: [PATCH 62/78] [maven-release-plugin] prepare release clojure-1.11.0-beta1 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 59159805a1..4be09160a6 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar -1.11.0-master-SNAPSHOT +1.11.0-beta1 http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git -HEAD +clojure-1.11.0-beta1 From 84811650bb33846c7212f391468f9661819b906b Mon Sep 17 00:00:00 2001 From: Clojure Build Date: Wed, 2 Feb 2022 15:07:32 -0600 Subject: [PATCH 63/78] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 4be09160a6..59159805a1 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar -1.11.0-beta1 +1.11.0-master-SNAPSHOT http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git -clojure-1.11.0-beta1 +HEAD From 3fbdffadabbc36436525a0183f2b3c8aca8648a3 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Tue, 15 Feb 2022 10:52:35 -0600 Subject: [PATCH 64/78] Changelog updates for 1.11 Signed-off-by: Alex Miller --- changes.md | 159 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 159 insertions(+) diff --git a/changes.md b/changes.md index 4df7e28540..46b45cbda1 100644 --- a/changes.md +++ b/changes.md @@ -1,5 +1,164 @@ +# Changes to Clojure in Version 1.11.0 + +## 1 Compatibility + +### 1.1 Security + +Because XML external entity (XXE) attacks can be used to disclose local files using file schemes or relative paths in the system identifier, `clojure.xml/parse` now disables external entity processing by default. + +See: https://owasp.org/www-community/vulnerabilities/XML_External_Entity_(XXE)_Processing + +This change disables the following SAX parser features: + +* `http://apache.org/xml/features/nonvalidating/load-external-dtd` +* `http://xml.org/sax/features/external-general-entities` +* `http://xml.org/sax/features/external-parameter-entities` + +If you rely on these features, modify your calls to `clojure.xml/parse` to explicitly +supply `startparse-sax` function as the final argument: +`(clojure.xml/parse the-string clojure.xml/startparse-sax)` +This modification also works on prior Clojure versions. + +* [CLJ-2611](http://dev.clojure.org/jira/browse/CLJ-2611) clojure.xml now disables XXE processing by default + +### 1.2 Dependencies + +Updated dependencies: + +* spec.alpha dependency to 0.3.218 - [changes](https://github.com/clojure/spec.alpha/blob/master/CHANGES.md) +* core.specs.alpha dependency to 0.2.62 - [changes](https://github.com/clojure/core.specs.alpha/blob/master/CHANGES.md) + +## 2 Features + +### 2.1 Keyword argument functions take a trailing map + +Keyword arguments are optional trailing variadic arguments of the form *akey aval bkey bval...*. +In Clojure 1.11, functions taking keyword arguments can now be passed a map instead of or in addition +to and following the key/value pairs. When a lone map is passed, it is used for destructuring, else +a trailing map is added to the key/value pair map by `conj`. + +Also see: https://clojure.org/news/2021/03/18/apis-serving-people-and-programs + +* [CLJ-2603](https://clojure.atlassian.net/browse/CLJ-2603) Clojure keyword argument functions now also accept a map + +### 2.2 `:as-alias` in `require` + +Spec (and other libs) rely on qualified keywords as spec names. +Namespace aliasing in `ns` makes long names shorter but required namespaces to be loadable. +This change adds `:as-alias` to `require`, which is like `:as` but does not require the namespace to load. + +* [CLJ-2123](https://clojure.atlassian.net/browse/CLJ-2123) Add :as-alias option to require like :as but not load +* [CLJ-2665](https://clojure.atlassian.net/browse/CLJ-2665) Fix require with :as and :as-alias to load + +## 3 New functions and namespaces + +### 3.1 clojure.math and numeric helper functions + +Added a new clojure.math namespace which provides wrappers for the functions available in java.lang.Math. +These functions are narrowed to only `long` and `double` overloads and provide primitive support without reflection. + +In addition, the following functions were added to clojure.core: + +* `abs` - absolute value in optimized form for all Clojure numeric types (long, double, ratio, bigint, bigdecimal) +* `NaN?` - predicate for doubles to check whether "not a number" +* `infinite?` - predicate for doubles to check whether positive or negative infinity + +* [CLJ-2668](https://clojure.atlassian.net/browse/CLJ-2668) Add NaN? and infinite? predicates +* [CLJ-2664](https://clojure.atlassian.net/browse/CLJ-2664) Add clojure.java.math namespace, wrappers for java.lang.Math +* [CLJ-2673](https://clojure.atlassian.net/browse/CLJ-2673) Add `abs`, and update `min` and `max` to use Math impls when possible +* [CLJ-2677](https://clojure.atlassian.net/browse/CLJ-2677) clojure.math - fix method reflection in bodies and inlines, fix docstrings, renamed +* [CLJ-2689](https://clojure.atlassian.net/browse/CLJ-2689) Fix clojure.math tests to be more tolerant of floating point comparisons + +### 3.2 Parser functions + +Added the following parsing functions to clojure.core: + +* `parse-double` - parses floating point number, including scientific notation +* `parse-long` - parses integer in long range +* `parse-boolean` - parses `"true"` or `"false"` to the canonical boolean values +* `parse-uuid` - parses a UUID string to java.util.UUID + +All of these functions expect a string argument and return either the parsed value or `nil` if the value +is in invalid format. + +* [CLJ-2667](https://clojure.atlassian.net/browse/CLJ-2667) Add functions to parse a single long/double/uuid/boolean from a string + +### 3.2 `random-uuid` + +Added `random-uuid`, a function to construct a random java.util.UUID. + +* [CLJ-1925](https://clojure.atlassian.net/browse/CLJ-1925) Add random-uuid + +### 3.3 `update-keys` and `update-vals` + +Added: + +* `update-keys` - applies a function to every key in a map, `m f => {(f k) v ...}` +* `update-vals` - applies a function to every value in a map, `m f => {k (f v) ...}` + +* [CLJ-1959](https://clojure.atlassian.net/browse/CLJ-1959) Add implementation of update-keys +* [CLJ-2651](https://clojure.atlassian.net/browse/CLJ-2651) Add implementation of update-vals + +### 3.4 `iteration` + +Added `iteration`, to repeatedly apply a (possibly impure) step function with continuation state. +This can be used e.g. to consume APIs that return paginated or batched data. + +* [CLJ-2555](https://clojure.atlassian.net/browse/CLJ-2555) Add `iteration` generator function +* [CLJ-2690](https://clojure.atlassian.net/browse/CLJ-2690) Improve `iteration` docstring and arg names +* [CLJ-2685](https://clojure.atlassian.net/browse/CLJ-2685) Fix `iteration` generative test failure + +## 4 Fixes + +### 4.1 Compiler + +* [CLJ-2680](https://clojure.atlassian.net/browse/CLJ-2680) Fix type hinting a primitive local with matching type hint to not error +* [CLJ-1180](https://clojure.atlassian.net/browse/CLJ-1180) Fix resolution of class type hints in `defprotocol` +* [CLJ-1973](https://clojure.atlassian.net/browse/CLJ-1973) Make order of emitted protocol methods in generated classes reproducible + +### 4.2 Core + +* [CLJ-1879](https://clojure.atlassian.net/browse/CLJ-1879) IKVReduce - make IPersistentMap case faster and extend to Object, detaching it from any fully enumerable set of types +* [CLJ-2065](https://clojure.atlassian.net/browse/CLJ-2065) IKVReduce - add direct support for SubVector +* [CLJ-2663](https://clojure.atlassian.net/browse/CLJ-2663) Fix vector `=` not terminating when called with infinite sequence +* [CLJ-2679](https://clojure.atlassian.net/browse/CLJ-2679) Fix hash collisions in `case` expressions on symbols +* [CLJ-2600](https://clojure.atlassian.net/browse/CLJ-2600) Don't block `realized?` of `delay` on pending result +* [CLJ-2649](https://clojure.atlassian.net/browse/CLJ-2649) Fix order of checks in `some-fn` and `every-pred` for 3 predicate case to match other unrollings +* [CLJ-2234](https://clojure.atlassian.net/browse/CLJ-2234) Fix multimethod preferences to correctly use local hierarchy when it exists +* [CLJ-2556](https://clojure.atlassian.net/browse/CLJ-2556) Fix `into` completion so `halt-when` works + +### 4.3 Performance + +* [CLJ-1808](https://clojure.atlassian.net/browse/CLJ-1808) `map-invert` should use `reduce-kv` and transient +* [CLJ-2621](https://clojure.atlassian.net/browse/CLJ-2621) Fix unnecessary boxing of unused return in statement context for instance method expr +* [CLJ-2670](https://clojure.atlassian.net/browse/CLJ-2670) Use Math.exact... methods for checked long math ops for performance +* [CLJ-2636](https://clojure.atlassian.net/browse/CLJ-2636) Get rid of reflection on java.util.Properties when defining `*clojure-version*` +* [CLJ-1509](https://clojure.atlassian.net/browse/CLJ-1509) AOT compile clojure.instant, clojure.uuid, clojure.core.reducers in build + +### 4.4 Error messages + +* [CLJ-2529](https://clojure.atlassian.net/browse/CLJ-2529) Fix incorrect reporting of runtime errors as compiler errors in calls through `Compiler.load()` +* [CLJ-2350](https://clojure.atlassian.net/browse/CLJ-2350) Improve keyword arity exception message + +### 4.5 Docstrings + +* [CLJ-2249](https://clojure.atlassian.net/browse/CLJ-2249) Clarify `get` docstring regarding sets, strings, arrays, ILookup +* [CLJ-2488](https://clojure.atlassian.net/browse/CLJ-2488) Add definition to `reify` docstring +* [CLJ-1360](https://clojure.atlassian.net/browse/CLJ-1360) Update `clojure.string/split` docstring regarding trailing empty parts +* [CLJ-2444](https://clojure.atlassian.net/browse/CLJ-2444) Fix typo in `test-vars` docstring +* [CLJ-2666](https://clojure.atlassian.net/browse/CLJ-2666) Make Clojure Java API javadoc text match the example + +### 4.6 Other enhancements + +* [CLJ-2493](https://clojure.atlassian.net/browse/CLJ-2493) clojure.java.browse - Fix `browse-url` hanging on call to xdg-open +* [CLJ-1908](https://clojure.atlassian.net/browse/CLJ-1908) clojure.test - Add `run-test` and `run-test-var` to run single test with fixtures and report +* [CLJ-1379](https://clojure.atlassian.net/browse/CLJ-1379) clojure.test - Fix quoting of `:actual` form in `:pass` maps +* [CLJ-2620](https://clojure.atlassian.net/browse/CLJ-2620) clojure.server - Fix asymmetric handling of `:exception` `:val`s in `prepl` +* [CLJ-2387](https://clojure.atlassian.net/browse/CLJ-2387) clojure.server - Fix off-by-one in socket server port validation + + # Changes to Clojure in Version 1.10.3 ## 1 Changes reverted From 7b102d84c60ed88d62989d6fd4a6994bd33b3bec Mon Sep 17 00:00:00 2001 From: Paula Gearon Date: Sat, 5 Feb 2022 15:14:01 -0500 Subject: [PATCH 65/78] CLJ-2695: parse-double test does not test out-of range values Signed-off-by: Alex Miller --- test/clojure/test_clojure/parse.clj | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/test/clojure/test_clojure/parse.clj b/test/clojure/test_clojure/parse.clj index 953beefb4d..8078c527f6 100644 --- a/test/clojure/test_clojure/parse.clj +++ b/test/clojure/test_clojure/parse.clj @@ -52,12 +52,15 @@ "Infinity" Double/POSITIVE_INFINITY "-Infinity" Double/NEGATIVE_INFINITY "1.7976931348623157E308" Double/MAX_VALUE - "4.9E-324" Double/MIN_VALUE) + "4.9E-324" Double/MIN_VALUE + "1.7976931348623157E309" Double/POSITIVE_INFINITY ;; past max double + "2.5e-324" Double/MIN_VALUE ;; past min double, above half minimum + "2.4e-324" 0.0) ;; below minimum double (is (Double/isNaN (parse-double "NaN"))) (are [s] ;; nil on invalid string - (nil? (parse-long s)) - "1.7976931348623157E309" ;; past max double - "9.9E-324")) ;; past min double + (nil? (parse-double s)) + "double" ;; invalid string + "1.7976931348623157G309")) ;; invalid, but similar to valid ;; generative test - gen double -> str -> parse, compare (deftest test-gen-parse-double @@ -96,4 +99,4 @@ nil false true - 100)) \ No newline at end of file + 100)) From 0971ce23f4cb3a1042483c56a36e4954da26ca70 Mon Sep 17 00:00:00 2001 From: Clojure Build Date: Wed, 16 Feb 2022 10:22:29 -0600 Subject: [PATCH 66/78] [maven-release-plugin] prepare release clojure-1.11.0-rc1 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 59159805a1..dc91d0a4aa 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar -1.11.0-master-SNAPSHOT +1.11.0-rc1 http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git -HEAD +clojure-1.11.0-rc1 From 9af0d1d9a0dc34c406c3588dfe9b60dbe4530981 Mon Sep 17 00:00:00 2001 From: Clojure Build Date: Wed, 16 Feb 2022 10:22:29 -0600 Subject: [PATCH 67/78] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index dc91d0a4aa..59159805a1 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar -1.11.0-rc1 +1.11.0-master-SNAPSHOT http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git -clojure-1.11.0-rc1 +HEAD From f376cf62bb0c30f72b0df4ee94c38fa503fa4be7 Mon Sep 17 00:00:00 2001 From: Clojure Build Date: Tue, 22 Mar 2022 10:16:08 -0500 Subject: [PATCH 68/78] [maven-release-plugin] prepare release clojure-1.11.0 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 59159805a1..e237f52448 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar -1.11.0-master-SNAPSHOT +1.11.0 http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git -HEAD +clojure-1.11.0 From 48818bd96afc2c8ee8ee76075f7a186289c6517a Mon Sep 17 00:00:00 2001 From: Clojure Build Date: Tue, 22 Mar 2022 10:16:08 -0500 Subject: [PATCH 69/78] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index e237f52448..2dd37faaad 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar -1.11.0 +1.12.0-master-SNAPSHOT http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git -clojure-1.11.0 +HEAD From 1da6b07722790e898faa261a816a7a070fd93ac5 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Wed, 30 Mar 2022 15:41:32 -0500 Subject: [PATCH 70/78] CLJ-2701 Set serialVersionUIDs for Keyword and ArraySeq to retain 1.10.3 values Signed-off-by: Alex Miller --- src/jvm/clojure/lang/ArraySeq.java | 3 +++ src/jvm/clojure/lang/Keyword.java | 2 ++ 2 files changed, 5 insertions(+) diff --git a/src/jvm/clojure/lang/ArraySeq.java b/src/jvm/clojure/lang/ArraySeq.java index 49a74b660d..5f54d87aaf 100644 --- a/src/jvm/clojure/lang/ArraySeq.java +++ b/src/jvm/clojure/lang/ArraySeq.java @@ -15,6 +15,9 @@ import java.lang.reflect.Array; public class ArraySeq extends ASeq implements IndexedSeq, IReduce{ + +private static final long serialVersionUID = -9069152683729302290L; + public final Object[] array; final int i; //ISeq _rest; diff --git a/src/jvm/clojure/lang/Keyword.java b/src/jvm/clojure/lang/Keyword.java index 145df4f73b..253f455e4a 100644 --- a/src/jvm/clojure/lang/Keyword.java +++ b/src/jvm/clojure/lang/Keyword.java @@ -23,6 +23,8 @@ public class Keyword implements IFn, Comparable, Named, Serializable, IHashEq { +private static final long serialVersionUID = -2105088845257724163L; + private static ConcurrentHashMap > table = new ConcurrentHashMap(); static final ReferenceQueue rq = new ReferenceQueue(); public final Symbol sym; From e917dcc003bdd56660d5057407ea7739d2736af2 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Fri, 1 Apr 2022 12:46:31 -0500 Subject: [PATCH 71/78] Update changelog for 1.11.1 --- changes.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/changes.md b/changes.md index 46b45cbda1..f18b330f4a 100644 --- a/changes.md +++ b/changes.md @@ -1,5 +1,10 @@ +# Changes to Clojure in Version 1.11.1 + +* [CLJ-2701](https://clojure.atlassian.net/browse/CLJ-2701) + Pin serialVersionUID for Keyword and ArraySeq back to 1.10.3 values to retain binary serialization + # Changes to Clojure in Version 1.11.0 ## 1 Compatibility From 3f1c36d779a43b1951ddaa9cdf6250b1d739621b Mon Sep 17 00:00:00 2001 From: Clojure Build Date: Fri, 1 Apr 2022 12:52:28 -0500 Subject: [PATCH 72/78] [maven-release-plugin] prepare release clojure-1.11.1-rc1 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 2dd37faaad..4496e1353f 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar -1.12.0-master-SNAPSHOT +1.11.1-rc1 http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git -HEAD +clojure-1.11.1-rc1 From cef38abac0d7139f4d38324290eaf2c40b8924a7 Mon Sep 17 00:00:00 2001 From: Clojure Build Date: Fri, 1 Apr 2022 12:52:28 -0500 Subject: [PATCH 73/78] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 4496e1353f..2dd37faaad 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar -1.11.1-rc1 +1.12.0-master-SNAPSHOT http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git -clojure-1.11.1-rc1 +HEAD From ce55092f2b2f5481d25cff6205470c1335760ef6 Mon Sep 17 00:00:00 2001 From: Clojure Build Date: Tue, 5 Apr 2022 09:33:41 -0500 Subject: [PATCH 74/78] [maven-release-plugin] prepare release clojure-1.11.1 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 2dd37faaad..b15f640224 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar -1.12.0-master-SNAPSHOT +1.11.1 http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git -HEAD +clojure-1.11.1 From 777456f5f485ed42cee386344fbce891c559ec4e Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Thu, 7 Mar 2024 12:54:43 -0600 Subject: [PATCH 75/78] CLJ-2839 Infinite seq class hashCode() is infinite loop --- src/clj/clojure/core.clj | 3 ++- src/jvm/clojure/lang/Cycle.java | 9 +++++++++ src/jvm/clojure/lang/Iterate.java | 8 ++++++++ src/jvm/clojure/lang/Repeat.java | 13 +++++++++++++ test/clojure/test_clojure/sequences.clj | 10 ++++++++++ test/clojure/test_clojure/serialization.clj | 9 ++++++++- 6 files changed, 50 insertions(+), 2 deletions(-) diff --git a/src/clj/clojure/core.clj b/src/clj/clojure/core.clj index 42abb7f00a..1e7c6977cc 100644 --- a/src/clj/clojure/core.clj +++ b/src/clj/clojure/core.clj @@ -3028,7 +3028,8 @@ [n x] (take n (repeat x))) (defn iterate - "Returns a lazy sequence of x, (f x), (f (f x)) etc. f must be free of side-effects" + "Returns a lazy (infinite!) sequence of x, (f x), (f (f x)) etc. + f must be free of side-effects" {:added "1.0" :static true} [f x] (clojure.lang.Iterate/create f x) ) diff --git a/src/jvm/clojure/lang/Cycle.java b/src/jvm/clojure/lang/Cycle.java index 877695558a..0be07b5949 100644 --- a/src/jvm/clojure/lang/Cycle.java +++ b/src/jvm/clojure/lang/Cycle.java @@ -93,4 +93,13 @@ public Object reduce(IFn f, Object start){ s = all; } } + +public int hashCode(){ + throw new UnsupportedOperationException(); +} + +public int hasheq(){ + throw new UnsupportedOperationException(); +} + } diff --git a/src/jvm/clojure/lang/Iterate.java b/src/jvm/clojure/lang/Iterate.java index aec0c14aa2..5aaf9cbb52 100644 --- a/src/jvm/clojure/lang/Iterate.java +++ b/src/jvm/clojure/lang/Iterate.java @@ -84,4 +84,12 @@ public Object reduce(IFn rf, Object start){ v = f.invoke(v); } } + +public int hashCode(){ + throw new UnsupportedOperationException(); +} + +public int hasheq(){ + throw new UnsupportedOperationException(); +} } diff --git a/src/jvm/clojure/lang/Repeat.java b/src/jvm/clojure/lang/Repeat.java index 2ce4f2dab2..9547d66523 100644 --- a/src/jvm/clojure/lang/Repeat.java +++ b/src/jvm/clojure/lang/Repeat.java @@ -97,4 +97,17 @@ public Object reduce(IFn f, Object start){ } } +public int hashCode(){ + if(count <= 0) + throw new UnsupportedOperationException(); + else + return super.hashCode(); +} + +public int hasheq(){ + if(count <= 0) + throw new UnsupportedOperationException(); + else + return super.hasheq(); +} } diff --git a/test/clojure/test_clojure/sequences.clj b/test/clojure/test_clojure/sequences.clj index 4eb99e7860..f0927061a4 100644 --- a/test/clojure/test_clojure/sequences.clj +++ b/test/clojure/test_clojure/sequences.clj @@ -1458,6 +1458,16 @@ :kf #(some-> % :k #{0 1 2}) :vf :item)))))) +(deftest infinite-seq-hash + (are [e] (thrown? Exception (.hashCode ^Object e)) + (iterate identity nil) + (cycle [1]) + (repeat 1)) + (are [e] (thrown? Exception (.hasheq ^clojure.lang.IHashEq e)) + (iterate identity nil) + (cycle [1]) + (repeat 1))) + (defspec iteration-seq-equals-reduce 1000 (prop/for-all [initk gen/int seed gen/int] diff --git a/test/clojure/test_clojure/serialization.clj b/test/clojure/test_clojure/serialization.clj index 51a0d6a263..c9befc49cd 100644 --- a/test/clojure/test_clojure/serialization.clj +++ b/test/clojure/test_clojure/serialization.clj @@ -183,4 +183,11 @@ ;; stateful seqs (enumeration-seq (java.util.Collections/enumeration (range 50))) - (iterator-seq (.iterator (range 50))))) \ No newline at end of file + (iterator-seq (.iterator (range 50))))) + +;; necessary for CVE-2024-22871 +(deftest CLJ-2839 + (are [e] (thrown? Exception (.hashCode ^Object (-> e serialize deserialize))) + (repeat 1) + (iterate identity nil) + (cycle [1]))) \ No newline at end of file From 5366a0e9e6df8ade159772703da3ac32c352fcdc Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Fri, 8 Mar 2024 08:41:03 -0600 Subject: [PATCH 76/78] add github actions to clojure-1.11-dev branch --- .github/workflows/release.yml | 19 +++++++++++++++++++ .github/workflows/snapshot.yml | 8 ++++++++ .github/workflows/test.yml | 26 ++++++++++++++++++++++++++ 3 files changed, 53 insertions(+) create mode 100644 .github/workflows/release.yml create mode 100644 .github/workflows/snapshot.yml create mode 100644 .github/workflows/test.yml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000000..d30437293c --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,19 @@ +name: Release on demand + +on: + workflow_dispatch: + inputs: + releaseVersion: + description: "Version to release" + required: true + snapshotVersion: + description: "Snapshot version after release" + required: true + +jobs: + call-release: + uses: clojure/build.ci/.github/workflows/release.yml@master + with: + releaseVersion: ${{ github.event.inputs.releaseVersion }} + snapshotVersion: ${{ github.event.inputs.snapshotVersion }} + secrets: inherit diff --git a/.github/workflows/snapshot.yml b/.github/workflows/snapshot.yml new file mode 100644 index 0000000000..24729578c1 --- /dev/null +++ b/.github/workflows/snapshot.yml @@ -0,0 +1,8 @@ +name: Snapshot on demand + +on: [workflow_dispatch] + +jobs: + call-snapshot: + uses: clojure/build.ci/.github/workflows/snapshot.yml@master + secrets: inherit diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000000..b50a9813d1 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,26 @@ +name: Test + +on: + push: + workflow_dispatch: + +jobs: + test: + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest] # macOS-latest, windows-latest] + java-version: ["8", "11", "17", "21"] + distribution: ["temurin", "corretto"] + profile: ["test-direct", "test-no-direct"] + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v3 + - name: Set up Java + uses: actions/setup-java@v3 + with: + java-version: ${{ matrix.java-version }} + distribution: ${{ matrix.distribution }} + cache: 'maven' + - name: Build with Maven + run: mvn -ntp -B -P${{ matrix.profile }} clean test From 63474dbaf356cbbc38ed9bd9f3a01c5800b8a6c4 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Fri, 8 Mar 2024 08:44:11 -0600 Subject: [PATCH 77/78] update pom to snapshot version --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index b15f640224..24ea0e131f 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar -1.11.1 +1.11.2-master-SNAPSHOT http://clojure.org/ Clojure core environment and runtime library. From 218054f1f2ddfc69ef4f9d17f916de35e4a4effe Mon Sep 17 00:00:00 2001 From: clojure-buildDate: Fri, 8 Mar 2024 14:46:47 +0000 Subject: [PATCH 78/78] [maven-release-plugin] prepare release clojure-1.11.2 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 24ea0e131f..a36970cfce 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar -1.11.2-master-SNAPSHOT +1.11.2 http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git -clojure-1.11.1 +clojure-1.11.2