-
Notifications
You must be signed in to change notification settings - Fork 3
Description
The return value from mksub is not the full matching collection. This caused problems for me especially when matching vectors of one item.
user=> (require '[squarepeg.core :as sp])
nil
user=> (def v1 (sp/mksub (sp/mklit 1)))
'user/v1
user=> (v1 [[1]] {} {} {})
{:i (), :b {}, :r 1, :s [1], :m {}}
; expected :r [1]
user=> (def v12 (sp/mkseq (sp/mksub (sp/mklit 1)) (sp/mksub (sp/mklit 2))))
'user/v12
user=> (v12 [[1] [2]] {} {} {})
{:i (), :b {}, :r [1 2], :s [1 2], :m {}}
; expected :r [[1] [2]]
I'm now using a modified version of mksub which returns the full matching collection and tries to maintain the seq/vector distinction of the input. Also, I wanted to match exact sequences so I added sp/end to the sub-rule so that it would reject any extra stuff. I take an optional predicate so that I can restrict my match to vector? or seq? in cases where that matters. You're welcome to use any or all of these changes if you like them.
(require '[squarepeg.core :as sp])
(defn mk-sequential
([rule] (mk-sequential sequential? rule))
([pred rule]
(let [coll-rule (if rule (sp/mkseq rule sp/end) sp/end)]
(fn [input bindings context memo]
(if (and (seq input) (pred (first input)))
(let [r (coll-rule (first input) bindings context memo)]
(if (sp/success? r)
;; try to maintain seq/vector distinction of input, :s value is vector
(let [res (if (seq? (first input)) (seq (:s r)) (:s r))]
(sp/succeed res [res] (rest input) (:b r) (:m r)))
r))
(sp/fail "Input not a seq." memo))))))