diff options
| author | Stefan Monnier | 2012-05-04 22:05:49 -0400 |
|---|---|---|
| committer | Stefan Monnier | 2012-05-04 22:05:49 -0400 |
| commit | 5342bb062f39a387e9a770b3edef881ee4a72f17 (patch) | |
| tree | 68d5c44d686d090bb2eb649a09e330b3dc54e859 | |
| parent | f95e9344c9a9e0f5d28df1a9e8ac0ebed3c512fb (diff) | |
| download | emacs-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/ChangeLog | 7 | ||||
| -rw-r--r-- | lisp/emacs-lisp/pcase.el | 64 |
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 @@ | |||
| 1 | 2012-05-05 Stefan Monnier <monnier@iro.umontreal.ca> | 1 | 2012-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)))) |