mirror of
https://git.savannah.gnu.org/git/emacs.git
synced 2024-12-29 11:02:01 +00:00
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.
This commit is contained in:
parent
ce5b520a37
commit
b38b1ec071
@ -1,3 +1,34 @@
|
|||||||
|
2011-02-17 Stefan Monnier <monnier@iro.umontreal.ca>
|
||||||
|
|
||||||
|
* files.el (lexical-binding): Add a safe-local-variable property.
|
||||||
|
|
||||||
|
* emacs-lisp/cl-macs.el (cl-byte-compile-block): Disable optimization
|
||||||
|
in lexbind, because it needs a different implementation.
|
||||||
|
|
||||||
|
* 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.
|
||||||
|
|
||||||
|
* 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.
|
||||||
|
|
||||||
|
* 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.
|
||||||
|
|
||||||
2011-02-12 Stefan Monnier <monnier@iro.umontreal.ca>
|
2011-02-12 Stefan Monnier <monnier@iro.umontreal.ca>
|
||||||
|
|
||||||
* emacs-lisp/byte-lexbind.el: Delete.
|
* emacs-lisp/byte-lexbind.el: Delete.
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
;;; -*- lexical-binding: t -*-
|
;;; doc-view.el --- View PDF/PostScript/DVI files in Emacs -*- lexical-binding: t -*-
|
||||||
;;; doc-view.el --- View PDF/PostScript/DVI files in Emacs
|
|
||||||
|
|
||||||
;; Copyright (C) 2007-2011 Free Software Foundation, Inc.
|
;; Copyright (C) 2007-2011 Free Software Foundation, Inc.
|
||||||
;;
|
;;
|
||||||
|
@ -248,7 +248,18 @@
|
|||||||
;; are no collisions, and that byte-compile-tag-number is reasonable
|
;; are no collisions, and that byte-compile-tag-number is reasonable
|
||||||
;; after this is spliced in. The provided list is destroyed.
|
;; after this is spliced in. The provided list is destroyed.
|
||||||
(defun byte-inline-lapcode (lap)
|
(defun byte-inline-lapcode (lap)
|
||||||
(setq byte-compile-output (nconc (nreverse lap) byte-compile-output)))
|
;; "Replay" the operations: we used to just do
|
||||||
|
;; (setq byte-compile-output (nconc (nreverse lap) byte-compile-output))
|
||||||
|
;; but that fails to update byte-compile-depth, so we had to assume
|
||||||
|
;; that `lap' ends up adding exactly 1 element to the stack. This
|
||||||
|
;; happens to be true for byte-code generated by bytecomp.el without
|
||||||
|
;; lexical-binding, but it's not true in general, and it's not true for
|
||||||
|
;; code output by bytecomp.el with lexical-binding.
|
||||||
|
(dolist (op lap)
|
||||||
|
(cond
|
||||||
|
((eq (car op) 'TAG) (byte-compile-out-tag op))
|
||||||
|
((memq (car op) byte-goto-ops) (byte-compile-goto (car op) (cdr op)))
|
||||||
|
(t (byte-compile-out (car op) (cdr op))))))
|
||||||
|
|
||||||
(defun byte-compile-inline-expand (form)
|
(defun byte-compile-inline-expand (form)
|
||||||
(let* ((name (car form))
|
(let* ((name (car form))
|
||||||
@ -266,25 +277,32 @@
|
|||||||
(cdr (assq name byte-compile-function-environment)))))
|
(cdr (assq name byte-compile-function-environment)))))
|
||||||
(if (and (consp fn) (eq (car fn) 'autoload))
|
(if (and (consp fn) (eq (car fn) 'autoload))
|
||||||
(error "File `%s' didn't define `%s'" (nth 1 fn) name))
|
(error "File `%s' didn't define `%s'" (nth 1 fn) name))
|
||||||
(if (and (symbolp fn) (not (eq fn t)))
|
(cond
|
||||||
(byte-compile-inline-expand (cons fn (cdr form)))
|
((and (symbolp fn) (not (eq fn t))) ;A function alias.
|
||||||
(if (byte-code-function-p fn)
|
(byte-compile-inline-expand (cons fn (cdr form))))
|
||||||
(let (string)
|
((and (byte-code-function-p fn)
|
||||||
(fetch-bytecode fn)
|
;; FIXME: This works to inline old-style-byte-codes into
|
||||||
(setq string (aref fn 1))
|
;; old-style-byte-codes, but not mixed cases (not sure
|
||||||
;; Isn't it an error for `string' not to be unibyte?? --stef
|
;; about new-style into new-style).
|
||||||
(if (fboundp 'string-as-unibyte)
|
(not lexical-binding)
|
||||||
(setq string (string-as-unibyte string)))
|
(not (and (>= (length fn) 7)
|
||||||
;; `byte-compile-splice-in-already-compiled-code'
|
(aref fn 6)))) ;6 = COMPILED_PUSH_ARGS
|
||||||
;; takes care of inlining the body.
|
;; (message "Inlining %S byte-code" name)
|
||||||
(cons `(lambda ,(aref fn 0)
|
(fetch-bytecode fn)
|
||||||
(byte-code ,string ,(aref fn 2) ,(aref fn 3)))
|
(let ((string (aref fn 1)))
|
||||||
(cdr form)))
|
;; Isn't it an error for `string' not to be unibyte?? --stef
|
||||||
(if (eq (car-safe fn) 'lambda)
|
(if (fboundp 'string-as-unibyte)
|
||||||
(macroexpand-all (cons fn (cdr form))
|
(setq string (string-as-unibyte string)))
|
||||||
byte-compile-macro-environment)
|
;; `byte-compile-splice-in-already-compiled-code'
|
||||||
;; Give up on inlining.
|
;; takes care of inlining the body.
|
||||||
form))))))
|
(cons `(lambda ,(aref fn 0)
|
||||||
|
(byte-code ,string ,(aref fn 2) ,(aref fn 3)))
|
||||||
|
(cdr form))))
|
||||||
|
((eq (car-safe fn) 'lambda)
|
||||||
|
(macroexpand-all (cons fn (cdr form))
|
||||||
|
byte-compile-macro-environment))
|
||||||
|
(t ;; Give up on inlining.
|
||||||
|
form)))))
|
||||||
|
|
||||||
;; ((lambda ...) ...)
|
;; ((lambda ...) ...)
|
||||||
(defun byte-compile-unfold-lambda (form &optional name)
|
(defun byte-compile-unfold-lambda (form &optional name)
|
||||||
@ -1298,10 +1316,7 @@
|
|||||||
(if (not (memq byte-optimize '(t lap)))
|
(if (not (memq byte-optimize '(t lap)))
|
||||||
(byte-compile-normal-call form)
|
(byte-compile-normal-call form)
|
||||||
(byte-inline-lapcode
|
(byte-inline-lapcode
|
||||||
(byte-decompile-bytecode-1 (nth 1 form) (nth 2 form) t))
|
(byte-decompile-bytecode-1 (nth 1 form) (nth 2 form) t))))
|
||||||
(setq byte-compile-maxdepth (max (+ byte-compile-depth (nth 3 form))
|
|
||||||
byte-compile-maxdepth))
|
|
||||||
(setq byte-compile-depth (1+ byte-compile-depth))))
|
|
||||||
|
|
||||||
(put 'byte-code 'byte-compile 'byte-compile-splice-in-already-compiled-code)
|
(put 'byte-code 'byte-compile 'byte-compile-splice-in-already-compiled-code)
|
||||||
|
|
||||||
|
@ -752,9 +752,10 @@ BYTES and PC are updated after evaluating all the arguments."
|
|||||||
(bytes-var (car (last args 2)))
|
(bytes-var (car (last args 2)))
|
||||||
(pc-var (car (last args))))
|
(pc-var (car (last args))))
|
||||||
`(setq ,bytes-var ,(if (null (cdr byte-exprs))
|
`(setq ,bytes-var ,(if (null (cdr byte-exprs))
|
||||||
`(cons ,@byte-exprs ,bytes-var)
|
`(progn (assert (<= 0 ,(car byte-exprs)))
|
||||||
`(nconc (list ,@(reverse byte-exprs)) ,bytes-var))
|
(cons ,@byte-exprs ,bytes-var))
|
||||||
,pc-var (+ ,(length byte-exprs) ,pc-var))))
|
`(nconc (list ,@(reverse byte-exprs)) ,bytes-var))
|
||||||
|
,pc-var (+ ,(length byte-exprs) ,pc-var))))
|
||||||
|
|
||||||
(defmacro byte-compile-push-bytecode-const2 (opcode const2 bytes pc)
|
(defmacro byte-compile-push-bytecode-const2 (opcode const2 bytes pc)
|
||||||
"Push OPCODE and the two-byte constant CONST2 onto BYTES, and add 3 to PC.
|
"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."
|
|||||||
;; These insns all put their operand into one extra byte.
|
;; These insns all put their operand into one extra byte.
|
||||||
(byte-compile-push-bytecodes opcode off bytes pc))
|
(byte-compile-push-bytecodes opcode off bytes pc))
|
||||||
((= opcode byte-discardN)
|
((= opcode byte-discardN)
|
||||||
;; byte-discardN is wierd in that it encodes a flag in the
|
;; byte-discardN is weird in that it encodes a flag in the
|
||||||
;; top bit of its one-byte argument. If the argument is
|
;; top bit of its one-byte argument. If the argument is
|
||||||
;; too large to fit in 7 bits, the opcode can be repeated.
|
;; too large to fit in 7 bits, the opcode can be repeated.
|
||||||
(let ((flag (if (eq op 'byte-discardN-preserve-tos) #x80 0)))
|
(let ((flag (if (eq op 'byte-discardN-preserve-tos) #x80 0)))
|
||||||
@ -1330,11 +1331,11 @@ extra args."
|
|||||||
(eq 'lambda (car-safe (cdr-safe old)))
|
(eq 'lambda (car-safe (cdr-safe old)))
|
||||||
(setq old (cdr old)))
|
(setq old (cdr old)))
|
||||||
(let ((sig1 (byte-compile-arglist-signature
|
(let ((sig1 (byte-compile-arglist-signature
|
||||||
(if (eq 'lambda (car-safe old))
|
(pcase old
|
||||||
(nth 1 old)
|
(`(lambda ,args . ,_) args)
|
||||||
(if (byte-code-function-p old)
|
(`(closure ,_ ,_ ,args . ,_) args)
|
||||||
(aref old 0)
|
((pred byte-code-function-p) (aref old 0))
|
||||||
'(&rest def)))))
|
(t '(&rest def)))))
|
||||||
(sig2 (byte-compile-arglist-signature (nth 2 form))))
|
(sig2 (byte-compile-arglist-signature (nth 2 form))))
|
||||||
(unless (byte-compile-arglist-signatures-congruent-p sig1 sig2)
|
(unless (byte-compile-arglist-signatures-congruent-p sig1 sig2)
|
||||||
(byte-compile-set-symbol-position (nth 1 form))
|
(byte-compile-set-symbol-position (nth 1 form))
|
||||||
@ -1402,14 +1403,7 @@ extra args."
|
|||||||
;; but such warnings are never useful,
|
;; but such warnings are never useful,
|
||||||
;; so don't warn about them.
|
;; so don't warn about them.
|
||||||
macroexpand cl-macroexpand-all
|
macroexpand cl-macroexpand-all
|
||||||
cl-compiling-file)))
|
cl-compiling-file))))
|
||||||
;; Avoid warnings for things which are safe because they
|
|
||||||
;; have suitable compiler macros, but those aren't
|
|
||||||
;; expanded at this stage. There should probably be more
|
|
||||||
;; here than caaar and friends.
|
|
||||||
(not (and (eq (get func 'byte-compile)
|
|
||||||
'cl-byte-compile-compiler-macro)
|
|
||||||
(string-match "\\`c[ad]+r\\'" (symbol-name func)))))
|
|
||||||
(byte-compile-warn "function `%s' from cl package called at runtime"
|
(byte-compile-warn "function `%s' from cl package called at runtime"
|
||||||
func)))
|
func)))
|
||||||
form)
|
form)
|
||||||
@ -2701,8 +2695,8 @@ If FORM is a lambda or a macro, byte-compile it as a function."
|
|||||||
(if (eq (car-safe form) 'list)
|
(if (eq (car-safe form) 'list)
|
||||||
(byte-compile-top-level (nth 1 bytecomp-int))
|
(byte-compile-top-level (nth 1 bytecomp-int))
|
||||||
(setq bytecomp-int (list 'interactive
|
(setq bytecomp-int (list 'interactive
|
||||||
(byte-compile-top-level
|
(byte-compile-top-level
|
||||||
(nth 1 bytecomp-int)))))))
|
(nth 1 bytecomp-int)))))))
|
||||||
((cdr bytecomp-int)
|
((cdr bytecomp-int)
|
||||||
(byte-compile-warn "malformed interactive spec: %s"
|
(byte-compile-warn "malformed interactive spec: %s"
|
||||||
(prin1-to-string bytecomp-int)))))
|
(prin1-to-string bytecomp-int)))))
|
||||||
@ -2788,6 +2782,9 @@ If FORM is a lambda or a macro, byte-compile it as a function."
|
|||||||
(byte-compile-tag-number 0)
|
(byte-compile-tag-number 0)
|
||||||
(byte-compile-depth 0)
|
(byte-compile-depth 0)
|
||||||
(byte-compile-maxdepth 0)
|
(byte-compile-maxdepth 0)
|
||||||
|
(byte-compile-lexical-environment
|
||||||
|
(when (eq output-type 'lambda)
|
||||||
|
byte-compile-lexical-environment))
|
||||||
(byte-compile-output nil))
|
(byte-compile-output nil))
|
||||||
(if (memq byte-optimize '(t source))
|
(if (memq byte-optimize '(t source))
|
||||||
(setq form (byte-optimize-form form for-effect)))
|
(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."
|
|||||||
(stringp (nth 1 form)) (vectorp (nth 2 form))
|
(stringp (nth 1 form)) (vectorp (nth 2 form))
|
||||||
(natnump (nth 3 form)))
|
(natnump (nth 3 form)))
|
||||||
form
|
form
|
||||||
;; Set up things for a lexically-bound function
|
;; Set up things for a lexically-bound function.
|
||||||
(when (and lexical-binding (eq output-type 'lambda))
|
(when (and lexical-binding (eq output-type 'lambda))
|
||||||
;; See how many arguments there are, and set the current stack depth
|
;; See how many arguments there are, and set the current stack depth
|
||||||
;; accordingly
|
;; accordingly.
|
||||||
(dolist (var byte-compile-lexical-environment)
|
(setq byte-compile-depth (length byte-compile-lexical-environment))
|
||||||
(setq byte-compile-depth (1+ byte-compile-depth)))
|
|
||||||
;; If there are args, output a tag to record the initial
|
;; If there are args, output a tag to record the initial
|
||||||
;; stack-depth for the optimizer
|
;; stack-depth for the optimizer.
|
||||||
(when (> byte-compile-depth 0)
|
(when (> byte-compile-depth 0)
|
||||||
(byte-compile-out-tag (byte-compile-make-tag))))
|
(byte-compile-out-tag (byte-compile-make-tag))))
|
||||||
;; Now compile FORM
|
;; Now compile FORM
|
||||||
@ -2964,9 +2960,10 @@ That command is designed for interactive use only" bytecomp-fn))
|
|||||||
;; for CL compiler macros since the symbol may be
|
;; for CL compiler macros since the symbol may be
|
||||||
;; `cl-byte-compile-compiler-macro' but if CL isn't
|
;; `cl-byte-compile-compiler-macro' but if CL isn't
|
||||||
;; loaded, this function doesn't exist.
|
;; loaded, this function doesn't exist.
|
||||||
(or (not (memq bytecomp-handler
|
(and (not (eq bytecomp-handler
|
||||||
'(cl-byte-compile-compiler-macro)))
|
;; Already handled by macroexpand-all.
|
||||||
(functionp bytecomp-handler)))
|
'cl-byte-compile-compiler-macro))
|
||||||
|
(functionp bytecomp-handler)))
|
||||||
(funcall bytecomp-handler form)
|
(funcall bytecomp-handler form)
|
||||||
(byte-compile-normal-call form))
|
(byte-compile-normal-call form))
|
||||||
(if (byte-compile-warning-enabled-p 'cl-functions)
|
(if (byte-compile-warning-enabled-p 'cl-functions)
|
||||||
@ -3612,7 +3609,7 @@ discarding."
|
|||||||
(byte-defop-compiler-1 while)
|
(byte-defop-compiler-1 while)
|
||||||
(byte-defop-compiler-1 funcall)
|
(byte-defop-compiler-1 funcall)
|
||||||
(byte-defop-compiler-1 let)
|
(byte-defop-compiler-1 let)
|
||||||
(byte-defop-compiler-1 let*)
|
(byte-defop-compiler-1 let* byte-compile-let)
|
||||||
|
|
||||||
(defun byte-compile-progn (form)
|
(defun byte-compile-progn (form)
|
||||||
(byte-compile-body-do-effect (cdr form)))
|
(byte-compile-body-do-effect (cdr form)))
|
||||||
@ -3819,10 +3816,8 @@ Return the offset in the form (VAR . OFFSET)."
|
|||||||
(byte-compile-push-constant nil)))))
|
(byte-compile-push-constant nil)))))
|
||||||
|
|
||||||
(defun byte-compile-not-lexical-var-p (var)
|
(defun byte-compile-not-lexical-var-p (var)
|
||||||
(or (not (symbolp var)) ; form is not a list
|
(or (not (symbolp var))
|
||||||
(if (eval-when-compile (fboundp 'special-variable-p))
|
(special-variable-p var)
|
||||||
(special-variable-p var)
|
|
||||||
(boundp var))
|
|
||||||
(memq var byte-compile-bound-variables)
|
(memq var byte-compile-bound-variables)
|
||||||
(memq var '(nil t))
|
(memq var '(nil t))
|
||||||
(keywordp var)))
|
(keywordp var)))
|
||||||
@ -3833,9 +3828,8 @@ INIT-LEXENV should be a lexical-environment alist describing the
|
|||||||
positions of the init value that have been pushed on the stack.
|
positions of the init value that have been pushed on the stack.
|
||||||
Return non-nil if the TOS value was popped."
|
Return non-nil if the TOS value was popped."
|
||||||
;; The presence of lexical bindings mean that we may have to
|
;; The presence of lexical bindings mean that we may have to
|
||||||
;; juggle things on the stack, either to move them to TOS for
|
;; juggle things on the stack, to move them to TOS for
|
||||||
;; dynamic binding, or to put them in a non-stack environment
|
;; dynamic binding.
|
||||||
;; vector.
|
|
||||||
(cond ((not (byte-compile-not-lexical-var-p var))
|
(cond ((not (byte-compile-not-lexical-var-p var))
|
||||||
;; VAR is a simple stack-allocated lexical variable
|
;; VAR is a simple stack-allocated lexical variable
|
||||||
(push (assq var init-lexenv)
|
(push (assq var init-lexenv)
|
||||||
@ -3883,56 +3877,41 @@ binding slots have been popped."
|
|||||||
|
|
||||||
(defun byte-compile-let (form)
|
(defun byte-compile-let (form)
|
||||||
"Generate code for the `let' form FORM."
|
"Generate code for the `let' form FORM."
|
||||||
;; First compute the binding values in the old scope.
|
(let ((clauses (cadr form))
|
||||||
(let ((varlist (car (cdr form)))
|
(init-lexenv nil))
|
||||||
(init-lexenv nil))
|
(when (eq (car form) 'let)
|
||||||
(dolist (var varlist)
|
;; First compute the binding values in the old scope.
|
||||||
(push (byte-compile-push-binding-init var) init-lexenv))
|
(dolist (var clauses)
|
||||||
;; Now do the bindings, execute the body, and undo the bindings.
|
(push (byte-compile-push-binding-init var) init-lexenv)))
|
||||||
(let ((byte-compile-bound-variables byte-compile-bound-variables) ;new scope
|
;; New scope.
|
||||||
(varlist (reverse (car (cdr form))))
|
(let ((byte-compile-bound-variables byte-compile-bound-variables)
|
||||||
(byte-compile-lexical-environment byte-compile-lexical-environment))
|
(byte-compile-lexical-environment byte-compile-lexical-environment))
|
||||||
(dolist (var varlist)
|
;; Bind the variables.
|
||||||
(let ((var (if (consp var) (car var) var)))
|
;; For `let', do it in reverse order, because it makes no
|
||||||
(cond ((null lexical-binding)
|
;; semantic difference, but it is a lot more efficient since the
|
||||||
;; If there are no lexical bindings, we can do things simply.
|
;; values are now in reverse order on the stack.
|
||||||
(byte-compile-dynamic-variable-bind var))
|
(dolist (var (if (eq (car form) 'let) (reverse clauses) clauses))
|
||||||
((byte-compile-bind var init-lexenv)
|
(unless (eq (car form) 'let)
|
||||||
(pop init-lexenv)))))
|
(push (byte-compile-push-binding-init var) init-lexenv))
|
||||||
|
(let ((var (if (consp var) (car var) var)))
|
||||||
|
(cond ((null lexical-binding)
|
||||||
|
;; If there are no lexical bindings, we can do things simply.
|
||||||
|
(byte-compile-dynamic-variable-bind var))
|
||||||
|
((byte-compile-bind var init-lexenv)
|
||||||
|
(pop init-lexenv)))))
|
||||||
;; Emit the body.
|
;; Emit the body.
|
||||||
(byte-compile-body-do-effect (cdr (cdr form)))
|
(let ((init-stack-depth byte-compile-depth))
|
||||||
;; Unbind the variables.
|
(byte-compile-body-do-effect (cdr (cdr form)))
|
||||||
(if lexical-binding
|
;; Unbind the variables.
|
||||||
;; Unbind both lexical and dynamic variables.
|
(if lexical-binding
|
||||||
(byte-compile-unbind varlist init-lexenv t)
|
;; Unbind both lexical and dynamic variables.
|
||||||
;; Unbind dynamic variables.
|
(progn
|
||||||
(byte-compile-out 'byte-unbind (length varlist))))))
|
(assert (or (eq byte-compile-depth init-stack-depth)
|
||||||
|
(eq byte-compile-depth (1+ init-stack-depth))))
|
||||||
(defun byte-compile-let* (form)
|
(byte-compile-unbind clauses init-lexenv (> byte-compile-depth
|
||||||
"Generate code for the `let*' form FORM."
|
init-stack-depth)))
|
||||||
(let ((byte-compile-bound-variables byte-compile-bound-variables) ;new scope
|
;; Unbind dynamic variables.
|
||||||
(clauses (cadr form))
|
(byte-compile-out 'byte-unbind (length clauses)))))))
|
||||||
(init-lexenv nil)
|
|
||||||
;; bind these to restrict the scope of any changes
|
|
||||||
|
|
||||||
(byte-compile-lexical-environment byte-compile-lexical-environment))
|
|
||||||
;; Bind the variables
|
|
||||||
(dolist (var clauses)
|
|
||||||
(push (byte-compile-push-binding-init var) init-lexenv)
|
|
||||||
(let ((var (if (consp var) (car var) var)))
|
|
||||||
(cond ((null lexical-binding)
|
|
||||||
;; If there are no lexical bindings, we can do things simply.
|
|
||||||
(byte-compile-dynamic-variable-bind var))
|
|
||||||
((byte-compile-bind var init-lexenv)
|
|
||||||
(pop init-lexenv)))))
|
|
||||||
;; Emit the body
|
|
||||||
(byte-compile-body-do-effect (cdr (cdr form)))
|
|
||||||
;; Unbind the variables
|
|
||||||
(if lexical-binding
|
|
||||||
;; Unbind both lexical and dynamic variables
|
|
||||||
(byte-compile-unbind clauses init-lexenv t)
|
|
||||||
;; Unbind dynamic variables
|
|
||||||
(byte-compile-out 'byte-unbind (length clauses)))))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -4254,8 +4233,8 @@ binding slots have been popped."
|
|||||||
(progn
|
(progn
|
||||||
;; ## remove this someday
|
;; ## remove this someday
|
||||||
(and byte-compile-depth
|
(and byte-compile-depth
|
||||||
(not (= (cdr (cdr tag)) byte-compile-depth))
|
(not (= (cdr (cdr tag)) byte-compile-depth))
|
||||||
(error "Compiler bug: depth conflict at tag %d" (car (cdr tag))))
|
(error "Compiler bug: depth conflict at tag %d" (car (cdr tag))))
|
||||||
(setq byte-compile-depth (cdr (cdr tag))))
|
(setq byte-compile-depth (cdr (cdr tag))))
|
||||||
(setcdr (cdr tag) byte-compile-depth)))
|
(setcdr (cdr tag) byte-compile-depth)))
|
||||||
|
|
||||||
|
@ -70,6 +70,15 @@
|
|||||||
;;
|
;;
|
||||||
;;; Code:
|
;;; Code:
|
||||||
|
|
||||||
|
;;; TODO:
|
||||||
|
;; - Use abstract `make-closure' and `closure-ref' expressions, which bytecomp
|
||||||
|
;; should turn into building corresponding byte-code function.
|
||||||
|
;; - don't use `curry', instead build a new compiled-byte-code object
|
||||||
|
;; (merge the closure env into the static constants pool).
|
||||||
|
;; - use relative addresses for byte-code-stack-ref.
|
||||||
|
;; - warn about unused lexical vars.
|
||||||
|
;; - clean up cconv-closure-convert-rec, especially the `let' binding part.
|
||||||
|
|
||||||
(eval-when-compile (require 'cl))
|
(eval-when-compile (require 'cl))
|
||||||
|
|
||||||
(defconst cconv-liftwhen 3
|
(defconst cconv-liftwhen 3
|
||||||
@ -187,14 +196,14 @@ Returns a list of free variables."
|
|||||||
-- TOPLEVEL(optional) is a boolean variable, true if we are at the root of AST
|
-- TOPLEVEL(optional) is a boolean variable, true if we are at the root of AST
|
||||||
|
|
||||||
Returns a form where all lambdas don't have any free variables."
|
Returns a form where all lambdas don't have any free variables."
|
||||||
(message "Entering cconv-closure-convert...")
|
;; (message "Entering cconv-closure-convert...")
|
||||||
(let ((cconv-mutated '())
|
(let ((cconv-mutated '())
|
||||||
(cconv-lambda-candidates '())
|
(cconv-lambda-candidates '())
|
||||||
(cconv-captured '())
|
(cconv-captured '())
|
||||||
(cconv-captured+mutated '()))
|
(cconv-captured+mutated '()))
|
||||||
;; Analyse form - fill these variables with new information
|
;; Analyse form - fill these variables with new information.
|
||||||
(cconv-analyse-form form '() 0)
|
(cconv-analyse-form form '() 0)
|
||||||
;; Calculate an intersection of cconv-mutated and cconv-captured
|
;; Calculate an intersection of cconv-mutated and cconv-captured.
|
||||||
(dolist (mvr cconv-mutated)
|
(dolist (mvr cconv-mutated)
|
||||||
(when (memq mvr cconv-captured) ;
|
(when (memq mvr cconv-captured) ;
|
||||||
(push mvr cconv-captured+mutated)))
|
(push mvr cconv-captured+mutated)))
|
||||||
@ -216,14 +225,51 @@ Returns a form where all lambdas don't have any free variables."
|
|||||||
res))
|
res))
|
||||||
|
|
||||||
(defconst cconv--dummy-var (make-symbol "ignored"))
|
(defconst cconv--dummy-var (make-symbol "ignored"))
|
||||||
|
(defconst cconv--env-var (make-symbol "env"))
|
||||||
|
|
||||||
(defun cconv-closure-convert-rec
|
(defun cconv--set-diff (s1 s2)
|
||||||
(form emvrs fvrs envs lmenvs)
|
"Return elements of set S1 that are not in set S2."
|
||||||
|
(let ((res '()))
|
||||||
|
(dolist (x s1)
|
||||||
|
(unless (memq x s2) (push x res)))
|
||||||
|
(nreverse res)))
|
||||||
|
|
||||||
|
(defun cconv--set-diff-map (s m)
|
||||||
|
"Return elements of set S that are not in Dom(M)."
|
||||||
|
(let ((res '()))
|
||||||
|
(dolist (x s)
|
||||||
|
(unless (assq x m) (push x res)))
|
||||||
|
(nreverse res)))
|
||||||
|
|
||||||
|
(defun cconv--map-diff (m1 m2)
|
||||||
|
"Return the submap of map M1 that has Dom(M2) removed."
|
||||||
|
(let ((res '()))
|
||||||
|
(dolist (x m1)
|
||||||
|
(unless (assq (car x) m2) (push x res)))
|
||||||
|
(nreverse res)))
|
||||||
|
|
||||||
|
(defun cconv--map-diff-elem (m x)
|
||||||
|
"Return the map M minus any mapping for X."
|
||||||
|
;; Here we assume that X appears at most once in M.
|
||||||
|
(let* ((b (assq x m))
|
||||||
|
(res (if b (remq b m) m)))
|
||||||
|
(assert (null (assq x res))) ;; Check the assumption was warranted.
|
||||||
|
res))
|
||||||
|
|
||||||
|
(defun cconv--map-diff-set (m s)
|
||||||
|
"Return the map M minus any mapping for elements of S."
|
||||||
|
;; Here we assume that X appears at most once in M.
|
||||||
|
(let ((res '()))
|
||||||
|
(dolist (b m)
|
||||||
|
(unless (memq (car b) s) (push b res)))
|
||||||
|
(nreverse res)))
|
||||||
|
|
||||||
|
(defun cconv-closure-convert-rec (form emvrs fvrs envs lmenvs)
|
||||||
;; This function actually rewrites the tree.
|
;; This function actually rewrites the tree.
|
||||||
"Eliminates all free variables of all lambdas in given forms.
|
"Eliminates all free variables of all lambdas in given forms.
|
||||||
Arguments:
|
Arguments:
|
||||||
-- FORM is a piece of Elisp code after macroexpansion.
|
-- FORM is a piece of Elisp code after macroexpansion.
|
||||||
-- LMENVS is a list of environments used for lambda-lifting. Initially empty.
|
-- LMENVS is a list of environments used for lambda-lifting. Initially empty.
|
||||||
-- EMVRS is a list that contains mutated variables that are visible
|
-- EMVRS is a list that contains mutated variables that are visible
|
||||||
within current environment.
|
within current environment.
|
||||||
-- ENVS is an environment(list of free variables) of current closure.
|
-- 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."
|
|||||||
(setq lmenvs (remq old-lmenv lmenvs))
|
(setq lmenvs (remq old-lmenv lmenvs))
|
||||||
(push new-lmenv lmenvs)
|
(push new-lmenv lmenvs)
|
||||||
(push `(,closedsym ,var) binders-new))))
|
(push `(,closedsym ,var) binders-new))))
|
||||||
;; we push the element after redefined free variables
|
;; We push the element after redefined free variables are
|
||||||
;; are processes. this is important to avoid the bug
|
;; processed. This is important to avoid the bug when free
|
||||||
;; when free variable and the function have the same
|
;; variable and the function have the same name.
|
||||||
;; name
|
|
||||||
(push (list var new-val) binders-new)
|
(push (list var new-val) binders-new)
|
||||||
|
|
||||||
(when (eq letsym 'let*) ; update fvrs
|
(when (eq letsym 'let*) ; update fvrs
|
||||||
@ -355,11 +400,7 @@ Returns a form where all lambdas don't have any free variables."
|
|||||||
(when emvr-push
|
(when emvr-push
|
||||||
(push emvr-push emvrs)
|
(push emvr-push emvrs)
|
||||||
(setq emvr-push nil))
|
(setq emvr-push nil))
|
||||||
(let (lmenvs-1) ; remove var from lmenvs if redefined
|
(setq lmenvs (cconv--map-diff-elem lmenvs var))
|
||||||
(dolist (iter lmenvs)
|
|
||||||
(when (not (assq var lmenvs))
|
|
||||||
(push iter lmenvs-1)))
|
|
||||||
(setq lmenvs lmenvs-1))
|
|
||||||
(when lmenv-push
|
(when lmenv-push
|
||||||
(push lmenv-push lmenvs)
|
(push lmenv-push lmenvs)
|
||||||
(setq lmenv-push nil)))
|
(setq lmenv-push nil)))
|
||||||
@ -368,19 +409,10 @@ Returns a form where all lambdas don't have any free variables."
|
|||||||
|
|
||||||
(let (var fvrs-1 emvrs-1 lmenvs-1)
|
(let (var fvrs-1 emvrs-1 lmenvs-1)
|
||||||
;; Here we update emvrs, fvrs and lmenvs lists
|
;; Here we update emvrs, fvrs and lmenvs lists
|
||||||
(dolist (vr fvrs)
|
(setq fvrs (cconv--set-diff-map fvrs binders-new))
|
||||||
; safely remove
|
(setq emvrs (cconv--set-diff-map emvrs binders-new))
|
||||||
(when (not (assq vr binders-new)) (push vr fvrs-1)))
|
|
||||||
(setq fvrs fvrs-1)
|
|
||||||
(dolist (vr emvrs)
|
|
||||||
; safely remove
|
|
||||||
(when (not (assq vr binders-new)) (push vr emvrs-1)))
|
|
||||||
(setq emvrs emvrs-1)
|
|
||||||
; push new
|
|
||||||
(setq emvrs (append emvrs emvrs-new))
|
(setq emvrs (append emvrs emvrs-new))
|
||||||
(dolist (vr lmenvs)
|
(setq lmenvs (cconv--set-diff-map lmenvs binders-new))
|
||||||
(when (not (assq (car vr) binders-new))
|
|
||||||
(push vr lmenvs-1)))
|
|
||||||
(setq lmenvs (append lmenvs lmenvs-new)))
|
(setq lmenvs (append lmenvs lmenvs-new)))
|
||||||
|
|
||||||
;; Here we do the same letbinding as for let* above
|
;; 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."
|
|||||||
(symbol-name var))))
|
(symbol-name var))))
|
||||||
|
|
||||||
(setq new-lmenv (list (car lmenv)))
|
(setq new-lmenv (list (car lmenv)))
|
||||||
(dolist (frv (cdr lmenv)) (if (eq frv var)
|
(dolist (frv (cdr lmenv))
|
||||||
(push closedsym new-lmenv)
|
(push (if (eq frv var) closedsym frv)
|
||||||
(push frv new-lmenv)))
|
new-lmenv))
|
||||||
(setq new-lmenv (reverse new-lmenv))
|
(setq new-lmenv (reverse new-lmenv))
|
||||||
(setq lmenvs (remq lmenv lmenvs))
|
(setq lmenvs (remq lmenv lmenvs))
|
||||||
(push new-lmenv lmenvs)
|
(push new-lmenv lmenvs)
|
||||||
@ -449,13 +481,9 @@ Returns a form where all lambdas don't have any free variables."
|
|||||||
(`(quote . ,_) form) ; quote form
|
(`(quote . ,_) form) ; quote form
|
||||||
|
|
||||||
(`(function . ((lambda ,vars . ,body-forms))) ; function form
|
(`(function . ((lambda ,vars . ,body-forms))) ; function form
|
||||||
(let (fvrs-new) ; we remove vars from fvrs
|
(let* ((fvrs-new (cconv--set-diff fvrs vars)) ; Remove vars from fvrs.
|
||||||
(dolist (elm fvrs) ;i use such a tricky way to avoid side effects
|
(fv (delete-dups (cconv-freevars form '())))
|
||||||
(when (not (memq elm vars))
|
(leave fvrs-new) ; leave=non-nil if we should leave env unchanged.
|
||||||
(push elm fvrs-new)))
|
|
||||||
(setq fvrs fvrs-new))
|
|
||||||
(let* ((fv (delete-dups (cconv-freevars form '())))
|
|
||||||
(leave fvrs) ; leave = non nil if we should leave env unchanged
|
|
||||||
(body-forms-new '())
|
(body-forms-new '())
|
||||||
(letbind '())
|
(letbind '())
|
||||||
(mv nil)
|
(mv nil)
|
||||||
@ -470,7 +498,7 @@ Returns a form where all lambdas don't have any free variables."
|
|||||||
(if (eq (length envs) (length fv))
|
(if (eq (length envs) (length fv))
|
||||||
(let ((fv-temp fv))
|
(let ((fv-temp fv))
|
||||||
(while (and fv-temp leave)
|
(while (and fv-temp leave)
|
||||||
(when (not (memq (car fv-temp) fvrs)) (setq leave nil))
|
(when (not (memq (car fv-temp) fvrs-new)) (setq leave nil))
|
||||||
(setq fv-temp (cdr fv-temp))))
|
(setq fv-temp (cdr fv-temp))))
|
||||||
(setq leave nil))
|
(setq leave nil))
|
||||||
|
|
||||||
@ -479,23 +507,30 @@ Returns a form where all lambdas don't have any free variables."
|
|||||||
(dolist (elm fv)
|
(dolist (elm fv)
|
||||||
(push
|
(push
|
||||||
(cconv-closure-convert-rec
|
(cconv-closure-convert-rec
|
||||||
|
;; Remove `elm' from `emvrs' for this call because in case
|
||||||
|
;; `elm' is a variable that's wrapped in a cons-cell, we
|
||||||
|
;; want to put the cons-cell itself in the closure, rather
|
||||||
|
;; than just a copy of its current content.
|
||||||
elm (remq elm emvrs) fvrs envs lmenvs)
|
elm (remq elm emvrs) fvrs envs lmenvs)
|
||||||
envector)) ; process vars for closure vector
|
envector)) ; Process vars for closure vector.
|
||||||
(setq envector (reverse envector))
|
(setq envector (reverse envector))
|
||||||
(setq envs fv))
|
(setq envs fv))
|
||||||
(setq envector `(env))) ; leave unchanged
|
(setq envector `(,cconv--env-var))) ; Leave unchanged.
|
||||||
(setq fvrs fv)) ; update substitution list
|
(setq fvrs-new fv)) ; Update substitution list.
|
||||||
|
|
||||||
;; the difference between envs and fvrs is explained
|
(setq emvrs (cconv--set-diff emvrs vars))
|
||||||
;; in comment in the beginning of the function
|
(setq lmenvs (cconv--map-diff-set lmenvs vars))
|
||||||
(dolist (elm cconv-captured+mutated) ; find mutated arguments
|
|
||||||
(setq mv (car elm)) ; used in inner closures
|
;; The difference between envs and fvrs is explained
|
||||||
|
;; in comment in the beginning of the function.
|
||||||
|
(dolist (elm cconv-captured+mutated) ; Find mutated arguments
|
||||||
|
(setq mv (car elm)) ; used in inner closures.
|
||||||
(when (and (memq mv vars) (eq form (caddr elm)))
|
(when (and (memq mv vars) (eq form (caddr elm)))
|
||||||
(progn (push mv emvrs)
|
(progn (push mv emvrs)
|
||||||
(push `(,mv (list ,mv)) letbind))))
|
(push `(,mv (list ,mv)) letbind))))
|
||||||
(dolist (elm body-forms) ; convert function body
|
(dolist (elm body-forms) ; convert function body
|
||||||
(push (cconv-closure-convert-rec
|
(push (cconv-closure-convert-rec
|
||||||
elm emvrs fvrs envs lmenvs)
|
elm emvrs fvrs-new envs lmenvs)
|
||||||
body-forms-new))
|
body-forms-new))
|
||||||
|
|
||||||
(setq body-forms-new
|
(setq body-forms-new
|
||||||
@ -509,12 +544,12 @@ Returns a form where all lambdas don't have any free variables."
|
|||||||
; 1 free variable - do not build vector
|
; 1 free variable - do not build vector
|
||||||
((null (cdr envector))
|
((null (cdr envector))
|
||||||
`(curry
|
`(curry
|
||||||
(function (lambda (env . ,vars) . ,body-forms-new))
|
(function (lambda (,cconv--env-var . ,vars) . ,body-forms-new))
|
||||||
,(car envector)))
|
,(car envector)))
|
||||||
; >=2 free variables - build vector
|
; >=2 free variables - build vector
|
||||||
(t
|
(t
|
||||||
`(curry
|
`(curry
|
||||||
(function (lambda (env . ,vars) . ,body-forms-new))
|
(function (lambda (,cconv--env-var . ,vars) . ,body-forms-new))
|
||||||
(vector . ,envector))))))
|
(vector . ,envector))))))
|
||||||
|
|
||||||
(`(function . ,_) form) ; same as quote
|
(`(function . ,_) form) ; same as quote
|
||||||
@ -674,13 +709,10 @@ Returns a form where all lambdas don't have any free variables."
|
|||||||
(let ((free (memq form fvrs)))
|
(let ((free (memq form fvrs)))
|
||||||
(if free ;form is a free variable
|
(if free ;form is a free variable
|
||||||
(let* ((numero (- (length fvrs) (length free)))
|
(let* ((numero (- (length fvrs) (length free)))
|
||||||
(var '()))
|
(var (if (null (cdr envs))
|
||||||
(assert numero)
|
cconv--env-var
|
||||||
(if (null (cdr envs))
|
;; Replace form => (aref env #)
|
||||||
(setq var 'env)
|
`(aref ,cconv--env-var ,numero))))
|
||||||
;replace form =>
|
|
||||||
;(aref env #)
|
|
||||||
(setq var `(aref env ,numero)))
|
|
||||||
(if (memq form emvrs) ; form => (car (aref env #)) if mutable
|
(if (memq form emvrs) ; form => (car (aref env #)) if mutable
|
||||||
`(car ,var)
|
`(car ,var)
|
||||||
var))
|
var))
|
||||||
|
@ -282,7 +282,7 @@ Not documented
|
|||||||
;;;;;; do-all-symbols do-symbols dotimes dolist do* do loop return-from
|
;;;;;; do-all-symbols do-symbols dotimes dolist do* do loop return-from
|
||||||
;;;;;; return block etypecase typecase ecase case load-time-value
|
;;;;;; return block etypecase typecase ecase case load-time-value
|
||||||
;;;;;; eval-when destructuring-bind function* defmacro* defun* gentemp
|
;;;;;; eval-when destructuring-bind function* defmacro* defun* gentemp
|
||||||
;;;;;; gensym) "cl-macs" "cl-macs.el" "0904b956872432ae7cc5fa9abcefce63")
|
;;;;;; gensym) "cl-macs" "cl-macs.el" "7602128fa01003de9a8df4c752865300")
|
||||||
;;; Generated autoloads from cl-macs.el
|
;;; Generated autoloads from cl-macs.el
|
||||||
|
|
||||||
(autoload 'gensym "cl-macs" "\
|
(autoload 'gensym "cl-macs" "\
|
||||||
|
@ -602,7 +602,13 @@ called from BODY."
|
|||||||
|
|
||||||
(put 'cl-block-wrapper 'byte-compile 'cl-byte-compile-block)
|
(put 'cl-block-wrapper 'byte-compile 'cl-byte-compile-block)
|
||||||
(defun cl-byte-compile-block (cl-form)
|
(defun cl-byte-compile-block (cl-form)
|
||||||
(if (fboundp 'byte-compile-form-do-effect) ; Check for optimizing compiler
|
;; Here we try to determine if a catch tag is used or not, so as to get rid
|
||||||
|
;; of the catch when it's not used.
|
||||||
|
(if (and (fboundp 'byte-compile-form-do-effect) ; Optimizing compiler?
|
||||||
|
;; FIXME: byte-compile-top-level can only be used for code that is
|
||||||
|
;; closed (as the name implies), so for lexical scoping we should
|
||||||
|
;; implement this optimization differently.
|
||||||
|
(not lexical-binding))
|
||||||
(progn
|
(progn
|
||||||
(let* ((cl-entry (cons (nth 1 (nth 1 (nth 1 cl-form))) nil))
|
(let* ((cl-entry (cons (nth 1 (nth 1 (nth 1 cl-form))) nil))
|
||||||
(cl-active-block-names (cons cl-entry cl-active-block-names))
|
(cl-active-block-names (cons cl-entry cl-active-block-names))
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
;;; -*- lexical-binding: t -*-
|
;;; pcase.el --- ML-style pattern-matching macro for Elisp -*- lexical-binding: t -*-
|
||||||
;;; pcase.el --- ML-style pattern-matching macro for Elisp
|
|
||||||
|
|
||||||
;; Copyright (C) 2010-2011 Free Software Foundation, Inc.
|
;; Copyright (C) 2010-2011 Free Software Foundation, Inc.
|
||||||
|
|
||||||
|
@ -2851,18 +2851,19 @@ asking you for confirmation."
|
|||||||
;;
|
;;
|
||||||
;; For variables defined in the C source code the declaration should go here:
|
;; For variables defined in the C source code the declaration should go here:
|
||||||
|
|
||||||
(mapc (lambda (pair)
|
(dolist (pair
|
||||||
(put (car pair) 'safe-local-variable (cdr pair)))
|
'((buffer-read-only . booleanp) ;; C source code
|
||||||
'((buffer-read-only . booleanp) ;; C source code
|
(default-directory . stringp) ;; C source code
|
||||||
(default-directory . stringp) ;; C source code
|
(fill-column . integerp) ;; C source code
|
||||||
(fill-column . integerp) ;; C source code
|
(indent-tabs-mode . booleanp) ;; C source code
|
||||||
(indent-tabs-mode . booleanp) ;; C source code
|
(left-margin . integerp) ;; C source code
|
||||||
(left-margin . integerp) ;; C source code
|
(no-update-autoloads . booleanp)
|
||||||
(no-update-autoloads . booleanp)
|
(lexical-binding . booleanp) ;; C source code
|
||||||
(tab-width . integerp) ;; C source code
|
(tab-width . integerp) ;; C source code
|
||||||
(truncate-lines . booleanp) ;; C source code
|
(truncate-lines . booleanp) ;; C source code
|
||||||
(word-wrap . booleanp) ;; C source code
|
(word-wrap . booleanp) ;; C source code
|
||||||
(bidi-display-reordering . booleanp))) ;; C source code
|
(bidi-display-reordering . booleanp))) ;; C source code
|
||||||
|
(put (car pair) 'safe-local-variable (cdr pair)))
|
||||||
|
|
||||||
(put 'bidi-paragraph-direction 'safe-local-variable
|
(put 'bidi-paragraph-direction 'safe-local-variable
|
||||||
(lambda (v) (memq v '(nil right-to-left left-to-right))))
|
(lambda (v) (memq v '(nil right-to-left left-to-right))))
|
||||||
|
@ -530,7 +530,7 @@ suitable file is found, return nil."
|
|||||||
(let ((fill-begin (point)))
|
(let ((fill-begin (point)))
|
||||||
(insert (car high) "\n")
|
(insert (car high) "\n")
|
||||||
(fill-region fill-begin (point)))
|
(fill-region fill-begin (point)))
|
||||||
(setq doc (cdr high))))
|
(setq doc (cdr high))))
|
||||||
(let* ((obsolete (and
|
(let* ((obsolete (and
|
||||||
;; function might be a lambda construct.
|
;; function might be a lambda construct.
|
||||||
(symbolp function)
|
(symbolp function)
|
||||||
|
@ -1,3 +1,13 @@
|
|||||||
|
2011-02-17 Stefan Monnier <monnier@iro.umontreal.ca>
|
||||||
|
|
||||||
|
* 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):
|
||||||
|
* data.c (Finteractive_form): Understand `closure's.
|
||||||
|
|
||||||
|
* bytecode.c (exec_byte_code): Fix handling of &rest.
|
||||||
|
|
||||||
2011-02-12 Stefan Monnier <monnier@iro.umontreal.ca>
|
2011-02-12 Stefan Monnier <monnier@iro.umontreal.ca>
|
||||||
|
|
||||||
* bytecode.c (Bvec_ref, Bvec_set): Remove.
|
* bytecode.c (Bvec_ref, Bvec_set): Remove.
|
||||||
|
@ -500,7 +500,9 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth,
|
|||||||
optional = 1;
|
optional = 1;
|
||||||
else if (EQ (XCAR (at), Qand_rest))
|
else if (EQ (XCAR (at), Qand_rest))
|
||||||
{
|
{
|
||||||
PUSH (Flist (nargs, args));
|
PUSH (pushed < nargs
|
||||||
|
? Flist (nargs - pushed, args)
|
||||||
|
: Qnil);
|
||||||
pushed = nargs;
|
pushed = nargs;
|
||||||
at = Qnil;
|
at = Qnil;
|
||||||
break;
|
break;
|
||||||
|
@ -755,6 +755,8 @@ Value, if non-nil, is a list \(interactive SPEC). */)
|
|||||||
else if (CONSP (fun))
|
else if (CONSP (fun))
|
||||||
{
|
{
|
||||||
Lisp_Object funcar = XCAR (fun);
|
Lisp_Object funcar = XCAR (fun);
|
||||||
|
if (EQ (funcar, Qclosure))
|
||||||
|
fun = Fcdr (XCDR (fun)), funcar = Fcar (fun);
|
||||||
if (EQ (funcar, Qlambda))
|
if (EQ (funcar, Qlambda))
|
||||||
return Fassq (Qinteractive, Fcdr (XCDR (fun)));
|
return Fassq (Qinteractive, Fcdr (XCDR (fun)));
|
||||||
else if (EQ (funcar, Qautoload))
|
else if (EQ (funcar, Qautoload))
|
||||||
|
34
src/eval.c
34
src/eval.c
@ -78,16 +78,6 @@ Lisp_Object Vrun_hooks;
|
|||||||
|
|
||||||
Lisp_Object Vautoload_queue;
|
Lisp_Object Vautoload_queue;
|
||||||
|
|
||||||
/* When lexical binding is being used, this is non-nil, and contains an
|
|
||||||
alist of lexically-bound variable, or (t), indicating an empty
|
|
||||||
environment. The lisp name of this variable is
|
|
||||||
`internal-interpreter-environment'. Every element of this list
|
|
||||||
can be either a cons (VAR . VAL) specifying a lexical binding,
|
|
||||||
or a single symbol VAR indicating that this variable should use
|
|
||||||
dynamic scoping. */
|
|
||||||
|
|
||||||
Lisp_Object Vinternal_interpreter_environment;
|
|
||||||
|
|
||||||
/* Current number of specbindings allocated in specpdl. */
|
/* Current number of specbindings allocated in specpdl. */
|
||||||
|
|
||||||
EMACS_INT specpdl_size;
|
EMACS_INT specpdl_size;
|
||||||
@ -2092,9 +2082,11 @@ then strings and vectors are not accepted. */)
|
|||||||
if (!CONSP (fun))
|
if (!CONSP (fun))
|
||||||
return Qnil;
|
return Qnil;
|
||||||
funcar = XCAR (fun);
|
funcar = XCAR (fun);
|
||||||
|
if (EQ (funcar, Qclosure))
|
||||||
|
fun = Fcdr (XCDR (fun)), funcar = Fcar (fun);
|
||||||
if (EQ (funcar, Qlambda))
|
if (EQ (funcar, Qlambda))
|
||||||
return !NILP (Fassq (Qinteractive, Fcdr (XCDR (fun)))) ? Qt : if_prop;
|
return !NILP (Fassq (Qinteractive, Fcdr (XCDR (fun)))) ? Qt : if_prop;
|
||||||
if (EQ (funcar, Qautoload))
|
else if (EQ (funcar, Qautoload))
|
||||||
return !NILP (Fcar (Fcdr (Fcdr (XCDR (fun))))) ? Qt : if_prop;
|
return !NILP (Fcar (Fcdr (Fcdr (XCDR (fun))))) ? Qt : if_prop;
|
||||||
else
|
else
|
||||||
return Qnil;
|
return Qnil;
|
||||||
@ -3695,6 +3687,8 @@ mark_backtrace (void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EXFUN (Funintern, 2);
|
||||||
|
|
||||||
void
|
void
|
||||||
syms_of_eval (void)
|
syms_of_eval (void)
|
||||||
{
|
{
|
||||||
@ -3840,19 +3834,27 @@ DECL is a list `(declare ...)' containing the declarations.
|
|||||||
The value the function returns is not used. */);
|
The value the function returns is not used. */);
|
||||||
Vmacro_declaration_function = Qnil;
|
Vmacro_declaration_function = Qnil;
|
||||||
|
|
||||||
|
/* When lexical binding is being used,
|
||||||
|
vinternal_interpreter_environment is non-nil, and contains an alist
|
||||||
|
of lexically-bound variable, or (t), indicating an empty
|
||||||
|
environment. The lisp name of this variable would be
|
||||||
|
`internal-interpreter-environment' if it weren't hidden.
|
||||||
|
Every element of this list can be either a cons (VAR . VAL)
|
||||||
|
specifying a lexical binding, or a single symbol VAR indicating
|
||||||
|
that this variable should use dynamic scoping. */
|
||||||
Qinternal_interpreter_environment
|
Qinternal_interpreter_environment
|
||||||
= intern_c_string ("internal-interpreter-environment");
|
= intern_c_string ("internal-interpreter-environment");
|
||||||
staticpro (&Qinternal_interpreter_environment);
|
staticpro (&Qinternal_interpreter_environment);
|
||||||
#if 0 /* Don't export this variable to Elisp, so noone can mess with it
|
DEFVAR_LISP ("internal-interpreter-environment",
|
||||||
(Just imagine if someone makes it buffer-local). */
|
Vinternal_interpreter_environment,
|
||||||
DEFVAR__LISP ("internal-interpreter-environment",
|
|
||||||
Vinternal_interpreter_environment,
|
|
||||||
doc: /* If non-nil, the current lexical environment of the lisp interpreter.
|
doc: /* If non-nil, the current lexical environment of the lisp interpreter.
|
||||||
When lexical binding is not being used, this variable is nil.
|
When lexical binding is not being used, this variable is nil.
|
||||||
A value of `(t)' indicates an empty environment, otherwise it is an
|
A value of `(t)' indicates an empty environment, otherwise it is an
|
||||||
alist of active lexical bindings. */);
|
alist of active lexical bindings. */);
|
||||||
#endif
|
|
||||||
Vinternal_interpreter_environment = Qnil;
|
Vinternal_interpreter_environment = Qnil;
|
||||||
|
/* Don't export this variable to Elisp, so noone can mess with it
|
||||||
|
(Just imagine if someone makes it buffer-local). */
|
||||||
|
Funintern (Qinternal_interpreter_environment, Qnil);
|
||||||
|
|
||||||
Vrun_hooks = intern_c_string ("run-hooks");
|
Vrun_hooks = intern_c_string ("run-hooks");
|
||||||
staticpro (&Vrun_hooks);
|
staticpro (&Vrun_hooks);
|
||||||
|
@ -2855,7 +2855,7 @@ extern void syms_of_lread (void);
|
|||||||
|
|
||||||
/* Defined in eval.c */
|
/* Defined in eval.c */
|
||||||
extern Lisp_Object Qautoload, Qexit, Qinteractive, Qcommandp, Qdefun, Qmacro;
|
extern Lisp_Object Qautoload, Qexit, Qinteractive, Qcommandp, Qdefun, Qmacro;
|
||||||
extern Lisp_Object Qinhibit_quit;
|
extern Lisp_Object Qinhibit_quit, Qclosure;
|
||||||
extern Lisp_Object Vautoload_queue;
|
extern Lisp_Object Vautoload_queue;
|
||||||
extern Lisp_Object Vsignaling_function;
|
extern Lisp_Object Vsignaling_function;
|
||||||
extern int handling_signal;
|
extern int handling_signal;
|
||||||
|
Loading…
Reference in New Issue
Block a user