aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Monnier2012-05-04 22:05:49 -0400
committerStefan Monnier2012-05-04 22:05:49 -0400
commit5342bb062f39a387e9a770b3edef881ee4a72f17 (patch)
tree68d5c44d686d090bb2eb649a09e330b3dc54e859
parentf95e9344c9a9e0f5d28df1a9e8ac0ebed3c512fb (diff)
downloademacs-5342bb062f39a387e9a770b3edef881ee4a72f17.tar.gz
emacs-5342bb062f39a387e9a770b3edef881ee4a72f17.zip
* lisp/emacs-lisp/pcase.el (pcase--let*): New function.
(pcase--expand, pcase-codegen, pcase--q1): Use it to reduce nesting a bit more. (pcase--split-pred): Be more clever about ruling out overlap between a predicate and some constant pattern. (pcase--q1): Use `null' instead of (eq foo nil).
-rw-r--r--lisp/ChangeLog7
-rw-r--r--lisp/emacs-lisp/pcase.el64
2 files changed, 46 insertions, 25 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog
index 276cd7fca6f..9780e1265fb 100644
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -1,5 +1,12 @@
12012-05-05 Stefan Monnier <monnier@iro.umontreal.ca> 12012-05-05 Stefan Monnier <monnier@iro.umontreal.ca>
2 2
3 * emacs-lisp/pcase.el (pcase--let*): New function.
4 (pcase--expand, pcase-codegen, pcase--q1): Use it to reduce nesting
5 a bit more.
6 (pcase--split-pred): Be more clever about ruling out overlap between
7 a predicate and some constant pattern.
8 (pcase--q1): Use `null' instead of (eq foo nil).
9
3 * subr.el (setq-local, defvar-local): New macros. 10 * subr.el (setq-local, defvar-local): New macros.
4 (kbd): Redefine as an alias. 11 (kbd): Redefine as an alias.
5 (with-selected-window): Leave unrelated frames alone. 12 (with-selected-window): Leave unrelated frames alone.
diff --git a/lisp/emacs-lisp/pcase.el b/lisp/emacs-lisp/pcase.el
index afbc5df85ce..0d115cc56f5 100644
--- a/lisp/emacs-lisp/pcase.el
+++ b/lisp/emacs-lisp/pcase.el
@@ -148,6 +148,7 @@ of the form (UPAT EXP)."
148 `(let ,(nreverse bindings) (pcase-let* ,matches ,@body))))) 148 `(let ,(nreverse bindings) (pcase-let* ,matches ,@body)))))
149 149
150(defmacro pcase-dolist (spec &rest body) 150(defmacro pcase-dolist (spec &rest body)
151 (declare (indent 1))
151 (if (pcase--trivial-upat-p (car spec)) 152 (if (pcase--trivial-upat-p (car spec))
152 `(dolist ,spec ,@body) 153 `(dolist ,spec ,@body)
153 (let ((tmpvar (make-symbol "x"))) 154 (let ((tmpvar (make-symbol "x")))
@@ -217,10 +218,10 @@ of the form (UPAT EXP)."
217 (cdr case)))) 218 (cdr case))))
218 cases)))) 219 cases))))
219 (if (null defs) main 220 (if (null defs) main
220 `(let ,defs ,main)))) 221 (pcase--let* defs main))))
221 222
222(defun pcase-codegen (code vars) 223(defun pcase-codegen (code vars)
223 `(let ,(mapcar (lambda (b) (list (car b) (cdr b))) vars) 224 `(let* ,(mapcar (lambda (b) (list (car b) (cdr b))) vars)
224 ,@code)) 225 ,@code))
225 226
226(defun pcase--small-branch-p (code) 227(defun pcase--small-branch-p (code)
@@ -255,6 +256,13 @@ of the form (UPAT EXP)."
255 ((memq (car-safe then) '(if cond)) (pcase--if `(not ,test) else then)) 256 ((memq (car-safe then) '(if cond)) (pcase--if `(not ,test) else then))
256 (t `(if ,test ,then ,else)))) 257 (t `(if ,test ,then ,else))))
257 258
259;; Again, try and reduce nesting.
260(defun pcase--let* (binders body)
261 (if (eq (car-safe body) 'let*)
262 `(let* ,(append binders (nth 1 body))
263 ,@(nthcdr 2 body))
264 `(let* ,binders ,body)))
265
258(defun pcase--upat (qpattern) 266(defun pcase--upat (qpattern)
259 (cond 267 (cond
260 ((eq (car-safe qpattern) '\,) (cadr qpattern)) 268 ((eq (car-safe qpattern) '\,) (cadr qpattern))
@@ -433,26 +441,26 @@ MATCH is the pattern that needs to be matched, of the form:
433(defun pcase--split-pred (upat pat) 441(defun pcase--split-pred (upat pat)
434 ;; FIXME: For predicates like (pred (> a)), two such predicates may 442 ;; FIXME: For predicates like (pred (> a)), two such predicates may
435 ;; actually refer to different variables `a'. 443 ;; actually refer to different variables `a'.
436 (cond 444 (let (test)
437 ((equal upat pat) (cons :pcase--succeed :pcase--fail)) 445 (cond
438 ((and (eq 'pred (car upat)) 446 ((equal upat pat) (cons :pcase--succeed :pcase--fail))
439 (eq 'pred (car-safe pat)) 447 ((and (eq 'pred (car upat))
440 (or (member (cons (cadr upat) (cadr pat)) 448 (eq 'pred (car-safe pat))
441 pcase-mutually-exclusive-predicates) 449 (or (member (cons (cadr upat) (cadr pat))
442 (member (cons (cadr pat) (cadr upat)) 450 pcase-mutually-exclusive-predicates)
443 pcase-mutually-exclusive-predicates))) 451 (member (cons (cadr pat) (cadr upat))
444 (cons :pcase--fail nil)) 452 pcase-mutually-exclusive-predicates)))
445 ;; ((and (eq 'pred (car upat)) 453 (cons :pcase--fail nil))
446 ;; (eq '\` (car-safe pat)) 454 ((and (eq 'pred (car upat))
447 ;; (symbolp (cadr upat)) 455 (eq '\` (car-safe pat))
448 ;; (or (symbolp (cadr pat)) (stringp (cadr pat)) (numberp (cadr pat))) 456 (symbolp (cadr upat))
449 ;; (get (cadr upat) 'side-effect-free) 457 (or (symbolp (cadr pat)) (stringp (cadr pat)) (numberp (cadr pat)))
450 ;; (progn (message "Trying predicate %S" (cadr upat)) 458 (get (cadr upat) 'side-effect-free)
451 ;; (ignore-errors 459 (ignore-errors
452 ;; (funcall (cadr upat) (cadr pat))))) 460 (setq test (list (funcall (cadr upat) (cadr pat))))))
453 ;; (message "Simplify pred %S against %S" upat pat) 461 (if (car test)
454 ;; (cons nil :pcase--fail)) 462 (cons nil :pcase--fail)
455 )) 463 (cons :pcase--fail nil))))))
456 464
457(defun pcase--fgrep (vars sexp) 465(defun pcase--fgrep (vars sexp)
458 "Check which of the symbols VARS appear in SEXP." 466 "Check which of the symbols VARS appear in SEXP."
@@ -673,16 +681,22 @@ Otherwise, it defers to REST which is a list of branches of the form
673 ;; The byte-compiler could do that for us, but it would have to pay 681 ;; The byte-compiler could do that for us, but it would have to pay
674 ;; attention to the `consp' test in order to figure out that car/cdr 682 ;; attention to the `consp' test in order to figure out that car/cdr
675 ;; can't signal errors and our byte-compiler is not that clever. 683 ;; can't signal errors and our byte-compiler is not that clever.
676 `(let (,@(if (get syma 'pcase-used) `((,syma (car ,sym)))) 684 ;; FIXME: Some of those let bindings occur too early (they are used in
685 ;; `then-body', but only within some sub-branch).
686 (pcase--let*
687 `(,@(if (get syma 'pcase-used) `((,syma (car ,sym))))
677 ,@(if (get symd 'pcase-used) `((,symd (cdr ,sym))))) 688 ,@(if (get symd 'pcase-used) `((,symd (cdr ,sym)))))
678 ,then-body) 689 then-body)
679 (pcase--u else-rest)))) 690 (pcase--u else-rest))))
680 ((or (integerp qpat) (symbolp qpat) (stringp qpat)) 691 ((or (integerp qpat) (symbolp qpat) (stringp qpat))
681 (let* ((splitrest (pcase--split-rest 692 (let* ((splitrest (pcase--split-rest
682 sym (apply-partially 'pcase--split-equal qpat) rest)) 693 sym (apply-partially 'pcase--split-equal qpat) rest))
683 (then-rest (car splitrest)) 694 (then-rest (car splitrest))
684 (else-rest (cdr splitrest))) 695 (else-rest (cdr splitrest)))
685 (pcase--if `(,(if (stringp qpat) #'equal #'eq) ,sym ',qpat) 696 (pcase--if (cond
697 ((stringp qpat) `(equal ,sym ,qpat))
698 ((null qpat) `(null ,sym))
699 (t `(eq ,sym ',qpat)))
686 (pcase--u1 matches code vars then-rest) 700 (pcase--u1 matches code vars then-rest)
687 (pcase--u else-rest)))) 701 (pcase--u else-rest))))
688 (t (error "Unknown QPattern %s" qpat)))) 702 (t (error "Unknown QPattern %s" qpat))))