aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMattias EngdegÄrd2026-01-19 12:02:12 +0100
committerMattias EngdegÄrd2026-01-22 10:56:59 +0100
commit45089f9588e1fccda16fd4a69a618695453c8d88 (patch)
tree10d6498bd20dc9cb93c02f1add685eac9935d07e
parent2696eff451e6b42edddca66c807c320cb89aee35 (diff)
downloademacs-45089f9588e1fccda16fd4a69a618695453c8d88.tar.gz
emacs-45089f9588e1fccda16fd4a69a618695453c8d88.zip
* lisp/emacs-lisp/macroexp.el (macroexp--expand-all): Speed up.
Manicure pcase patterns to avoid performance-sapping internal functions and switch-breaking gaps, resulting in smaller code and less allocation.
-rw-r--r--lisp/emacs-lisp/macroexp.el181
1 files changed, 99 insertions, 82 deletions
diff --git a/lisp/emacs-lisp/macroexp.el b/lisp/emacs-lisp/macroexp.el
index dcb519b33b5..d9ca6f0b19a 100644
--- a/lisp/emacs-lisp/macroexp.el
+++ b/lisp/emacs-lisp/macroexp.el
@@ -469,16 +469,23 @@ Assumes the caller has bound `macroexpand-all-environment'."
469 (macroexp-warn-and-return 469 (macroexp-warn-and-return
470 (format-message "`condition-case' without handlers") 470 (format-message "`condition-case' without handlers")
471 exp-body (list 'suspicious 'condition-case) t form)))) 471 exp-body (list 'suspicious 'condition-case) t form))))
472 (`(,(or 'defvar 'defconst) ,(and name (pred symbolp)) . ,_) 472 (`(,(or 'defvar 'defconst) . ,args)
473 (push name macroexp--dynvars) 473 (if (and (car-safe args) (symbolp (car-safe args)))
474 (macroexp--all-forms form 2)) 474 (progn
475 (`(function ,(and f `(lambda . ,_))) 475 (push (car args) macroexp--dynvars)
476 (let ((macroexp--dynvars macroexp--dynvars)) 476 (macroexp--all-forms form 2))
477 (macroexp--cons fn 477 form))
478 (macroexp--cons (macroexp--all-forms f 2) 478 (`(function . ,rest)
479 nil 479 (if (and (eq (car-safe (car-safe rest)) 'lambda)
480 (cdr form)) 480 (null (cdr rest)))
481 form))) 481 (let ((f (car rest)))
482 (let ((macroexp--dynvars macroexp--dynvars))
483 (macroexp--cons fn
484 (macroexp--cons (macroexp--all-forms f 2)
485 nil
486 (cdr form))
487 form)))
488 form))
482 (`(,(or 'function 'quote) . ,_) form) 489 (`(,(or 'function 'quote) . ,_) form)
483 (`(,(and fun (or 'let 'let*)) . ,(or `(,bindings . ,body) 490 (`(,(and fun (or 'let 'let*)) . ,(or `(,bindings . ,body)
484 pcase--dontcare)) 491 pcase--dontcare))
@@ -495,82 +502,88 @@ Assumes the caller has bound `macroexpand-all-environment'."
495 (macroexp--all-forms body)) 502 (macroexp--all-forms body))
496 (cdr form)) 503 (cdr form))
497 form))) 504 form)))
498 (`(while) 505 (`(while . ,args)
499 (macroexp-warn-and-return 506 (if args
500 (format-message "missing `while' condition") 507 (macroexp--all-forms form 1)
501 `(signal 'wrong-number-of-arguments '(while 0)) 508 (macroexp-warn-and-return
502 nil 'compile-only form)) 509 (format-message "missing `while' condition")
503 (`(unwind-protect ,expr) 510 `(signal 'wrong-number-of-arguments '(while 0))
504 (macroexp-warn-and-return 511 nil 'compile-only form)))
505 (format-message "`unwind-protect' without unwind forms") 512 (`(unwind-protect . ,args)
506 (macroexp--expand-all expr) 513 (if (cdr-safe args)
507 (list 'suspicious 'unwind-protect) t form)) 514 (macroexp--all-forms form 1)
508 (`(setq ,(and var (pred symbolp) 515 (macroexp-warn-and-return
509 (pred (not booleanp)) (pred (not keywordp))) 516 (format-message "`unwind-protect' without unwind forms")
510 ,expr) 517 (macroexp--expand-all (car-safe args))
511 ;; Fast path for the setq common case. 518 (list 'suspicious 'unwind-protect) t form)))
512 (let ((new-expr (macroexp--expand-all expr)))
513 (if (eq new-expr expr)
514 form
515 `(,fn ,var ,new-expr))))
516 (`(setq . ,args) 519 (`(setq . ,args)
517 ;; Normalize to a sequence of (setq SYM EXPR). 520 (let ((nargs (length args))
518 ;; Malformed code is translated to code that signals an error 521 (var (car-safe args)))
519 ;; at run time. 522 (if (and (= nargs 2)
520 (let ((nargs (length args))) 523 (symbolp var)
521 (if (oddp nargs) 524 (not (booleanp var)) (not (keywordp var)))
522 (macroexp-warn-and-return 525 ;; Fast path for the common case.
523 (format-message "odd number of arguments in `setq' form") 526 (let* ((expr (nth 1 args))
524 `(signal 'wrong-number-of-arguments '(setq ,nargs)) 527 (new-expr (macroexp--expand-all expr)))
525 nil 'compile-only fn) 528 (if (eq new-expr expr)
526 (let ((assignments nil)) 529 form
527 (while (consp (cdr-safe args)) 530 `(,fn ,var ,new-expr)))
528 (let* ((var (car args)) 531 ;; Normalize to a sequence of (setq SYM EXPR).
529 (expr (cadr args)) 532 ;; Malformed code is translated to code that signals an error
530 (new-expr (macroexp--expand-all expr)) 533 ;; at run time.
531 (assignment 534 (if (oddp nargs)
532 (if (and (symbolp var) 535 (macroexp-warn-and-return
533 (not (booleanp var)) (not (keywordp var))) 536 (format-message "odd number of arguments in `setq' form")
534 `(,fn ,var ,new-expr) 537 `(signal 'wrong-number-of-arguments '(setq ,nargs))
535 (macroexp-warn-and-return 538 nil 'compile-only fn)
536 (format-message "attempt to set %s `%s'" 539 (let ((assignments nil))
537 (if (symbolp var) 540 (while (consp (cdr-safe args))
538 "constant" 541 (let* ((var (car args))
539 "non-variable") 542 (expr (cadr args))
540 var) 543 (new-expr (macroexp--expand-all expr))
541 (cond 544 (assignment
542 ((keywordp var) 545 (if (and (symbolp var)
543 ;; Accept `(setq :a :a)' for compatibility. 546 (not (booleanp var))
544 `(if (eq ,var ,new-expr) 547 (not (keywordp var)))
545 ,var 548 `(,fn ,var ,new-expr)
546 (signal 'setting-constant (list ',var)))) 549 (macroexp-warn-and-return
547 ((symbolp var) 550 (format-message "attempt to set %s `%s'"
548 `(signal 'setting-constant (list ',var))) 551 (if (symbolp var)
549 (t 552 "constant"
550 `(signal 'wrong-type-argument 553 "non-variable")
551 (list 'symbolp ',var)))) 554 var)
552 nil 'compile-only var)))) 555 (cond
553 (push assignment assignments)) 556 ((keywordp var)
554 (setq args (cddr args))) 557 ;; Accept `(setq :a :a)' for compatibility.
555 (cons 'progn (nreverse assignments)))))) 558 ;; FIXME: Why, exactly? It's useless.
556 (`(,(and fun `(lambda . ,_)) . ,args) 559 `(if (eq ,var ,new-expr)
557 (macroexp--cons (macroexp--all-forms fun 2) 560 ,var
558 (macroexp--all-forms args) 561 (signal 'setting-constant (list ',var))))
559 form)) 562 ((symbolp var)
563 `(signal 'setting-constant (list ',var)))
564 (t
565 `(signal 'wrong-type-argument
566 (list 'symbolp ',var))))
567 nil 'compile-only var))))
568 (push assignment assignments))
569 (setq args (cddr args)))
570 (cons 'progn (nreverse assignments)))))))
560 (`(funcall ,exp . ,args) 571 (`(funcall ,exp . ,args)
561 (let ((eexp (macroexp--expand-all exp)) 572 (let ((eexp (macroexp--expand-all exp))
562 (eargs (macroexp--all-forms args))) 573 (eargs (macroexp--all-forms args)))
563 (pcase eexp 574 (if (eq (car-safe eexp) 'function)
564 ;; Rewrite (funcall #'foo bar) to (foo bar), in case `foo' 575 (let ((f (cadr eexp)))
565 ;; has a compiler-macro, or to unfold it. 576 (cond
566 ((and `#',f 577 ;; Rewrite (funcall #'foo bar) to (foo bar), in case `foo'
567 (guard (and (symbolp f) 578 ;; has a compiler-macro, or to unfold it.
568 ;; bug#46636 579 ((and (symbolp f)
569 (not (or (special-form-p f) (macrop f)))))) 580 ;; bug#46636
570 (macroexp--expand-all `(,f . ,eargs))) 581 (not (or (special-form-p f) (macrop f))))
571 (`#'(lambda . ,_) 582 (macroexp--expand-all `(,f . ,eargs)))
572 (macroexp--unfold-lambda `(,fn ,eexp . ,eargs))) 583 ((eq (car-safe f) 'lambda)
573 (_ `(,fn ,eexp . ,eargs))))) 584 (macroexp--unfold-lambda `(,fn ,eexp . ,eargs)))
585 (t `(,fn ,eexp . ,eargs))))
586 `(,fn ,eexp . ,eargs))))
574 (`(funcall . ,_) form) ;bug#53227 587 (`(funcall . ,_) form) ;bug#53227
575 (`(,(and func (pred symbolp)) . ,_) 588 (`(,(and func (pred symbolp)) . ,_)
576 (let ((handler (function-get func 'compiler-macro))) 589 (let ((handler (function-get func 'compiler-macro)))
@@ -597,6 +610,10 @@ Assumes the caller has bound `macroexpand-all-environment'."
597 newform 610 newform
598 (macroexp--expand-all form))) 611 (macroexp--expand-all form)))
599 (macroexp--expand-all newform)))))) 612 (macroexp--expand-all newform))))))
613 (`(,(and fun `(lambda . ,_)) . ,args)
614 (macroexp--cons (macroexp--all-forms fun 2)
615 (macroexp--all-forms args)
616 form))
600 (_ form)))))) 617 (_ form))))))
601 618
602;;;###autoload 619;;;###autoload