Add support for &rest match for non-list sequences (like . for improper lists)

master
Matus Goljer 12 years ago
parent 8f9fc4113d
commit 947ffdaa1a
  1. 5
      README.md
  2. 60
      dash.el
  3. 7
      dev/examples.el

@ -1763,6 +1763,11 @@ Vectors:
If the `pattern` is longer than `source`, an `error` is If the `pattern` is longer than `source`, an `error` is
thrown. thrown.
[a1 a2 a3 ... &rest rest] ) - as above, but bind the rest of
the sequence to `rest`. This is
conceptually the same as improper list
matching (a1 a2 ... aN . rest)
Key/value stores: Key/value stores:
(&plist key0 a0 ... keyN aN) - bind value mapped by keyK in the (&plist key0 a0 ... keyN aN) - bind value mapped by keyK in the

@ -1208,9 +1208,17 @@ SOURCE is a proper or improper list."
(t (t
(list (list match-form s))))) (list (list match-form s)))))
;; TODO: add support to match the "rest" of the sequence, so that we (defun dash--vector-tail (seq start)
;; can break apart strings for example "Return the tail of SEQ starting at START."
;; (-let (([h &rest tail] "fobar")) (list h tail)) => (102 "obar") (cond
((vectorp seq)
(let* ((re-length (- (length seq) start))
(re (make-vector re-length 0)))
(--dotimes re-length (aset re it (aref seq (+ it start))))
re))
((stringp seq)
(substring seq start))))
(defun dash--match-vector (match-form source) (defun dash--match-vector (match-form source)
"Setup a vector matching environment and call the real matcher." "Setup a vector matching environment and call the real matcher."
(let ((s (make-symbol "--dash-source--"))) (let ((s (make-symbol "--dash-source--")))
@ -1223,22 +1231,41 @@ MATCH-FORM is a vector. Each element of MATCH-FORM is either a
symbol, which gets bound to the respective value in source or symbol, which gets bound to the respective value in source or
another match form which gets destructured recursively. another match form which gets destructured recursively.
If second-from-last place in MATCH-FORM is the symbol &rest, the
next element of the MATCH-FORM is matched against the tail of
SOURCE, starting at index of the &rest symbol. This is
conceptually the same as the (head . tail) match for improper
lists, where dot plays the role of &rest.
SOURCE is a vector. SOURCE is a vector.
If the MATCH-FORM vector is shorter than SOURCE vector, only If the MATCH-FORM vector is shorter than SOURCE vector, only
the (length MATCH-FORM) places are bound, the rest of the SOURCE the (length MATCH-FORM) places are bound, the rest of the SOURCE
is discarded." is discarded."
(let ((i 0)) (let ((i 0)
(-flatten-n 1 (--map (l (length match-form))
(let ((m (aref match-form i))) (re))
(prog1 (cond (while (< i l)
((and (symbolp m) (let ((m (aref match-form i)))
;; do not match symbols starting with _ (push (cond
(not (eq (aref (symbol-name m) 0) ?_))) ((and (symbolp m)
(list (list m `(aref ,source ,i)))) (eq m '&rest))
(t (dash--match m `(aref ,source ,i)))) ;; the reversing here is necessary, because we reverse
(setq i (1+ i)))) ;; `re' in the end. That would then incorrectly
match-form)))) ;; reorder sub-expression matches
(prog1 (nreverse
(dash--match
(aref match-form (1+ i))
`(dash--vector-tail ,source ,i)))
(setq i l)))
((and (symbolp m)
;; do not match symbols starting with _
(not (eq (aref (symbol-name m) 0) ?_)))
(list (list m `(aref ,source ,i))))
(t (nreverse (dash--match m `(aref ,source ,i)))))
re)
(setq i (1+ i))))
(nreverse (-flatten-n 1 re))))
(defun dash--match-kv (match-form source) (defun dash--match-kv (match-form source)
"Setup a kv matching environment and call the real matcher. "Setup a kv matching environment and call the real matcher.
@ -1381,6 +1408,11 @@ Vectors:
If the PATTERN is longer than SOURCE, an `error' is If the PATTERN is longer than SOURCE, an `error' is
thrown. thrown.
[a1 a2 a3 ... &rest rest] ) - as above, but bind the rest of
the sequence to REST. This is
conceptually the same as improper list
matching (a1 a2 ... aN . rest)
Key/value stores: Key/value stores:
(&plist key0 a0 ... keyN aN) - bind value mapped by keyK in the (&plist key0 a0 ... keyN aN) - bind value mapped by keyK in the

@ -720,14 +720,19 @@ new list."
(list bar face inv)) => '(2 foo-face t) (list bar face inv)) => '(2 foo-face t)
(-let [(a (b c) d) (list 1 (list 2 3) 4 5 6)] (list a b c d)) => '(1 2 3 4) (-let [(a (b c) d) (list 1 (list 2 3) 4 5 6)] (list a b c d)) => '(1 2 3 4)
(-let [[a _ c] [1 2 3 4]] (list a c)) => '(1 3) (-let [[a _ c] [1 2 3 4]] (list a c)) => '(1 3)
(-let [[a (b c) d] [1 (2 3) 4]] (list a b c d)) => '(1 2 3 4)
(-let [[a b c] (string ?f ?o ?b ?a ?r)] (list a b c)) => '(?f ?o ?b) (-let [[a b c] (string ?f ?o ?b ?a ?r)] (list a b c)) => '(?f ?o ?b)
(-let [[a b c] "abcdef"] (list a b c)) => '(?a ?b ?c)
(-let [[a (b [c]) d] [1 (2 [3 4]) 5 6]] (list a b c d)) => '(1 2 3 5) (-let [[a (b [c]) d] [1 (2 [3 4]) 5 6]] (list a b c d)) => '(1 2 3 5)
(-let [(a b c d) (list 1 2 3 4 5 6)] (list a b c d)) => '(1 2 3 4) (-let [(a b c d) (list 1 2 3 4 5 6)] (list a b c d)) => '(1 2 3 4)
;; d is bound to nil. I don't think we want to error in such a case. ;; d is bound to nil. I don't think we want to error in such a case.
;; After all (car nil) => nil ;; After all (car nil) => nil
(-let [(a b c d) (list 1 2 3)] (list a b c d)) => '(1 2 3 nil) (-let [(a b c d) (list 1 2 3)] (list a b c d)) => '(1 2 3 nil)
(-let [[a b c] [1 2 3 4]] (list a b c)) => '(1 2 3) (-let [[a b c] [1 2 3 4]] (list a b c)) => '(1 2 3)
;; here we error, because "vectors" are rigit, immutable structures, (-let [[a b &rest c] "abcdef"] (list a b c)) => '(?a ?b "cdef")
(-let [[a b &rest c] [1 2 3 4 5 6]] (list a b c)) => '(1 2 [3 4 5 6])
(-let [[a b &rest [c d]] [1 2 3 4 5 6]] (list a b c d)) => '(1 2 3 4)
;; here we error, because "vectors" are rigid, immutable structures,
;; so we should know how many elements there are ;; so we should know how many elements there are
(condition-case nil (condition-case nil
(-let [[a b c d] [1 2 3]] (-let [[a b c d] [1 2 3]]

Loading…
Cancel
Save