]> git.eshelyaron.com Git - emacs.git/commitdiff
Add a pcase pattern for maps and `map-let' based on it
authorNicolas Petton <nicolas@petton.fr>
Tue, 2 Jun 2015 20:13:38 +0000 (22:13 +0200)
committerNicolas Petton <nicolas@petton.fr>
Tue, 2 Jun 2015 20:19:48 +0000 (22:19 +0200)
* lisp/emacs-lisp/map.el (map-let): New macro.
(map--make-pcase-bindings, map--make-pcase-patterns): New functions.
* test/automated/map-tests.el: New test for `map-let'.

lisp/emacs-lisp/map.el
test/automated/map-tests.el

index 8801b2aba7a7496a29d9dcbb5287b481fcaecd20..dea2abcb0e8947ab9b51960e2f5b7a88e0681fa2 100644 (file)
 
 (require 'seq)
 
+(pcase-defmacro map (&rest args)
+  "pcase pattern matching map elements.
+Matches if the object is a map (list, hash-table or array), and
+binds values from ARGS to the corresponding element of the map.
+
+ARGS can be an alist of key/binding pairs of a list of keys."
+  `(and (pred map-p)
+        ,@(map--make-pcase-bindings args)))
+
+(defmacro map-let (args map &rest body)
+  "Bind the variables in ARGS to the elements of MAP then evaluate BODY.
+
+ARGS can be an alist of key/binding pairs or a list of keys.  MAP
+can be a list, hash-table or array."
+  (declare (indent 2) (debug t))
+  `(pcase-let ((,(map--make-pcase-patterns args) ,map))
+     ,@body))
+
 (defun map-elt (map key &optional default)
   "Perform a lookup in MAP of KEY and return its associated value.
 If KEY is not found, return DEFAULT which defaults to nil.
@@ -331,5 +349,22 @@ If KEY is not found, return DEFAULT which defaults to nil."
                map)
     ht))
 
+(defun map--make-pcase-bindings (args)
+  "Return a list of pcase bindings from ARGS to the elements of a map."
+  (seq-map (lambda (elt)
+             (if (consp elt)
+                 `(app (pcase--flip map-elt ',(car elt)) ,(cdr elt))
+               `(app (pcase--flip map-elt ',elt) ,elt)))
+           args))
+
+(defun map--make-pcase-patterns (args)
+  "Return a list of `(map ...)' pcase patterns built from ARGS."
+  (cons 'map
+        (seq-map (lambda (elt)
+                   (if (and (consp elt) (eq 'map (car elt)))
+                       (map--make-pcase-patterns elt)
+                     elt))
+                 args)))
+
 (provide 'map)
 ;;; map.el ends here
index e65af89427584450710e486d0ffaecac8a501421..2f7d4eb0572b47d1bbf7db2a4491ce1f4058e8d2 100644 (file)
@@ -317,5 +317,17 @@ Evaluate BODY for each created map.
     (assert (map-empty-p (map-into nil 'hash-table)))
     (should-error (map-into [1 2 3] 'string))))
 
+(ert-deftest test-map-let ()
+  (map-let (foo bar baz) '((foo . 1) (bar . 2))
+    (assert (= foo 1))
+    (assert (= bar 2))
+    (assert (null baz)))
+  (map-let ((foo . a)
+            (bar . b)
+            (baz . c)) '((foo . 1) (bar . 2))
+    (assert (= a 1))
+    (assert (= b 2))
+    (assert (null c))))
+
 (provide 'map-tests)
 ;;; map-tests.el ends here