Skip to content

Commit

Permalink
Add clj-kondo exports and config, fix linting errors, some addt'l fix…
Browse files Browse the repository at this point in the history
…es (#16)

* Add clj-kondo exports and config, fix linting errors, some addt'l fixes

* Add notes to CHANGELOG for next release

* Add clj-kondo linter to github actions workflow
  • Loading branch information
k13gomez authored Mar 4, 2024
1 parent 853576f commit 173ca2a
Show file tree
Hide file tree
Showing 16 changed files with 243 additions and 40 deletions.
1 change: 1 addition & 0 deletions .clj-kondo/config.edn
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{:config-paths ["../resources/clj-kondo.exports/cnuernber/ham-fisted"]}
2 changes: 2 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ jobs:
uses: DeLaGuardo/[email protected]
with:
cli: 1.11.1.1413
- name: Run clojure linter
run: scripts/lint
- name: Run automated tests
run: scripts/run-tests
- name: Cache dependencies
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@ pom.xml
*.asc
issue-data
jdk-*
.clj-kondo
.lsp
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
# 2.XXX
* Add clj-kondo exports and config, fix linting errors
* Remove support for and call to `take-last` 1-arity, which was not valid.
* Fix variable arity `merge-with`, which was not correctly implemented.

# 2.017
* Faster compose-reducers especially where there really are a lot of reducers.

Expand Down
4 changes: 3 additions & 1 deletion deps.edn
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{:paths ["src" "target/classes"]
{:paths ["src" "resources" "target/classes"]
:deps {it.unimi.dsi/fastutil-core {:mvn/version "8.5.8"}
com.github.ben-manes.caffeine/caffeine {:mvn/version "2.9.3"}}

Expand All @@ -22,6 +22,8 @@
:build
{:deps {io.github.clojure/tools.build {:git/tag "v0.9.6" :git/sha "8e78bcc"}}
:ns-default build}
:clj-kondo {:extra-deps {clj-kondo/clj-kondo {:mvn/version "2024.02.12"}}
:main-opts ["-m" "clj-kondo.main"]}
:test
{:extra-deps {com.cognitect/test-runner
{:git/url "https://github.com/cognitect-labs/test-runner"
Expand Down
6 changes: 3 additions & 3 deletions dev/src/perftest.clj
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@

(def map-non-numeric-constructors
{:clj #(into {} %)
:hamf-trie hamf/mut-trie-map
#_#_:hamf-trie hamf/mut-trie-map
:hamf-hashmap hamf/mut-map
:java hamf/java-hashmap})

Expand Down Expand Up @@ -80,7 +80,7 @@
[(merge (hamf/mapmap (fn [entry]
[(key entry) (benchmark-us ((val entry) data))])
map-constructors)
{:n-elems n-elems :test :hashmap-construction :numeric? numeric?} )
{:n-elems n-elems :test :hashmap-construction :numeric? numeric?})
(merge (hamf/mapmap #(vector (key %)
(benchmark-us
(reduce (fn [acc data]
Expand All @@ -92,7 +92,7 @@
(merge (hamf/mapmap #(vector (key %)
(benchmark-us
(fn [acc map]
(reduce (fn [kv] kv)
(reduce (fn [& kv] kv)
nil
(val %)))))
map-data)
Expand Down
21 changes: 21 additions & 0 deletions resources/clj-kondo.exports/cnuernber/ham-fisted/config.edn
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{:skip-comments true
:lint-as {ham-fisted.defprotocol/defprotocol clojure.core/defprotocol
ham-fisted.defprotocol/extend-protocol clojure.core/extend-protocol
ham-fisted.defprotocol/extend-type clojure.core/extend-type}
:hooks {:analyze-call {ham-fisted.hlet/let hooks.ham-fisted/analyze-hlet-macro
ham-fisted.function/function hooks.ham-fisted/analyze-1-arg-fn-macro
ham-fisted.function/long-predicate hooks.ham-fisted/analyze-1-arg-fn-macro
ham-fisted.function/long-unary-operator hooks.ham-fisted/analyze-1-arg-fn-macro
ham-fisted.function/double-predicate hooks.ham-fisted/analyze-1-arg-fn-macro
ham-fisted.function/double-unary-operator hooks.ham-fisted/analyze-1-arg-fn-macro
ham-fisted.function/obj->long hooks.ham-fisted/analyze-1-arg-fn-macro
ham-fisted.function/long->double hooks.ham-fisted/analyze-1-arg-fn-macro
ham-fisted.function/bi-function hooks.ham-fisted/analyze-2-arg-fn-macro
ham-fisted.function/binary-predicate hooks.ham-fisted/analyze-2-arg-fn-macro
ham-fisted.function/long-binary-operator hooks.ham-fisted/analyze-2-arg-fn-macro
ham-fisted.function/double-binary-operator hooks.ham-fisted/analyze-2-arg-fn-macro
ham-fisted.reduce/long-accumulator hooks.ham-fisted/analyze-2-arg-fn-macro
ham-fisted.reduce/double-accumulator hooks.ham-fisted/analyze-2-arg-fn-macro
ham-fisted.reduce/indexed-accum hooks.ham-fisted/analyze-indexed-reduce-fn-macro
ham-fisted.alists/make-prim-array-list hooks.ham-fisted/analyze-make-prim-array-list-macro
ham-fisted.lazy-noncaching/make-readonly-list hooks.ham-fisted/analyze-indexed-make-list-macro}}}
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
(ns hooks.ham-fisted
(:require [clj-kondo.hooks-api :as api]))

(defn node-value
[node]
(when node
(api/sexpr node)))

(defn analyze-hlet-macro
[{:keys [:node]}]
(let [[bindings & body] (rest (:children node))
new-node (api/list-node
(list*
(api/token-node 'clojure.core/let)
(api/vector-node
(concat
[(api/token-node 'dbls)
(api/token-node 'clojure.core/vec)
(api/token-node 'lngs)
(api/token-node 'clojure.core/vec)
(api/token-node 'lng-fns)
(api/token-node 'clojure.core/vec)
(api/token-node 'dbl-fns)
(api/token-node 'clojure.core/vec)
(api/token-node 'obj-fns)
(api/token-node 'clojure.core/vec)]
(:children bindings)))
body))]
{:node new-node}))

(defn analyze-1-arg-fn-macro
[{:keys [:node]}]
(let [[arg1 & body] (rest (:children node))
new-node (api/list-node
(list*
(api/token-node 'clojure.core/fn)
(api/vector-node [arg1])
body))]
{:node new-node}))

(defn analyze-2-arg-fn-macro
[{:keys [:node]}]
(let [[arg1 arg2 & body] (rest (:children node))
new-node (api/list-node
(list*
(api/token-node 'clojure.core/fn)
(api/vector-node [arg1 arg2])
body))]
{:node new-node}))

(defn analyze-indexed-reduce-fn-macro
[{:keys [:node]}]
(let [[acc-arg idx-arg obj-arg & body] (rest (:children node))
new-node (api/list-node
(list*
(api/token-node 'clojure.core/fn)
(api/vector-node [acc-arg
(api/vector-node [idx-arg obj-arg])])
body))]
{:node new-node}))

(defn analyze-indexed-make-list-macro
[{:keys [:node]}]
(let [children (rest (:children node))
_input-args (drop-last 3 children)
[nel-arg idx-arg & body] (take-last 3 children)
new-node (api/list-node
(list
(api/token-node 'clojure.core/map)
(api/list-node
(list*
(api/token-node 'clojure.core/fn)
(api/vector-node [idx-arg])
body))
(api/list-node
(list
(api/token-node 'clojure.core/range)
(api/token-node nel-arg)))))]
{:node new-node}))

(defn analyze-make-prim-array-list-macro
[{:keys [:node]}]
(let [[lname ary-tag iface getname setname addname set-cast-fn get-cast-fn obj-cast-fn add-all-reduce] (rest (:children node))
new-node (api/list-node
(list
(api/token-node 'clojure.core/deftype)
(vary-meta lname assoc :tag (node-value ary-tag))
(api/vector-node
[(api/token-node 'data)
(api/token-node 'n-elems)
(api/token-node 'm)])
iface
(api/list-node
(list
getname
(api/vector-node
[(api/token-node '_)
(api/token-node 'idx)])
(api/list-node
(list
get-cast-fn
(api/list-node
(list
(api/token-node 'clojure.core/aget)
(api/token-node 'data)
(api/token-node 'idx)))))))
(api/list-node
(list
setname
(api/vector-node
[(api/token-node '_)
(api/token-node 'idx)
(api/token-node 'v)])
(api/list-node
(list
(api/token-node 'clojure.core/aset)
(api/token-node 'data)
(api/token-node 'idx)
(api/list-node
(list
set-cast-fn
(api/token-node 'v)))))))
(api/list-node
(list
addname
(api/vector-node
[(api/token-node '_)
(api/token-node 'v)])
(api/list-node
(list
(api/token-node 'clojure.core/aset)
(api/token-node 'data)
(api/token-node 'n-elems)
(api/list-node
(list
obj-cast-fn
(api/token-node 'v)))))))
(api/list-node
(list
(api/token-node 'addAllReducible)
(api/vector-node
[(api/token-node 'this)
(api/token-node 'coll)])
(api/list-node
(list
add-all-reduce
(api/token-node 'this)
(api/token-node 'coll)))))))]
{:node new-node}))
5 changes: 5 additions & 0 deletions scripts/lint
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/bin/bash

scripts/compile
clojure -M:dev:test:clj-kondo --copy-configs --dependencies --parallel --lint "$(clojure -A:dev:test -Spath)"
clojure -M:dev:test:clj-kondo --lint "src:test" --fail-level "error"
3 changes: 1 addition & 2 deletions src/ham_fisted/api.clj
Original file line number Diff line number Diff line change
Expand Up @@ -1141,7 +1141,7 @@ ham_fisted.PersistentHashMap
([f m1] m1)
([f m1 m2] (map-union f m1 m2))
([f m1 m2 & args]
(union-reduce-maps f (apply-concat [(map-union f m1 m2)] args))))
(union-reduce-maps f (apply-concat [[(map-union f m1 m2)] args]))))


(defn memoize
Expand Down Expand Up @@ -2418,7 +2418,6 @@ ham-fisted.api> (binary-search data 1.1 nil)
(defn take-last
"Take the last N values of the collection. If the input is random-access,
the result will be random-access."
([n] (clojure.core/take-last n))
([n coll]
(when coll
(let [coll (->reducible coll)]
Expand Down
2 changes: 1 addition & 1 deletion src/ham_fisted/lazy_noncaching.clj
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@
"Lazy nonaching map but f simply gets a single random-access list of arguments.
The argument list may be mutably updated between calls."
([f c1]
(let [rdc (fn [rfn acc] (reduce c1 (fn [acc v] (rfn acc (f [v])))))]
(let [rdc (fn [rfn acc] (reduce (fn [acc v] (rfn acc (f [v]))) acc c1))]
(if-let [c1 (as-random-access c1)]
(reify IMutList
(size [this] (.size c1))
Expand Down
2 changes: 1 addition & 1 deletion src/ham_fisted/protocols.clj
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
[java.util.function DoubleConsumer]
[java.util Map]
[ham_fisted Sum Sum$SimpleSum Reducible IFnDef$ODO ParallelOptions
Reductions])
Reductions IMutList])
(:refer-clojure :exclude [reduce set?]))


Expand Down
33 changes: 20 additions & 13 deletions test/ham_fisted/api_test.clj
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,26 @@


(deftest parallism-primitives-pass-errors
(is (thrown? Exception (count (hamf/upmap
(fn [^long idx]
(when (== idx 77) (throw (Exception. "Error!!"))) idx)
(range 100)))))
(is (thrown? Exception (count (hamf/pmap (fn [^long idx]
(when (== idx 77) (throw (Exception. "Error!!"))) idx)
(range 100)))))
(is (thrown? Exception (hamf/upgroups (fn [^long sidx ^long eidx]
(when (>= sidx 70)
(throw (Exception. "Error!!"))) sidx))))
(is (thrown? Exception (hamf/pgroups (fn [^long sidx ^long eidx]
(when (>= sidx 70)
(throw (Exception. "Error!!"))) sidx)))))
(is (thrown-with-msg? Exception #"Error!!"
(doall (hamf/upmap
(fn [^long idx]
(when (== idx 77) (throw (Exception. "Error!!"))) idx)
(range 100)))))
(is (thrown-with-msg? Exception #"Error!!"
(doall (hamf/pmap (fn [^long idx]
(when (== idx 77) (throw (Exception. "Error!!"))) idx)
(range 100)))))
(is (thrown-with-msg? Exception #"Error!!"
(doall (hamf/upgroups 1000 (fn [^long sidx ^long eidx]
(when (>= sidx 10)
(throw (Exception. "Error!!")))
sidx)
{:batch-size 100}))))
(is (thrown-with-msg? Exception #"Error!!"
(doall (hamf/pgroups 1000 (fn [^long sidx ^long eidx]
(when (>= sidx 10)
(throw (Exception. "Error!!"))) sidx)
{:batch-size 100})))))


(deftest group-by-nil
Expand Down
28 changes: 11 additions & 17 deletions test/ham_fisted/defprotocol_test.clj
Original file line number Diff line number Diff line change
Expand Up @@ -109,19 +109,22 @@
(is (= "two-arg baz!" (baz obj nil)))
(is (thrown? AbstractMethodError (baz obj)))))
(testing "error conditions checked when defining protocols"
(is (thrown-with-cause-msg?
(is #_{:clj-kondo/ignore [:unresolved-symbol]}
(thrown-with-cause-msg?
Exception
#"Definition of function m in protocol badprotdef must take at least one arg."
(eval '(defprotocol badprotdef (m [])))))
(is (thrown-with-cause-msg?
(is #_{:clj-kondo/ignore [:unresolved-symbol]}
(thrown-with-cause-msg?
Exception
#"Function m in protocol badprotdef was redefined. Specify all arities in single definition."
(eval '(defprotocol badprotdef (m [this arg]) (m [this arg1 arg2]))))))
(testing "you can redefine a protocol with different methods"
(eval '(defprotocol Elusive (old-method [x])))
(eval '(defprotocol Elusive (new-method [x])))
(is (= :new-method (eval '(new-method (reify Elusive (new-method [x] :new-method))))))
(is (fails-with-cause? IllegalArgumentException #"No method of interface: .*\.Elusive found for function: old-method of protocol: Elusive \(The protocol method may have been defined before and removed\.\)"
(is #_{:clj-kondo/ignore [:unresolved-symbol]}
(fails-with-cause? IllegalArgumentException #"No method of interface: .*\.Elusive found for function: old-method of protocol: Elusive \(The protocol method may have been defined before and removed\.\)"
(eval '(old-method (reify Elusive (new-method [x] :new-method))))))))

(deftype HasMarkers []
Expand Down Expand Up @@ -168,12 +171,14 @@

(deftest illegal-extending
(testing "you cannot extend a protocol to a type that implements the protocol inline"
(is (fails-with-cause? IllegalArgumentException #".*HasProtocolInline already directly implements interface"
(is #_{:clj-kondo/ignore [:unresolved-symbol]}
(fails-with-cause? IllegalArgumentException #".*HasProtocolInline already directly implements interface"
(eval '(extend ham_fisted.defprotocol_test.HasProtocolInline
ham-fisted.defprotocol-test.examples/ExampleProtocol
{:foo (fn [_] :extended)})))))
(testing "you cannot extend to an interface"
(is (fails-with-cause? IllegalArgumentException #"interface ham_fisted.defprotocol_test.examples.ExampleProtocol is not a protocol"
(is #_{:clj-kondo/ignore [:unresolved-symbol]}
(fails-with-cause? IllegalArgumentException #"interface ham_fisted.defprotocol_test.examples.ExampleProtocol is not a protocol"
(eval '(extend ham_fisted.defprotocol_test.HasProtocolInline
ham_fisted.defprotocol_test.examples.ExampleProtocol
{:foo (fn [_] :extended)}))))))
Expand Down Expand Up @@ -233,15 +238,4 @@
(defprotocol P
(^ISeq f [_]))

(ns ham-fisted.defprotocol-test.other
(:use clojure.test)
(:require [ham-fisted.defprotocol :refer [defprotocol extend-type extend extend-protocol satisfies? extends?]])
(:refer-clojure :exclude [defprotocol extend-type extend extend-protocol satisfies? extends?]))

(defn cf [val]
(let [aseq (ham-fisted.defprotocol-test/f val)]
(count aseq)))
(extend-protocol ham-fisted.defprotocol-test/P String
(f [s] (seq s)))
(deftest test-resolve-type-hints-in-protocol-methods
(is (= 4 (cf "test"))))
;;; continues in defprotocol_test/other.clj
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
(ns ham_fisted.protocols-test.hash-collisions
(:use clojure.test))
(ns ham-fisted.defprotocol-test.hash-collisions-test
(:refer-clojure :exclude [defprotocol extend-type extend extend-protocol satisfies? extends?])
(:require [clojure.test :refer [deftest is]]
[ham-fisted.defprotocol :refer [defprotocol extend-type extend extend-protocol satisfies? extends?]]))

(defprotocol TestProtocolA
(method-a [this] "Test method A"))
Expand Down
Loading

0 comments on commit 173ca2a

Please sign in to comment.