From 5e3fde03b45877d3e30f859a14c10043e637aa63 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Sat, 27 Jun 2015 08:34:44 -0700 Subject: [PATCH] Improve docstring for macroexp-let2 * lisp/emacs-lisp/macroexp.el (macroexp-let2): Improve as per suggestion by RMS in: http://lists.gnu.org/archive/html/emacs-devel/2015-06/msg00621.html Also, rename args to match new doc string. --- lisp/emacs-lisp/macroexp.el | 45 ++++++++++++++++++++++++++++--------- 1 file changed, 34 insertions(+), 11 deletions(-) diff --git a/lisp/emacs-lisp/macroexp.el b/lisp/emacs-lisp/macroexp.el index e9af3b08997..57cbec580b0 100644 --- a/lisp/emacs-lisp/macroexp.el +++ b/lisp/emacs-lisp/macroexp.el @@ -341,21 +341,44 @@ definitions to shadow the loaded ones for use in file byte-compilation." ((memq (car-safe then) '(if cond)) (macroexp-if `(not ,test) else then)) (t `(if ,test ,then ,else)))) -(defmacro macroexp-let2 (test var exp &rest exps) - "Bind VAR to a copyable expression that returns the value of EXP. -This is like \\=`(let ((v ,EXP)) ,EXPS) except that `v' is a new generated -symbol which EXPS can find in VAR. -TEST should be the name of a predicate on EXP checking whether the `let' can -be skipped; if nil, as is usual, `macroexp-const-p' is used." +(defmacro macroexp-let2 (test sym exp &rest body) + "Evaluate BODY with SYM bound to an expression for EXP's value. +The intended usage is that BODY generates an expression that +will refer to EXP's value multiple times, but will evaluate +EXP only once. As BODY generates that expression, it should +use SYM to stand for the value of EXP. + +If EXP is a simple, safe expression, then SYM's value is EXP itself. +Otherwise, SYM's value is a symbol which holds the value produced by +evaluating EXP. The return value incorporates the value of BODY, plus +additional code to evaluate EXP once and save the result so SYM can +refer to it. + +If BODY consists of multiple forms, they are all evaluated +but only the last one's value matters. + +TEST is a predicate to determine whether EXP qualifies as simple and +safe; if TEST is nil, only constant expressions qualify. + +Example: + (macroexp-let2 nil foo EXP + \\=`(* ,foo ,foo)) +generates an expression that evaluates EXP once, +then returns the square of that value. +You could do this with + (let ((foovar EXP)) + (* foovar foovar)) +but using `macroexp-let2' produces more efficient code in +cases where EXP is a constant." (declare (indent 3) (debug (sexp sexp form body))) (let ((bodysym (make-symbol "body")) (expsym (make-symbol "exp"))) `(let* ((,expsym ,exp) - (,var (if (funcall #',(or test #'macroexp-const-p) ,expsym) - ,expsym (make-symbol ,(symbol-name var)))) - (,bodysym ,(macroexp-progn exps))) - (if (eq ,var ,expsym) ,bodysym - (macroexp-let* (list (list ,var ,expsym)) + (,sym (if (funcall #',(or test #'macroexp-const-p) ,expsym) + ,expsym (make-symbol ,(symbol-name sym)))) + (,bodysym ,(macroexp-progn body))) + (if (eq ,sym ,expsym) ,bodysym + (macroexp-let* (list (list ,sym ,expsym)) ,bodysym))))) (defmacro macroexp-let2* (test bindings &rest body) -- 2.39.2