diff options
| author | Stefan Monnier | 2011-02-18 08:55:51 -0500 |
|---|---|---|
| committer | Stefan Monnier | 2011-02-18 08:55:51 -0500 |
| commit | 9a05edc4fcf1eff8966ac327e479bb8f9ca219a9 (patch) | |
| tree | 3acd222eb137a5679a297a2fd8702e1e0adde505 | |
| parent | b38b1ec071ee9752da53f2485902165fe728e8fa (diff) | |
| download | emacs-9a05edc4fcf1eff8966ac327e479bb8f9ca219a9.tar.gz emacs-9a05edc4fcf1eff8966ac327e479bb8f9ca219a9.zip | |
* lisp/emacs-lisp/pcase.el (pcase--expand, pcase--u, pcase--u1, pcase--q1):
Avoid destructuring-bind which results in poorer code.
| -rw-r--r-- | lisp/ChangeLog | 5 | ||||
| -rw-r--r-- | lisp/emacs-lisp/pcase.el | 70 |
2 files changed, 47 insertions, 28 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 142deda9505..6b6555ab7e3 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog | |||
| @@ -1,3 +1,8 @@ | |||
| 1 | 2011-02-18 Stefan Monnier <monnier@iro.umontreal.ca> | ||
| 2 | |||
| 3 | * emacs-lisp/pcase.el (pcase--expand, pcase--u, pcase--u1, pcase--q1): | ||
| 4 | Avoid destructuring-bind which results in poorer code. | ||
| 5 | |||
| 1 | 2011-02-17 Stefan Monnier <monnier@iro.umontreal.ca> | 6 | 2011-02-17 Stefan Monnier <monnier@iro.umontreal.ca> |
| 2 | 7 | ||
| 3 | * files.el (lexical-binding): Add a safe-local-variable property. | 8 | * files.el (lexical-binding): Add a safe-local-variable property. |
diff --git a/lisp/emacs-lisp/pcase.el b/lisp/emacs-lisp/pcase.el index a338de251ed..c8a07738fe5 100644 --- a/lisp/emacs-lisp/pcase.el +++ b/lisp/emacs-lisp/pcase.el | |||
| @@ -37,8 +37,6 @@ | |||
| 37 | 37 | ||
| 38 | ;;; Code: | 38 | ;;; Code: |
| 39 | 39 | ||
| 40 | (eval-when-compile (require 'cl)) | ||
| 41 | |||
| 42 | ;; Macro-expansion of pcase is reasonably fast, so it's not a problem | 40 | ;; Macro-expansion of pcase is reasonably fast, so it's not a problem |
| 43 | ;; when byte-compiling a file, but when interpreting the code, if the pcase | 41 | ;; when byte-compiling a file, but when interpreting the code, if the pcase |
| 44 | ;; is in a loop, the repeated macro-expansion becomes terribly costly, so we | 42 | ;; is in a loop, the repeated macro-expansion becomes terribly costly, so we |
| @@ -155,7 +153,9 @@ of the form (UPAT EXP)." | |||
| 155 | ;; to a separate function if that number is too high. | 153 | ;; to a separate function if that number is too high. |
| 156 | ;; | 154 | ;; |
| 157 | ;; We've already used this branch. So it is shared. | 155 | ;; We've already used this branch. So it is shared. |
| 158 | (destructuring-bind (code prevvars res) prev | 156 | (let* ((code (car prev)) (cdrprev (cdr prev)) |
| 157 | (prevvars (car cdrprev)) (cddrprev (cdr cdrprev)) | ||
| 158 | (res (car cddrprev))) | ||
| 159 | (unless (symbolp res) | 159 | (unless (symbolp res) |
| 160 | ;; This is the first repeat, so we have to move | 160 | ;; This is the first repeat, so we have to move |
| 161 | ;; the branch to a separate function. | 161 | ;; the branch to a separate function. |
| @@ -256,15 +256,18 @@ MATCH is the pattern that needs to be matched, of the form: | |||
| 256 | (and MATCH ...) | 256 | (and MATCH ...) |
| 257 | (or MATCH ...)" | 257 | (or MATCH ...)" |
| 258 | (when (setq branches (delq nil branches)) | 258 | (when (setq branches (delq nil branches)) |
| 259 | (destructuring-bind (match code &rest vars) (car branches) | 259 | (let* ((carbranch (car branches)) |
| 260 | (match (car carbranch)) (cdarbranch (cdr carbranch)) | ||
| 261 | (code (car cdarbranch)) | ||
| 262 | (vars (cdr cdarbranch))) | ||
| 260 | (pcase--u1 (list match) code vars (cdr branches))))) | 263 | (pcase--u1 (list match) code vars (cdr branches))))) |
| 261 | 264 | ||
| 262 | (defun pcase--and (match matches) | 265 | (defun pcase--and (match matches) |
| 263 | (if matches `(and ,match ,@matches) match)) | 266 | (if matches `(and ,match ,@matches) match)) |
| 264 | 267 | ||
| 265 | (defun pcase--split-match (sym splitter match) | 268 | (defun pcase--split-match (sym splitter match) |
| 266 | (case (car match) | 269 | (cond |
| 267 | ((match) | 270 | ((eq (car match) 'match) |
| 268 | (if (not (eq sym (cadr match))) | 271 | (if (not (eq sym (cadr match))) |
| 269 | (cons match match) | 272 | (cons match match) |
| 270 | (let ((pat (cddr match))) | 273 | (let ((pat (cddr match))) |
| @@ -278,7 +281,7 @@ MATCH is the pattern that needs to be matched, of the form: | |||
| 278 | (cdr pat))))) | 281 | (cdr pat))))) |
| 279 | (t (let ((res (funcall splitter (cddr match)))) | 282 | (t (let ((res (funcall splitter (cddr match)))) |
| 280 | (cons (or (car res) match) (or (cdr res) match)))))))) | 283 | (cons (or (car res) match) (or (cdr res) match)))))))) |
| 281 | ((or and) | 284 | ((memq (car match) '(or and)) |
| 282 | (let ((then-alts '()) | 285 | (let ((then-alts '()) |
| 283 | (else-alts '()) | 286 | (else-alts '()) |
| 284 | (neutral-elem (if (eq 'or (car match)) | 287 | (neutral-elem (if (eq 'or (car match)) |
| @@ -408,32 +411,37 @@ and otherwise defers to REST which is a list of branches of the form | |||
| 408 | (pcase--u1 (cons `(match ,var or . ,(nreverse simples)) (cdr matches)) | 411 | (pcase--u1 (cons `(match ,var or . ,(nreverse simples)) (cdr matches)) |
| 409 | code vars | 412 | code vars |
| 410 | (if (null others) rest | 413 | (if (null others) rest |
| 411 | (cons (list* | 414 | (cons (cons |
| 412 | (pcase--and (if (cdr others) | 415 | (pcase--and (if (cdr others) |
| 413 | (cons 'or (nreverse others)) | 416 | (cons 'or (nreverse others)) |
| 414 | (car others)) | 417 | (car others)) |
| 415 | (cdr matches)) | 418 | (cdr matches)) |
| 416 | code vars) | 419 | (cons code vars)) |
| 417 | rest)))) | 420 | rest)))) |
| 418 | (t | 421 | (t |
| 419 | (pcase--u1 (cons (pop alts) (cdr matches)) code vars | 422 | (pcase--u1 (cons (pop alts) (cdr matches)) code vars |
| 420 | (if (null alts) (progn (error "Please avoid it") rest) | 423 | (if (null alts) (progn (error "Please avoid it") rest) |
| 421 | (cons (list* | 424 | (cons (cons |
| 422 | (pcase--and (if (cdr alts) | 425 | (pcase--and (if (cdr alts) |
| 423 | (cons 'or alts) (car alts)) | 426 | (cons 'or alts) (car alts)) |
| 424 | (cdr matches)) | 427 | (cdr matches)) |
| 425 | code vars) | 428 | (cons code vars)) |
| 426 | rest))))))) | 429 | rest))))))) |
| 427 | ((eq 'match (caar matches)) | 430 | ((eq 'match (caar matches)) |
| 428 | (destructuring-bind (op sym &rest upat) (pop matches) | 431 | (let* ((popmatches (pop matches)) |
| 432 | (op (car popmatches)) (cdrpopmatches (cdr popmatches)) | ||
| 433 | (sym (car cdrpopmatches)) | ||
| 434 | (upat (cdr cdrpopmatches))) | ||
| 429 | (cond | 435 | (cond |
| 430 | ((memq upat '(t _)) (pcase--u1 matches code vars rest)) | 436 | ((memq upat '(t _)) (pcase--u1 matches code vars rest)) |
| 431 | ((eq upat 'dontcare) :pcase--dontcare) | 437 | ((eq upat 'dontcare) :pcase--dontcare) |
| 432 | ((functionp upat) (error "Feature removed, use (pred %s)" upat)) | 438 | ((functionp upat) (error "Feature removed, use (pred %s)" upat)) |
| 433 | ((memq (car-safe upat) '(guard pred)) | 439 | ((memq (car-safe upat) '(guard pred)) |
| 434 | (destructuring-bind (then-rest &rest else-rest) | 440 | (let* ((splitrest |
| 435 | (pcase--split-rest | 441 | (pcase--split-rest |
| 436 | sym (apply-partially #'pcase--split-pred upat) rest) | 442 | sym (apply-partially #'pcase--split-pred upat) rest)) |
| 443 | (then-rest (car splitrest)) | ||
| 444 | (else-rest (cdr splitrest))) | ||
| 437 | (pcase--if (if (and (eq (car upat) 'pred) (symbolp (cadr upat))) | 445 | (pcase--if (if (and (eq (car upat) 'pred) (symbolp (cadr upat))) |
| 438 | `(,(cadr upat) ,sym) | 446 | `(,(cadr upat) ,sym) |
| 439 | (let* ((exp (cadr upat)) | 447 | (let* ((exp (cadr upat)) |
| @@ -472,13 +480,15 @@ and otherwise defers to REST which is a list of branches of the form | |||
| 472 | (setq all nil)))) | 480 | (setq all nil)))) |
| 473 | (if all | 481 | (if all |
| 474 | ;; Use memq for (or `a `b `c `d) rather than a big tree. | 482 | ;; Use memq for (or `a `b `c `d) rather than a big tree. |
| 475 | (let ((elems (mapcar 'cadr (cdr upat)))) | 483 | (let* ((elems (mapcar 'cadr (cdr upat))) |
| 476 | (destructuring-bind (then-rest &rest else-rest) | 484 | (splitrest |
| 477 | (pcase--split-rest | 485 | (pcase--split-rest |
| 478 | sym (apply-partially #'pcase--split-member elems) rest) | 486 | sym (apply-partially #'pcase--split-member elems) rest)) |
| 479 | (pcase--if `(,(if memq-fine #'memq #'member) ,sym ',elems) | 487 | (then-rest (car splitrest)) |
| 480 | (pcase--u1 matches code vars then-rest) | 488 | (else-rest (cdr splitrest))) |
| 481 | (pcase--u else-rest)))) | 489 | (pcase--if `(,(if memq-fine #'memq #'member) ,sym ',elems) |
| 490 | (pcase--u1 matches code vars then-rest) | ||
| 491 | (pcase--u else-rest))) | ||
| 482 | (pcase--u1 (cons `(match ,sym ,@(cadr upat)) matches) code vars | 492 | (pcase--u1 (cons `(match ,sym ,@(cadr upat)) matches) code vars |
| 483 | (append (mapcar (lambda (upat) | 493 | (append (mapcar (lambda (upat) |
| 484 | `((and (match ,sym . ,upat) ,@matches) | 494 | `((and (match ,sym . ,upat) ,@matches) |
| @@ -527,10 +537,12 @@ and if not, defers to REST which is a list of branches of the form | |||
| 527 | ((consp qpat) | 537 | ((consp qpat) |
| 528 | (let ((syma (make-symbol "xcar")) | 538 | (let ((syma (make-symbol "xcar")) |
| 529 | (symd (make-symbol "xcdr"))) | 539 | (symd (make-symbol "xcdr"))) |
| 530 | (destructuring-bind (then-rest &rest else-rest) | 540 | (let* ((splitrest (pcase--split-rest |
| 531 | (pcase--split-rest sym | 541 | sym |
| 532 | (apply-partially #'pcase--split-consp syma symd) | 542 | (apply-partially #'pcase--split-consp syma symd) |
| 533 | rest) | 543 | rest)) |
| 544 | (then-rest (car splitrest)) | ||
| 545 | (else-rest (cdr splitrest))) | ||
| 534 | (pcase--if `(consp ,sym) | 546 | (pcase--if `(consp ,sym) |
| 535 | `(let ((,syma (car ,sym)) | 547 | `(let ((,syma (car ,sym)) |
| 536 | (,symd (cdr ,sym))) | 548 | (,symd (cdr ,sym))) |
| @@ -540,8 +552,10 @@ and if not, defers to REST which is a list of branches of the form | |||
| 540 | code vars then-rest)) | 552 | code vars then-rest)) |
| 541 | (pcase--u else-rest))))) | 553 | (pcase--u else-rest))))) |
| 542 | ((or (integerp qpat) (symbolp qpat) (stringp qpat)) | 554 | ((or (integerp qpat) (symbolp qpat) (stringp qpat)) |
| 543 | (destructuring-bind (then-rest &rest else-rest) | 555 | (let* ((splitrest (pcase--split-rest |
| 544 | (pcase--split-rest sym (apply-partially 'pcase--split-equal qpat) rest) | 556 | sym (apply-partially 'pcase--split-equal qpat) rest)) |
| 557 | (then-rest (car splitrest)) | ||
| 558 | (else-rest (cdr splitrest))) | ||
| 545 | (pcase--if `(,(if (stringp qpat) #'equal #'eq) ,sym ',qpat) | 559 | (pcase--if `(,(if (stringp qpat) #'equal #'eq) ,sym ',qpat) |
| 546 | (pcase--u1 matches code vars then-rest) | 560 | (pcase--u1 matches code vars then-rest) |
| 547 | (pcase--u else-rest)))) | 561 | (pcase--u else-rest)))) |