diff options
| author | Stefan Monnier | 2012-09-04 13:40:25 -0400 |
|---|---|---|
| committer | Stefan Monnier | 2012-09-04 13:40:25 -0400 |
| commit | 972debf2e7381b4fd2c70f9c1fd585d8bd137917 (patch) | |
| tree | 6e9da9768df8fc4e29ce881a6b64e91806a7a564 | |
| parent | 1088b9226e7dac7314dab52ef0696a5f540900cd (diff) | |
| download | emacs-972debf2e7381b4fd2c70f9c1fd585d8bd137917.tar.gz emacs-972debf2e7381b4fd2c70f9c1fd585d8bd137917.zip | |
Macro-expand interpreted code during load.
* src/lread.c (readevalloop): Call internal-macroexpand-for-load to perform
eager (load-time) macro-expansion.
* src/lisp.mk (lisp): Add macroexp.
* lisp/loadup.el: Load macroexp. Remove hack.
* lisp/emacs-lisp/macroexp.el (macroexp--eval-if-compile): New function.
(macroexp--expand-all): Use it to get better warnings.
(macroexp--backtrace, macroexp--trim-backtrace-frame)
(internal-macroexpand-for-load): New functions.
(macroexp--pending-eager-loads): New var.
(emacs-startup-hook): New hack to replace one in loadup.el.
* lisp/emacs-lisp/cl-macs.el (cl--compiler-macro-list*)
(cl--compiler-macro-cXXr): Move to top, before they can be used.
(cl-psetf): Simplify.
(cl-defstruct): Add indent rule.
| -rw-r--r-- | etc/NEWS | 7 | ||||
| -rw-r--r-- | lisp/ChangeLog | 24 | ||||
| -rw-r--r-- | lisp/emacs-lisp/cl-loaddefs.el | 28 | ||||
| -rw-r--r-- | lisp/emacs-lisp/cl-macs.el | 56 | ||||
| -rw-r--r-- | lisp/emacs-lisp/macroexp.el | 110 | ||||
| -rw-r--r-- | lisp/emacs-lisp/pcase.el | 2 | ||||
| -rw-r--r-- | lisp/loadup.el | 28 | ||||
| -rw-r--r-- | src/ChangeLog | 6 | ||||
| -rw-r--r-- | src/lisp.mk | 1 | ||||
| -rw-r--r-- | src/lread.c | 13 |
10 files changed, 206 insertions, 69 deletions
| @@ -601,6 +601,13 @@ are deprecated and will be removed eventually. | |||
| 601 | 601 | ||
| 602 | * Lisp changes in Emacs 24.3 | 602 | * Lisp changes in Emacs 24.3 |
| 603 | 603 | ||
| 604 | ** Interpreted files get eagerly macro-expanded during load. | ||
| 605 | This can significantly speed up execution of non-byte-compiled code, but can | ||
| 606 | also bump into harmless and previously unnoticed cyclic dependencies. | ||
| 607 | These should not be fatal: they will simply cause the macro-calls to be left | ||
| 608 | for later expansion (as before), but will also result in a warning describing | ||
| 609 | the cycle. | ||
| 610 | |||
| 604 | ** New minor mode `read-only-mode' to replace toggle-read-only (now obsolete). | 611 | ** New minor mode `read-only-mode' to replace toggle-read-only (now obsolete). |
| 605 | 612 | ||
| 606 | ** New functions `autoloadp' and `autoload-do-load'. | 613 | ** New functions `autoloadp' and `autoload-do-load'. |
diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 4707834fe6b..64dda45276c 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog | |||
| @@ -1,3 +1,17 @@ | |||
| 1 | 2012-09-04 Stefan Monnier <monnier@iro.umontreal.ca> | ||
| 2 | |||
| 3 | * loadup.el: Load macroexp. Remove hack. | ||
| 4 | * emacs-lisp/macroexp.el (macroexp--eval-if-compile): New function. | ||
| 5 | (macroexp--expand-all): Use it to get better warnings. | ||
| 6 | (macroexp--backtrace, macroexp--trim-backtrace-frame) | ||
| 7 | (internal-macroexpand-for-load): New functions. | ||
| 8 | (macroexp--pending-eager-loads): New var. | ||
| 9 | (emacs-startup-hook): New hack to replace one in loadup.el. | ||
| 10 | * emacs-lisp/cl-macs.el (cl--compiler-macro-list*) | ||
| 11 | (cl--compiler-macro-cXXr): Move to top, before they can be used. | ||
| 12 | (cl-psetf): Simplify. | ||
| 13 | (cl-defstruct): Add indent rule. | ||
| 14 | |||
| 1 | 2012-09-04 Lars Ingebrigtsen <larsi@gnus.org> | 15 | 2012-09-04 Lars Ingebrigtsen <larsi@gnus.org> |
| 2 | 16 | ||
| 3 | * mail/smtpmail.el (smtpmail-send-it): Prefer the From: header | 17 | * mail/smtpmail.el (smtpmail-send-it): Prefer the From: header |
| @@ -21,10 +35,8 @@ | |||
| 21 | (temp-buffer-window-show-hook): New hooks. | 35 | (temp-buffer-window-show-hook): New hooks. |
| 22 | (temp-buffer-window-setup, temp-buffer-window-show) | 36 | (temp-buffer-window-setup, temp-buffer-window-show) |
| 23 | (with-temp-buffer-window): New functions. | 37 | (with-temp-buffer-window): New functions. |
| 24 | (fit-window-to-buffer): Remove unused optional argument | 38 | (fit-window-to-buffer): Remove unused optional argument OVERRIDE. |
| 25 | OVERRIDE. | 39 | (special-display-popup-frame): Make sure the window used shows BUFFER. |
| 26 | (special-display-popup-frame): Make sure the window used shows | ||
| 27 | BUFFER. | ||
| 28 | 40 | ||
| 29 | * help.el (temp-buffer-resize-mode): Fix doc-string. | 41 | * help.el (temp-buffer-resize-mode): Fix doc-string. |
| 30 | (resize-temp-buffer-window): New optional argument WINDOW. | 42 | (resize-temp-buffer-window): New optional argument WINDOW. |
| @@ -166,8 +178,8 @@ | |||
| 166 | 2012-08-29 Michael Albinus <michael.albinus@gmx.de> | 178 | 2012-08-29 Michael Albinus <michael.albinus@gmx.de> |
| 167 | 179 | ||
| 168 | * eshell/esh-ext.el (eshell-external-command): Do not examine | 180 | * eshell/esh-ext.el (eshell-external-command): Do not examine |
| 169 | remote shell scripts. See | 181 | remote shell scripts. |
| 170 | <https://bugs.launchpad.net/ubuntu/+source/emacs23/+bug/1035790>. | 182 | See <https://bugs.launchpad.net/ubuntu/+source/emacs23/+bug/1035790>. |
| 171 | 183 | ||
| 172 | * net/tramp-sh.el (tramp-remote-path): Add "/sbin" and | 184 | * net/tramp-sh.el (tramp-remote-path): Add "/sbin" and |
| 173 | "/usr/local/sbin". | 185 | "/usr/local/sbin". |
diff --git a/lisp/emacs-lisp/cl-loaddefs.el b/lisp/emacs-lisp/cl-loaddefs.el index 470ca17d3a0..7d70d22c9cd 100644 --- a/lisp/emacs-lisp/cl-loaddefs.el +++ b/lisp/emacs-lisp/cl-loaddefs.el | |||
| @@ -249,8 +249,7 @@ Remove from SYMBOL's plist the property PROPNAME and its value. | |||
| 249 | 249 | ||
| 250 | ;;;*** | 250 | ;;;*** |
| 251 | 251 | ||
| 252 | ;;;### (autoloads (cl--compiler-macro-cXXr cl--compiler-macro-list* | 252 | ;;;### (autoloads (cl--compiler-macro-adjoin cl-defsubst cl-compiler-macroexpand |
| 253 | ;;;;;; cl--compiler-macro-adjoin cl-defsubst cl-compiler-macroexpand | ||
| 254 | ;;;;;; cl-define-compiler-macro cl-assert cl-check-type cl-typep | 253 | ;;;;;; cl-define-compiler-macro cl-assert cl-check-type cl-typep |
| 255 | ;;;;;; cl-deftype cl-defstruct cl-callf2 cl-callf cl-letf* cl-letf | 254 | ;;;;;; cl-deftype cl-defstruct cl-callf2 cl-callf cl-letf* cl-letf |
| 256 | ;;;;;; cl-rotatef cl-shiftf cl-remf cl-psetf cl-declare cl-the cl-locally | 255 | ;;;;;; cl-rotatef cl-shiftf cl-remf cl-psetf cl-declare cl-the cl-locally |
| @@ -260,9 +259,20 @@ Remove from SYMBOL's plist the property PROPNAME and its value. | |||
| 260 | ;;;;;; cl-do cl-loop cl-return-from cl-return cl-block cl-etypecase | 259 | ;;;;;; cl-do cl-loop cl-return-from cl-return cl-block cl-etypecase |
| 261 | ;;;;;; cl-typecase cl-ecase cl-case cl-load-time-value cl-eval-when | 260 | ;;;;;; cl-typecase cl-ecase cl-case cl-load-time-value cl-eval-when |
| 262 | ;;;;;; cl-destructuring-bind cl-function cl-defmacro cl-defun cl-gentemp | 261 | ;;;;;; cl-destructuring-bind cl-function cl-defmacro cl-defun cl-gentemp |
| 263 | ;;;;;; cl-gensym) "cl-macs" "cl-macs.el" "9676d5517e8b9246c09fe78984c68bef") | 262 | ;;;;;; cl-gensym cl--compiler-macro-cXXr cl--compiler-macro-list*) |
| 263 | ;;;;;; "cl-macs" "cl-macs.el" "e09b4be5072a8b52d40af6e073876e76") | ||
| 264 | ;;; Generated autoloads from cl-macs.el | 264 | ;;; Generated autoloads from cl-macs.el |
| 265 | 265 | ||
| 266 | (autoload 'cl--compiler-macro-list* "cl-macs" "\ | ||
| 267 | |||
| 268 | |||
| 269 | \(fn FORM ARG &rest OTHERS)" nil nil) | ||
| 270 | |||
| 271 | (autoload 'cl--compiler-macro-cXXr "cl-macs" "\ | ||
| 272 | |||
| 273 | |||
| 274 | \(fn FORM X)" nil nil) | ||
| 275 | |||
| 266 | (autoload 'cl-gensym "cl-macs" "\ | 276 | (autoload 'cl-gensym "cl-macs" "\ |
| 267 | Generate a new uninterned symbol. | 277 | Generate a new uninterned symbol. |
| 268 | The name is made by appending a number to PREFIX, default \"G\". | 278 | The name is made by appending a number to PREFIX, default \"G\". |
| @@ -659,6 +669,8 @@ value, that slot cannot be set via `setf'. | |||
| 659 | 669 | ||
| 660 | (put 'cl-defstruct 'doc-string-elt '2) | 670 | (put 'cl-defstruct 'doc-string-elt '2) |
| 661 | 671 | ||
| 672 | (put 'cl-defstruct 'lisp-indent-function '1) | ||
| 673 | |||
| 662 | (autoload 'cl-deftype "cl-macs" "\ | 674 | (autoload 'cl-deftype "cl-macs" "\ |
| 663 | Define NAME as a new data type. | 675 | Define NAME as a new data type. |
| 664 | The type name can then be used in `cl-typecase', `cl-check-type', etc. | 676 | The type name can then be used in `cl-typecase', `cl-check-type', etc. |
| @@ -722,16 +734,6 @@ surrounded by (cl-block NAME ...). | |||
| 722 | 734 | ||
| 723 | \(fn FORM A LIST &rest KEYS)" nil nil) | 735 | \(fn FORM A LIST &rest KEYS)" nil nil) |
| 724 | 736 | ||
| 725 | (autoload 'cl--compiler-macro-list* "cl-macs" "\ | ||
| 726 | |||
| 727 | |||
| 728 | \(fn FORM ARG &rest OTHERS)" nil nil) | ||
| 729 | |||
| 730 | (autoload 'cl--compiler-macro-cXXr "cl-macs" "\ | ||
| 731 | |||
| 732 | |||
| 733 | \(fn FORM X)" nil nil) | ||
| 734 | |||
| 735 | ;;;*** | 737 | ;;;*** |
| 736 | 738 | ||
| 737 | ;;;### (autoloads (cl-tree-equal cl-nsublis cl-sublis cl-nsubst-if-not | 739 | ;;;### (autoloads (cl-tree-equal cl-nsublis cl-sublis cl-nsubst-if-not |
diff --git a/lisp/emacs-lisp/cl-macs.el b/lisp/emacs-lisp/cl-macs.el index 9a59aa0c6db..aba412cc8f5 100644 --- a/lisp/emacs-lisp/cl-macs.el +++ b/lisp/emacs-lisp/cl-macs.el | |||
| @@ -58,6 +58,33 @@ | |||
| 58 | 58 | ||
| 59 | ;;; Initialization. | 59 | ;;; Initialization. |
| 60 | 60 | ||
| 61 | ;; Place compiler macros at the beginning, otherwise uses of the corresponding | ||
| 62 | ;; functions can lead to recursive-loads that prevent the calls from | ||
| 63 | ;; being optimized. | ||
| 64 | |||
| 65 | ;;;###autoload | ||
| 66 | (defun cl--compiler-macro-list* (_form arg &rest others) | ||
| 67 | (let* ((args (reverse (cons arg others))) | ||
| 68 | (form (car args))) | ||
| 69 | (while (setq args (cdr args)) | ||
| 70 | (setq form `(cons ,(car args) ,form))) | ||
| 71 | form)) | ||
| 72 | |||
| 73 | ;;;###autoload | ||
| 74 | (defun cl--compiler-macro-cXXr (form x) | ||
| 75 | (let* ((head (car form)) | ||
| 76 | (n (symbol-name (car form))) | ||
| 77 | (i (- (length n) 2))) | ||
| 78 | (if (not (string-match "c[ad]+r\\'" n)) | ||
| 79 | (if (and (fboundp head) (symbolp (symbol-function head))) | ||
| 80 | (cl--compiler-macro-cXXr (cons (symbol-function head) (cdr form)) | ||
| 81 | x) | ||
| 82 | (error "Compiler macro for cXXr applied to non-cXXr form")) | ||
| 83 | (while (> i (match-beginning 0)) | ||
| 84 | (setq x (list (if (eq (aref n i) ?a) 'car 'cdr) x)) | ||
| 85 | (setq i (1- i))) | ||
| 86 | x))) | ||
| 87 | |||
| 61 | ;;; Some predicates for analyzing Lisp forms. | 88 | ;;; Some predicates for analyzing Lisp forms. |
| 62 | ;; These are used by various | 89 | ;; These are used by various |
| 63 | ;; macro expanders to optimize the results in certain common cases. | 90 | ;; macro expanders to optimize the results in certain common cases. |
| @@ -1905,8 +1932,6 @@ See Info node `(cl)Declarations' for details." | |||
| 1905 | (cl-do-proclaim (pop specs) nil))) | 1932 | (cl-do-proclaim (pop specs) nil))) |
| 1906 | nil) | 1933 | nil) |
| 1907 | 1934 | ||
| 1908 | |||
| 1909 | |||
| 1910 | ;;; The standard modify macros. | 1935 | ;;; The standard modify macros. |
| 1911 | 1936 | ||
| 1912 | ;; `setf' is now part of core Elisp, defined in gv.el. | 1937 | ;; `setf' is now part of core Elisp, defined in gv.el. |
| @@ -1929,7 +1954,7 @@ before assigning any PLACEs to the corresponding values. | |||
| 1929 | (or p (error "Odd number of arguments to cl-psetf")) | 1954 | (or p (error "Odd number of arguments to cl-psetf")) |
| 1930 | (pop p)) | 1955 | (pop p)) |
| 1931 | (if simple | 1956 | (if simple |
| 1932 | `(progn (setf ,@args) nil) | 1957 | `(progn (setq ,@args) nil) |
| 1933 | (setq args (reverse args)) | 1958 | (setq args (reverse args)) |
| 1934 | (let ((expr `(setf ,(cadr args) ,(car args)))) | 1959 | (let ((expr `(setf ,(cadr args) ,(car args)))) |
| 1935 | (while (setq args (cddr args)) | 1960 | (while (setq args (cddr args)) |
| @@ -2119,7 +2144,7 @@ one keyword is supported, `:read-only'. If this has a non-nil | |||
| 2119 | value, that slot cannot be set via `setf'. | 2144 | value, that slot cannot be set via `setf'. |
| 2120 | 2145 | ||
| 2121 | \(fn NAME SLOTS...)" | 2146 | \(fn NAME SLOTS...)" |
| 2122 | (declare (doc-string 2) | 2147 | (declare (doc-string 2) (indent 1) |
| 2123 | (debug | 2148 | (debug |
| 2124 | (&define ;Makes top-level form not be wrapped. | 2149 | (&define ;Makes top-level form not be wrapped. |
| 2125 | [&or symbolp | 2150 | [&or symbolp |
| @@ -2597,14 +2622,6 @@ surrounded by (cl-block NAME ...). | |||
| 2597 | `(if (cl-member ,a ,list ,@keys) ,list (cons ,a ,list)) | 2622 | `(if (cl-member ,a ,list ,@keys) ,list (cons ,a ,list)) |
| 2598 | form)) | 2623 | form)) |
| 2599 | 2624 | ||
| 2600 | ;;;###autoload | ||
| 2601 | (defun cl--compiler-macro-list* (_form arg &rest others) | ||
| 2602 | (let* ((args (reverse (cons arg others))) | ||
| 2603 | (form (car args))) | ||
| 2604 | (while (setq args (cdr args)) | ||
| 2605 | (setq form `(cons ,(car args) ,form))) | ||
| 2606 | form)) | ||
| 2607 | |||
| 2608 | (defun cl--compiler-macro-get (_form sym prop &optional def) | 2625 | (defun cl--compiler-macro-get (_form sym prop &optional def) |
| 2609 | (if def | 2626 | (if def |
| 2610 | `(cl-getf (symbol-plist ,sym) ,prop ,def) | 2627 | `(cl-getf (symbol-plist ,sym) ,prop ,def) |
| @@ -2616,21 +2633,6 @@ surrounded by (cl-block NAME ...). | |||
| 2616 | (cl--make-type-test temp (cl--const-expr-val type))) | 2633 | (cl--make-type-test temp (cl--const-expr-val type))) |
| 2617 | form)) | 2634 | form)) |
| 2618 | 2635 | ||
| 2619 | ;;;###autoload | ||
| 2620 | (defun cl--compiler-macro-cXXr (form x) | ||
| 2621 | (let* ((head (car form)) | ||
| 2622 | (n (symbol-name (car form))) | ||
| 2623 | (i (- (length n) 2))) | ||
| 2624 | (if (not (string-match "c[ad]+r\\'" n)) | ||
| 2625 | (if (and (fboundp head) (symbolp (symbol-function head))) | ||
| 2626 | (cl--compiler-macro-cXXr (cons (symbol-function head) (cdr form)) | ||
| 2627 | x) | ||
| 2628 | (error "Compiler macro for cXXr applied to non-cXXr form")) | ||
| 2629 | (while (> i (match-beginning 0)) | ||
| 2630 | (setq x (list (if (eq (aref n i) ?a) 'car 'cdr) x)) | ||
| 2631 | (setq i (1- i))) | ||
| 2632 | x))) | ||
| 2633 | |||
| 2634 | (dolist (y '(cl-first cl-second cl-third cl-fourth | 2636 | (dolist (y '(cl-first cl-second cl-third cl-fourth |
| 2635 | cl-fifth cl-sixth cl-seventh | 2637 | cl-fifth cl-sixth cl-seventh |
| 2636 | cl-eighth cl-ninth cl-tenth | 2638 | cl-eighth cl-ninth cl-tenth |
diff --git a/lisp/emacs-lisp/macroexp.el b/lisp/emacs-lisp/macroexp.el index 70eab149837..394225d697e 100644 --- a/lisp/emacs-lisp/macroexp.el +++ b/lisp/emacs-lisp/macroexp.el | |||
| @@ -100,6 +100,17 @@ each clause." | |||
| 100 | (error (message "Compiler-macro error for %S: %S" (car form) err) | 100 | (error (message "Compiler-macro error for %S: %S" (car form) err) |
| 101 | form))) | 101 | form))) |
| 102 | 102 | ||
| 103 | (defun macroexp--eval-if-compile (&rest _forms) | ||
| 104 | "Pseudo function used internally by macroexp to delay warnings. | ||
| 105 | The purpose is to delay warnings to bytecomp.el, so they can use things | ||
| 106 | like `byte-compile-log-warning' to get better file-and-line-number data | ||
| 107 | and also to avoid outputting the warning during normal execution." | ||
| 108 | nil) | ||
| 109 | (put 'macroexp--eval-if-compile 'byte-compile | ||
| 110 | (lambda (form) | ||
| 111 | (mapc (lambda (x) (funcall (eval x))) (cdr form)) | ||
| 112 | (byte-compile-constant nil))) | ||
| 113 | |||
| 103 | (defun macroexp--expand-all (form) | 114 | (defun macroexp--expand-all (form) |
| 104 | "Expand all macros in FORM. | 115 | "Expand all macros in FORM. |
| 105 | This is an internal version of `macroexpand-all'. | 116 | This is an internal version of `macroexpand-all'. |
| @@ -112,14 +123,17 @@ Assumes the caller has bound `macroexpand-all-environment'." | |||
| 112 | (macroexpand (macroexp--all-forms form 1) | 123 | (macroexpand (macroexp--all-forms form 1) |
| 113 | macroexpand-all-environment) | 124 | macroexpand-all-environment) |
| 114 | ;; Normal form; get its expansion, and then expand arguments. | 125 | ;; Normal form; get its expansion, and then expand arguments. |
| 115 | (let ((new-form (macroexpand form macroexpand-all-environment))) | 126 | (let ((new-form |
| 116 | (when (and (not (eq form new-form)) ;It was a macro call. | 127 | (macroexpand form macroexpand-all-environment))) |
| 117 | (car-safe form) | 128 | (setq form |
| 118 | (symbolp (car form)) | 129 | (if (and (not (eq form new-form)) ;It was a macro call. |
| 119 | (get (car form) 'byte-obsolete-info) | 130 | (car-safe form) |
| 120 | (fboundp 'byte-compile-warn-obsolete)) | 131 | (symbolp (car form)) |
| 121 | (byte-compile-warn-obsolete (car form))) | 132 | (get (car form) 'byte-obsolete-info)) |
| 122 | (setq form new-form)) | 133 | `(progn (macroexp--eval-if-compile |
| 134 | (lambda () (byte-compile-warn-obsolete ',(car form)))) | ||
| 135 | ,new-form) | ||
| 136 | new-form))) | ||
| 123 | (pcase form | 137 | (pcase form |
| 124 | (`(cond . ,clauses) | 138 | (`(cond . ,clauses) |
| 125 | (macroexp--cons 'cond (macroexp--all-clauses clauses) form)) | 139 | (macroexp--cons 'cond (macroexp--all-clauses clauses) form)) |
| @@ -323,6 +337,86 @@ symbol itself." | |||
| 323 | "Return non-nil if EXP can be copied without extra cost." | 337 | "Return non-nil if EXP can be copied without extra cost." |
| 324 | (or (symbolp exp) (macroexp-const-p exp))) | 338 | (or (symbolp exp) (macroexp-const-p exp))) |
| 325 | 339 | ||
| 340 | ;;; Load-time macro-expansion. | ||
| 341 | |||
| 342 | ;; Because macro-expansion used to be more lazy, eager macro-expansion | ||
| 343 | ;; tends to bump into previously harmless/unnoticeable cyclic-dependencies. | ||
| 344 | ;; So, we have to delay macro-expansion like we used to when we detect | ||
| 345 | ;; such a cycle, and we also want to help coders resolve those cycles (since | ||
| 346 | ;; they can be non-obvious) by providing a usefully trimmed backtrace | ||
| 347 | ;; (hopefully) highlighting the problem. | ||
| 348 | |||
| 349 | (defun macroexp--backtrace () | ||
| 350 | "Return the Elisp backtrace, more recent frames first." | ||
| 351 | (let ((bt ()) | ||
| 352 | (i 0)) | ||
| 353 | (while | ||
| 354 | (let ((frame (backtrace-frame i))) | ||
| 355 | (when frame | ||
| 356 | (push frame bt) | ||
| 357 | (setq i (1+ i))))) | ||
| 358 | (nreverse bt))) | ||
| 359 | |||
| 360 | (defun macroexp--trim-backtrace-frame (frame) | ||
| 361 | (pcase frame | ||
| 362 | (`(,_ macroexpand (,head . ,_) . ,_) `(macroexpand (,head …))) | ||
| 363 | (`(,_ internal-macroexpand-for-load (,head ,second . ,_) . ,_) | ||
| 364 | (if (or (symbolp second) | ||
| 365 | (and (eq 'quote (car-safe second)) | ||
| 366 | (symbolp (cadr second)))) | ||
| 367 | `(macroexpand-all (,head ,second …)) | ||
| 368 | '(macroexpand-all …))) | ||
| 369 | (`(,_ load-with-code-conversion ,name . ,_) | ||
| 370 | `(load ,(file-name-nondirectory name))))) | ||
| 371 | |||
| 372 | (defvar macroexp--pending-eager-loads nil | ||
| 373 | "Stack of files currently undergoing eager macro-expansion.") | ||
| 374 | |||
| 375 | (defun internal-macroexpand-for-load (form) | ||
| 376 | ;; Called from the eager-macroexpansion in readevalloop. | ||
| 377 | (cond | ||
| 378 | ;; Don't repeat the same warning for every top-level element. | ||
| 379 | ((eq 'skip (car macroexp--pending-eager-loads)) form) | ||
| 380 | ;; If we detect a cycle, skip macro-expansion for now, and output a warning | ||
| 381 | ;; with a trimmed backtrace. | ||
| 382 | ((and load-file-name (member load-file-name macroexp--pending-eager-loads)) | ||
| 383 | (let* ((bt (delq nil | ||
| 384 | (mapcar #'macroexp--trim-backtrace-frame | ||
| 385 | (macroexp--backtrace)))) | ||
| 386 | (elem `(load ,(file-name-nondirectory load-file-name))) | ||
| 387 | (tail (member elem (cdr (member elem bt))))) | ||
| 388 | (if tail (setcdr tail (list '…))) | ||
| 389 | (if (eq (car-safe (car bt)) 'macroexpand-all) (setq bt (cdr bt))) | ||
| 390 | (message "Warning: Eager macro-expansion skipped due to cycle:\n %s" | ||
| 391 | (mapconcat #'prin1-to-string (nreverse bt) " => ")) | ||
| 392 | (push 'skip macroexp--pending-eager-loads) | ||
| 393 | form)) | ||
| 394 | (t | ||
| 395 | (condition-case err | ||
| 396 | (let ((macroexp--pending-eager-loads | ||
| 397 | (cons load-file-name macroexp--pending-eager-loads))) | ||
| 398 | (macroexpand-all form)) | ||
| 399 | (error | ||
| 400 | ;; Hopefully this shouldn't happen thanks to the cycle detection, | ||
| 401 | ;; but in case it does happen, let's catch the error and give the | ||
| 402 | ;; code a chance to macro-expand later. | ||
| 403 | (message "Eager macro-expansion failure: %S" err) | ||
| 404 | form))))) | ||
| 405 | |||
| 406 | ;; ¡¡¡ Big Ugly Hack !!! | ||
| 407 | ;; src/bootstrap-emacs is mostly used to compile .el files, so it needs | ||
| 408 | ;; macroexp, bytecomp, cconv, and byte-opt to be fast. Generally this is done | ||
| 409 | ;; by compiling those files first, but this only makes a difference if those | ||
| 410 | ;; files are not preloaded. But macroexp.el is preloaded so we reload it if | ||
| 411 | ;; the current version is interpreted and there's a compiled version available. | ||
| 412 | (eval-when-compile | ||
| 413 | (add-hook 'emacs-startup-hook | ||
| 414 | (lambda () | ||
| 415 | (and (not (byte-code-function-p | ||
| 416 | (symbol-function 'macroexpand-all))) | ||
| 417 | (locate-library "macroexp.elc") | ||
| 418 | (load "macroexp.elc"))))) | ||
| 419 | |||
| 326 | (provide 'macroexp) | 420 | (provide 'macroexp) |
| 327 | 421 | ||
| 328 | ;;; macroexp.el ends here | 422 | ;;; macroexp.el ends here |
diff --git a/lisp/emacs-lisp/pcase.el b/lisp/emacs-lisp/pcase.el index 4aeed7e4d0e..09e47b69b91 100644 --- a/lisp/emacs-lisp/pcase.el +++ b/lisp/emacs-lisp/pcase.el | |||
| @@ -60,6 +60,8 @@ | |||
| 60 | ;; is in a loop, the repeated macro-expansion becomes terribly costly, so we | 60 | ;; is in a loop, the repeated macro-expansion becomes terribly costly, so we |
| 61 | ;; memoize previous macro expansions to try and avoid recomputing them | 61 | ;; memoize previous macro expansions to try and avoid recomputing them |
| 62 | ;; over and over again. | 62 | ;; over and over again. |
| 63 | ;; FIXME: Now that macroexpansion is also performed when loading an interpreted | ||
| 64 | ;; file, this is not a real problem any more. | ||
| 63 | (defconst pcase--memoize (make-hash-table :weakness 'key :test 'eq)) | 65 | (defconst pcase--memoize (make-hash-table :weakness 'key :test 'eq)) |
| 64 | ;; (defconst pcase--memoize-1 (make-hash-table :test 'eq)) | 66 | ;; (defconst pcase--memoize-1 (make-hash-table :test 'eq)) |
| 65 | ;; (defconst pcase--memoize-2 (make-hash-table :weakness 'key :test 'equal)) | 67 | ;; (defconst pcase--memoize-2 (make-hash-table :weakness 'key :test 'equal)) |
diff --git a/lisp/loadup.el b/lisp/loadup.el index a460fcab339..d389427bafd 100644 --- a/lisp/loadup.el +++ b/lisp/loadup.el | |||
| @@ -102,6 +102,19 @@ | |||
| 102 | (setq load-source-file-function 'load-with-code-conversion) | 102 | (setq load-source-file-function 'load-with-code-conversion) |
| 103 | (load "files") | 103 | (load "files") |
| 104 | 104 | ||
| 105 | ;; Load-time macro-expansion can only take effect after setting | ||
| 106 | ;; load-source-file-function because of where it is called in lread.c. | ||
| 107 | (load "emacs-lisp/macroexp") | ||
| 108 | (if (byte-code-function-p (symbol-function 'macroexpand-all)) | ||
| 109 | nil | ||
| 110 | ;; Since loaddefs is not yet loaded, macroexp's uses of pcase will simply | ||
| 111 | ;; fail until pcase is explicitly loaded. This also means that we have to | ||
| 112 | ;; disable eager macro-expansion while loading pcase. | ||
| 113 | (let ((macroexp--pending-eager-loads '(skip))) | ||
| 114 | (load "emacs-lisp/pcase")) | ||
| 115 | ;; Re-load macroexp so as to eagerly macro-expand its uses of pcase. | ||
| 116 | (load "emacs-lisp/macroexp")) | ||
| 117 | |||
| 105 | (load "cus-face") | 118 | (load "cus-face") |
| 106 | (load "faces") ; after here, `defface' may be used. | 119 | (load "faces") ; after here, `defface' may be used. |
| 107 | 120 | ||
| @@ -266,21 +279,6 @@ | |||
| 266 | ;For other systems, you must edit ../src/Makefile.in. | 279 | ;For other systems, you must edit ../src/Makefile.in. |
| 267 | (load "site-load" t) | 280 | (load "site-load" t) |
| 268 | 281 | ||
| 269 | ;; ¡¡¡ Big Ugly Hack !!! | ||
| 270 | ;; src/bootstrap-emacs is mostly used to compile .el files, so it needs | ||
| 271 | ;; macroexp, bytecomp, cconv, and byte-opt to be fast. Generally this is done | ||
| 272 | ;; by compiling those files first, but this only makes a difference if those | ||
| 273 | ;; files are not preloaded. As it so happens, macroexp.el tends to be | ||
| 274 | ;; accidentally preloaded in src/bootstrap-emacs because cl.el and cl-macs.el | ||
| 275 | ;; require it. So let's unload it here, if needed, to make sure the | ||
| 276 | ;; byte-compiled version is used. | ||
| 277 | (if (or (not (fboundp 'macroexpand-all)) | ||
| 278 | (byte-code-function-p (symbol-function 'macroexpand-all))) | ||
| 279 | nil | ||
| 280 | (fmakunbound 'macroexpand-all) | ||
| 281 | (setq features (delq 'macroexp features)) | ||
| 282 | (autoload 'macroexpand-all "macroexp")) | ||
| 283 | |||
| 284 | ;; Determine which last version number to use | 282 | ;; Determine which last version number to use |
| 285 | ;; based on the executables that now exist. | 283 | ;; based on the executables that now exist. |
| 286 | (if (and (or (equal (nth 3 command-line-args) "dump") | 284 | (if (and (or (equal (nth 3 command-line-args) "dump") |
diff --git a/src/ChangeLog b/src/ChangeLog index 1dd307b16de..b2634c4fdc4 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,3 +1,9 @@ | |||
| 1 | 2012-09-04 Stefan Monnier <monnier@iro.umontreal.ca> | ||
| 2 | |||
| 3 | * lread.c (readevalloop): Call internal-macroexpand-for-load to perform | ||
| 4 | eager (load-time) macro-expansion. | ||
| 5 | * lisp.mk (lisp): Add macroexp. | ||
| 6 | |||
| 1 | 2012-09-04 Paul Eggert <eggert@cs.ucla.edu> | 7 | 2012-09-04 Paul Eggert <eggert@cs.ucla.edu> |
| 2 | 8 | ||
| 3 | Simplify redefinition of 'abort' (Bug#12316). | 9 | Simplify redefinition of 'abort' (Bug#12316). |
diff --git a/src/lisp.mk b/src/lisp.mk index 162d8819917..3d60e07dea3 100644 --- a/src/lisp.mk +++ b/src/lisp.mk | |||
| @@ -65,6 +65,7 @@ lisp = \ | |||
| 65 | $(lispsource)/format.elc \ | 65 | $(lispsource)/format.elc \ |
| 66 | $(lispsource)/bindings.elc \ | 66 | $(lispsource)/bindings.elc \ |
| 67 | $(lispsource)/files.elc \ | 67 | $(lispsource)/files.elc \ |
| 68 | $(lispsource)/emacs-lisp/macroexp.elc \ | ||
| 68 | $(lispsource)/cus-face.elc \ | 69 | $(lispsource)/cus-face.elc \ |
| 69 | $(lispsource)/faces.elc \ | 70 | $(lispsource)/faces.elc \ |
| 70 | $(lispsource)/button.elc \ | 71 | $(lispsource)/button.elc \ |
diff --git a/src/lread.c b/src/lread.c index c15c8da3f7b..4f3a93b16b4 100644 --- a/src/lread.c +++ b/src/lread.c | |||
| @@ -1680,6 +1680,17 @@ readevalloop (Lisp_Object readcharfun, | |||
| 1680 | int whole_buffer = 0; | 1680 | int whole_buffer = 0; |
| 1681 | /* 1 on the first time around. */ | 1681 | /* 1 on the first time around. */ |
| 1682 | int first_sexp = 1; | 1682 | int first_sexp = 1; |
| 1683 | Lisp_Object macroexpand = intern ("internal-macroexpand-for-load"); | ||
| 1684 | |||
| 1685 | if (NILP (Ffboundp (macroexpand)) | ||
| 1686 | /* Don't macroexpand in .elc files, since it should have been done | ||
| 1687 | already. We actually don't know whether we're in a .elc file or not, | ||
| 1688 | so we use circumstancial evidence: .el files normally go through | ||
| 1689 | Vload_source_file_function -> load-with-code-conversion | ||
| 1690 | -> eval-buffer. */ | ||
| 1691 | || EQ (readcharfun, Qget_file_char) | ||
| 1692 | || EQ (readcharfun, Qget_emacs_mule_file_char)) | ||
| 1693 | macroexpand = Qnil; | ||
| 1683 | 1694 | ||
| 1684 | if (MARKERP (readcharfun)) | 1695 | if (MARKERP (readcharfun)) |
| 1685 | { | 1696 | { |
| @@ -1809,6 +1820,8 @@ readevalloop (Lisp_Object readcharfun, | |||
| 1809 | unbind_to (count1, Qnil); | 1820 | unbind_to (count1, Qnil); |
| 1810 | 1821 | ||
| 1811 | /* Now eval what we just read. */ | 1822 | /* Now eval what we just read. */ |
| 1823 | if (!NILP (macroexpand)) | ||
| 1824 | val = call1 (macroexpand, val); | ||
| 1812 | val = eval_sub (val); | 1825 | val = eval_sub (val); |
| 1813 | 1826 | ||
| 1814 | if (printflag) | 1827 | if (printflag) |