Subject: Re: lambda-returning defmacro, capture
From: rpw3@rpw3.org (Rob Warnock)
Date: Mon, 18 Dec 2006 05:34:14 -0600
Newsgroups: comp.lang.lisp
Message-ID: <Y_Cdnbvi_4Ir4RvYnZ2dnUVZ_tunnZ2d@speakeasy.net>
Yesterday, I wrote:
+---------------
| The [symbol macro] bug in CMUCL is understood, and a fix is in progress.
| There is no reason to avoid symbol macros unless you both must use CMUCL
| *and* cannot wait for a fix. [If you want to fix it yourself, the
| problem is in "src/code/eval.lisp", in the function MACROEXPAND-1.
| If you compare the first COND there with the similar one in the
| MACRO-FUNCTION function just above, the fix may be obvious.]
+---------------

Just so everyone knows, the modified version of MACROEXPAND-1
[attached below -- the change is in the first branch of the COND]
has been submitted to one of the CMUCL developers, who assures me
that it will be in the CVS tree "real soon now". Meanwhile, you
can compile/load this version into your copy of CMUCL-19c (wrap a
WITHOUT-PACKAGE-LOCKS around the LOAD) and the bug will go away.
Here's a test case:

    > (defvar *foo* 13)    

    *FOO*
    > (define-symbol-macro foo *foo*)

    FOO
    > (defun foo () foo)

    FOO
    > (let ((foo 57))
        (list foo (incf foo) foo (foo)))

    (57 58 58 13)
    > 

Without the patch, you'll get (57 14 57 14).


-Rob

-----
Rob Warnock                     <rpw3@rpw3.org>
627 26th Avenue                 <URL:http://rpw3.org/>
San Mateo, CA 94403             (650)572-2607

======= attachment: extracted from $CMUCL/src/code/eval.lisp ==============
(in-package "LISP")

;;; Macroexpand-1  --  Public
;;;
;;;    The Env is a LEXENV or NIL (the null environment.)
;;;
(defun macroexpand-1 (form &optional env)
  "If form is a macro (or symbol macro), expands it once.  Returns two values,
   the expanded form and a T-or-NIL flag indicating whether the form was, in
   fact, a macro.  Env is the lexical environment to expand in, which defaults
   to the null environment."
  (cond ((and (consp form) (symbolp (car form)))
         (let ((def (macro-function (car form) env)))
           (if def
               (values (invoke-macroexpand-hook def form env) t)
               (values form nil))))
        ((symbolp form)
         (let* ((venv (when env (c::lexenv-variables env)))
                (local-def (cdr (assoc form venv))))
           (cond (local-def
                   (if (and (consp local-def)
                            (eq (car local-def) 'macro))
                     (values (cdr local-def) t)
                     (values form nil)))
                 ((eq (info variable kind form) :macro)
                  (values (info variable macro-expansion form) t))
                 (t
                  (values form nil)))))
        (t
         (values form nil))))