Commit d032d5e7 authored by Stefan Monnier's avatar Stefan Monnier
Browse files

* doc/lispref/variables.texi (Scope): Mention the availability of lexbind.

(Lexical Binding): New node.
* doc/lispref/eval.texi (Eval): Add `eval's new `lexical' arg.
* lisp/emacs-lisp/cconv.el (cconv-liftwhen): Increase threshold.
(cconv-closure-convert-rec): Convert interactive spec in empty lexenv.
(cconv-analyse-use): Improve unused vars warnings.
(cconv-analyse-form): Analyze interactive spec in empty lexenv.
* lisp/emacs-lisp/bytecomp.el (byte-compile-lambda): Always byte-compile
the interactive spec in lexical-binding mode.
(byte-compile-refresh-preloaded): Don't reload byte-compiler files.
* lisp/custom.el (custom-initialize-default): Use defvar.
(custom-declare-variable): Set the special-variable-p flag.
* lisp/help-fns.el (help-make-usage): Drop leading underscores.
* lisp/dired.el (dired-revert, dired-make-relative): Mark unused args.
(dired-unmark-all-files): Remove unused var `query'.
(dired-overwrite-confirmed): Declare.
(dired-restore-desktop-buffer): Don't use dynamically scoped arg names.
* lisp/mpc.el: Mark unused args.
(mpc--faster-toggle): Remove unused var `songnb'.
* lisp/server.el (server-kill-buffer-running): Move before first use.
* lisp/minibuffer.el: Mark unused args.
* src/callint.c (quotify_arg): Simplify the logic.
(Fcall_interactively): Use lexical binding when evaluating the
interactive spec of a lexically bound function.
parent 39605a34
......@@ -13,8 +13,8 @@
m4_ifndef([AC_AUTOCONF_VERSION],
[m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.67],,
[m4_warning([this file was generated for autoconf 2.67.
m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.68],,
[m4_warning([this file was generated for autoconf 2.68.
You have another version of autoconf. It may work, but is not guaranteed to.
If you have problems, you may need to regenerate the build system entirely.
To do so, use the procedure documented by the package, typically `autoreconf'.])])
......
This diff is collapsed.
2011-03-01 Stefan Monnier <monnier@iro.umontreal.ca>
* variables.texi (Scope): Mention the availability of lexical scoping.
(Lexical Binding): New node.
* eval.texi (Eval): Add `eval's new `lexical' arg.
2011-02-25 Stefan Monnier <monnier@iro.umontreal.ca>
* vol2.texi (Top):
......
......@@ -466,7 +466,8 @@ Functions
* Declaring Functions:: Telling the compiler that a function is defined.
* Function Safety:: Determining whether a function is safe to call.
* Related Topics:: Cross-references to specific Lisp primitives
that have a special bearing on how functions work.
that have a special bearing on how
functions work.
Lambda Expressions
......
......@@ -585,6 +585,11 @@ occurrence in a program being run. On rare occasions, you may need to
write code that evaluates a form that is computed at run time, such as
after reading a form from text being edited or getting one from a
property list. On these occasions, use the @code{eval} function.
Often @code{eval} is not needed and something else should be used instead.
For example, to get the value of a variable, while @code{eval} works,
@code{symbol-value} is preferable; or rather than store expressions
in a property list that then need to go through @code{eval}, it is better to
store functions instead that are then passed to @code{funcall}.
The functions and variables described in this section evaluate forms,
specify limits to the evaluation process, or record recently returned
......@@ -596,10 +601,13 @@ to store an expression in the data structure and evaluate it. Using
functions provides the ability to pass information to them as
arguments.
@defun eval form
@defun eval form &optional lexical
This is the basic function evaluating an expression. It evaluates
@var{form} in the current environment and returns the result. How the
evaluation proceeds depends on the type of the object (@pxref{Forms}).
@var{lexical} if non-nil means to evaluate @var{form} using lexical scoping
rules (@pxref{Lexical Binding}) instead of the default dynamic scoping used
historically in Emacs Lisp.
Since @code{eval} is a function, the argument expression that appears
in a call to @code{eval} is evaluated twice: once as preparation before
......
......@@ -25,22 +25,22 @@ textual Lisp program is written using the read syntax for the symbol
representing the variable.
@menu
* Global Variables:: Variable values that exist permanently, everywhere.
* Constant Variables:: Certain "variables" have values that never change.
* Local Variables:: Variable values that exist only temporarily.
* Void Variables:: Symbols that lack values.
* Defining Variables:: A definition says a symbol is used as a variable.
* Tips for Defining:: Things you should think about when you
* Global Variables:: Variable values that exist permanently, everywhere.
* Constant Variables:: Certain "variables" have values that never change.
* Local Variables:: Variable values that exist only temporarily.
* Void Variables:: Symbols that lack values.
* Defining Variables:: A definition says a symbol is used as a variable.
* Tips for Defining:: Things you should think about when you
define a variable.
* Accessing Variables:: Examining values of variables whose names
* Accessing Variables:: Examining values of variables whose names
are known only at run time.
* Setting Variables:: Storing new values in variables.
* Variable Scoping:: How Lisp chooses among local and global values.
* Buffer-Local Variables:: Variable values in effect only in one buffer.
* File Local Variables:: Handling local variable lists in files.
* Directory Local Variables:: Local variables common to all files in a directory.
* Frame-Local Variables:: Frame-local bindings for variables.
* Variable Aliases:: Variables that are aliases for other variables.
* Setting Variables:: Storing new values in variables.
* Variable Scoping:: How Lisp chooses among local and global values.
* Buffer-Local Variables:: Variable values in effect only in one buffer.
* File Local Variables:: Handling local variable lists in files.
* Directory Local Variables:: Local variables common to all files in a directory.
* Frame-Local Variables:: Frame-local bindings for variables.
* Variable Aliases:: Variables that are aliases for other variables.
* Variables with Restricted Values:: Non-constant variables whose value can
@emph{not} be an arbitrary Lisp object.
@end menu
......@@ -437,14 +437,18 @@ this reason, user options must be defined with @code{defvar}.
This special form defines @var{symbol} as a variable and can also
initialize and document it. The definition informs a person reading
your code that @var{symbol} is used as a variable that might be set or
changed. Note that @var{symbol} is not evaluated; the symbol to be
defined must appear explicitly in the @code{defvar}.
changed. It also declares this variable as @dfn{special}, meaning that it
should always use dynamic scoping rules. Note that @var{symbol} is not
evaluated; the symbol to be defined must appear explicitly in the
@code{defvar}.
If @var{symbol} is void and @var{value} is specified, @code{defvar}
evaluates it and sets @var{symbol} to the result. But if @var{symbol}
already has a value (i.e., it is not void), @var{value} is not even
evaluated, and @var{symbol}'s value remains unchanged. If @var{value}
is omitted, the value of @var{symbol} is not changed in any case.
evaluated, and @var{symbol}'s value remains unchanged.
If @var{value} is omitted, the value of @var{symbol} is not changed in any
case; instead, the only effect of @code{defvar} is to declare locally that this
variable exists elsewhere and should hence always use dynamic scoping rules.
If @var{symbol} has a buffer-local binding in the current buffer,
@code{defvar} operates on the default value, which is buffer-independent,
......@@ -881,7 +885,7 @@ the others.
@cindex extent
@cindex dynamic scoping
@cindex lexical scoping
Local bindings in Emacs Lisp have @dfn{indefinite scope} and
By default, local bindings in Emacs Lisp have @dfn{indefinite scope} and
@dfn{dynamic extent}. @dfn{Scope} refers to @emph{where} textually in
the source code the binding can be accessed. ``Indefinite scope'' means
that any part of the program can potentially access the variable
......@@ -893,6 +897,8 @@ lasts as long as the activation of the construct that established it.
@dfn{dynamic scoping}. By contrast, most programming languages use
@dfn{lexical scoping}, in which references to a local variable must be
located textually within the function or block that binds the variable.
Emacs can also support lexical scoping, upon request (@pxref{Lexical
Binding}).
@cindex CL note---special variables
@quotation
......@@ -901,11 +907,12 @@ dynamically scoped, like all variables in Emacs Lisp.
@end quotation
@menu
* Scope:: Scope means where in the program a value is visible.
* Scope:: Scope means where in the program a value is visible.
Comparison with other languages.
* Extent:: Extent means how long in time a value exists.
* Impl of Scope:: Two ways to implement dynamic scoping.
* Using Scoping:: How to use dynamic scoping carefully and avoid problems.
* Extent:: Extent means how long in time a value exists.
* Impl of Scope:: Two ways to implement dynamic scoping.
* Using Scoping:: How to use dynamic scoping carefully and avoid problems.
* Lexical Binding::
@end menu
@node Scope
......@@ -969,12 +976,12 @@ Here, when @code{foo} is called by @code{binder}, it binds @code{x}.
by @code{foo} instead of the one bound by @code{binder}.
@end itemize
Emacs Lisp uses dynamic scoping because simple implementations of
Emacs Lisp used dynamic scoping by default because simple implementations of
lexical scoping are slow. In addition, every Lisp system needs to offer
dynamic scoping at least as an option; if lexical scoping is the norm,
there must be a way to specify dynamic scoping instead for a particular
variable. It might not be a bad thing for Emacs to offer both, but
implementing it with dynamic scoping only was much easier.
dynamic scoping at least as an option; if lexical scoping is the norm, there
must be a way to specify dynamic scoping instead for a particular variable.
Nowadays, Emacs offers both, but the default is still to use exclusively
dynamic scoping.
@node Extent
@subsection Extent
......@@ -1088,6 +1095,48 @@ for inter-function usage. It also avoids a warning from the byte
compiler. Choose the variable's name to avoid name conflicts---don't
use short names like @code{x}.
@node Lexical Binding
@subsection Use of Lexical Scoping
Emacs Lisp can be evaluated in two different modes: in dynamic binding mode or
lexical binding mode. In dynamic binding mode, all local variables use dynamic
scoping, whereas in lexical binding mode variables that have been declared
@dfn{special} (i.e., declared with @code{defvar} or @code{defconst}) use
dynamic scoping and all others use lexical scoping.
@defvar lexical-binding
When non-nil, evaluation of Lisp code uses lexical scoping for non-special
local variables instead of dynamic scoping. If nil, dynamic scoping is used
for all local variables. This variable is typically set for a whole Elisp file
via file local variables (@pxref{File Local Variables}).
@end defvar
@defun special-variable-p SYMBOL
Return whether SYMBOL has been declared as a special variable, via
@code{defvar} or @code{defconst}.
@end defun
The use of a special variable as a formal argument in a function is generally
discouraged and its behavior in lexical binding mode is unspecified (it may use
lexical scoping sometimes and dynamic scoping other times).
Functions like @code{symbol-value}, @code{boundp}, or @code{set} only know
about dynamically scoped variables, so you cannot get the value of a lexical
variable via @code{symbol-value} and neither can you change it via @code{set}.
Another particularity is that code in the body of a @code{defun} or
@code{defmacro} cannot refer to surrounding lexical variables.
Evaluation of a @code{lambda} expression in lexical binding mode will not just
return that lambda expression unchanged, as in the dynamic binding case, but
will instead construct a new object that remembers the current lexical
environment in which that lambda expression was defined, so that the function
body can later be evaluated in the proper context. Those objects are called
@dfn{closures}. They are also functions, in the sense that they are accepted
by @code{funcall}, and they are represented by a cons cell whose @code{car} is
the symbol @code{closure}.
@node Buffer-Local Variables
@section Buffer-Local Variables
@cindex variable, buffer-local
......@@ -1103,9 +1152,9 @@ local to each terminal, or to each frame. @xref{Multiple Terminals},
and @xref{Frame-Local Variables}.)
@menu
* Intro to Buffer-Local:: Introduction and concepts.
* Creating Buffer-Local:: Creating and destroying buffer-local bindings.
* Default Value:: The default value is seen in buffers
* Intro to Buffer-Local:: Introduction and concepts.
* Creating Buffer-Local:: Creating and destroying buffer-local bindings.
* Default Value:: The default value is seen in buffers
that don't have their own buffer-local values.
@end menu
......
2011-03-01 Stefan Monnier <monnier@iro.umontreal.ca>
* emacs-lisp/cconv.el (cconv-liftwhen): Increase threshold.
(cconv-closure-convert-rec): Convert interactive spec in empty lexenv.
(cconv-analyse-use): Improve unused vars warnings.
(cconv-analyse-form): Analyze interactive spec in empty lexenv.
* emacs-lisp/bytecomp.el (byte-compile-lambda): Always byte-compile
the interactive spec in lexical-binding mode.
(byte-compile-refresh-preloaded): Don't reload byte-compiler files.
* custom.el (custom-initialize-default): Use defvar.
(custom-declare-variable): Set the special-variable-p flag.
* help-fns.el (help-make-usage): Drop leading underscores.
* dired.el (dired-revert, dired-make-relative): Mark unused args.
(dired-unmark-all-files): Remove unused var `query'.
(dired-overwrite-confirmed): Declare.
(dired-restore-desktop-buffer): Don't use dynamically scoped arg names.
* mpc.el: Mark unused args.
(mpc--faster-toggle): Remove unused var `songnb'.
* server.el (server-kill-buffer-running): Move before first use.
* minibuffer.el: Mark unused args.
2011-02-26 Stefan Monnier <monnier@iro.umontreal.ca>
* emacs-lisp/cconv.el (cconv-closure-convert-rec): Fix last change for
......@@ -335,6 +356,15 @@
Merge funvec patch.
2004-05-20 Miles Bader <miles@gnu.org>
* subr.el (functionp): Use `funvecp' instead of
`byte-compiled-function-p'.
* help-fns.el (describe-function-1): Describe curried functions
and other funvecs as such.
(help-highlight-arguments): Only format things that look like a
function.
2004-04-29 Miles Bader <miles@gnu.org>
* emacs-lisp/bytecomp.el (byte-compile-top-level): Add new entries
......
2004-05-20 Miles Bader <miles@gnu.org>
* subr.el (functionp): Use `funvecp' instead of
`byte-compiled-function-p'.
* help-fns.el (describe-function-1): Describe curried functions
and other funvecs as such.
(help-highlight-arguments): Only format things that look like a
function.
;; arch-tag: 87f75aac-de53-40d7-96c7-3befaa771cb1
......@@ -222,6 +222,9 @@ compile-onefile:
# cannot have prerequisites.
.el.elc:
@echo Compiling $<
@# The BIG_STACK_OPTS are only needed to byte-compile the byte-compiler
@# files, which is normally done in compile-first, but may also be
@# recompiled via this rule.
@$(emacs) $(BIG_STACK_OPTS) $(BYTE_COMPILE_EXTRA_FLAGS) \
-f batch-byte-compile $<
......
......@@ -55,11 +55,9 @@ Otherwise, if symbol has a `saved-value' property, it will evaluate
the car of that and use it as the default binding for symbol.
Otherwise, VALUE will be evaluated and used as the default binding for
symbol."
(unless (default-boundp symbol)
;; Use the saved value if it exists, otherwise the standard setting.
(set-default symbol (eval (if (get symbol 'saved-value)
(car (get symbol 'saved-value))
value)))))
(eval `(defvar ,symbol ,(if (get symbol 'saved-value)
(car (get symbol 'saved-value))
value))))
(defun custom-initialize-set (symbol value)
"Initialize SYMBOL based on VALUE.
......@@ -81,15 +79,15 @@ The value is either the symbol's current value
\(as obtained using the `:get' function), if any,
or the value in the symbol's `saved-value' property if any,
or (last of all) VALUE."
(funcall (or (get symbol 'custom-set) 'set-default)
symbol
(cond ((default-boundp symbol)
(funcall (or (get symbol 'custom-get) 'default-value)
symbol))
((get symbol 'saved-value)
(eval (car (get symbol 'saved-value))))
(t
(eval value)))))
(funcall (or (get symbol 'custom-set) 'set-default)
symbol
(cond ((default-boundp symbol)
(funcall (or (get symbol 'custom-get) 'default-value)
symbol))
((get symbol 'saved-value)
(eval (car (get symbol 'saved-value))))
(t
(eval value)))))
(defun custom-initialize-changed (symbol value)
"Initialize SYMBOL with VALUE.
......@@ -142,10 +140,8 @@ set to nil, as the value is no longer rogue."
;; Maybe this option was rogue in an earlier version. It no longer is.
(when (get symbol 'force-value)
(put symbol 'force-value nil))
(when doc
(if (keywordp doc)
(error "Doc string is missing")
(put symbol 'variable-documentation doc)))
(if (keywordp doc)
(error "Doc string is missing"))
(let ((initialize 'custom-initialize-reset)
(requests nil))
(unless (memq :group args)
......@@ -189,6 +185,13 @@ set to nil, as the value is no longer rogue."
;; Do the actual initialization.
(unless custom-dont-initialize
(funcall initialize symbol default)))
;; Use defvar to set the docstring as well as the special-variable-p flag.
;; FIXME: We should reproduce more of `defvar's behavior, such as the warning
;; when the var is currently let-bound.
(if (not (default-boundp symbol))
;; Don't use defvar to avoid setting a default-value when undesired.
(when doc (put symbol 'variable-documentation doc))
(eval `(defvar ,symbol nil ,@(when doc (list doc)))))
(push symbol current-load-list)
(run-hooks 'custom-define-hook)
symbol)
......
......@@ -1168,7 +1168,7 @@ If HDR is non-nil, insert a header line with the directory name."
;; Reverting a dired buffer
(defun dired-revert (&optional arg noconfirm)
(defun dired-revert (&optional _arg _noconfirm)
"Reread the dired buffer.
Must also be called after `dired-actual-switches' have changed.
Should not fail even on completely garbaged buffers.
......@@ -2129,7 +2129,7 @@ Optional arg GLOBAL means to replace all matches."
;; dired-get-filename.
(concat (or dir default-directory) file))
(defun dired-make-relative (file &optional dir ignore)
(defun dired-make-relative (file &optional dir _ignore)
"Convert FILE (an absolute file name) to a name relative to DIR.
If this is impossible, return FILE unchanged.
DIR must be a directory name, not a file name."
......@@ -3219,7 +3219,7 @@ Type \\[help-command] at that time for help."
(interactive "cRemove marks (RET means all): \nP")
(save-excursion
(let* ((count 0)
(inhibit-read-only t) case-fold-search query
(inhibit-read-only t) case-fold-search
(string (format "\n%c" mark))
(help-form "\
Type SPC or `y' to unmark one file, DEL or `n' to skip to next,
......@@ -3494,6 +3494,8 @@ Anything else means ask for each directory."
(declare-function dnd-get-local-file-name "dnd" (uri &optional must-exist))
(declare-function dnd-get-local-file-uri "dnd" (uri))
(defvar dired-overwrite-confirmed) ;Defined in dired-aux.
(defun dired-dnd-handle-local-file (uri action)
"Copy, move or link a file to the dired directory.
URI is the file to handle, ACTION is one of copy, move, link or ask.
......@@ -3572,21 +3574,21 @@ Ask means pop up a menu for the user to select one of copy, move or link."
(function (lambda (f) (desktop-file-name (car f) dirname)))
dired-subdir-alist)))))
(defun dired-restore-desktop-buffer (desktop-buffer-file-name
desktop-buffer-name
desktop-buffer-misc)
(defun dired-restore-desktop-buffer (_file-name
_buffer-name
misc-data)
"Restore a dired buffer specified in a desktop file."
;; First element of `desktop-buffer-misc' is the value of `dired-directory'.
;; First element of `misc-data' is the value of `dired-directory'.
;; This value is a directory name, optionally with shell wildcard or
;; a directory name followed by list of files.
(let* ((dired-dir (car desktop-buffer-misc))
(let* ((dired-dir (car misc-data))
(dir (if (consp dired-dir) (car dired-dir) dired-dir)))
(if (file-directory-p (file-name-directory dir))
(progn
(dired dired-dir)
;; The following elements of `desktop-buffer-misc' are the keys
;; The following elements of `misc-data' are the keys
;; from `dired-subdir-alist'.
(mapc 'dired-maybe-insert-subdir (cdr desktop-buffer-misc))
(mapc 'dired-maybe-insert-subdir (cdr misc-data))
(current-buffer))
(message "Desktop: Directory %s no longer exists." dir)
(when desktop-missing-file-warning (sit-for 1))
......
......@@ -308,6 +308,10 @@
;; ((lambda ...) ...)
(defun byte-compile-unfold-lambda (form &optional name)
;; In lexical-binding mode, let and functions don't bind vars in the same way
;; (let obey special-variable-p, but functions don't). This doesn't matter
;; here, because function's behavior is underspecified so it can safely be
;; turned into a `let', even though the reverse is not true.
(or name (setq name "anonymous lambda"))
(let ((lambda (car form))
(values (cdr form)))
......
......@@ -2563,6 +2563,7 @@ If FORM is a lambda or a macro, byte-compile it as a function."
;; b-c-lambda didn't produce a compiled-function, so it's either a trivial
;; function, or this is Emacs 18, or generate-emacs19-bytecodes is off.
((let (tmp)
;; FIXME: can this happen?
(if (and (setq tmp (assq 'byte-code (cdr-safe (cdr fun))))
(null (cdr (memq tmp fun))))
;; Generate a make-byte-code call.
......@@ -2587,7 +2588,7 @@ If FORM is a lambda or a macro, byte-compile it as a function."
(list 'quote fun))))))
;; Turn a function into an ordinary lambda. Needed for v18 files.
(defun byte-compile-byte-code-unmake (function)
(defun byte-compile-byte-code-unmake (function) ;FIXME: what is it?
(if (consp function)
function;;It already is a lambda.
(setq function (append function nil)) ; turn it into a list
......@@ -2685,16 +2686,19 @@ If FORM is a lambda or a macro, byte-compile it as a function."
;; compile it, because `call-interactively' looks at the
;; args of `list'. Actually, compile it to get warnings,
;; but don't use the result.
(let ((form (nth 1 bytecomp-int)))
(let* ((form (nth 1 bytecomp-int))
(newform (byte-compile-top-level form)))
(while (memq (car-safe form) '(let let* progn save-excursion))
(while (consp (cdr form))
(setq form (cdr form)))
(setq form (car form)))
(if (eq (car-safe form) 'list)
(byte-compile-top-level (nth 1 bytecomp-int))
(setq bytecomp-int (list 'interactive
(byte-compile-top-level
(nth 1 bytecomp-int)))))))
(if (and (eq (car-safe form) 'list)
;; The spec is evaled in callint.c in dynamic-scoping
;; mode, so just leaving the form unchanged would mean
;; it won't be eval'd in the right mode.
(not lexical-binding))
nil
(setq bytecomp-int `(interactive ,newform)))))
((cdr bytecomp-int)
(byte-compile-warn "malformed interactive spec: %s"
(prin1-to-string bytecomp-int)))))
......@@ -3826,7 +3830,6 @@ Return the offset in the form (VAR . OFFSET)."
(byte-compile-push-constant nil)))))
(defun byte-compile-not-lexical-var-p (var)
;; FIXME: this doesn't catch defcustoms!
(or (not (symbolp var))
(special-variable-p var)
(memq var byte-compile-bound-variables)
......@@ -4560,7 +4563,14 @@ Use with caution."
(setq f (car f))
(if (string-match "elc\\'" f) (setq f (substring f 0 -1)))
(when (and (file-readable-p f)
(file-newer-than-file-p f emacs-file))
(file-newer-than-file-p f emacs-file)
;; Don't reload the source version of the files below
;; because that causes subsequent byte-compilation to
;; be a lot slower and need a higher max-lisp-eval-depth,
;; so it can cause recompilation to fail.
(not (member (file-name-nondirectory f)
'("pcase.el" "bytecomp.el" "macroexp.el"
"cconv.el" "byte-opt.el"))))
(message "Reloading stale %s" (file-name-nondirectory f))
(condition-case nil
(load f 'noerror nil 'nosuffix)
......
......@@ -65,21 +65,54 @@
;;
;;; Code:
;;; TODO:
;; - pay attention to `interactive': its arg is run in an empty env.
;; TODO:
;; - canonize code in macro-expand so we don't have to handle (let (var) body)
;; and other oddities.
;; - Change new byte-code representation, so it directly gives the
;; number of mandatory and optional arguments as well as whether or
;; not there's a &rest arg.
;; - warn about unused lexical vars.
;; - clean up cconv-closure-convert-rec, especially the `let' binding part.
;; - new byte codes for unwind-protect, catch, and condition-case so that
;; closures aren't needed at all.
;; - a reference to a var that is known statically to always hold a constant
;; should be turned into a byte-constant rather than a byte-stack-ref.
;; Hmm... right, that's called constant propagation and could be done here
;; But when that constant is a function, we have to be careful to make sure
;; the bytecomp only compiles it once.
;; - Since we know here when a variable is not mutated, we could pass that
;; info to the byte-compiler, e.g. by using a new `immutable-let'.
;; - add tail-calls to bytecode.c and the bytecompiler.
;; (defmacro dlet (binders &rest body)
;; ;; Works in both lexical and non-lexical mode.
;; `(progn
;; ,@(mapcar (lambda (binder)
;; `(defvar ,(if (consp binder) (car binder) binder)))
;; binders)
;; (let ,binders ,@body)))
;; (defmacro llet (binders &rest body)
;; ;; Only works in lexical-binding mode.
;; `(funcall
;; (lambda ,(mapcar (lambda (binder) (if (consp binder) (car binder) binder))
;; binders)
;; ,@body)
;; ,@(mapcar (lambda (binder) (if (consp binder) (cadr binder)))
;; binders)))
;; (defmacro letrec (binders &rest body)
;; ;; Only useful in lexical-binding mode.
;; ;; As a special-form, we could implement it more efficiently (and cleanly,
;; ;; making the vars actually unbound during evaluation of the binders).
;; `(let ,(mapcar (lambda (binder) (if (consp binder) (car binder) binder))
;; binders)
;; ,@(delq nil (mapcar (lambda (binder) (if (consp binder) `(setq ,@binder)))
;; binders))
;; ,@body))
(eval-when-compile (require 'cl))
(defconst cconv-liftwhen 3
(defconst cconv-liftwhen 6
"Try to do lambda lifting if the number of arguments + free variables
is less than this number.")
;; List of all the variables that are both captured by a closure
......@@ -212,13 +245,13 @@ Returns a form where all lambdas don't have any free variables."
;; This function actually rewrites the tree.
"Eliminates all free variables of all lambdas in given forms.
Arguments:
-- FORM is a piece of Elisp code after macroexpansion.
-- LMENVS is a list of environments used for lambda-lifting. Initially empty.
-- EMVRS is a list that contains mutated variables that are visible
- FORM is a piece of Elisp code after macroexpansion.
- LMENVS is a list of environments used for lambda-lifting. Initially empty.
- EMVRS is a list that contains mutated variables that are visible
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.
Initially empty.
-- FVRS is a list of variables to substitute in each context.
- FVRS is a list of variables to substitute in each context.
Initially empty.
Returns a form where all lambdas don't have any free variables."
......@@ -270,10 +303,17 @@ Returns a form where all lambdas don't have any free variables."
; lambda lifting condition
(if (or (not fv) (< cconv-liftwhen (length funcvars)))
; do not lift
(cconv-closure-convert-rec
value emvrs fvrs envs lmenvs)
(progn
;; (byte-compile-log-warning
;; (format "Not λ-lifting `%S': %d > %d"
;; var (length funcvars) cconv-liftwhen))
(cconv-closure-convert-rec
value emvrs fvrs envs lmenvs))
; lift
(progn
;; (byte-compile-log-warning
;; (format "λ-lifting `%S'" var))
(setq cconv-freevars-alist
;; Now that we know we'll λ-lift, consume the
;; freevar data.
......@@ -579,6 +619,12 @@ Returns a form where all lambdas don't have any free variables."
cdr-new))
`(,callsym . ,(reverse cdr-new))))))
(`(interactive . ,forms)
`(interactive
,@(mapcar (lambda (form)
(cconv-closure-convert-rec form nil nil nil nil))
forms)))
(`(,func . ,body-forms) ; first element is function or whatever
; function-like forms are:
; or, and, if, progn, prog1, prog2,
......@@ -608,23 +654,34 @@ Returns a form where all lambdas don't have any free variables."
;; Only used to test the code in non-lexbind Emacs.
(defalias 'byte-compile-not-lexical-var-p 'boundp))
(defun cconv-analyse-use (vardata form)
(defun cconv-analyse-use (vardata form varkind)
"Analyse the use of a variable.
VARDATA should be (BINDER READ MUTATED CAPTURED CALLED).
VARKIND is the name of the kind of variable.
FORM is the parent form that binds this var."
;; use = `(,binder ,read ,mutated ,captured ,called)
(pcase vardata
(`(,binder nil ,_ ,_ nil)
;; FIXME: Don't warn about unused fun-args.
;; FIXME: Don't warn about uninterned vars or _ vars.
;; FIXME: This gives warnings in the wrong order and with wrong line