diff options
| author | Daniel Colascione | 2014-04-22 00:04:34 -0700 |
|---|---|---|
| committer | Daniel Colascione | 2014-04-22 00:04:34 -0700 |
| commit | 12b1389c9039dd374951673ca43b1ddf65df400d (patch) | |
| tree | f4d36afc9d1ccdd72f3d801b350d79d25dd5e8bb | |
| parent | c98212f9e7cef496dded06eba4476033062c171f (diff) | |
| download | emacs-12b1389c9039dd374951673ca43b1ddf65df400d.tar.gz emacs-12b1389c9039dd374951673ca43b1ddf65df400d.zip | |
Correctly macroexpand top-level forms during eager macroexpand
* lisp/emacs-lisp/byte-run.el (eval-when-compile, eval-and-compile):
Improve docstrings.
* lisp/emacs-lisp/macroexp.el (internal-macroexpand-for-load): Add
`full-p' parameter; when nil, call `macroexpand' instead of
`macroexpand-all'.
* src/lread.c (readevalloop_eager_expand_eval): New function
that can recurse into toplevel forms.
(readevalloop): Call it.
* src/lisp.h: Declare Qprogn.
* src/callint.c (Qprogn): No longer static.
* test/automated/bytecomp-tests.el (test-byte-comp-compile-and-load):
Add compile flag.
(test-byte-comp-macro-expansion)
(test-byte-comp-macro-expansion-eval-and-compile)
(test-byte-comp-macro-expansion-eval-when-compile)
(test-byte-comp-macro-expand-lexical-override): Use it.
(test-eager-load-macro-expansion)
(test-eager-load-macro-expansion-eval-and-compile)
(test-eager-load-macro-expansion-eval-when-compile)
(test-eager-load-macro-expand-lexical-override): New tests.
| -rw-r--r-- | lisp/ChangeLog | 7 | ||||
| -rw-r--r-- | lisp/emacs-lisp/byte-run.el | 13 | ||||
| -rw-r--r-- | lisp/emacs-lisp/macroexp.el | 6 | ||||
| -rw-r--r-- | src/ChangeLog | 8 | ||||
| -rw-r--r-- | src/callint.c | 4 | ||||
| -rw-r--r-- | src/lisp.h | 1 | ||||
| -rw-r--r-- | src/lread.c | 28 | ||||
| -rw-r--r-- | test/ChangeLog | 14 | ||||
| -rw-r--r-- | test/automated/bytecomp-tests.el | 56 |
9 files changed, 118 insertions, 19 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 38871c7ff32..06e2732becc 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog | |||
| @@ -1,5 +1,12 @@ | |||
| 1 | 2014-04-22 Daniel Colascione <dancol@dancol.org> | 1 | 2014-04-22 Daniel Colascione <dancol@dancol.org> |
| 2 | 2 | ||
| 3 | * emacs-lisp/macroexp.el (internal-macroexpand-for-load): Add | ||
| 4 | `full-p' parameter; when nil, call `macroexpand' instead of | ||
| 5 | `macroexpand-all'. | ||
| 6 | |||
| 7 | * emacs-lisp/byte-run.el (eval-when-compile, eval-and-compile): | ||
| 8 | Improve docstrings. | ||
| 9 | |||
| 3 | * emacs-lisp/bytecomp.el (byte-compile-initial-macro-environment): | 10 | * emacs-lisp/bytecomp.el (byte-compile-initial-macro-environment): |
| 4 | Use lambda function values, not quoted lambdas. | 11 | Use lambda function values, not quoted lambdas. |
| 5 | (byte-compile-recurse-toplevel): Remove extraneous &optional. | 12 | (byte-compile-recurse-toplevel): Remove extraneous &optional. |
diff --git a/lisp/emacs-lisp/byte-run.el b/lisp/emacs-lisp/byte-run.el index dc08b870569..be011e2146c 100644 --- a/lisp/emacs-lisp/byte-run.el +++ b/lisp/emacs-lisp/byte-run.el | |||
| @@ -398,13 +398,20 @@ If you think you need this, you're probably making a mistake somewhere." | |||
| 398 | 398 | ||
| 399 | (defmacro eval-when-compile (&rest body) | 399 | (defmacro eval-when-compile (&rest body) |
| 400 | "Like `progn', but evaluates the body at compile time if you're compiling. | 400 | "Like `progn', but evaluates the body at compile time if you're compiling. |
| 401 | Thus, the result of the body appears to the compiler as a quoted constant. | 401 | Thus, the result of the body appears to the compiler as a quoted |
| 402 | In interpreted code, this is entirely equivalent to `progn'." | 402 | constant. In interpreted code, this is entirely equivalent to |
| 403 | `progn', except that the value of the expression may be (but is | ||
| 404 | not necessarily) computed at load time if eager macro expansion | ||
| 405 | is enabled." | ||
| 403 | (declare (debug (&rest def-form)) (indent 0)) | 406 | (declare (debug (&rest def-form)) (indent 0)) |
| 404 | (list 'quote (eval (cons 'progn body) lexical-binding))) | 407 | (list 'quote (eval (cons 'progn body) lexical-binding))) |
| 405 | 408 | ||
| 406 | (defmacro eval-and-compile (&rest body) | 409 | (defmacro eval-and-compile (&rest body) |
| 407 | "Like `progn', but evaluates the body at compile time and at load time." | 410 | "Like `progn', but evaluates the body at compile time and at |
| 411 | load time. In interpreted code, this is entirely equivalent to | ||
| 412 | `progn', except that the value of the expression may be (but is | ||
| 413 | not necessarily) computed at load time if eager macro expansion | ||
| 414 | is enabled." | ||
| 408 | (declare (debug t) (indent 0)) | 415 | (declare (debug t) (indent 0)) |
| 409 | ;; When the byte-compiler expands code, this macro is not used, so we're | 416 | ;; When the byte-compiler expands code, this macro is not used, so we're |
| 410 | ;; either about to run `body' (plain interpretation) or we're doing eager | 417 | ;; either about to run `body' (plain interpretation) or we're doing eager |
diff --git a/lisp/emacs-lisp/macroexp.el b/lisp/emacs-lisp/macroexp.el index c2bfc891b72..44727daf76a 100644 --- a/lisp/emacs-lisp/macroexp.el +++ b/lisp/emacs-lisp/macroexp.el | |||
| @@ -405,7 +405,7 @@ symbol itself." | |||
| 405 | (defvar macroexp--pending-eager-loads nil | 405 | (defvar macroexp--pending-eager-loads nil |
| 406 | "Stack of files currently undergoing eager macro-expansion.") | 406 | "Stack of files currently undergoing eager macro-expansion.") |
| 407 | 407 | ||
| 408 | (defun internal-macroexpand-for-load (form) | 408 | (defun internal-macroexpand-for-load (form full-p) |
| 409 | ;; Called from the eager-macroexpansion in readevalloop. | 409 | ;; Called from the eager-macroexpansion in readevalloop. |
| 410 | (cond | 410 | (cond |
| 411 | ;; Don't repeat the same warning for every top-level element. | 411 | ;; Don't repeat the same warning for every top-level element. |
| @@ -428,7 +428,9 @@ symbol itself." | |||
| 428 | (condition-case err | 428 | (condition-case err |
| 429 | (let ((macroexp--pending-eager-loads | 429 | (let ((macroexp--pending-eager-loads |
| 430 | (cons load-file-name macroexp--pending-eager-loads))) | 430 | (cons load-file-name macroexp--pending-eager-loads))) |
| 431 | (macroexpand-all form)) | 431 | (if full-p |
| 432 | (macroexpand-all form) | ||
| 433 | (macroexpand form))) | ||
| 432 | (error | 434 | (error |
| 433 | ;; Hopefully this shouldn't happen thanks to the cycle detection, | 435 | ;; Hopefully this shouldn't happen thanks to the cycle detection, |
| 434 | ;; but in case it does happen, let's catch the error and give the | 436 | ;; but in case it does happen, let's catch the error and give the |
diff --git a/src/ChangeLog b/src/ChangeLog index bb05be04d3e..bb2e2bad555 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,3 +1,11 @@ | |||
| 1 | 2014-04-22 Daniel Colascione <dancol@dancol.org> | ||
| 2 | |||
| 3 | * lread.c (readevalloop_eager_expand_eval): New function | ||
| 4 | that can recurse into toplevel forms. | ||
| 5 | (readevalloop): Call it. | ||
| 6 | * lisp.h: Declare Qprogn. | ||
| 7 | * callint.c (Qprogn): No longer static. | ||
| 8 | |||
| 1 | 2014-04-19 Stefan Monnier <monnier@iro.umontreal.ca> | 9 | 2014-04-19 Stefan Monnier <monnier@iro.umontreal.ca> |
| 2 | 10 | ||
| 3 | * intervals.c (rotate_right, rotate_left): Fix up length computation. | 11 | * intervals.c (rotate_right, rotate_left): Fix up length computation. |
diff --git a/src/callint.c b/src/callint.c index 35411bf9b5c..54f04cdee17 100644 --- a/src/callint.c +++ b/src/callint.c | |||
| @@ -38,8 +38,8 @@ static Lisp_Object Qread_number; | |||
| 38 | 38 | ||
| 39 | Lisp_Object Qmouse_leave_buffer_hook; | 39 | Lisp_Object Qmouse_leave_buffer_hook; |
| 40 | 40 | ||
| 41 | static Lisp_Object Qlist, Qlet, Qletx, Qsave_excursion, Qprogn, Qif; | 41 | static Lisp_Object Qlist, Qlet, Qletx, Qsave_excursion, Qif; |
| 42 | Lisp_Object Qwhen; | 42 | Lisp_Object Qwhen, Qprogn; |
| 43 | static Lisp_Object preserved_fns; | 43 | static Lisp_Object preserved_fns; |
| 44 | 44 | ||
| 45 | /* Marker used within call-interactively to refer to point. */ | 45 | /* Marker used within call-interactively to refer to point. */ |
diff --git a/src/lisp.h b/src/lisp.h index 6ef0f83aea4..4c310f69662 100644 --- a/src/lisp.h +++ b/src/lisp.h | |||
| @@ -4027,6 +4027,7 @@ extern void syms_of_minibuf (void); | |||
| 4027 | /* Defined in callint.c. */ | 4027 | /* Defined in callint.c. */ |
| 4028 | 4028 | ||
| 4029 | extern Lisp_Object Qminus, Qplus; | 4029 | extern Lisp_Object Qminus, Qplus; |
| 4030 | extern Lisp_Object Qprogn; | ||
| 4030 | extern Lisp_Object Qwhen; | 4031 | extern Lisp_Object Qwhen; |
| 4031 | extern Lisp_Object Qmouse_leave_buffer_hook; | 4032 | extern Lisp_Object Qmouse_leave_buffer_hook; |
| 4032 | extern void syms_of_callint (void); | 4033 | extern void syms_of_callint (void); |
diff --git a/src/lread.c b/src/lread.c index 4990d25eda1..4edd1177fb4 100644 --- a/src/lread.c +++ b/src/lread.c | |||
| @@ -1763,6 +1763,29 @@ end_of_file_error (void) | |||
| 1763 | xsignal0 (Qend_of_file); | 1763 | xsignal0 (Qend_of_file); |
| 1764 | } | 1764 | } |
| 1765 | 1765 | ||
| 1766 | static Lisp_Object | ||
| 1767 | readevalloop_eager_expand_eval (Lisp_Object val, Lisp_Object macroexpand) | ||
| 1768 | { | ||
| 1769 | /* If we macroexpand the toplevel form non-recursively and it ends | ||
| 1770 | up being a `progn' (or if it was a progn to start), treat each | ||
| 1771 | form in the progn as a top-level form. This way, if one form in | ||
| 1772 | the progn defines a macro, that macro is in effect when we expand | ||
| 1773 | the remaining forms. See similar code in bytecomp.el. */ | ||
| 1774 | val = call2 (macroexpand, val, Qnil); | ||
| 1775 | if (EQ (CAR_SAFE (val), Qprogn)) | ||
| 1776 | { | ||
| 1777 | Lisp_Object subforms = XCDR (val); | ||
| 1778 | val = Qnil; | ||
| 1779 | for (; CONSP (subforms); subforms = XCDR (subforms)) | ||
| 1780 | val = readevalloop_eager_expand_eval (XCAR (subforms), | ||
| 1781 | macroexpand); | ||
| 1782 | } | ||
| 1783 | else | ||
| 1784 | val = eval_sub (call2 (macroexpand, val, Qt)); | ||
| 1785 | |||
| 1786 | return val; | ||
| 1787 | } | ||
| 1788 | |||
| 1766 | /* UNIBYTE specifies how to set load_convert_to_unibyte | 1789 | /* UNIBYTE specifies how to set load_convert_to_unibyte |
| 1767 | for this invocation. | 1790 | for this invocation. |
| 1768 | READFUN, if non-nil, is used instead of `read'. | 1791 | READFUN, if non-nil, is used instead of `read'. |
| @@ -1930,8 +1953,9 @@ readevalloop (Lisp_Object readcharfun, | |||
| 1930 | 1953 | ||
| 1931 | /* Now eval what we just read. */ | 1954 | /* Now eval what we just read. */ |
| 1932 | if (!NILP (macroexpand)) | 1955 | if (!NILP (macroexpand)) |
| 1933 | val = call1 (macroexpand, val); | 1956 | val = readevalloop_eager_expand_eval (val, macroexpand); |
| 1934 | val = eval_sub (val); | 1957 | else |
| 1958 | val = eval_sub (val); | ||
| 1935 | 1959 | ||
| 1936 | if (printflag) | 1960 | if (printflag) |
| 1937 | { | 1961 | { |
diff --git a/test/ChangeLog b/test/ChangeLog index 1163402fd19..1caf0b3eb85 100644 --- a/test/ChangeLog +++ b/test/ChangeLog | |||
| @@ -1,7 +1,19 @@ | |||
| 1 | 2014-04-22 Daniel Colascione <dancol@dancol.org> | 1 | 2014-04-22 Daniel Colascione <dancol@dancol.org> |
| 2 | 2 | ||
| 3 | * automated/bytecomp-tests.el (test-byte-comp-compile-and-load): | ||
| 4 | Add compile flag. | ||
| 5 | (test-byte-comp-macro-expansion) | ||
| 6 | (test-byte-comp-macro-expansion-eval-and-compile) | ||
| 7 | (test-byte-comp-macro-expansion-eval-when-compile) | ||
| 8 | (test-byte-comp-macro-expand-lexical-override): Use it. | ||
| 9 | (test-eager-load-macro-expansion) | ||
| 10 | (test-eager-load-macro-expansion-eval-and-compile) | ||
| 11 | (test-eager-load-macro-expansion-eval-when-compile) | ||
| 12 | (test-eager-load-macro-expand-lexical-override): New tests. | ||
| 13 | |||
| 3 | * automated/cl-lib.el (cl-lib-struct-accessors): Fix test to | 14 | * automated/cl-lib.el (cl-lib-struct-accessors): Fix test to |
| 4 | account for removal of `cl-struct-set-slot-value'. | 15 | account for removal of `cl-struct-set-slot-value'. Also, move |
| 16 | the defstruct to top level. | ||
| 5 | 17 | ||
| 6 | 2014-04-21 Daniel Colascione <dancol@dancol.org> | 18 | 2014-04-21 Daniel Colascione <dancol@dancol.org> |
| 7 | 19 | ||
diff --git a/test/automated/bytecomp-tests.el b/test/automated/bytecomp-tests.el index e61c7c3a41d..a7fbdbe2e7f 100644 --- a/test/automated/bytecomp-tests.el +++ b/test/automated/bytecomp-tests.el | |||
| @@ -305,30 +305,33 @@ Subtests signal errors if something goes wrong." | |||
| 305 | 'face fail-face))) | 305 | 'face fail-face))) |
| 306 | (insert "\n")))) | 306 | (insert "\n")))) |
| 307 | 307 | ||
| 308 | (defun test-byte-comp-compile-and-load (&rest forms) | 308 | (defun test-byte-comp-compile-and-load (compile &rest forms) |
| 309 | (let ((elfile nil) | 309 | (let ((elfile nil) |
| 310 | (elcfile nil)) | 310 | (elcfile nil)) |
| 311 | (unwind-protect | 311 | (unwind-protect |
| 312 | (progn | 312 | (progn |
| 313 | (setf elfile (make-temp-file "test-bytecomp" nil ".el")) | 313 | (setf elfile (make-temp-file "test-bytecomp" nil ".el")) |
| 314 | (setf elcfile (make-temp-file "test-bytecomp" nil ".elc")) | 314 | (when compile |
| 315 | (setf elcfile (make-temp-file "test-bytecomp" nil ".elc"))) | ||
| 315 | (with-temp-buffer | 316 | (with-temp-buffer |
| 316 | (dolist (form forms) | 317 | (dolist (form forms) |
| 317 | (print form (current-buffer))) | 318 | (print form (current-buffer))) |
| 318 | (write-region (point-min) (point-max) elfile)) | 319 | (write-region (point-min) (point-max) elfile)) |
| 319 | (let ((byte-compile-dest-file elcfile)) | 320 | (if compile |
| 320 | (byte-compile-file elfile t))) | 321 | (let ((byte-compile-dest-file elcfile)) |
| 322 | (byte-compile-file elfile t)) | ||
| 323 | (load elfile))) | ||
| 321 | (when elfile (delete-file elfile)) | 324 | (when elfile (delete-file elfile)) |
| 322 | (when elcfile (delete-file elcfile))))) | 325 | (when elcfile (delete-file elcfile))))) |
| 323 | (put 'test-byte-comp-compile-and-load 'lisp-indent-function 0) | 326 | (put 'test-byte-comp-compile-and-load 'lisp-indent-function 1) |
| 324 | 327 | ||
| 325 | (ert-deftest test-byte-comp-macro-expansion () | 328 | (ert-deftest test-byte-comp-macro-expansion () |
| 326 | (test-byte-comp-compile-and-load | 329 | (test-byte-comp-compile-and-load t |
| 327 | '(progn (defmacro abc (arg) 1) (defun def () (abc 2)))) | 330 | '(progn (defmacro abc (arg) 1) (defun def () (abc 2)))) |
| 328 | (should (equal (funcall 'def) 1))) | 331 | (should (equal (funcall 'def) 1))) |
| 329 | 332 | ||
| 330 | (ert-deftest test-byte-comp-macro-expansion-eval-and-compile () | 333 | (ert-deftest test-byte-comp-macro-expansion-eval-and-compile () |
| 331 | (test-byte-comp-compile-and-load | 334 | (test-byte-comp-compile-and-load t |
| 332 | '(eval-and-compile (defmacro abc (arg) -1) (defun def () (abc 2)))) | 335 | '(eval-and-compile (defmacro abc (arg) -1) (defun def () (abc 2)))) |
| 333 | (should (equal (funcall 'def) -1))) | 336 | (should (equal (funcall 'def) -1))) |
| 334 | 337 | ||
| @@ -336,7 +339,7 @@ Subtests signal errors if something goes wrong." | |||
| 336 | ;; Make sure we interpret eval-when-compile forms properly. CLISP | 339 | ;; Make sure we interpret eval-when-compile forms properly. CLISP |
| 337 | ;; and SBCL interpreter eval-when-compile (well, the CL equivalent) | 340 | ;; and SBCL interpreter eval-when-compile (well, the CL equivalent) |
| 338 | ;; in the same way. | 341 | ;; in the same way. |
| 339 | (test-byte-comp-compile-and-load | 342 | (test-byte-comp-compile-and-load t |
| 340 | '(eval-when-compile | 343 | '(eval-when-compile |
| 341 | (defmacro abc (arg) -10) | 344 | (defmacro abc (arg) -10) |
| 342 | (defun abc-1 () (abc 2))) | 345 | (defun abc-1 () (abc 2))) |
| @@ -349,13 +352,48 @@ Subtests signal errors if something goes wrong." | |||
| 349 | ;; macrolet since macrolet's is explicitly called out as being | 352 | ;; macrolet since macrolet's is explicitly called out as being |
| 350 | ;; equivalent to toplevel, but CLISP and SBCL both evaluate the form | 353 | ;; equivalent to toplevel, but CLISP and SBCL both evaluate the form |
| 351 | ;; this way, so we should too. | 354 | ;; this way, so we should too. |
| 352 | (test-byte-comp-compile-and-load | 355 | (test-byte-comp-compile-and-load t |
| 353 | '(require 'cl-lib) | 356 | '(require 'cl-lib) |
| 354 | '(cl-macrolet ((m () 4)) | 357 | '(cl-macrolet ((m () 4)) |
| 355 | (defmacro m () 5) | 358 | (defmacro m () 5) |
| 356 | (defun def () (m)))) | 359 | (defun def () (m)))) |
| 357 | (should (equal (funcall 'def) 4))) | 360 | (should (equal (funcall 'def) 4))) |
| 358 | 361 | ||
| 362 | (ert-deftest test-eager-load-macro-expansion () | ||
| 363 | (test-byte-comp-compile-and-load nil | ||
| 364 | '(progn (defmacro abc (arg) 1) (defun def () (abc 2)))) | ||
| 365 | (should (equal (funcall 'def) 1))) | ||
| 366 | |||
| 367 | (ert-deftest test-eager-load-macro-expansion-eval-and-compile () | ||
| 368 | (test-byte-comp-compile-and-load nil | ||
| 369 | '(eval-and-compile (defmacro abc (arg) -1) (defun def () (abc 2)))) | ||
| 370 | (should (equal (funcall 'def) -1))) | ||
| 371 | |||
| 372 | (ert-deftest test-eager-load-macro-expansion-eval-when-compile () | ||
| 373 | ;; Make sure we interpret eval-when-compile forms properly. CLISP | ||
| 374 | ;; and SBCL interpreter eval-when-compile (well, the CL equivalent) | ||
| 375 | ;; in the same way. | ||
| 376 | (test-byte-comp-compile-and-load nil | ||
| 377 | '(eval-when-compile | ||
| 378 | (defmacro abc (arg) -10) | ||
| 379 | (defun abc-1 () (abc 2))) | ||
| 380 | '(defmacro abc-2 () (abc-1)) | ||
| 381 | '(defun def () (abc-2))) | ||
| 382 | (should (equal (funcall 'def) -10))) | ||
| 383 | |||
| 384 | (ert-deftest test-eager-load-macro-expand-lexical-override () | ||
| 385 | ;; Intuitively, one might expect the defmacro to override the | ||
| 386 | ;; macrolet since macrolet's is explicitly called out as being | ||
| 387 | ;; equivalent to toplevel, but CLISP and SBCL both evaluate the form | ||
| 388 | ;; this way, so we should too. | ||
| 389 | (test-byte-comp-compile-and-load nil | ||
| 390 | '(require 'cl-lib) | ||
| 391 | '(cl-macrolet ((m () 4)) | ||
| 392 | (defmacro m () 5) | ||
| 393 | (defun def () (m)))) | ||
| 394 | (should (equal (funcall 'def) 4))) | ||
| 395 | |||
| 396 | |||
| 359 | ;; Local Variables: | 397 | ;; Local Variables: |
| 360 | ;; no-byte-compile: t | 398 | ;; no-byte-compile: t |
| 361 | ;; End: | 399 | ;; End: |