From: Kaz Kylheku
Subject: How to do this, without COMPILER-LET extension.
Date: 
Message-ID: <cf333042.0302271704.159c9a59@posting.google.com>
I would like to write a macro which takes some &body forms and places
them into a form that makes a local macros visible to those forms. I
would like invocations of that local macro to stash some information
derived from its arguments into some compile-time variable that holds
a list, and then have another local macro be able to pull out that
information, and use it to build its expansion. E.g:

  (my-macro 
     (remember x) ; x is pushed into some list at macroexpansion time
     (remember y) ; y ditto
     ...
     (recall)) ; x and y are recalled and used in expansion

In the real code, the (recall) part would be implicit; my-macro would
stick that into the expansion, but this is irrelevant.

If you had a ``magic'' macro-expansion-time binding construct, the
expansion of the above could look like this:

  (magic-let (%%some-magic-variable%%)
    (macrolet ((remember (arg)
                 (push arg %%some-magic-variable%%)
                 (values))
               (recall ()
                  `(whatever ,@%%some-magic-variable%%))
       (remember x)
       (remember y)
       (recall))

Are there any easy ways to get macrolets to communicate with each
other at expansion time to achieve transformations like this? I read
the ANSI committee's 1989 document ``COMPILER-LET-CONFUSION Writeup''
which explains why COMPILER-LET was removed, but it's not obvious to
me how the portable workaround strategies apply to the above case.

From: Paul F. Dietz
Subject: Re: How to do this, without COMPILER-LET extension.
Date: 
Message-ID: <MRmcnSyrMpNfIcOjXTWcoQ@dls.net>
Kaz Kylheku wrote:

> Are there any easy ways to get macrolets to communicate with each
> other at expansion time to achieve transformations like this?

The usual trick is to stash information in the macro environment
with an auxiliary macrolet, and use macroexpand to extract that
information.  This extra macrolet's macro would never actually
be expanded in code.

	Paul
From: Kaz Kylheku
Subject: Re: How to do this, without COMPILER-LET extension.
Date: 
Message-ID: <cf333042.0302280934.56c0d8a8@posting.google.com>
"Paul F. Dietz" <·····@dls.net> wrote in message news:<······················@dls.net>...
> Kaz Kylheku wrote:
> 
> > Are there any easy ways to get macrolets to communicate with each
> > other at expansion time to achieve transformations like this?
> 
> The usual trick is to stash information in the macro environment
> with an auxiliary macrolet, and use macroexpand to extract that
> information.  This extra macrolet's macro would never actually
> be expanded in code.

Thanks for the comment and the IRC discussion.

As you know, I went with your idea of using the SYMBOL-VALUE slot of
an uninterned symbol to pass the context among the macros.

The following macro captures the simple essence of the idea:

(defmacro outer (&body body)
  (let ((var (gensym "VAR-")))
    (setf (symbol-value var) nil)
    `(macrolet ((collect (item)
                  (push item (symbol-value ',var))
                  (values))
                (recall ()
                  `(quote ,(symbol-value ',var))))
       ,@body)))

(outer (collect a) (collect b) (collect c) (recall)) -> (C B A)

Everything appears cool. The GENSYM call ensures that each expansion
of OUTER creates a fresh context variable for the macrolets, so nested
instances don't interfere with each other.

The reason I think need this, by the way, is because I'm developing a
macro like RESTART-CASE but with more features. In this macro, I need
to take specially designated blocks of code and move them to the end
of a TAGBODY, where they are identified by a symbol. The place where
they are moved from is replaced with a GO to its corresponding moved
block. Executing this GO will perform a non-local exit to complete the
restart.  The designation is implemented by macrolets, which have to
produce the (GO ...) expansion and collect the body forms into the
context list. The body forms later have to be regurgitated, which can
be done by a hidden macrolet inserted into the expansion.
From: Kaz Kylheku
Subject: Re: How to do this, without COMPILER-LET extension.
Date: 
Message-ID: <cf333042.0303031015.643513f1@posting.google.com>
···@ashi.footprints.net (Kaz Kylheku) wrote in message > The reason I think need this, by the way, is because I'm developing a
> macro like RESTART-CASE but with more features. In this macro, I need
> to take specially designated blocks of code and move them to the end
> of a TAGBODY, where they are identified by a symbol. The place where
> they are moved from is replaced with a GO to its corresponding moved
> block. Executing this GO will perform a non-local exit to complete the
> restart.

But it turns out that I don't need to do this. Over the weekend, I
discovered that Lisp has this wonderful feature called a ``lexical
closure''. With this feature, you can move code around without moving
code around; just package it up as an object and call it from wherever
you wanted to move it to.

:) :) :)

So I solved the problem like this: the specially designated block of
code is put into a lambda. The closure object is assigned to a hidden
local variable, and then a GO is executed to a hidden tag in the
enclosing construct. This gives me the necessary non-local exit. The
hidden tag is before a piece of code which funcalls the closure
through that variable.

So the problem was solved without the use of any compile-time
variables to communicate between macrolets.