aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Monnier2015-03-23 23:40:06 -0400
committerStefan Monnier2015-03-23 23:40:06 -0400
commitd7d72624b29f0eeb2c242e976703e4755c6d7bef (patch)
treed08fe0858f3ddff12aed30604dd52f47efc870e9
parentae277259b1cf8d913893417e4ca284040f5a543f (diff)
downloademacs-d7d72624b29f0eeb2c242e976703e4755c6d7bef.tar.gz
emacs-d7d72624b29f0eeb2c242e976703e4755c6d7bef.zip
Add cl-struct specific optimizations to pcase.
* lisp/emacs-lisp/cl-macs.el (cl--struct-all-parents) (cl--pcase-mutually-exclusive-p): New functions. (pcase--mutually-exclusive-p): Advise to optimize cl-struct patterns. * lisp/emacs-lisp/pcase.el (pcase--split-pred): Handle quoted string.
-rw-r--r--lisp/ChangeLog9
-rw-r--r--lisp/emacs-lisp/cl-macs.el52
-rw-r--r--lisp/emacs-lisp/pcase.el1
3 files changed, 58 insertions, 4 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog
index 8670e450e28..25ac7ae6782 100644
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -1,3 +1,12 @@
12015-03-24 Stefan Monnier <monnier@iro.umontreal.ca>
2
3 Add cl-struct specific optimizations to pcase.
4 * emacs-lisp/cl-macs.el (cl--struct-all-parents)
5 (cl--pcase-mutually-exclusive-p): New functions.
6 (pcase--mutually-exclusive-p): Advise to optimize cl-struct patterns.
7
8 * emacs-lisp/pcase.el (pcase--split-pred): Handle quoted string.
9
12015-03-23 Stefan Monnier <monnier@iro.umontreal.ca> 102015-03-23 Stefan Monnier <monnier@iro.umontreal.ca>
2 11
3 Add new `cl-struct' and `eieio' pcase patterns. 12 Add new `cl-struct' and `eieio' pcase patterns.
diff --git a/lisp/emacs-lisp/cl-macs.el b/lisp/emacs-lisp/cl-macs.el
index a81d217e4ee..5d55a1d4579 100644
--- a/lisp/emacs-lisp/cl-macs.el
+++ b/lisp/emacs-lisp/cl-macs.el
@@ -2770,16 +2770,25 @@ non-nil value, that slot cannot be set via `setf'.
2770 2770
2771;;; Add cl-struct support to pcase 2771;;; Add cl-struct support to pcase
2772 2772
2773(defun cl--struct-all-parents (class)
2774 (when (cl--struct-class-p class)
2775 (let ((res ())
2776 (classes (list class)))
2777 ;; BFS precedence.
2778 (while (let ((class (pop classes)))
2779 (push class res)
2780 (setq classes
2781 (append classes
2782 (cl--class-parents class)))))
2783 (nreverse res))))
2784
2773;;;###autoload 2785;;;###autoload
2774(pcase-defmacro cl-struct (type &rest fields) 2786(pcase-defmacro cl-struct (type &rest fields)
2775 "Pcase patterns to match cl-structs. 2787 "Pcase patterns to match cl-structs.
2776Elements of FIELDS can be of the form (NAME UPAT) in which case the contents of 2788Elements of FIELDS can be of the form (NAME UPAT) in which case the contents of
2777field NAME is matched against UPAT, or they can be of the form NAME which 2789field NAME is matched against UPAT, or they can be of the form NAME which
2778is a shorthand for (NAME NAME)." 2790is a shorthand for (NAME NAME)."
2779 ;; FIXME: This works well for a destructuring pcase-let, but for straight 2791 `(and (pred (pcase--flip cl-typep ',type))
2780 ;; pcase, it suffers seriously from a lack of support for cl-typep in
2781 ;; pcase--mutually-exclusive-p.
2782 `(and (pred (pcase--swap cl-typep ',type))
2783 ,@(mapcar 2792 ,@(mapcar
2784 (lambda (field) 2793 (lambda (field)
2785 (let* ((name (if (consp field) (car field) field)) 2794 (let* ((name (if (consp field) (car field) field))
@@ -2790,6 +2799,41 @@ is a shorthand for (NAME NAME)."
2790 ,pat))) 2799 ,pat)))
2791 fields))) 2800 fields)))
2792 2801
2802(defun cl--pcase-mutually-exclusive-p (orig pred1 pred2)
2803 "Extra special cases for `cl-typep' predicates."
2804 (let* ((x1 pred1) (x2 pred2)
2805 (t1
2806 (and (eq 'pcase--flip (car-safe x1)) (setq x1 (cdr x1))
2807 (eq 'cl-typep (car-safe x1)) (setq x1 (cdr x1))
2808 (null (cdr-safe x1)) (setq x1 (car x1))
2809 (eq 'quote (car-safe x1)) (cadr x1)))
2810 (t2
2811 (and (eq 'pcase--flip (car-safe x2)) (setq x2 (cdr x2))
2812 (eq 'cl-typep (car-safe x2)) (setq x2 (cdr x2))
2813 (null (cdr-safe x2)) (setq x2 (car x2))
2814 (eq 'quote (car-safe x2)) (cadr x2))))
2815 (or
2816 (and (symbolp t1) (symbolp t2)
2817 (let ((c1 (cl--find-class t1))
2818 (c2 (cl--find-class t2)))
2819 (and c1 c2
2820 (not (or (memq c1 (cl--struct-all-parents c2))
2821 (memq c2 (cl--struct-all-parents c1)))))))
2822 (let ((c1 (and (symbolp t1) (cl--find-class t1))))
2823 (and c1 (cl--struct-class-p c1)
2824 (funcall orig (if (eq 'list (cl-struct-sequence-type t1))
2825 'consp 'vectorp)
2826 pred2)))
2827 (let ((c2 (and (symbolp t2) (cl--find-class t2))))
2828 (and c2 (cl--struct-class-p c2)
2829 (funcall orig pred1
2830 (if (eq 'list (cl-struct-sequence-type t2))
2831 'consp 'vectorp))))
2832 (funcall orig pred1 pred2))))
2833(advice-add 'pcase--mutually-exclusive-p
2834 :around #'cl--pcase-mutually-exclusive-p)
2835
2836
2793(defun cl-struct-sequence-type (struct-type) 2837(defun cl-struct-sequence-type (struct-type)
2794 "Return the sequence used to build STRUCT-TYPE. 2838 "Return the sequence used to build STRUCT-TYPE.
2795STRUCT-TYPE is a symbol naming a struct type. Return 'vector or 2839STRUCT-TYPE is a symbol naming a struct type. Return 'vector or
diff --git a/lisp/emacs-lisp/pcase.el b/lisp/emacs-lisp/pcase.el
index a9933e46bbd..3a2fa4fdc81 100644
--- a/lisp/emacs-lisp/pcase.el
+++ b/lisp/emacs-lisp/pcase.el
@@ -582,6 +582,7 @@ MATCH is the pattern that needs to be matched, of the form:
582 (cond ((eq 'pred (car-safe pat)) (cadr pat)) 582 (cond ((eq 'pred (car-safe pat)) (cadr pat))
583 ((not (eq 'quote (car-safe pat))) nil) 583 ((not (eq 'quote (car-safe pat))) nil)
584 ((consp (cadr pat)) #'consp) 584 ((consp (cadr pat)) #'consp)
585 ((stringp (cadr pat)) #'stringp)
585 ((vectorp (cadr pat)) #'vectorp) 586 ((vectorp (cadr pat)) #'vectorp)
586 ((byte-code-function-p (cadr pat)) 587 ((byte-code-function-p (cadr pat))
587 #'byte-code-function-p)))) 588 #'byte-code-function-p))))