Re: Order of macroexpansion
- From: Kaz Kylheku <kkylheku@xxxxxxxxx>
- Date: Thu, 31 Jan 2008 15:12:41 -0800 (PST)
On Jan 31, 5:15 am, Peter Hildebrandt <peter.hildebra...@xxxxxxxxx>
wrote:
Say, I have the macros outer and inner, and I write the following:
(outer 10 (inner +1))
Is it specified, in which order outer and inner are expanded?
Consider:
(defmacro base1 (&rest crap) 'blorg)
(defclass derived (base1 base2 base3) ())
Do you see what the problem would be if (base1 ...) got expanded
before (defclass ...)?
The DEFCLASS macro completely controls the meaning of (base1 base2
base3). This syntax isn't a macro call.
The only way that some constituent of a macro call is itself a macro
call is if that constituent survives into the replacement form in such
a way that further macroexpansion of the replacement form eventually
recognizes it as a macro call.
Needless to say, this doesn't happen with the list of superclasses in
a DEFCLASS.
I see that in sbcl outer is expanded before inner, and I can do the following:
(let (store)
(defmacro outer (val &body body) (setf store val) `(progn ,@body))
(defmacro inner (expr) `(,expr ,store)))
That is, store is first setf'd by outer, then read by inner.
Is this implementation specific, or can I rely on this?
The problem is that INNER and OUTER are completely independent macros.
You are assuming that one or more INNER's is always embedded in an
OUTER, and that OUTER's do not nest.
Wha tabout this:
(outer
;; store variable is set up by outside outer
(inner ...) ;; inner uses this store
(outer ...) ;; this outer clobbers store with new value
(inner ...) ;; this inner uses clobbered value
)
If you want an outer macro to prepare some storage location that is
used by macros that are embedded within that form, you have to do a
little more work.
Firstly, to make sure that it's totally transparent, you probably want
to dynamically allocate a location for each macro, and give it a
different name (gensym).
You probably want to use macrolets for the inner macros. That is to
say, the outer macro generates a macrolet form which provides local
macros that make the embedded inner macros work. This macrolet can
be customized such that the inner macros know the identity of the
secret variable instantiated just for them by the outer macro (for
that particular expansion only). In a different expansion of the outer
macro, a whole new set of inner macrolets is generated, which know
about a different secret storage location.
The secret storage location can just be the SYMBOL-VALUE slot of a
gensym.
Something like:
(defmacro outer (form &body body)
(let ((secret-sym (gensym)))
;; Stash form in secret place.
;; NOTE: form is not evaluated.
(setf (symbol-value secret-sym) form)
`(macrolet ((inner (expr)
`(,expr ,(symbol-value ,',secret-sym))))
,@body)))
So when OUTER is being expanded the above expander function allocates
a gensym. The argument form goes into the value slot of that symbol
via the SETF. In the macro expansion, the body is wrapped in a
macrolet which defines an INNER macro. This INNER macro is customized.
Each occurence of OUTER generates slightly different source code for
INNER, because the source code of inner contains the identity of the
secret symbol, thanks to the ,',SECRET-SYM splice. An INNER macro
can only be used within an enclosing OUTER. It is expanded using the
definition provided by the most enclosing OUTER, and so uses the
secret location set up by that innermost OUTER.
.
- Prev by Date: Re: Arc already more popular than Python...
- Next by Date: Re: Can I use a docstring followed by DECLARE in a local function?
- Previous by thread: Re: Order of macroexpansion
- Next by thread: Re: Order of macroexpansion
- Index(es):
Relevant Pages
|