diff options
author | Stefan Monnier <monnier@iro.umontreal.ca> | 2022-05-25 17:53:39 -0400 |
---|---|---|
committer | Stefan Monnier <monnier@iro.umontreal.ca> | 2022-05-26 12:21:32 -0400 |
commit | 80ba4c170756049a101b4e6692882ac30ba5e1a5 (patch) | |
tree | 6dd293220256c8ce06e474c9457a4e448f7dd7ee /lisp/emacs-lisp | |
parent | 77b5840d4ab37c1485745def5ec0c9b9f6cb137f (diff) | |
download | emacs-80ba4c170756049a101b4e6692882ac30ba5e1a5.tar.gz emacs-80ba4c170756049a101b4e6692882ac30ba5e1a5.tar.bz2 emacs-80ba4c170756049a101b4e6692882ac30ba5e1a5.zip |
eval.c: New functions `defvar-1` and `defconst-1` (bug#55156)
The bytecode interpreter can't directly call special forms, so
the byte-compiler usually converts special forms into some sequence of
byte codes (basically, providing a duplicate definition of the special
form). There are still two exceptions to this: `defconst` and `defvar`,
where the compiler instead generates a convoluted chunk of code like:
(funcall '(lambda (x) (defvar <sym> x <doc>)) <value>)
where the quote makes sure we keep the function non-compiled, so as
to end up running the special form at run time.
Get rid of this workaround by introducing `defvar-1` and `defconst-1`
which provide a *functional* interface to the functionality of the
corresponding special form.
* src/eval.c (defvar, Fdefvar_1, Fdefconst_1): New functions, extracted from
`Fdefvar` and `Fdefconst`.
(Fdefvar, Fdefconst): Use them.
(syms_of_eval): `defsubr` the new functions.
* lisp/emacs-lisp/bytecomp.el (byte-compile-tmp-var): Delete const.
(byte-compile-defvar): Simplify using the new functions.
* doc/lispref/variables.texi (Defining Variables): Adjust the doc of
`defvar` to reflect the actual semantics implemented.
Diffstat (limited to 'lisp/emacs-lisp')
-rw-r--r-- | lisp/emacs-lisp/bytecomp.el | 23 |
1 files changed, 10 insertions, 13 deletions
diff --git a/lisp/emacs-lisp/bytecomp.el b/lisp/emacs-lisp/bytecomp.el index d7140ad9e63..ee530f95d09 100644 --- a/lisp/emacs-lisp/bytecomp.el +++ b/lisp/emacs-lisp/bytecomp.el @@ -4943,8 +4943,6 @@ binding slots have been popped." (push (nth 1 (nth 1 form)) byte-compile-global-not-obsolete-vars)) (byte-compile-normal-call form)) -(defconst byte-compile-tmp-var (make-symbol "def-tmp-var")) - (defun byte-compile-defvar (form) ;; This is not used for file-level defvar/consts. (when (and (symbolp (nth 1 form)) @@ -4977,18 +4975,17 @@ binding slots have been popped." string "third arg to `%s %s' is not a string: %s" fun var string)) + ;; Delegate the actual work to the function version of the + ;; special form, named with a "-1" suffix. (byte-compile-form-do-effect - (if (cddr form) ; `value' provided - ;; Quote with `quote' to prevent byte-compiling the body, - ;; which would lead to an inf-loop. - `(funcall '(lambda (,byte-compile-tmp-var) - (,fun ,var ,byte-compile-tmp-var ,@(nthcdr 3 form))) - ,value) - (if (eq fun 'defconst) - ;; This will signal an appropriate error at runtime. - `(eval ',form) - ;; A simple (defvar foo) just returns foo. - `',var))))) + (cond + ((eq fun 'defconst) `(defconst-1 ',var ,@(nthcdr 2 form))) + ((not (cddr form)) `',var) ; A simple (defvar foo) just returns foo. + (t `(defvar-1 ',var + ;; Don't eval `value' if `defvar' wouldn't eval it either. + ,(if (macroexp-const-p value) value + `(if (boundp ',var) nil ,value)) + ,@(nthcdr 3 form))))))) (defun byte-compile-autoload (form) (and (macroexp-const-p (nth 1 form)) |