emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[elpa] externals/dash 947ffda 341/426: Add support for &rest match for n


From: Phillip Lord
Subject: [elpa] externals/dash 947ffda 341/426: Add support for &rest match for non-list sequences (like . for improper lists)
Date: Tue, 04 Aug 2015 19:38:44 +0000

branch: externals/dash
commit 947ffdaa1ae0eb0c72c6a0bc6d5467fde9bc7122
Author: Matus Goljer <address@hidden>
Commit: Matus Goljer <address@hidden>

    Add support for &rest match for non-list sequences (like . for improper 
lists)
---
 README.md       |    5 ++++
 dash.el         |   60 ++++++++++++++++++++++++++++++++++++++++++------------
 dev/examples.el |    7 +++++-
 3 files changed, 57 insertions(+), 15 deletions(-)

diff --git a/README.md b/README.md
index 5b425ac..a2f3bf0 100644
--- a/README.md
+++ b/README.md
@@ -1763,6 +1763,11 @@ Vectors:
                      If the `pattern` is longer than `source`, an `error` is
                      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:
 
     (&plist key0 a0 ... keyN aN) - bind value mapped by keyK in the
diff --git a/dash.el b/dash.el
index 7efe2b7..de2122e 100644
--- a/dash.el
+++ b/dash.el
@@ -1208,9 +1208,17 @@ SOURCE is a proper or improper list."
    (t
     (list (list match-form s)))))
 
-;; TODO: add support to match the "rest" of the sequence, so that we
-;; can break apart strings for example
-;; (-let (([h &rest tail] "fobar")) (list h tail)) => (102 "obar")
+(defun dash--vector-tail (seq start)
+  "Return the tail of SEQ starting at START."
+  (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)
   "Setup a vector matching environment and call the real matcher."
   (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
 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.
 
 If the MATCH-FORM vector is shorter than SOURCE vector, only
 the (length MATCH-FORM) places are bound, the rest of the SOURCE
 is discarded."
-  (let ((i 0))
-    (-flatten-n 1 (--map
-                   (let ((m (aref match-form i)))
-                     (prog1 (cond
-                             ((and (symbolp m)
-                                   ;; do not match symbols starting with _
-                                   (not (eq (aref (symbol-name m) 0) ?_)))
-                              (list (list m `(aref ,source ,i))))
-                             (t (dash--match m `(aref ,source ,i))))
-                       (setq i (1+ i))))
-                   match-form))))
+  (let ((i 0)
+        (l (length match-form))
+        (re))
+    (while (< i l)
+      (let ((m (aref match-form i)))
+        (push (cond
+               ((and (symbolp m)
+                     (eq m '&rest))
+                ;; the reversing here is necessary, because we reverse
+                ;; `re' in the end.  That would then incorrectly
+                ;; 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)
   "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
                    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:
 
   (&plist key0 a0 ... keyN aN) - bind value mapped by keyK in the
diff --git a/dev/examples.el b/dev/examples.el
index d78bccc..55f3572 100644
--- a/dev/examples.el
+++ b/dev/examples.el
@@ -720,14 +720,19 @@ new list."
       (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 _ 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] "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) (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.
     ;; 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] [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
     (condition-case nil
         (-let [[a b c d] [1 2 3]]



reply via email to

[Prev in Thread] Current Thread [Next in Thread]