aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Monnier2016-05-30 16:33:07 -0400
committerStefan Monnier2016-05-30 16:33:07 -0400
commit89cc852af3c7a17684b0d3083eca1ef2731f1f41 (patch)
tree46a1b7901bf2b155291cda29a1ad68f35ab47469
parent060026b9162ed5a76e95d98eea4b8f3204f6b941 (diff)
downloademacs-89cc852af3c7a17684b0d3083eca1ef2731f1f41.tar.gz
emacs-89cc852af3c7a17684b0d3083eca1ef2731f1f41.zip
* lisp/emacs-lisp/pcase.el (pcase-mutually-exclusive-predicates): Add `atom'.
-rw-r--r--lisp/emacs-lisp/pcase.el51
1 files changed, 47 insertions, 4 deletions
diff --git a/lisp/emacs-lisp/pcase.el b/lisp/emacs-lisp/pcase.el
index 7e164c0fe5c..b18472d7e3d 100644
--- a/lisp/emacs-lisp/pcase.el
+++ b/lisp/emacs-lisp/pcase.el
@@ -105,6 +105,8 @@
105 specs))))) 105 specs)))))
106 (edebug-match cursor (cons '&or specs)))) 106 (edebug-match cursor (cons '&or specs))))
107 107
108(fset 'pcase--canon #'identity)
109
108;;;###autoload 110;;;###autoload
109(defmacro pcase (exp &rest cases) 111(defmacro pcase (exp &rest cases)
110 "Evaluate EXP and attempt to match it against structural patterns. 112 "Evaluate EXP and attempt to match it against structural patterns.
@@ -332,7 +334,8 @@ any kind of error."
332 ;; to a separate function if that number is too high. 334 ;; to a separate function if that number is too high.
333 ;; 335 ;;
334 ;; We've already used this branch. So it is shared. 336 ;; We've already used this branch. So it is shared.
335 (let* ((code (car prev)) (cdrprev (cdr prev)) 337 (let* (;; (code (car prev))
338 (cdrprev (cdr prev))
336 (prevvars (car cdrprev)) (cddrprev (cdr cdrprev)) 339 (prevvars (car cdrprev)) (cddrprev (cdr cdrprev))
337 (res (car cddrprev))) 340 (res (car cddrprev)))
338 (unless (symbolp res) 341 (unless (symbolp res)
@@ -434,8 +437,10 @@ to this macro."
434 ;; Don't use let*, otherwise macroexp-let* may merge it with some surrounding 437 ;; Don't use let*, otherwise macroexp-let* may merge it with some surrounding
435 ;; let* which might prevent the setcar/setcdr in pcase--expand's fancy 438 ;; let* which might prevent the setcar/setcdr in pcase--expand's fancy
436 ;; codegen from later metamorphosing this let into a funcall. 439 ;; codegen from later metamorphosing this let into a funcall.
437 `(let ,(mapcar (lambda (b) (list (car b) (cdr b))) vars) 440 (if vars
438 ,@code)) 441 `(let ,(mapcar (lambda (b) (list (car b) (cdr b))) vars)
442 ,@code)
443 `(progn ,@code)))
439 444
440(defun pcase--small-branch-p (code) 445(defun pcase--small-branch-p (code)
441 (and (= 1 (length code)) 446 (and (= 1 (length code))
@@ -451,7 +456,36 @@ to this macro."
451 (cond 456 (cond
452 ((eq else :pcase--dontcare) then) 457 ((eq else :pcase--dontcare) then)
453 ((eq then :pcase--dontcare) (debug) else) ;Can/should this ever happen? 458 ((eq then :pcase--dontcare) (debug) else) ;Can/should this ever happen?
454 (t (macroexp-if test then else)))) 459 ;; FIXME: The code below shows that there are some opportunities for sharing,
460 ;; but it's rarely useful to do it here, since almost all sharing found
461 ;; shares a trivial expression.
462 ;; But among the common trivial expressions are those of the form
463 ;; (funcall pcase-0). For this case, there could be a significant payoff
464 ;; if we could find the sharing-opportunity earlier so as to avoid
465 ;; the creation of pcase-0.
466 ;; ((and (eq 'if (car-safe then))
467 ;; (equal (macroexp-unprogn (macroexp-progn (nthcdr 3 then)))
468 ;; (macroexp-unprogn else)))
469 ;; (let ((res (macroexp-if `(and ,test ,(nth 1 then))
470 ;; (nth 2 then) else)))
471 ;; (message "if+if => if-and: sharing %S" else)
472 ;; res))
473 ;; ((and (eq 'if (car-safe else))
474 ;; (equal (nth 2 else) then))
475 ;; (let ((res (macroexp-if `(or ,test ,(nth 1 else))
476 ;; then (macroexp-progn (nthcdr 3 else)))))
477 ;; (message "if+if => if-or: sharing %S" then)
478 ;; res))
479 (t
480 ;; (cond
481 ;; ((and (eq 'cond (car-safe then))
482 ;; (equal `(cond ,@(nthcdr 2 then)) else))
483 ;; (message "if+cond => cond-and: sharing %S" else))
484 ;; ((and (eq 'cond (car-safe else))
485 ;; (equal (macroexp-unprogn (macroexp-progn (cdr (nth 1 else))))
486 ;; (macroexp-unprogn then)))
487 ;; (message "if+cond => cond-or: sharing %S" then)))
488 (macroexp-if test then else))))
455 489
456;; Note about MATCH: 490;; Note about MATCH:
457;; When we have patterns like `(PAT1 . PAT2), after performing the `consp' 491;; When we have patterns like `(PAT1 . PAT2), after performing the `consp'
@@ -509,6 +543,7 @@ MATCH is the pattern that needs to be matched, of the form:
509 (numberp . stringp) 543 (numberp . stringp)
510 (numberp . byte-code-function-p) 544 (numberp . byte-code-function-p)
511 (consp . arrayp) 545 (consp . arrayp)
546 (consp . atom)
512 (consp . vectorp) 547 (consp . vectorp)
513 (consp . stringp) 548 (consp . stringp)
514 (consp . byte-code-function-p) 549 (consp . byte-code-function-p)
@@ -918,6 +953,14 @@ QPAT can take the following forms:
918 ((or (stringp qpat) (integerp qpat) (symbolp qpat)) `',qpat) 953 ((or (stringp qpat) (integerp qpat) (symbolp qpat)) `',qpat)
919 (t (error "Unknown QPAT: %S" qpat)))) 954 (t (error "Unknown QPAT: %S" qpat))))
920 955
956;;; Extra definitions that use pcase.
957
958(defun pcase--canon (e)
959 (pcase e
960 (`(progn ,e) (pcase--canon e))
961 (`(cond (,test . ,then) (t . ,else))
962 `(if ,test ,(macroexp-progn then) ,(macroexp-progn else)))))
963
921 964
922(provide 'pcase) 965(provide 'pcase)
923;;; pcase.el ends here 966;;; pcase.el ends here