[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
master 2f90fa1: Add a `pcase-setq' macro
From: |
Lars Ingebrigtsen |
Subject: |
master 2f90fa1: Add a `pcase-setq' macro |
Date: |
Wed, 11 Aug 2021 17:54:41 -0400 (EDT) |
branch: master
commit 2f90fa19b8fdc70303232d389553afa524c72509
Author: Earl Hyatt <okamsn@protonmail.com>
Commit: Lars Ingebrigtsen <larsi@gnus.org>
Add a `pcase-setq' macro
* doc/lispref/control.texi (Destructuring with pcase Patterns):
Document this macro.
* lisp/emacs-lisp/pcase.el (pcase-setq): New macro. This macro is
the 'setq' equivalent of 'pcase-let'.
* test/lisp/emacs-lisp/pcase-tests.el (pcase-setq): Test this new
macro. (bug#49809).
---
doc/lispref/control.texi | 4 ++++
etc/NEWS | 4 ++++
lisp/emacs-lisp/pcase.el | 38 +++++++++++++++++++++++++++++
test/lisp/emacs-lisp/pcase-tests.el | 48 +++++++++++++++++++++++++++++++++++++
4 files changed, 94 insertions(+)
diff --git a/doc/lispref/control.texi b/doc/lispref/control.texi
index 5026d0a..aacf66c 100644
--- a/doc/lispref/control.texi
+++ b/doc/lispref/control.texi
@@ -1312,6 +1312,10 @@ element of @var{list}. The bindings are performed as if
by
up being equivalent to @code{dolist} (@pxref{Iteration}).
@end defmac
+@defmac pcase-setq pattern value@dots{}
+Assign values to variables in a @code{setq} form, destructuring each
+@var{value} according to its respective @var{pattern}.
+@end defmac
@node Iteration
@section Iteration
diff --git a/etc/NEWS b/etc/NEWS
index 18fa54b..ffe8f5b 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -559,6 +559,10 @@ The new 'cl-type' pattern compares types using 'cl-typep',
which allows
comparing simple types like '(cl-type integer)', as well as forms like
'(cl-type (integer 0 10))'.
+*** New macro 'pcase-setq'
+This macro is the 'setq' equivalent of 'pcase-let', which allows for
+destructuring patterns in a 'setq' form.
+
+++
** profiler.el
The results displayed by 'profiler-report' now have the usage figures
diff --git a/lisp/emacs-lisp/pcase.el b/lisp/emacs-lisp/pcase.el
index 006517d..d111d9e 100644
--- a/lisp/emacs-lisp/pcase.el
+++ b/lisp/emacs-lisp/pcase.el
@@ -317,6 +317,44 @@ of the elements of LIST is performed as if by `pcase-let'.
(pcase-let* ((,(car spec) ,tmpvar))
,@body)))))
+;;;###autoload
+(defmacro pcase-setq (pat val &rest args)
+ "Assign values to variables by destructuring with `pcase'.
+PATTERNS are normal `pcase' patterns, and VALUES are expression.
+
+Evaluation happens sequentially as in `setq' (not in parallel).
+
+An example: (pcase-setq `((,a) [(,b)]) '((1) [(2)]))
+
+When a PATTERN doesn't match it's VALUE, the pair is silently skipped.
+
+\(fn PATTERNS VALUE PATTERN VALUES ...)"
+ (declare (debug (&rest [pcase-PAT form])))
+ (cond
+ (args
+ (let ((arg-length (length args)))
+ (unless (= 0 (mod arg-length 2))
+ (signal 'wrong-number-of-arguments
+ (list 'pcase-setq (+ 2 arg-length)))))
+ (let ((result))
+ (while args
+ (push `(pcase-setq ,(pop args) ,(pop args))
+ result))
+ `(progn
+ (pcase-setq ,pat ,val)
+ ,@(nreverse result))))
+ ((pcase--trivial-upat-p pat)
+ `(setq ,pat ,val))
+ (t
+ (pcase-compile-patterns
+ val
+ (list (cons pat
+ (lambda (varvals &rest _)
+ `(setq ,@(mapcan (lambda (varval)
+ (let ((var (car varval))
+ (val (cadr varval)))
+ (list var val)))
+ varvals)))))))))
(defun pcase--trivial-upat-p (upat)
(and (symbolp upat) (not (memq upat pcase--dontcare-upats))))
diff --git a/test/lisp/emacs-lisp/pcase-tests.el
b/test/lisp/emacs-lisp/pcase-tests.el
index 02d3878..67882d0 100644
--- a/test/lisp/emacs-lisp/pcase-tests.el
+++ b/test/lisp/emacs-lisp/pcase-tests.el
@@ -110,4 +110,52 @@
(should-error (pcase 1
((cl-type notatype) 'integer))))
+(ert-deftest pcase-setq ()
+ (should (equal (let (a b)
+ (pcase-setq `(,a ,b) nil)
+ (list a b))
+ (list nil nil)))
+
+ (should (equal (let (a b)
+ (pcase-setq `((,a) (,b)) '((1) (2)))
+ (list a b))
+ (list 1 2)))
+
+ (should (equal (list 'unset 'unset)
+ (let ((a 'unset)
+ (b 'unset))
+ (pcase-setq `(,a ,b) nil)
+ (list a b))))
+
+ (should (equal (let (a b)
+ (pcase-setq `[,a ,b] [1 2])
+ (list a b))
+ '(1 2)))
+
+ (should (equal (let (a b)
+ (pcase-setq a 1 b 2)
+ (list a b))
+ '(1 2)))
+
+ (should (= (let (a)
+ (pcase-setq a 1 `(,a) '(2))
+ a)
+ 2))
+
+ (should (equal (let (array list-item array-copy)
+ (pcase-setq (or `(,list-item) array) [1 2 3]
+ array-copy array
+ ;; This re-sets `array' to nil.
+ (or `(,list-item) array) '(4))
+ (list array array-copy list-item))
+ '(nil [1 2 3] 4)))
+
+ (let ((a nil))
+ (should-error (pcase-setq a 1 b)
+ :type '(wrong-number-of-arguments))
+ (should (eq a nil)))
+
+ (should-error (pcase-setq a)
+ :type '(wrong-number-of-arguments)))
+
;;; pcase-tests.el ends here.
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- master 2f90fa1: Add a `pcase-setq' macro,
Lars Ingebrigtsen <=