diff options
| author | Stefan Monnier | 2015-03-23 23:40:06 -0400 |
|---|---|---|
| committer | Stefan Monnier | 2015-03-23 23:40:06 -0400 |
| commit | d7d72624b29f0eeb2c242e976703e4755c6d7bef (patch) | |
| tree | d08fe0858f3ddff12aed30604dd52f47efc870e9 | |
| parent | ae277259b1cf8d913893417e4ca284040f5a543f (diff) | |
| download | emacs-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/ChangeLog | 9 | ||||
| -rw-r--r-- | lisp/emacs-lisp/cl-macs.el | 52 | ||||
| -rw-r--r-- | lisp/emacs-lisp/pcase.el | 1 |
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 @@ | |||
| 1 | 2015-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 | |||
| 1 | 2015-03-23 Stefan Monnier <monnier@iro.umontreal.ca> | 10 | 2015-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. |
| 2776 | Elements of FIELDS can be of the form (NAME UPAT) in which case the contents of | 2788 | Elements of FIELDS can be of the form (NAME UPAT) in which case the contents of |
| 2777 | field NAME is matched against UPAT, or they can be of the form NAME which | 2789 | field NAME is matched against UPAT, or they can be of the form NAME which |
| 2778 | is a shorthand for (NAME NAME)." | 2790 | is 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. |
| 2795 | STRUCT-TYPE is a symbol naming a struct type. Return 'vector or | 2839 | STRUCT-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)))) |