Subject: Re: Macrolet within defmacro question
From: Erik Naggum <erik@naggum.no>
Date: 1999/11/02
Newsgroups: comp.lang.lisp
Message-ID: <3150510670469809@naggum.no>

* Wade Humeniuk
| Can you do a macrolet like this within a defmacro?

  yes, but remember that a macro is really an ordinary function, it is just
  called at a different time than other functions.  specifically, the macro
  is called with the form in question to yield the expansion, which is
  simply a new form as seen by the recipient of the value -- as with any
  other function, whatever was in scope _inside_ that function is gone when
  you exit it.  to capture something, the function needs to be in the scope
  of whatever you want to capture.

| What am I doing wrong???

  you're trying to use macros that are no longer in scope.

  the following should work as you expect, as it makes the macros visible
  in the _expanded_ form.  note that this doesn't have any significant
  cost.  to look at the results, I use Allegro CL's walker (excl::walk) --
  LWW probably has something similar that lets you macroexpand an entire
  form recursively and reduce the noise.

(defmacro declare-html-style-sheet ((type-of-ss &key (stream '*standard-output*))
                                    &rest elements &environment env)
  (declare (ignore type-of-ss env))
  `(macrolet ((COLOR (color-value)
		`(progn
		   (write-string "color: ")
		   (write-string (string-downcase ,color-value))
		   (write-char #\;)))
	      (ELEMENT (element-name &rest properties)
		`(progn
		   (write ,element-name)
		   (write-line ": {")
		   ,@properties
		   (write-line "}")))
	      (BODY (&rest properties)
		`(ELEMENT 'BODY ,@properties))
	      (ROOT (&rest properties)
		`(ELEMENT '* ,@properties)))
     (let ((*standard-output* ,stream))
       ,@elements)))

(excl::walk '(declare-html-style-sheet (:css2 :stream *standard-output*)
		(ROOT (COLOR :tan))
		(BODY (COLOR :olive))))
=> (progn
     (let ((*standard-output* *standard-output*))
       (progn
	 (write '*)
	 (write-line ": {")
	 (progn
	   (write-string "color: ")
	   (write-string (string-downcase :tan))
	   (write-char #\;))
	 (write-line "}"))
       (progn
	 (write 'BODY)
	 (write-line ": {")
	 (progn
	   (write-string "color: ")
	   (write-string (string-downcase :olive))
	   (write-char #\;))
	 (write-line "}"))))

  stylistically, I don't think exploiting the case insensitivity of Common
  Lisp is such a good idea.  it's better to stick to one form of a symbol.

#:Erik