aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Monnier2011-02-18 08:55:51 -0500
committerStefan Monnier2011-02-18 08:55:51 -0500
commit9a05edc4fcf1eff8966ac327e479bb8f9ca219a9 (patch)
tree3acd222eb137a5679a297a2fd8702e1e0adde505
parentb38b1ec071ee9752da53f2485902165fe728e8fa (diff)
downloademacs-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/ChangeLog5
-rw-r--r--lisp/emacs-lisp/pcase.el70
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 @@
12011-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
12011-02-17 Stefan Monnier <monnier@iro.umontreal.ca> 62011-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))))