diff options
| author | Stefan Monnier | 2011-02-17 16:19:13 -0500 |
|---|---|---|
| committer | Stefan Monnier | 2011-02-17 16:19:13 -0500 |
| commit | b38b1ec071ee9752da53f2485902165fe728e8fa (patch) | |
| tree | 318ca7399de648f910626f666a1d6e62d71e081c | |
| parent | ce5b520a3758e22c6516e0d864d8c1a3512bf457 (diff) | |
| download | emacs-b38b1ec071ee9752da53f2485902165fe728e8fa.tar.gz emacs-b38b1ec071ee9752da53f2485902165fe728e8fa.zip | |
Various compiler bug-fixes. MPC seems to run correctly now.
* lisp/files.el (lexical-binding): Add a safe-local-variable property.
* lisp/emacs-lisp/byte-opt.el (byte-inline-lapcode): Check how many elements
are added to the stack.
(byte-compile-splice-in-already-compiled-code): Don't touch lexical nor
byte-compile-depth now that byte-inline-lapcode does it for us.
(byte-compile-inline-expand): Don't inline dynbind byte code into
lexbind code, since it has to be done differently.
* lisp/emacs-lisp/bytecomp.el (byte-compile-arglist-warn):
Correctly extract arglist from `closure's.
(byte-compile-cl-warn): Compiler-macros are run earlier now.
(byte-compile-top-level): Bind byte-compile-lexical-environment to nil,
except for lambdas.
(byte-compile-form): Don't run the compiler-macro expander here.
(byte-compile-let): Merge with byte-compile-let*.
Don't preserve-body-value if the body's value was discarded.
* lisp/emacs-lisp/cconv.el (cconv--set-diff, cconv--set-diff-map)
(cconv--map-diff, cconv--map-diff-elem, cconv--map-diff-set): New funs.
(cconv--env-var): New constant.
(cconv-closure-convert-rec): Use it and use them. Fix a typo that
ended up forgetting to remove entries from lmenvs in `let'.
For `lambda' use the outer `fvrs' when building the closure and don't
forget to remove `vars' from the `emvrs' and `lmenvs' of the body.
* lisp/emacs-lisp/cl-macs.el (cl-byte-compile-block): Disable optimization
in lexbind, because it needs a different implementation.
* src/bytecode.c (exec_byte_code): Fix handling of &rest.
* src/eval.c (Vinternal_interpreter_environment): Remove.
(syms_of_eval): Do declare Vinternal_interpreter_environment as
a global lisp var, but unintern it to hide it.
(Fcommandp):
* src/data.c (Finteractive_form): Understand `closure's.
| -rw-r--r-- | lisp/ChangeLog | 31 | ||||
| -rw-r--r-- | lisp/doc-view.el | 4 | ||||
| -rw-r--r-- | lisp/emacs-lisp/byte-opt.el | 63 | ||||
| -rw-r--r-- | lisp/emacs-lisp/bytecomp.el | 149 | ||||
| -rw-r--r-- | lisp/emacs-lisp/cconv.el | 144 | ||||
| -rw-r--r-- | lisp/emacs-lisp/cl-loaddefs.el | 2 | ||||
| -rw-r--r-- | lisp/emacs-lisp/cl-macs.el | 8 | ||||
| -rw-r--r-- | lisp/emacs-lisp/pcase.el | 3 | ||||
| -rw-r--r-- | lisp/files.el | 25 | ||||
| -rw-r--r-- | lisp/help-fns.el | 2 | ||||
| -rw-r--r-- | src/ChangeLog | 10 | ||||
| -rw-r--r-- | src/bytecode.c | 4 | ||||
| -rw-r--r-- | src/data.c | 2 | ||||
| -rw-r--r-- | src/eval.c | 34 | ||||
| -rw-r--r-- | src/lisp.h | 2 |
15 files changed, 281 insertions, 202 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog index b972f17909a..142deda9505 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog | |||
| @@ -1,3 +1,34 @@ | |||
| 1 | 2011-02-17 Stefan Monnier <monnier@iro.umontreal.ca> | ||
| 2 | |||
| 3 | * files.el (lexical-binding): Add a safe-local-variable property. | ||
| 4 | |||
| 5 | * emacs-lisp/cl-macs.el (cl-byte-compile-block): Disable optimization | ||
| 6 | in lexbind, because it needs a different implementation. | ||
| 7 | |||
| 8 | * emacs-lisp/cconv.el (cconv--set-diff, cconv--set-diff-map) | ||
| 9 | (cconv--map-diff, cconv--map-diff-elem, cconv--map-diff-set): New funs. | ||
| 10 | (cconv--env-var): New constant. | ||
| 11 | (cconv-closure-convert-rec): Use it and use them. Fix a typo that | ||
| 12 | ended up forgetting to remove entries from lmenvs in `let'. | ||
| 13 | For `lambda' use the outer `fvrs' when building the closure and don't | ||
| 14 | forget to remove `vars' from the `emvrs' and `lmenvs' of the body. | ||
| 15 | |||
| 16 | * emacs-lisp/bytecomp.el (byte-compile-arglist-warn): | ||
| 17 | Correctly extract arglist from `closure's. | ||
| 18 | (byte-compile-cl-warn): Compiler-macros are run earlier now. | ||
| 19 | (byte-compile-top-level): Bind byte-compile-lexical-environment to nil, | ||
| 20 | except for lambdas. | ||
| 21 | (byte-compile-form): Don't run the compiler-macro expander here. | ||
| 22 | (byte-compile-let): Merge with byte-compile-let*. | ||
| 23 | Don't preserve-body-value if the body's value was discarded. | ||
| 24 | |||
| 25 | * emacs-lisp/byte-opt.el (byte-inline-lapcode): Check how many elements | ||
| 26 | are added to the stack. | ||
| 27 | (byte-compile-splice-in-already-compiled-code): Don't touch lexical nor | ||
| 28 | byte-compile-depth now that byte-inline-lapcode does it for us. | ||
| 29 | (byte-compile-inline-expand): Don't inline dynbind byte code into | ||
| 30 | lexbind code, since it has to be done differently. | ||
| 31 | |||
| 1 | 2011-02-12 Stefan Monnier <monnier@iro.umontreal.ca> | 32 | 2011-02-12 Stefan Monnier <monnier@iro.umontreal.ca> |
| 2 | 33 | ||
| 3 | * emacs-lisp/byte-lexbind.el: Delete. | 34 | * emacs-lisp/byte-lexbind.el: Delete. |
diff --git a/lisp/doc-view.el b/lisp/doc-view.el index 4f8c338409b..7bead624cc7 100644 --- a/lisp/doc-view.el +++ b/lisp/doc-view.el | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | ;;; -*- lexical-binding: t -*- | 1 | ;;; doc-view.el --- View PDF/PostScript/DVI files in Emacs -*- lexical-binding: t -*- |
| 2 | ;;; doc-view.el --- View PDF/PostScript/DVI files in Emacs | 2 | |
| 3 | 3 | ||
| 4 | ;; Copyright (C) 2007-2011 Free Software Foundation, Inc. | 4 | ;; Copyright (C) 2007-2011 Free Software Foundation, Inc. |
| 5 | ;; | 5 | ;; |
diff --git a/lisp/emacs-lisp/byte-opt.el b/lisp/emacs-lisp/byte-opt.el index 71960ad54dc..12df3251267 100644 --- a/lisp/emacs-lisp/byte-opt.el +++ b/lisp/emacs-lisp/byte-opt.el | |||
| @@ -248,7 +248,18 @@ | |||
| 248 | ;; are no collisions, and that byte-compile-tag-number is reasonable | 248 | ;; are no collisions, and that byte-compile-tag-number is reasonable |
| 249 | ;; after this is spliced in. The provided list is destroyed. | 249 | ;; after this is spliced in. The provided list is destroyed. |
| 250 | (defun byte-inline-lapcode (lap) | 250 | (defun byte-inline-lapcode (lap) |
| 251 | (setq byte-compile-output (nconc (nreverse lap) byte-compile-output))) | 251 | ;; "Replay" the operations: we used to just do |
| 252 | ;; (setq byte-compile-output (nconc (nreverse lap) byte-compile-output)) | ||
| 253 | ;; but that fails to update byte-compile-depth, so we had to assume | ||
| 254 | ;; that `lap' ends up adding exactly 1 element to the stack. This | ||
| 255 | ;; happens to be true for byte-code generated by bytecomp.el without | ||
| 256 | ;; lexical-binding, but it's not true in general, and it's not true for | ||
| 257 | ;; code output by bytecomp.el with lexical-binding. | ||
| 258 | (dolist (op lap) | ||
| 259 | (cond | ||
| 260 | ((eq (car op) 'TAG) (byte-compile-out-tag op)) | ||
| 261 | ((memq (car op) byte-goto-ops) (byte-compile-goto (car op) (cdr op))) | ||
| 262 | (t (byte-compile-out (car op) (cdr op)))))) | ||
| 252 | 263 | ||
| 253 | (defun byte-compile-inline-expand (form) | 264 | (defun byte-compile-inline-expand (form) |
| 254 | (let* ((name (car form)) | 265 | (let* ((name (car form)) |
| @@ -266,25 +277,32 @@ | |||
| 266 | (cdr (assq name byte-compile-function-environment))))) | 277 | (cdr (assq name byte-compile-function-environment))))) |
| 267 | (if (and (consp fn) (eq (car fn) 'autoload)) | 278 | (if (and (consp fn) (eq (car fn) 'autoload)) |
| 268 | (error "File `%s' didn't define `%s'" (nth 1 fn) name)) | 279 | (error "File `%s' didn't define `%s'" (nth 1 fn) name)) |
| 269 | (if (and (symbolp fn) (not (eq fn t))) | 280 | (cond |
| 270 | (byte-compile-inline-expand (cons fn (cdr form))) | 281 | ((and (symbolp fn) (not (eq fn t))) ;A function alias. |
| 271 | (if (byte-code-function-p fn) | 282 | (byte-compile-inline-expand (cons fn (cdr form)))) |
| 272 | (let (string) | 283 | ((and (byte-code-function-p fn) |
| 273 | (fetch-bytecode fn) | 284 | ;; FIXME: This works to inline old-style-byte-codes into |
| 274 | (setq string (aref fn 1)) | 285 | ;; old-style-byte-codes, but not mixed cases (not sure |
| 275 | ;; Isn't it an error for `string' not to be unibyte?? --stef | 286 | ;; about new-style into new-style). |
| 276 | (if (fboundp 'string-as-unibyte) | 287 | (not lexical-binding) |
| 277 | (setq string (string-as-unibyte string))) | 288 | (not (and (>= (length fn) 7) |
| 278 | ;; `byte-compile-splice-in-already-compiled-code' | 289 | (aref fn 6)))) ;6 = COMPILED_PUSH_ARGS |
| 279 | ;; takes care of inlining the body. | 290 | ;; (message "Inlining %S byte-code" name) |
| 280 | (cons `(lambda ,(aref fn 0) | 291 | (fetch-bytecode fn) |
| 281 | (byte-code ,string ,(aref fn 2) ,(aref fn 3))) | 292 | (let ((string (aref fn 1))) |
| 282 | (cdr form))) | 293 | ;; Isn't it an error for `string' not to be unibyte?? --stef |
| 283 | (if (eq (car-safe fn) 'lambda) | 294 | (if (fboundp 'string-as-unibyte) |
| 284 | (macroexpand-all (cons fn (cdr form)) | 295 | (setq string (string-as-unibyte string))) |
| 285 | byte-compile-macro-environment) | 296 | ;; `byte-compile-splice-in-already-compiled-code' |
| 286 | ;; Give up on inlining. | 297 | ;; takes care of inlining the body. |
| 287 | form)))))) | 298 | (cons `(lambda ,(aref fn 0) |
| 299 | (byte-code ,string ,(aref fn 2) ,(aref fn 3))) | ||
| 300 | (cdr form)))) | ||
| 301 | ((eq (car-safe fn) 'lambda) | ||
| 302 | (macroexpand-all (cons fn (cdr form)) | ||
| 303 | byte-compile-macro-environment)) | ||
| 304 | (t ;; Give up on inlining. | ||
| 305 | form))))) | ||
| 288 | 306 | ||
| 289 | ;; ((lambda ...) ...) | 307 | ;; ((lambda ...) ...) |
| 290 | (defun byte-compile-unfold-lambda (form &optional name) | 308 | (defun byte-compile-unfold-lambda (form &optional name) |
| @@ -1298,10 +1316,7 @@ | |||
| 1298 | (if (not (memq byte-optimize '(t lap))) | 1316 | (if (not (memq byte-optimize '(t lap))) |
| 1299 | (byte-compile-normal-call form) | 1317 | (byte-compile-normal-call form) |
| 1300 | (byte-inline-lapcode | 1318 | (byte-inline-lapcode |
| 1301 | (byte-decompile-bytecode-1 (nth 1 form) (nth 2 form) t)) | 1319 | (byte-decompile-bytecode-1 (nth 1 form) (nth 2 form) t)))) |
| 1302 | (setq byte-compile-maxdepth (max (+ byte-compile-depth (nth 3 form)) | ||
| 1303 | byte-compile-maxdepth)) | ||
| 1304 | (setq byte-compile-depth (1+ byte-compile-depth)))) | ||
| 1305 | 1320 | ||
| 1306 | (put 'byte-code 'byte-compile 'byte-compile-splice-in-already-compiled-code) | 1321 | (put 'byte-code 'byte-compile 'byte-compile-splice-in-already-compiled-code) |
| 1307 | 1322 | ||
diff --git a/lisp/emacs-lisp/bytecomp.el b/lisp/emacs-lisp/bytecomp.el index e9beb0c5792..d3ac50a671a 100644 --- a/lisp/emacs-lisp/bytecomp.el +++ b/lisp/emacs-lisp/bytecomp.el | |||
| @@ -752,9 +752,10 @@ BYTES and PC are updated after evaluating all the arguments." | |||
| 752 | (bytes-var (car (last args 2))) | 752 | (bytes-var (car (last args 2))) |
| 753 | (pc-var (car (last args)))) | 753 | (pc-var (car (last args)))) |
| 754 | `(setq ,bytes-var ,(if (null (cdr byte-exprs)) | 754 | `(setq ,bytes-var ,(if (null (cdr byte-exprs)) |
| 755 | `(cons ,@byte-exprs ,bytes-var) | 755 | `(progn (assert (<= 0 ,(car byte-exprs))) |
| 756 | `(nconc (list ,@(reverse byte-exprs)) ,bytes-var)) | 756 | (cons ,@byte-exprs ,bytes-var)) |
| 757 | ,pc-var (+ ,(length byte-exprs) ,pc-var)))) | 757 | `(nconc (list ,@(reverse byte-exprs)) ,bytes-var)) |
| 758 | ,pc-var (+ ,(length byte-exprs) ,pc-var)))) | ||
| 758 | 759 | ||
| 759 | (defmacro byte-compile-push-bytecode-const2 (opcode const2 bytes pc) | 760 | (defmacro byte-compile-push-bytecode-const2 (opcode const2 bytes pc) |
| 760 | "Push OPCODE and the two-byte constant CONST2 onto BYTES, and add 3 to PC. | 761 | "Push OPCODE and the two-byte constant CONST2 onto BYTES, and add 3 to PC. |
| @@ -817,7 +818,7 @@ CONST2 may be evaulated multiple times." | |||
| 817 | ;; These insns all put their operand into one extra byte. | 818 | ;; These insns all put their operand into one extra byte. |
| 818 | (byte-compile-push-bytecodes opcode off bytes pc)) | 819 | (byte-compile-push-bytecodes opcode off bytes pc)) |
| 819 | ((= opcode byte-discardN) | 820 | ((= opcode byte-discardN) |
| 820 | ;; byte-discardN is wierd in that it encodes a flag in the | 821 | ;; byte-discardN is weird in that it encodes a flag in the |
| 821 | ;; top bit of its one-byte argument. If the argument is | 822 | ;; top bit of its one-byte argument. If the argument is |
| 822 | ;; too large to fit in 7 bits, the opcode can be repeated. | 823 | ;; too large to fit in 7 bits, the opcode can be repeated. |
| 823 | (let ((flag (if (eq op 'byte-discardN-preserve-tos) #x80 0))) | 824 | (let ((flag (if (eq op 'byte-discardN-preserve-tos) #x80 0))) |
| @@ -1330,11 +1331,11 @@ extra args." | |||
| 1330 | (eq 'lambda (car-safe (cdr-safe old))) | 1331 | (eq 'lambda (car-safe (cdr-safe old))) |
| 1331 | (setq old (cdr old))) | 1332 | (setq old (cdr old))) |
| 1332 | (let ((sig1 (byte-compile-arglist-signature | 1333 | (let ((sig1 (byte-compile-arglist-signature |
| 1333 | (if (eq 'lambda (car-safe old)) | 1334 | (pcase old |
| 1334 | (nth 1 old) | 1335 | (`(lambda ,args . ,_) args) |
| 1335 | (if (byte-code-function-p old) | 1336 | (`(closure ,_ ,_ ,args . ,_) args) |
| 1336 | (aref old 0) | 1337 | ((pred byte-code-function-p) (aref old 0)) |
| 1337 | '(&rest def))))) | 1338 | (t '(&rest def))))) |
| 1338 | (sig2 (byte-compile-arglist-signature (nth 2 form)))) | 1339 | (sig2 (byte-compile-arglist-signature (nth 2 form)))) |
| 1339 | (unless (byte-compile-arglist-signatures-congruent-p sig1 sig2) | 1340 | (unless (byte-compile-arglist-signatures-congruent-p sig1 sig2) |
| 1340 | (byte-compile-set-symbol-position (nth 1 form)) | 1341 | (byte-compile-set-symbol-position (nth 1 form)) |
| @@ -1402,14 +1403,7 @@ extra args." | |||
| 1402 | ;; but such warnings are never useful, | 1403 | ;; but such warnings are never useful, |
| 1403 | ;; so don't warn about them. | 1404 | ;; so don't warn about them. |
| 1404 | macroexpand cl-macroexpand-all | 1405 | macroexpand cl-macroexpand-all |
| 1405 | cl-compiling-file))) | 1406 | cl-compiling-file)))) |
| 1406 | ;; Avoid warnings for things which are safe because they | ||
| 1407 | ;; have suitable compiler macros, but those aren't | ||
| 1408 | ;; expanded at this stage. There should probably be more | ||
| 1409 | ;; here than caaar and friends. | ||
| 1410 | (not (and (eq (get func 'byte-compile) | ||
| 1411 | 'cl-byte-compile-compiler-macro) | ||
| 1412 | (string-match "\\`c[ad]+r\\'" (symbol-name func))))) | ||
| 1413 | (byte-compile-warn "function `%s' from cl package called at runtime" | 1407 | (byte-compile-warn "function `%s' from cl package called at runtime" |
| 1414 | func))) | 1408 | func))) |
| 1415 | form) | 1409 | form) |
| @@ -2701,8 +2695,8 @@ If FORM is a lambda or a macro, byte-compile it as a function." | |||
| 2701 | (if (eq (car-safe form) 'list) | 2695 | (if (eq (car-safe form) 'list) |
| 2702 | (byte-compile-top-level (nth 1 bytecomp-int)) | 2696 | (byte-compile-top-level (nth 1 bytecomp-int)) |
| 2703 | (setq bytecomp-int (list 'interactive | 2697 | (setq bytecomp-int (list 'interactive |
| 2704 | (byte-compile-top-level | 2698 | (byte-compile-top-level |
| 2705 | (nth 1 bytecomp-int))))))) | 2699 | (nth 1 bytecomp-int))))))) |
| 2706 | ((cdr bytecomp-int) | 2700 | ((cdr bytecomp-int) |
| 2707 | (byte-compile-warn "malformed interactive spec: %s" | 2701 | (byte-compile-warn "malformed interactive spec: %s" |
| 2708 | (prin1-to-string bytecomp-int))))) | 2702 | (prin1-to-string bytecomp-int))))) |
| @@ -2788,6 +2782,9 @@ If FORM is a lambda or a macro, byte-compile it as a function." | |||
| 2788 | (byte-compile-tag-number 0) | 2782 | (byte-compile-tag-number 0) |
| 2789 | (byte-compile-depth 0) | 2783 | (byte-compile-depth 0) |
| 2790 | (byte-compile-maxdepth 0) | 2784 | (byte-compile-maxdepth 0) |
| 2785 | (byte-compile-lexical-environment | ||
| 2786 | (when (eq output-type 'lambda) | ||
| 2787 | byte-compile-lexical-environment)) | ||
| 2791 | (byte-compile-output nil)) | 2788 | (byte-compile-output nil)) |
| 2792 | (if (memq byte-optimize '(t source)) | 2789 | (if (memq byte-optimize '(t source)) |
| 2793 | (setq form (byte-optimize-form form for-effect))) | 2790 | (setq form (byte-optimize-form form for-effect))) |
| @@ -2798,14 +2795,13 @@ If FORM is a lambda or a macro, byte-compile it as a function." | |||
| 2798 | (stringp (nth 1 form)) (vectorp (nth 2 form)) | 2795 | (stringp (nth 1 form)) (vectorp (nth 2 form)) |
| 2799 | (natnump (nth 3 form))) | 2796 | (natnump (nth 3 form))) |
| 2800 | form | 2797 | form |
| 2801 | ;; Set up things for a lexically-bound function | 2798 | ;; Set up things for a lexically-bound function. |
| 2802 | (when (and lexical-binding (eq output-type 'lambda)) | 2799 | (when (and lexical-binding (eq output-type 'lambda)) |
| 2803 | ;; See how many arguments there are, and set the current stack depth | 2800 | ;; See how many arguments there are, and set the current stack depth |
| 2804 | ;; accordingly | 2801 | ;; accordingly. |
| 2805 | (dolist (var byte-compile-lexical-environment) | 2802 | (setq byte-compile-depth (length byte-compile-lexical-environment)) |
| 2806 | (setq byte-compile-depth (1+ byte-compile-depth))) | ||
| 2807 | ;; If there are args, output a tag to record the initial | 2803 | ;; If there are args, output a tag to record the initial |
| 2808 | ;; stack-depth for the optimizer | 2804 | ;; stack-depth for the optimizer. |
| 2809 | (when (> byte-compile-depth 0) | 2805 | (when (> byte-compile-depth 0) |
| 2810 | (byte-compile-out-tag (byte-compile-make-tag)))) | 2806 | (byte-compile-out-tag (byte-compile-make-tag)))) |
| 2811 | ;; Now compile FORM | 2807 | ;; Now compile FORM |
| @@ -2964,9 +2960,10 @@ That command is designed for interactive use only" bytecomp-fn)) | |||
| 2964 | ;; for CL compiler macros since the symbol may be | 2960 | ;; for CL compiler macros since the symbol may be |
| 2965 | ;; `cl-byte-compile-compiler-macro' but if CL isn't | 2961 | ;; `cl-byte-compile-compiler-macro' but if CL isn't |
| 2966 | ;; loaded, this function doesn't exist. | 2962 | ;; loaded, this function doesn't exist. |
| 2967 | (or (not (memq bytecomp-handler | 2963 | (and (not (eq bytecomp-handler |
| 2968 | '(cl-byte-compile-compiler-macro))) | 2964 | ;; Already handled by macroexpand-all. |
| 2969 | (functionp bytecomp-handler))) | 2965 | 'cl-byte-compile-compiler-macro)) |
| 2966 | (functionp bytecomp-handler))) | ||
| 2970 | (funcall bytecomp-handler form) | 2967 | (funcall bytecomp-handler form) |
| 2971 | (byte-compile-normal-call form)) | 2968 | (byte-compile-normal-call form)) |
| 2972 | (if (byte-compile-warning-enabled-p 'cl-functions) | 2969 | (if (byte-compile-warning-enabled-p 'cl-functions) |
| @@ -3612,7 +3609,7 @@ discarding." | |||
| 3612 | (byte-defop-compiler-1 while) | 3609 | (byte-defop-compiler-1 while) |
| 3613 | (byte-defop-compiler-1 funcall) | 3610 | (byte-defop-compiler-1 funcall) |
| 3614 | (byte-defop-compiler-1 let) | 3611 | (byte-defop-compiler-1 let) |
| 3615 | (byte-defop-compiler-1 let*) | 3612 | (byte-defop-compiler-1 let* byte-compile-let) |
| 3616 | 3613 | ||
| 3617 | (defun byte-compile-progn (form) | 3614 | (defun byte-compile-progn (form) |
| 3618 | (byte-compile-body-do-effect (cdr form))) | 3615 | (byte-compile-body-do-effect (cdr form))) |
| @@ -3819,10 +3816,8 @@ Return the offset in the form (VAR . OFFSET)." | |||
| 3819 | (byte-compile-push-constant nil))))) | 3816 | (byte-compile-push-constant nil))))) |
| 3820 | 3817 | ||
| 3821 | (defun byte-compile-not-lexical-var-p (var) | 3818 | (defun byte-compile-not-lexical-var-p (var) |
| 3822 | (or (not (symbolp var)) ; form is not a list | 3819 | (or (not (symbolp var)) |
| 3823 | (if (eval-when-compile (fboundp 'special-variable-p)) | 3820 | (special-variable-p var) |
| 3824 | (special-variable-p var) | ||
| 3825 | (boundp var)) | ||
| 3826 | (memq var byte-compile-bound-variables) | 3821 | (memq var byte-compile-bound-variables) |
| 3827 | (memq var '(nil t)) | 3822 | (memq var '(nil t)) |
| 3828 | (keywordp var))) | 3823 | (keywordp var))) |
| @@ -3833,9 +3828,8 @@ INIT-LEXENV should be a lexical-environment alist describing the | |||
| 3833 | positions of the init value that have been pushed on the stack. | 3828 | positions of the init value that have been pushed on the stack. |
| 3834 | Return non-nil if the TOS value was popped." | 3829 | Return non-nil if the TOS value was popped." |
| 3835 | ;; The presence of lexical bindings mean that we may have to | 3830 | ;; The presence of lexical bindings mean that we may have to |
| 3836 | ;; juggle things on the stack, either to move them to TOS for | 3831 | ;; juggle things on the stack, to move them to TOS for |
| 3837 | ;; dynamic binding, or to put them in a non-stack environment | 3832 | ;; dynamic binding. |
| 3838 | ;; vector. | ||
| 3839 | (cond ((not (byte-compile-not-lexical-var-p var)) | 3833 | (cond ((not (byte-compile-not-lexical-var-p var)) |
| 3840 | ;; VAR is a simple stack-allocated lexical variable | 3834 | ;; VAR is a simple stack-allocated lexical variable |
| 3841 | (push (assq var init-lexenv) | 3835 | (push (assq var init-lexenv) |
| @@ -3883,56 +3877,41 @@ binding slots have been popped." | |||
| 3883 | 3877 | ||
| 3884 | (defun byte-compile-let (form) | 3878 | (defun byte-compile-let (form) |
| 3885 | "Generate code for the `let' form FORM." | 3879 | "Generate code for the `let' form FORM." |
| 3886 | ;; First compute the binding values in the old scope. | 3880 | (let ((clauses (cadr form)) |
| 3887 | (let ((varlist (car (cdr form))) | 3881 | (init-lexenv nil)) |
| 3888 | (init-lexenv nil)) | 3882 | (when (eq (car form) 'let) |
| 3889 | (dolist (var varlist) | 3883 | ;; First compute the binding values in the old scope. |
| 3890 | (push (byte-compile-push-binding-init var) init-lexenv)) | 3884 | (dolist (var clauses) |
| 3891 | ;; Now do the bindings, execute the body, and undo the bindings. | 3885 | (push (byte-compile-push-binding-init var) init-lexenv))) |
| 3892 | (let ((byte-compile-bound-variables byte-compile-bound-variables) ;new scope | 3886 | ;; New scope. |
| 3893 | (varlist (reverse (car (cdr form)))) | 3887 | (let ((byte-compile-bound-variables byte-compile-bound-variables) |
| 3894 | (byte-compile-lexical-environment byte-compile-lexical-environment)) | 3888 | (byte-compile-lexical-environment byte-compile-lexical-environment)) |
| 3895 | (dolist (var varlist) | 3889 | ;; Bind the variables. |
| 3896 | (let ((var (if (consp var) (car var) var))) | 3890 | ;; For `let', do it in reverse order, because it makes no |
| 3897 | (cond ((null lexical-binding) | 3891 | ;; semantic difference, but it is a lot more efficient since the |
| 3898 | ;; If there are no lexical bindings, we can do things simply. | 3892 | ;; values are now in reverse order on the stack. |
| 3899 | (byte-compile-dynamic-variable-bind var)) | 3893 | (dolist (var (if (eq (car form) 'let) (reverse clauses) clauses)) |
| 3900 | ((byte-compile-bind var init-lexenv) | 3894 | (unless (eq (car form) 'let) |
| 3901 | (pop init-lexenv))))) | 3895 | (push (byte-compile-push-binding-init var) init-lexenv)) |
| 3896 | (let ((var (if (consp var) (car var) var))) | ||
| 3897 | (cond ((null lexical-binding) | ||
| 3898 | ;; If there are no lexical bindings, we can do things simply. | ||
| 3899 | (byte-compile-dynamic-variable-bind var)) | ||
| 3900 | ((byte-compile-bind var init-lexenv) | ||
| 3901 | (pop init-lexenv))))) | ||
| 3902 | ;; Emit the body. | 3902 | ;; Emit the body. |
| 3903 | (byte-compile-body-do-effect (cdr (cdr form))) | 3903 | (let ((init-stack-depth byte-compile-depth)) |
| 3904 | ;; Unbind the variables. | 3904 | (byte-compile-body-do-effect (cdr (cdr form))) |
| 3905 | (if lexical-binding | 3905 | ;; Unbind the variables. |
| 3906 | ;; Unbind both lexical and dynamic variables. | 3906 | (if lexical-binding |
| 3907 | (byte-compile-unbind varlist init-lexenv t) | 3907 | ;; Unbind both lexical and dynamic variables. |
| 3908 | ;; Unbind dynamic variables. | 3908 | (progn |
| 3909 | (byte-compile-out 'byte-unbind (length varlist)))))) | 3909 | (assert (or (eq byte-compile-depth init-stack-depth) |
| 3910 | 3910 | (eq byte-compile-depth (1+ init-stack-depth)))) | |
| 3911 | (defun byte-compile-let* (form) | 3911 | (byte-compile-unbind clauses init-lexenv (> byte-compile-depth |
| 3912 | "Generate code for the `let*' form FORM." | 3912 | init-stack-depth))) |
| 3913 | (let ((byte-compile-bound-variables byte-compile-bound-variables) ;new scope | 3913 | ;; Unbind dynamic variables. |
| 3914 | (clauses (cadr form)) | 3914 | (byte-compile-out 'byte-unbind (length clauses))))))) |
| 3915 | (init-lexenv nil) | ||
| 3916 | ;; bind these to restrict the scope of any changes | ||
| 3917 | |||
| 3918 | (byte-compile-lexical-environment byte-compile-lexical-environment)) | ||
| 3919 | ;; Bind the variables | ||
| 3920 | (dolist (var clauses) | ||
| 3921 | (push (byte-compile-push-binding-init var) init-lexenv) | ||
| 3922 | (let ((var (if (consp var) (car var) var))) | ||
| 3923 | (cond ((null lexical-binding) | ||
| 3924 | ;; If there are no lexical bindings, we can do things simply. | ||
| 3925 | (byte-compile-dynamic-variable-bind var)) | ||
| 3926 | ((byte-compile-bind var init-lexenv) | ||
| 3927 | (pop init-lexenv))))) | ||
| 3928 | ;; Emit the body | ||
| 3929 | (byte-compile-body-do-effect (cdr (cdr form))) | ||
| 3930 | ;; Unbind the variables | ||
| 3931 | (if lexical-binding | ||
| 3932 | ;; Unbind both lexical and dynamic variables | ||
| 3933 | (byte-compile-unbind clauses init-lexenv t) | ||
| 3934 | ;; Unbind dynamic variables | ||
| 3935 | (byte-compile-out 'byte-unbind (length clauses))))) | ||
| 3936 | 3915 | ||
| 3937 | 3916 | ||
| 3938 | 3917 | ||
| @@ -4254,8 +4233,8 @@ binding slots have been popped." | |||
| 4254 | (progn | 4233 | (progn |
| 4255 | ;; ## remove this someday | 4234 | ;; ## remove this someday |
| 4256 | (and byte-compile-depth | 4235 | (and byte-compile-depth |
| 4257 | (not (= (cdr (cdr tag)) byte-compile-depth)) | 4236 | (not (= (cdr (cdr tag)) byte-compile-depth)) |
| 4258 | (error "Compiler bug: depth conflict at tag %d" (car (cdr tag)))) | 4237 | (error "Compiler bug: depth conflict at tag %d" (car (cdr tag)))) |
| 4259 | (setq byte-compile-depth (cdr (cdr tag)))) | 4238 | (setq byte-compile-depth (cdr (cdr tag)))) |
| 4260 | (setcdr (cdr tag) byte-compile-depth))) | 4239 | (setcdr (cdr tag) byte-compile-depth))) |
| 4261 | 4240 | ||
diff --git a/lisp/emacs-lisp/cconv.el b/lisp/emacs-lisp/cconv.el index 10464047cd3..d8f5a7da44d 100644 --- a/lisp/emacs-lisp/cconv.el +++ b/lisp/emacs-lisp/cconv.el | |||
| @@ -70,6 +70,15 @@ | |||
| 70 | ;; | 70 | ;; |
| 71 | ;;; Code: | 71 | ;;; Code: |
| 72 | 72 | ||
| 73 | ;;; TODO: | ||
| 74 | ;; - Use abstract `make-closure' and `closure-ref' expressions, which bytecomp | ||
| 75 | ;; should turn into building corresponding byte-code function. | ||
| 76 | ;; - don't use `curry', instead build a new compiled-byte-code object | ||
| 77 | ;; (merge the closure env into the static constants pool). | ||
| 78 | ;; - use relative addresses for byte-code-stack-ref. | ||
| 79 | ;; - warn about unused lexical vars. | ||
| 80 | ;; - clean up cconv-closure-convert-rec, especially the `let' binding part. | ||
| 81 | |||
| 73 | (eval-when-compile (require 'cl)) | 82 | (eval-when-compile (require 'cl)) |
| 74 | 83 | ||
| 75 | (defconst cconv-liftwhen 3 | 84 | (defconst cconv-liftwhen 3 |
| @@ -187,14 +196,14 @@ Returns a list of free variables." | |||
| 187 | -- TOPLEVEL(optional) is a boolean variable, true if we are at the root of AST | 196 | -- TOPLEVEL(optional) is a boolean variable, true if we are at the root of AST |
| 188 | 197 | ||
| 189 | Returns a form where all lambdas don't have any free variables." | 198 | Returns a form where all lambdas don't have any free variables." |
| 190 | (message "Entering cconv-closure-convert...") | 199 | ;; (message "Entering cconv-closure-convert...") |
| 191 | (let ((cconv-mutated '()) | 200 | (let ((cconv-mutated '()) |
| 192 | (cconv-lambda-candidates '()) | 201 | (cconv-lambda-candidates '()) |
| 193 | (cconv-captured '()) | 202 | (cconv-captured '()) |
| 194 | (cconv-captured+mutated '())) | 203 | (cconv-captured+mutated '())) |
| 195 | ;; Analyse form - fill these variables with new information | 204 | ;; Analyse form - fill these variables with new information. |
| 196 | (cconv-analyse-form form '() 0) | 205 | (cconv-analyse-form form '() 0) |
| 197 | ;; Calculate an intersection of cconv-mutated and cconv-captured | 206 | ;; Calculate an intersection of cconv-mutated and cconv-captured. |
| 198 | (dolist (mvr cconv-mutated) | 207 | (dolist (mvr cconv-mutated) |
| 199 | (when (memq mvr cconv-captured) ; | 208 | (when (memq mvr cconv-captured) ; |
| 200 | (push mvr cconv-captured+mutated))) | 209 | (push mvr cconv-captured+mutated))) |
| @@ -216,14 +225,51 @@ Returns a form where all lambdas don't have any free variables." | |||
| 216 | res)) | 225 | res)) |
| 217 | 226 | ||
| 218 | (defconst cconv--dummy-var (make-symbol "ignored")) | 227 | (defconst cconv--dummy-var (make-symbol "ignored")) |
| 228 | (defconst cconv--env-var (make-symbol "env")) | ||
| 229 | |||
| 230 | (defun cconv--set-diff (s1 s2) | ||
| 231 | "Return elements of set S1 that are not in set S2." | ||
| 232 | (let ((res '())) | ||
| 233 | (dolist (x s1) | ||
| 234 | (unless (memq x s2) (push x res))) | ||
| 235 | (nreverse res))) | ||
| 236 | |||
| 237 | (defun cconv--set-diff-map (s m) | ||
| 238 | "Return elements of set S that are not in Dom(M)." | ||
| 239 | (let ((res '())) | ||
| 240 | (dolist (x s) | ||
| 241 | (unless (assq x m) (push x res))) | ||
| 242 | (nreverse res))) | ||
| 243 | |||
| 244 | (defun cconv--map-diff (m1 m2) | ||
| 245 | "Return the submap of map M1 that has Dom(M2) removed." | ||
| 246 | (let ((res '())) | ||
| 247 | (dolist (x m1) | ||
| 248 | (unless (assq (car x) m2) (push x res))) | ||
| 249 | (nreverse res))) | ||
| 250 | |||
| 251 | (defun cconv--map-diff-elem (m x) | ||
| 252 | "Return the map M minus any mapping for X." | ||
| 253 | ;; Here we assume that X appears at most once in M. | ||
| 254 | (let* ((b (assq x m)) | ||
| 255 | (res (if b (remq b m) m))) | ||
| 256 | (assert (null (assq x res))) ;; Check the assumption was warranted. | ||
| 257 | res)) | ||
| 219 | 258 | ||
| 220 | (defun cconv-closure-convert-rec | 259 | (defun cconv--map-diff-set (m s) |
| 221 | (form emvrs fvrs envs lmenvs) | 260 | "Return the map M minus any mapping for elements of S." |
| 261 | ;; Here we assume that X appears at most once in M. | ||
| 262 | (let ((res '())) | ||
| 263 | (dolist (b m) | ||
| 264 | (unless (memq (car b) s) (push b res))) | ||
| 265 | (nreverse res))) | ||
| 266 | |||
| 267 | (defun cconv-closure-convert-rec (form emvrs fvrs envs lmenvs) | ||
| 222 | ;; This function actually rewrites the tree. | 268 | ;; This function actually rewrites the tree. |
| 223 | "Eliminates all free variables of all lambdas in given forms. | 269 | "Eliminates all free variables of all lambdas in given forms. |
| 224 | Arguments: | 270 | Arguments: |
| 225 | -- FORM is a piece of Elisp code after macroexpansion. | 271 | -- FORM is a piece of Elisp code after macroexpansion. |
| 226 | -- LMENVS is a list of environments used for lambda-lifting. Initially empty. | 272 | -- LMENVS is a list of environments used for lambda-lifting. Initially empty. |
| 227 | -- EMVRS is a list that contains mutated variables that are visible | 273 | -- EMVRS is a list that contains mutated variables that are visible |
| 228 | within current environment. | 274 | within current environment. |
| 229 | -- ENVS is an environment(list of free variables) of current closure. | 275 | -- ENVS is an environment(list of free variables) of current closure. |
| @@ -343,10 +389,9 @@ Returns a form where all lambdas don't have any free variables." | |||
| 343 | (setq lmenvs (remq old-lmenv lmenvs)) | 389 | (setq lmenvs (remq old-lmenv lmenvs)) |
| 344 | (push new-lmenv lmenvs) | 390 | (push new-lmenv lmenvs) |
| 345 | (push `(,closedsym ,var) binders-new)))) | 391 | (push `(,closedsym ,var) binders-new)))) |
| 346 | ;; we push the element after redefined free variables | 392 | ;; We push the element after redefined free variables are |
| 347 | ;; are processes. this is important to avoid the bug | 393 | ;; processed. This is important to avoid the bug when free |
| 348 | ;; when free variable and the function have the same | 394 | ;; variable and the function have the same name. |
| 349 | ;; name | ||
| 350 | (push (list var new-val) binders-new) | 395 | (push (list var new-val) binders-new) |
| 351 | 396 | ||
| 352 | (when (eq letsym 'let*) ; update fvrs | 397 | (when (eq letsym 'let*) ; update fvrs |
| @@ -355,11 +400,7 @@ Returns a form where all lambdas don't have any free variables." | |||
| 355 | (when emvr-push | 400 | (when emvr-push |
| 356 | (push emvr-push emvrs) | 401 | (push emvr-push emvrs) |
| 357 | (setq emvr-push nil)) | 402 | (setq emvr-push nil)) |
| 358 | (let (lmenvs-1) ; remove var from lmenvs if redefined | 403 | (setq lmenvs (cconv--map-diff-elem lmenvs var)) |
| 359 | (dolist (iter lmenvs) | ||
| 360 | (when (not (assq var lmenvs)) | ||
| 361 | (push iter lmenvs-1))) | ||
| 362 | (setq lmenvs lmenvs-1)) | ||
| 363 | (when lmenv-push | 404 | (when lmenv-push |
| 364 | (push lmenv-push lmenvs) | 405 | (push lmenv-push lmenvs) |
| 365 | (setq lmenv-push nil))) | 406 | (setq lmenv-push nil))) |
| @@ -368,19 +409,10 @@ Returns a form where all lambdas don't have any free variables." | |||
| 368 | 409 | ||
| 369 | (let (var fvrs-1 emvrs-1 lmenvs-1) | 410 | (let (var fvrs-1 emvrs-1 lmenvs-1) |
| 370 | ;; Here we update emvrs, fvrs and lmenvs lists | 411 | ;; Here we update emvrs, fvrs and lmenvs lists |
| 371 | (dolist (vr fvrs) | 412 | (setq fvrs (cconv--set-diff-map fvrs binders-new)) |
| 372 | ; safely remove | 413 | (setq emvrs (cconv--set-diff-map emvrs binders-new)) |
| 373 | (when (not (assq vr binders-new)) (push vr fvrs-1))) | ||
| 374 | (setq fvrs fvrs-1) | ||
| 375 | (dolist (vr emvrs) | ||
| 376 | ; safely remove | ||
| 377 | (when (not (assq vr binders-new)) (push vr emvrs-1))) | ||
| 378 | (setq emvrs emvrs-1) | ||
| 379 | ; push new | ||
| 380 | (setq emvrs (append emvrs emvrs-new)) | 414 | (setq emvrs (append emvrs emvrs-new)) |
| 381 | (dolist (vr lmenvs) | 415 | (setq lmenvs (cconv--set-diff-map lmenvs binders-new)) |
| 382 | (when (not (assq (car vr) binders-new)) | ||
| 383 | (push vr lmenvs-1))) | ||
| 384 | (setq lmenvs (append lmenvs lmenvs-new))) | 416 | (setq lmenvs (append lmenvs lmenvs-new))) |
| 385 | 417 | ||
| 386 | ;; Here we do the same letbinding as for let* above | 418 | ;; Here we do the same letbinding as for let* above |
| @@ -402,9 +434,9 @@ Returns a form where all lambdas don't have any free variables." | |||
| 402 | (symbol-name var)))) | 434 | (symbol-name var)))) |
| 403 | 435 | ||
| 404 | (setq new-lmenv (list (car lmenv))) | 436 | (setq new-lmenv (list (car lmenv))) |
| 405 | (dolist (frv (cdr lmenv)) (if (eq frv var) | 437 | (dolist (frv (cdr lmenv)) |
| 406 | (push closedsym new-lmenv) | 438 | (push (if (eq frv var) closedsym frv) |
| 407 | (push frv new-lmenv))) | 439 | new-lmenv)) |
| 408 | (setq new-lmenv (reverse new-lmenv)) | 440 | (setq new-lmenv (reverse new-lmenv)) |
| 409 | (setq lmenvs (remq lmenv lmenvs)) | 441 | (setq lmenvs (remq lmenv lmenvs)) |
| 410 | (push new-lmenv lmenvs) | 442 | (push new-lmenv lmenvs) |
| @@ -449,13 +481,9 @@ Returns a form where all lambdas don't have any free variables." | |||
| 449 | (`(quote . ,_) form) ; quote form | 481 | (`(quote . ,_) form) ; quote form |
| 450 | 482 | ||
| 451 | (`(function . ((lambda ,vars . ,body-forms))) ; function form | 483 | (`(function . ((lambda ,vars . ,body-forms))) ; function form |
| 452 | (let (fvrs-new) ; we remove vars from fvrs | 484 | (let* ((fvrs-new (cconv--set-diff fvrs vars)) ; Remove vars from fvrs. |
| 453 | (dolist (elm fvrs) ;i use such a tricky way to avoid side effects | 485 | (fv (delete-dups (cconv-freevars form '()))) |
| 454 | (when (not (memq elm vars)) | 486 | (leave fvrs-new) ; leave=non-nil if we should leave env unchanged. |
| 455 | (push elm fvrs-new))) | ||
| 456 | (setq fvrs fvrs-new)) | ||
| 457 | (let* ((fv (delete-dups (cconv-freevars form '()))) | ||
| 458 | (leave fvrs) ; leave = non nil if we should leave env unchanged | ||
| 459 | (body-forms-new '()) | 487 | (body-forms-new '()) |
| 460 | (letbind '()) | 488 | (letbind '()) |
| 461 | (mv nil) | 489 | (mv nil) |
| @@ -470,7 +498,7 @@ Returns a form where all lambdas don't have any free variables." | |||
| 470 | (if (eq (length envs) (length fv)) | 498 | (if (eq (length envs) (length fv)) |
| 471 | (let ((fv-temp fv)) | 499 | (let ((fv-temp fv)) |
| 472 | (while (and fv-temp leave) | 500 | (while (and fv-temp leave) |
| 473 | (when (not (memq (car fv-temp) fvrs)) (setq leave nil)) | 501 | (when (not (memq (car fv-temp) fvrs-new)) (setq leave nil)) |
| 474 | (setq fv-temp (cdr fv-temp)))) | 502 | (setq fv-temp (cdr fv-temp)))) |
| 475 | (setq leave nil)) | 503 | (setq leave nil)) |
| 476 | 504 | ||
| @@ -479,23 +507,30 @@ Returns a form where all lambdas don't have any free variables." | |||
| 479 | (dolist (elm fv) | 507 | (dolist (elm fv) |
| 480 | (push | 508 | (push |
| 481 | (cconv-closure-convert-rec | 509 | (cconv-closure-convert-rec |
| 510 | ;; Remove `elm' from `emvrs' for this call because in case | ||
| 511 | ;; `elm' is a variable that's wrapped in a cons-cell, we | ||
| 512 | ;; want to put the cons-cell itself in the closure, rather | ||
| 513 | ;; than just a copy of its current content. | ||
| 482 | elm (remq elm emvrs) fvrs envs lmenvs) | 514 | elm (remq elm emvrs) fvrs envs lmenvs) |
| 483 | envector)) ; process vars for closure vector | 515 | envector)) ; Process vars for closure vector. |
| 484 | (setq envector (reverse envector)) | 516 | (setq envector (reverse envector)) |
| 485 | (setq envs fv)) | 517 | (setq envs fv)) |
| 486 | (setq envector `(env))) ; leave unchanged | 518 | (setq envector `(,cconv--env-var))) ; Leave unchanged. |
| 487 | (setq fvrs fv)) ; update substitution list | 519 | (setq fvrs-new fv)) ; Update substitution list. |
| 488 | 520 | ||
| 489 | ;; the difference between envs and fvrs is explained | 521 | (setq emvrs (cconv--set-diff emvrs vars)) |
| 490 | ;; in comment in the beginning of the function | 522 | (setq lmenvs (cconv--map-diff-set lmenvs vars)) |
| 491 | (dolist (elm cconv-captured+mutated) ; find mutated arguments | 523 | |
| 492 | (setq mv (car elm)) ; used in inner closures | 524 | ;; The difference between envs and fvrs is explained |
| 525 | ;; in comment in the beginning of the function. | ||
| 526 | (dolist (elm cconv-captured+mutated) ; Find mutated arguments | ||
| 527 | (setq mv (car elm)) ; used in inner closures. | ||
| 493 | (when (and (memq mv vars) (eq form (caddr elm))) | 528 | (when (and (memq mv vars) (eq form (caddr elm))) |
| 494 | (progn (push mv emvrs) | 529 | (progn (push mv emvrs) |
| 495 | (push `(,mv (list ,mv)) letbind)))) | 530 | (push `(,mv (list ,mv)) letbind)))) |
| 496 | (dolist (elm body-forms) ; convert function body | 531 | (dolist (elm body-forms) ; convert function body |
| 497 | (push (cconv-closure-convert-rec | 532 | (push (cconv-closure-convert-rec |
| 498 | elm emvrs fvrs envs lmenvs) | 533 | elm emvrs fvrs-new envs lmenvs) |
| 499 | body-forms-new)) | 534 | body-forms-new)) |
| 500 | 535 | ||
| 501 | (setq body-forms-new | 536 | (setq body-forms-new |
| @@ -509,12 +544,12 @@ Returns a form where all lambdas don't have any free variables." | |||
| 509 | ; 1 free variable - do not build vector | 544 | ; 1 free variable - do not build vector |
| 510 | ((null (cdr envector)) | 545 | ((null (cdr envector)) |
| 511 | `(curry | 546 | `(curry |
| 512 | (function (lambda (env . ,vars) . ,body-forms-new)) | 547 | (function (lambda (,cconv--env-var . ,vars) . ,body-forms-new)) |
| 513 | ,(car envector))) | 548 | ,(car envector))) |
| 514 | ; >=2 free variables - build vector | 549 | ; >=2 free variables - build vector |
| 515 | (t | 550 | (t |
| 516 | `(curry | 551 | `(curry |
| 517 | (function (lambda (env . ,vars) . ,body-forms-new)) | 552 | (function (lambda (,cconv--env-var . ,vars) . ,body-forms-new)) |
| 518 | (vector . ,envector)))))) | 553 | (vector . ,envector)))))) |
| 519 | 554 | ||
| 520 | (`(function . ,_) form) ; same as quote | 555 | (`(function . ,_) form) ; same as quote |
| @@ -674,13 +709,10 @@ Returns a form where all lambdas don't have any free variables." | |||
| 674 | (let ((free (memq form fvrs))) | 709 | (let ((free (memq form fvrs))) |
| 675 | (if free ;form is a free variable | 710 | (if free ;form is a free variable |
| 676 | (let* ((numero (- (length fvrs) (length free))) | 711 | (let* ((numero (- (length fvrs) (length free))) |
| 677 | (var '())) | 712 | (var (if (null (cdr envs)) |
| 678 | (assert numero) | 713 | cconv--env-var |
| 679 | (if (null (cdr envs)) | 714 | ;; Replace form => (aref env #) |
| 680 | (setq var 'env) | 715 | `(aref ,cconv--env-var ,numero)))) |
| 681 | ;replace form => | ||
| 682 | ;(aref env #) | ||
| 683 | (setq var `(aref env ,numero))) | ||
| 684 | (if (memq form emvrs) ; form => (car (aref env #)) if mutable | 716 | (if (memq form emvrs) ; form => (car (aref env #)) if mutable |
| 685 | `(car ,var) | 717 | `(car ,var) |
| 686 | var)) | 718 | var)) |
diff --git a/lisp/emacs-lisp/cl-loaddefs.el b/lisp/emacs-lisp/cl-loaddefs.el index e10dc10447c..a13e46ccc59 100644 --- a/lisp/emacs-lisp/cl-loaddefs.el +++ b/lisp/emacs-lisp/cl-loaddefs.el | |||
| @@ -282,7 +282,7 @@ Not documented | |||
| 282 | ;;;;;; do-all-symbols do-symbols dotimes dolist do* do loop return-from | 282 | ;;;;;; do-all-symbols do-symbols dotimes dolist do* do loop return-from |
| 283 | ;;;;;; return block etypecase typecase ecase case load-time-value | 283 | ;;;;;; return block etypecase typecase ecase case load-time-value |
| 284 | ;;;;;; eval-when destructuring-bind function* defmacro* defun* gentemp | 284 | ;;;;;; eval-when destructuring-bind function* defmacro* defun* gentemp |
| 285 | ;;;;;; gensym) "cl-macs" "cl-macs.el" "0904b956872432ae7cc5fa9abcefce63") | 285 | ;;;;;; gensym) "cl-macs" "cl-macs.el" "7602128fa01003de9a8df4c752865300") |
| 286 | ;;; Generated autoloads from cl-macs.el | 286 | ;;; Generated autoloads from cl-macs.el |
| 287 | 287 | ||
| 288 | (autoload 'gensym "cl-macs" "\ | 288 | (autoload 'gensym "cl-macs" "\ |
diff --git a/lisp/emacs-lisp/cl-macs.el b/lisp/emacs-lisp/cl-macs.el index 80e95724f1f..093e4fbf258 100644 --- a/lisp/emacs-lisp/cl-macs.el +++ b/lisp/emacs-lisp/cl-macs.el | |||
| @@ -602,7 +602,13 @@ called from BODY." | |||
| 602 | 602 | ||
| 603 | (put 'cl-block-wrapper 'byte-compile 'cl-byte-compile-block) | 603 | (put 'cl-block-wrapper 'byte-compile 'cl-byte-compile-block) |
| 604 | (defun cl-byte-compile-block (cl-form) | 604 | (defun cl-byte-compile-block (cl-form) |
| 605 | (if (fboundp 'byte-compile-form-do-effect) ; Check for optimizing compiler | 605 | ;; Here we try to determine if a catch tag is used or not, so as to get rid |
| 606 | ;; of the catch when it's not used. | ||
| 607 | (if (and (fboundp 'byte-compile-form-do-effect) ; Optimizing compiler? | ||
| 608 | ;; FIXME: byte-compile-top-level can only be used for code that is | ||
| 609 | ;; closed (as the name implies), so for lexical scoping we should | ||
| 610 | ;; implement this optimization differently. | ||
| 611 | (not lexical-binding)) | ||
| 606 | (progn | 612 | (progn |
| 607 | (let* ((cl-entry (cons (nth 1 (nth 1 (nth 1 cl-form))) nil)) | 613 | (let* ((cl-entry (cons (nth 1 (nth 1 (nth 1 cl-form))) nil)) |
| 608 | (cl-active-block-names (cons cl-entry cl-active-block-names)) | 614 | (cl-active-block-names (cons cl-entry cl-active-block-names)) |
diff --git a/lisp/emacs-lisp/pcase.el b/lisp/emacs-lisp/pcase.el index 7990df264a9..a338de251ed 100644 --- a/lisp/emacs-lisp/pcase.el +++ b/lisp/emacs-lisp/pcase.el | |||
| @@ -1,5 +1,4 @@ | |||
| 1 | ;;; -*- lexical-binding: t -*- | 1 | ;;; pcase.el --- ML-style pattern-matching macro for Elisp -*- lexical-binding: t -*- |
| 2 | ;;; pcase.el --- ML-style pattern-matching macro for Elisp | ||
| 3 | 2 | ||
| 4 | ;; Copyright (C) 2010-2011 Free Software Foundation, Inc. | 3 | ;; Copyright (C) 2010-2011 Free Software Foundation, Inc. |
| 5 | 4 | ||
diff --git a/lisp/files.el b/lisp/files.el index 8b42eaaddb8..e7dd96ca2ff 100644 --- a/lisp/files.el +++ b/lisp/files.el | |||
| @@ -2851,18 +2851,19 @@ asking you for confirmation." | |||
| 2851 | ;; | 2851 | ;; |
| 2852 | ;; For variables defined in the C source code the declaration should go here: | 2852 | ;; For variables defined in the C source code the declaration should go here: |
| 2853 | 2853 | ||
| 2854 | (mapc (lambda (pair) | 2854 | (dolist (pair |
| 2855 | (put (car pair) 'safe-local-variable (cdr pair))) | 2855 | '((buffer-read-only . booleanp) ;; C source code |
| 2856 | '((buffer-read-only . booleanp) ;; C source code | 2856 | (default-directory . stringp) ;; C source code |
| 2857 | (default-directory . stringp) ;; C source code | 2857 | (fill-column . integerp) ;; C source code |
| 2858 | (fill-column . integerp) ;; C source code | 2858 | (indent-tabs-mode . booleanp) ;; C source code |
| 2859 | (indent-tabs-mode . booleanp) ;; C source code | 2859 | (left-margin . integerp) ;; C source code |
| 2860 | (left-margin . integerp) ;; C source code | 2860 | (no-update-autoloads . booleanp) |
| 2861 | (no-update-autoloads . booleanp) | 2861 | (lexical-binding . booleanp) ;; C source code |
| 2862 | (tab-width . integerp) ;; C source code | 2862 | (tab-width . integerp) ;; C source code |
| 2863 | (truncate-lines . booleanp) ;; C source code | 2863 | (truncate-lines . booleanp) ;; C source code |
| 2864 | (word-wrap . booleanp) ;; C source code | 2864 | (word-wrap . booleanp) ;; C source code |
| 2865 | (bidi-display-reordering . booleanp))) ;; C source code | 2865 | (bidi-display-reordering . booleanp))) ;; C source code |
| 2866 | (put (car pair) 'safe-local-variable (cdr pair))) | ||
| 2866 | 2867 | ||
| 2867 | (put 'bidi-paragraph-direction 'safe-local-variable | 2868 | (put 'bidi-paragraph-direction 'safe-local-variable |
| 2868 | (lambda (v) (memq v '(nil right-to-left left-to-right)))) | 2869 | (lambda (v) (memq v '(nil right-to-left left-to-right)))) |
diff --git a/lisp/help-fns.el b/lisp/help-fns.el index 172a74d8c80..49767e6e9d3 100644 --- a/lisp/help-fns.el +++ b/lisp/help-fns.el | |||
| @@ -530,7 +530,7 @@ suitable file is found, return nil." | |||
| 530 | (let ((fill-begin (point))) | 530 | (let ((fill-begin (point))) |
| 531 | (insert (car high) "\n") | 531 | (insert (car high) "\n") |
| 532 | (fill-region fill-begin (point))) | 532 | (fill-region fill-begin (point))) |
| 533 | (setq doc (cdr high)))) | 533 | (setq doc (cdr high)))) |
| 534 | (let* ((obsolete (and | 534 | (let* ((obsolete (and |
| 535 | ;; function might be a lambda construct. | 535 | ;; function might be a lambda construct. |
| 536 | (symbolp function) | 536 | (symbolp function) |
diff --git a/src/ChangeLog b/src/ChangeLog index 6674fb31ca5..0b2ee8550ca 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,3 +1,13 @@ | |||
| 1 | 2011-02-17 Stefan Monnier <monnier@iro.umontreal.ca> | ||
| 2 | |||
| 3 | * eval.c (Vinternal_interpreter_environment): Remove. | ||
| 4 | (syms_of_eval): Do declare Vinternal_interpreter_environment as | ||
| 5 | a global lisp var, but unintern it to hide it. | ||
| 6 | (Fcommandp): | ||
| 7 | * data.c (Finteractive_form): Understand `closure's. | ||
| 8 | |||
| 9 | * bytecode.c (exec_byte_code): Fix handling of &rest. | ||
| 10 | |||
| 1 | 2011-02-12 Stefan Monnier <monnier@iro.umontreal.ca> | 11 | 2011-02-12 Stefan Monnier <monnier@iro.umontreal.ca> |
| 2 | 12 | ||
| 3 | * bytecode.c (Bvec_ref, Bvec_set): Remove. | 13 | * bytecode.c (Bvec_ref, Bvec_set): Remove. |
diff --git a/src/bytecode.c b/src/bytecode.c index 9bf6ae45ce9..1ad01aaf8f7 100644 --- a/src/bytecode.c +++ b/src/bytecode.c | |||
| @@ -500,7 +500,9 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth, | |||
| 500 | optional = 1; | 500 | optional = 1; |
| 501 | else if (EQ (XCAR (at), Qand_rest)) | 501 | else if (EQ (XCAR (at), Qand_rest)) |
| 502 | { | 502 | { |
| 503 | PUSH (Flist (nargs, args)); | 503 | PUSH (pushed < nargs |
| 504 | ? Flist (nargs - pushed, args) | ||
| 505 | : Qnil); | ||
| 504 | pushed = nargs; | 506 | pushed = nargs; |
| 505 | at = Qnil; | 507 | at = Qnil; |
| 506 | break; | 508 | break; |
diff --git a/src/data.c b/src/data.c index 83da3e103cb..2f17edd3fdc 100644 --- a/src/data.c +++ b/src/data.c | |||
| @@ -755,6 +755,8 @@ Value, if non-nil, is a list \(interactive SPEC). */) | |||
| 755 | else if (CONSP (fun)) | 755 | else if (CONSP (fun)) |
| 756 | { | 756 | { |
| 757 | Lisp_Object funcar = XCAR (fun); | 757 | Lisp_Object funcar = XCAR (fun); |
| 758 | if (EQ (funcar, Qclosure)) | ||
| 759 | fun = Fcdr (XCDR (fun)), funcar = Fcar (fun); | ||
| 758 | if (EQ (funcar, Qlambda)) | 760 | if (EQ (funcar, Qlambda)) |
| 759 | return Fassq (Qinteractive, Fcdr (XCDR (fun))); | 761 | return Fassq (Qinteractive, Fcdr (XCDR (fun))); |
| 760 | else if (EQ (funcar, Qautoload)) | 762 | else if (EQ (funcar, Qautoload)) |
diff --git a/src/eval.c b/src/eval.c index 9adfc983ced..63484d40e1b 100644 --- a/src/eval.c +++ b/src/eval.c | |||
| @@ -78,16 +78,6 @@ Lisp_Object Vrun_hooks; | |||
| 78 | 78 | ||
| 79 | Lisp_Object Vautoload_queue; | 79 | Lisp_Object Vautoload_queue; |
| 80 | 80 | ||
| 81 | /* When lexical binding is being used, this is non-nil, and contains an | ||
| 82 | alist of lexically-bound variable, or (t), indicating an empty | ||
| 83 | environment. The lisp name of this variable is | ||
| 84 | `internal-interpreter-environment'. Every element of this list | ||
| 85 | can be either a cons (VAR . VAL) specifying a lexical binding, | ||
| 86 | or a single symbol VAR indicating that this variable should use | ||
| 87 | dynamic scoping. */ | ||
| 88 | |||
| 89 | Lisp_Object Vinternal_interpreter_environment; | ||
| 90 | |||
| 91 | /* Current number of specbindings allocated in specpdl. */ | 81 | /* Current number of specbindings allocated in specpdl. */ |
| 92 | 82 | ||
| 93 | EMACS_INT specpdl_size; | 83 | EMACS_INT specpdl_size; |
| @@ -2092,9 +2082,11 @@ then strings and vectors are not accepted. */) | |||
| 2092 | if (!CONSP (fun)) | 2082 | if (!CONSP (fun)) |
| 2093 | return Qnil; | 2083 | return Qnil; |
| 2094 | funcar = XCAR (fun); | 2084 | funcar = XCAR (fun); |
| 2085 | if (EQ (funcar, Qclosure)) | ||
| 2086 | fun = Fcdr (XCDR (fun)), funcar = Fcar (fun); | ||
| 2095 | if (EQ (funcar, Qlambda)) | 2087 | if (EQ (funcar, Qlambda)) |
| 2096 | return !NILP (Fassq (Qinteractive, Fcdr (XCDR (fun)))) ? Qt : if_prop; | 2088 | return !NILP (Fassq (Qinteractive, Fcdr (XCDR (fun)))) ? Qt : if_prop; |
| 2097 | if (EQ (funcar, Qautoload)) | 2089 | else if (EQ (funcar, Qautoload)) |
| 2098 | return !NILP (Fcar (Fcdr (Fcdr (XCDR (fun))))) ? Qt : if_prop; | 2090 | return !NILP (Fcar (Fcdr (Fcdr (XCDR (fun))))) ? Qt : if_prop; |
| 2099 | else | 2091 | else |
| 2100 | return Qnil; | 2092 | return Qnil; |
| @@ -3695,6 +3687,8 @@ mark_backtrace (void) | |||
| 3695 | } | 3687 | } |
| 3696 | } | 3688 | } |
| 3697 | 3689 | ||
| 3690 | EXFUN (Funintern, 2); | ||
| 3691 | |||
| 3698 | void | 3692 | void |
| 3699 | syms_of_eval (void) | 3693 | syms_of_eval (void) |
| 3700 | { | 3694 | { |
| @@ -3840,19 +3834,27 @@ DECL is a list `(declare ...)' containing the declarations. | |||
| 3840 | The value the function returns is not used. */); | 3834 | The value the function returns is not used. */); |
| 3841 | Vmacro_declaration_function = Qnil; | 3835 | Vmacro_declaration_function = Qnil; |
| 3842 | 3836 | ||
| 3837 | /* When lexical binding is being used, | ||
| 3838 | vinternal_interpreter_environment is non-nil, and contains an alist | ||
| 3839 | of lexically-bound variable, or (t), indicating an empty | ||
| 3840 | environment. The lisp name of this variable would be | ||
| 3841 | `internal-interpreter-environment' if it weren't hidden. | ||
| 3842 | Every element of this list can be either a cons (VAR . VAL) | ||
| 3843 | specifying a lexical binding, or a single symbol VAR indicating | ||
| 3844 | that this variable should use dynamic scoping. */ | ||
| 3843 | Qinternal_interpreter_environment | 3845 | Qinternal_interpreter_environment |
| 3844 | = intern_c_string ("internal-interpreter-environment"); | 3846 | = intern_c_string ("internal-interpreter-environment"); |
| 3845 | staticpro (&Qinternal_interpreter_environment); | 3847 | staticpro (&Qinternal_interpreter_environment); |
| 3846 | #if 0 /* Don't export this variable to Elisp, so noone can mess with it | 3848 | DEFVAR_LISP ("internal-interpreter-environment", |
| 3847 | (Just imagine if someone makes it buffer-local). */ | 3849 | Vinternal_interpreter_environment, |
| 3848 | DEFVAR__LISP ("internal-interpreter-environment", | ||
| 3849 | Vinternal_interpreter_environment, | ||
| 3850 | doc: /* If non-nil, the current lexical environment of the lisp interpreter. | 3850 | doc: /* If non-nil, the current lexical environment of the lisp interpreter. |
| 3851 | When lexical binding is not being used, this variable is nil. | 3851 | When lexical binding is not being used, this variable is nil. |
| 3852 | A value of `(t)' indicates an empty environment, otherwise it is an | 3852 | A value of `(t)' indicates an empty environment, otherwise it is an |
| 3853 | alist of active lexical bindings. */); | 3853 | alist of active lexical bindings. */); |
| 3854 | #endif | ||
| 3855 | Vinternal_interpreter_environment = Qnil; | 3854 | Vinternal_interpreter_environment = Qnil; |
| 3855 | /* Don't export this variable to Elisp, so noone can mess with it | ||
| 3856 | (Just imagine if someone makes it buffer-local). */ | ||
| 3857 | Funintern (Qinternal_interpreter_environment, Qnil); | ||
| 3856 | 3858 | ||
| 3857 | Vrun_hooks = intern_c_string ("run-hooks"); | 3859 | Vrun_hooks = intern_c_string ("run-hooks"); |
| 3858 | staticpro (&Vrun_hooks); | 3860 | staticpro (&Vrun_hooks); |
diff --git a/src/lisp.h b/src/lisp.h index 906736bacad..0e7eeebc9da 100644 --- a/src/lisp.h +++ b/src/lisp.h | |||
| @@ -2855,7 +2855,7 @@ extern void syms_of_lread (void); | |||
| 2855 | 2855 | ||
| 2856 | /* Defined in eval.c */ | 2856 | /* Defined in eval.c */ |
| 2857 | extern Lisp_Object Qautoload, Qexit, Qinteractive, Qcommandp, Qdefun, Qmacro; | 2857 | extern Lisp_Object Qautoload, Qexit, Qinteractive, Qcommandp, Qdefun, Qmacro; |
| 2858 | extern Lisp_Object Qinhibit_quit; | 2858 | extern Lisp_Object Qinhibit_quit, Qclosure; |
| 2859 | extern Lisp_Object Vautoload_queue; | 2859 | extern Lisp_Object Vautoload_queue; |
| 2860 | extern Lisp_Object Vsignaling_function; | 2860 | extern Lisp_Object Vsignaling_function; |
| 2861 | extern int handling_signal; | 2861 | extern int handling_signal; |