[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

issue COMPILER-LET-CONFUSION



I agree with JonL's suggestion that, should we decide to adopt proposal
COMPILER-LET-CONFUSION:ELIMINATE, we should also provide users with a lot
of suggestions for converting old code.

After thinking about it for a while, I've come up with what ought to
be a fairly painless solution that should take care of just about all
cases where COMPILER-LET is currently used.  I've hacked together a
macro called FAKE-COMPILER-LET that is like COMPILER-LET but with
another argument, the list of macros which are supposed to see the
special variable bindings.  The semantics are fairly close to those of
COMPILER-LET-CONFUSION:REDEFINE, the exception being that it only
works if the macros are defined with DEFMACRO and not MACROLET.  I did
think about getting this to handle MACROLET'ed macros by passing
environments around, but it was apparent that the code would get much
hairier (reducing its value as an example) and it still wouldn't
handle all cases (like a nested MACROLET that shadows one of the
listed macros). 

;;; Imitation COMPILER-LET.  Second argument is a list of macros which
;;;    are to see the special bindings; these must have been defined using
;;;    DEFMACRO, not MACROLET (because expansion takes place in null
;;;    lexical environment).

(defmacro fake-compiler-let (binding-forms macros &body body)
    (expand-fake-compiler-let binding-forms macros body))

(eval-when (eval compile load)
    (defun expand-fake-compiler-let (binding-forms macros body)
	(let* ((vars    (mapcar #'(lambda (b)
				      (if (consp b) (car b) b))
				binding-forms))
	       (vals    (mapcar #'(lambda (b)
				      (if (consp b) (eval (cadr b)) nil))
				binding-forms))
	       (binders (mapcar #'(lambda (var val)
				      `(,var ',val))
				vars vals))
	       (defs    (mapcar #'(lambda (m)
				      `(,m (&whole w)
					   (let ,binders
					       (declare (special ,@vars))
					       (macroexpand-1 w))))
				macros)))
	    `(macrolet ((fake-compiler-let (binding-forms macros &body body)
			    (let ,binders
				(declare (special ,@vars))
				(expand-fake-compiler-let
				    binding-forms macros body)))
			,@defs)
	         ,@body)))
    )


;;; Example to illustrate nesting behavior

(eval-when (eval compile)
    (defvar *depth* 0)
    (defmacro current-depth ()
	*depth*)
    )

(fake-compiler-let ((*depth* (1+ *depth*)))
	           (current-depth)
    (format t "First value = ~s~%" (current-depth))
    (fake-compiler-let ((*depth* (1+ *depth*)))
		       (current-depth)
        (format t "Second value = ~s~%" (current-depth))))


How does this strike those of you who have been arguing against
removing COMPILER-LET from the language?

-Sandra
-------