Skip to content

Commit 668e05c

Browse files
committed
Fix construction of :guard patterns left hand sides.
1 parent 4df4a75 commit 668e05c

File tree

2 files changed

+96
-54
lines changed

2 files changed

+96
-54
lines changed

src/active/clojure/match.clj

Lines changed: 34 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -510,27 +510,47 @@
510510
(optional-clause? clause)
511511
{}))
512512

513-
(defn deep-merge-with
514-
"Like merge-with, but merges maps recursively, applying the given fn
515-
only when there's a non-map at a particular level.
516-
(deep-merge-with + {:a {:b {:c 1 :d {:x 1 :y 2}} :e 3} :f 4}
517-
{:a {:b {:c 2 :d {:z 9} :z 3} :e 100}})
518-
-> {:a {:b {:z 3, :c 3, :d {:z 9, :x 1, :y 2}}, :e 103}, :f 4}"
519-
[f & maps]
520-
(apply
521-
(fn m [& maps]
522-
(if (every? map? maps)
523-
(apply merge-with m maps)
524-
(apply f maps)))
525-
maps))
513+
(defn deep-merge [v & vs]
514+
(letfn [(rec-merge [v1 v2]
515+
(if (and (map? v1) (map? v2))
516+
(merge-with deep-merge v1 v2)
517+
v2))]
518+
(if (some identity vs)
519+
(reduce #(rec-merge %1 %2) v vs)
520+
v)))
521+
522+
(defn reduce-lhs
523+
[lhss]
524+
(reduce (fn [acc lhs]
525+
(cond
526+
(and (map? acc) (map? lhs))
527+
(deep-merge acc lhs)
528+
529+
(and (sequential? acc) (map? lhs))
530+
(let [[acc-map & tail] acc]
531+
(cons (deep-merge acc-map lhs) tail))
532+
533+
(and (map? acc) (sequential? lhs))
534+
(let [[lhs-map & tail] lhs]
535+
(cons (deep-merge acc lhs-map) tail))
536+
537+
(and (sequential? acc) (sequential? lhs))
538+
(let [[acc-map guard-key acc-tail] acc
539+
[lhs-map guard-key lhs-tail] lhs]
540+
(list (deep-merge acc-map lhs-map) :guard (concat acc-tail lhs-tail)))
541+
542+
:else
543+
(c/assertion-violation `reduce-lhs "not a valid lhs pattern:" lhs)))
544+
{}
545+
lhss))
526546

527547
(defn pattern->lhs
528548
[message pattern]
529549
(let [clauses (pattern-clauses pattern)]
530550
(->> pattern
531551
pattern-clauses
532552
(mapv (partial clause->lhs message))
533-
(apply deep-merge-with merge))))
553+
reduce-lhs)))
534554

535555
(defn clause->rhs
536556
[message bindings clause]

test/active/clojure/match_test.clj

Lines changed: 62 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,25 @@
129129
(-> (p/path-matches-clause [:x :y :z] (p/match-const "b"))
130130
(p/bind-match 'rebind))))))
131131

132+
(t/deftest reduce-lhs-test
133+
(t/is (empty? (p/reduce-lhs [])))
134+
(t/is (= {:x "x"} (p/reduce-lhs [{:x "x"}])))
135+
(t/is (= {:x "x" :y 'y} (p/reduce-lhs [{:x "x"} {:y 'y}])))
136+
(t/is (= {:x "other"} (p/reduce-lhs [{:x "X"} {:x "other"}])))
137+
(t/is (= (list {:x "x" :y "y"} :guard [:some-guard])
138+
(p/reduce-lhs [(list {:x "x"} :guard [:some-guard])
139+
{:y "y"}])))
140+
(t/is (= (list {:x "x" :y "y"})
141+
(p/reduce-lhs [{:x "x"} (list {:y "y"})])))
142+
143+
(t/is (= (list {:x "x" :y '_ :a 42 :z '_} :guard [:guard-1 :guard-2 :guard-3])
144+
(p/reduce-lhs [{:x "x"}
145+
(list {:y '_} :guard [:guard-1])
146+
(list {:y '_} :guard [:guard-2])
147+
{:a 42}
148+
(list {:z '_} :guard [:guard-3])]))))
149+
150+
132151
;; Imported test from active.clojure.match-test
133152
(def one-data
134153
{:kind "one" :x "x" :y "y" :z "z" :w "w"})
@@ -211,46 +230,49 @@
211230

212231

213232
;;; FIXME these tests all fail because compare-fn patterns dont work.
214-
;; (p/defpattern one-guard
215-
;; [(:kind #"one")
216-
;; (:x (:compare-fn #(= % (last ["a" "b" "c" "x"]))) :as x)
217-
;; (:y (:compare-fn #(= % (:y {:x "x" :y "y" :z "z"}))))
218-
;; (:z :as z)
219-
;; :w])
220-
221-
;; (def example-guard-matcher
222-
;; (p/map-matcher
223-
;; one-guard [x y z w]
224-
;; two [a b c Z Y X foo]
225-
;; :else false))
226-
227-
;; (def predicate-matcher
228-
;; (p/map-matcher
229-
;; ;; The order is important
230-
;; [(:x (:compare-fn #(string? %)))] ::string
231-
;; [(:x (:compare-fn (fn [x] (boolean? x))))] ::boolean
232-
;; [(:x (:compare-fn even?))] ::even
233-
;; [(:x (:compare-fn odd?))] ::odd))
234-
235-
;; (t/deftest map-matcher-predicate-test
236-
;; (t/is (= ::even (predicate-matcher {:x 42})))
237-
;; (t/is (= ::odd (predicate-matcher {:x 41})))
238-
;; (t/is (= ::string (predicate-matcher {:x "string"})))
239-
;; (t/is (= ::boolean (predicate-matcher {:x true}))))
240-
241-
;; (p/defpattern predicate-pattern
242-
;; [(:x (:compare-fn even?))])
243-
244-
;; (t/deftest map-matcher-polymorphism-test
245-
;; (t/testing "works with a pattern record"
246-
;; (t/is (= ::even
247-
;; ((p/map-matcher predicate-pattern ::even)
248-
;; {:x 42}))))
249-
250-
;; (t/testing "works with pattern syntax"
251-
;; (t/is (= ::even
252-
;; ((p/map-matcher [(:x (:compare-fn even?))] ::even)
253-
;; {:x 42})))))
233+
(p/defpattern one-guard
234+
[(:kind #"one")
235+
(:x (:compare-fn #(= % (last ["a" "b" "c" "x"]))) :as x)
236+
(:y (:compare-fn #(= % (:y {:x "x" :y "y" :z "z"}))))
237+
(:z :as z)
238+
:w])
239+
240+
(macroexpand-1 '(old-match/map-matcher [(:x (:compare-fn even?))
241+
:y] x))
242+
243+
(def example-guard-matcher
244+
(p/map-matcher
245+
one-guard [x y z w]
246+
two [a b c Z Y X foo]
247+
:else false))
248+
249+
(def predicate-matcher
250+
(p/map-matcher
251+
;; The order is important
252+
[(:x (:compare-fn #(string? %)))] ::string
253+
[(:x (:compare-fn (fn [x] (boolean? x))))] ::boolean
254+
[(:x (:compare-fn even?))] ::even
255+
[(:x (:compare-fn odd?))] ::odd))
256+
257+
(t/deftest map-matcher-predicate-test
258+
(t/is (= ::even (predicate-matcher {:x 42})))
259+
(t/is (= ::odd (predicate-matcher {:x 41})))
260+
(t/is (= ::string (predicate-matcher {:x "string"})))
261+
(t/is (= ::boolean (predicate-matcher {:x true}))))
262+
263+
(p/defpattern predicate-pattern
264+
[(:x (:compare-fn even?))])
265+
266+
(t/deftest map-matcher-polymorphism-test
267+
(t/testing "works with a pattern record"
268+
(t/is (= ::even
269+
((p/map-matcher predicate-pattern ::even)
270+
{:x 42}))))
271+
272+
(t/testing "works with pattern syntax"
273+
(t/is (= ::even
274+
((p/map-matcher [(:x (:compare-fn even?))] ::even)
275+
{:x 42})))))
254276

255277
;; FIXME this should work
256278
;; (t/deftest closes-over-outer-variables-test

0 commit comments

Comments
 (0)