From: Joerg Hoehle
Subject: how to code-walk EVAL-WHEN?
Date: 
Message-ID: <u7j4nipst.fsf@users.sourceforge.net>
Hi,

let's suppose I'm writing a killer application which is internally
based on a code-walker performing code transformation.  The problem
is, I don't know how to walk all of CL special operators.  Esp. I
don't know how to handle EVAL-WHEN.

This limit has very practical consequences.  E.g. the Iterate package
is based on a code walker & transformer. Arnesi/Bese is based on it,
as well as the series package.  Cool packages.

These packages all want to do something when faced with EVAL-WHEN
during expansion.  I argue that so far, these parts are hacks that
rely on undocumented requirements to work (e.g. must have loaded code
prior to compilation, so all macros are defined, or whatever)

So far, the naive approach has been to continue code walking inside
the body of EVAL-WHEN.  I call it naive because it could fail as the
required environment may not yet have been set up.

E.g.
(eval-when (:compile...)
  (defmacro foo ...))
or
(defmacro foo ... ; macro that expands to some EVAL-WHEN
  `(eval-when (:compile...) #))

(iterate
  (progn (eval-when (:compile...) (foo) #)
    etc.))

What would be a proper environment for walking EVAL-WHEN?
Is environments all that matters here?

Some implementation specific helpers have been used for code walking
as well, e.g. CLISP's ext:expand-form. However, CLISP's
ext:expand-form documents that it presumes EVAL-WHEN (EVAL) situations
and is therefore (theoretically) unsuitable for use during compilation.
Yet code walkers have been using this facility, and there have been
little problems in practice.

I argue there have been little problems because EVAL-WHEN is rarely
used, or is used in ways that does not disturb typical code walker
jobs (e.g. XREF), not because there's no problem.

I'd like to enhance the code walking ability of CL packages, where
possible.  But is there a consensus or any advice on handling
EVAL-WHEN as correctly as possible?

Regards,
	Jorg Hohle
Telekom/T-Systems Technology Center

From: Pascal Bourguignon
Subject: Re: how to code-walk EVAL-WHEN?
Date: 
Message-ID: <8764k74hur.fsf@thalassa.informatimago.com>
Joerg Hoehle <······@users.sourceforge.net> writes:
> let's suppose I'm writing a killer application which is internally
> based on a code-walker performing code transformation.  The problem
> is, I don't know how to walk all of CL special operators.  Esp. I
> don't know how to handle EVAL-WHEN.
>
> This limit has very practical consequences.  E.g. the Iterate package
> is based on a code walker & transformer. Arnesi/Bese is based on it,
> as well as the series package.  Cool packages.
>
> These packages all want to do something when faced with EVAL-WHEN
> during expansion.  I argue that so far, these parts are hacks that
> rely on undocumented requirements to work (e.g. must have loaded code
> prior to compilation, so all macros are defined, or whatever)
>
> So far, the naive approach has been to continue code walking inside
> the body of EVAL-WHEN.  I call it naive because it could fail as the
> required environment may not yet have been set up.
>
> E.g.
> (eval-when (:compile...)
>   (defmacro foo ...))
> or
> (defmacro foo ... ; macro that expands to some EVAL-WHEN
>   `(eval-when (:compile...) #))
>
> (iterate
>   (progn (eval-when (:compile...) (foo) #)
>     etc.))
>
> What would be a proper environment for walking EVAL-WHEN?
> Is environments all that matters here?

Depends on what the code walker is called for.

Eg. at run-time, the code walker could be called to analyse the forms
that would be executed at compilation time.  Or at macro-expansion
time, the code walker could be called to analyse the forms that would
be executed at run-time. etc.

So obviously, you need to add a parameter to your code walker,
indicating it what in what simulated time it should code walk.

-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

In a World without Walls and Fences, 
who needs Windows and Gates?
From: Kaz Kylheku
Subject: Re: how to code-walk EVAL-WHEN?
Date: 
Message-ID: <1147740184.432501.179370@i40g2000cwc.googlegroups.com>
Joerg Hoehle wrote:
> Hi,
>
> let's suppose I'm writing a killer application which is internally
> based on a code-walker performing code transformation.  The problem
> is, I don't know how to walk all of CL special operators.  Esp. I
> don't know how to handle EVAL-WHEN.

You have two major cases to worry about: top-level EVAL-WHEN and
non-top-level EVAL-WHEN.

Non-top-level EVAL-WHEN is easy. If it contains :execute, then it's
basically PROGN. If it doesn't contain :EXECUTE, then it's basically
(WHEN (NOT) ....).

To treat the top-level EVAL-WHEN, you have to know what situation you
are in. If you're just translating code, maybe it's okay to just leave
the EVAL-WHEN the way it is, and transform what is in the middle of it.
I.e. leave the EVAL-WHEN alone and let Lisp deal with it.

> This limit has very practical consequences.  E.g. the Iterate package
> is based on a code walker & transformer. Arnesi/Bese is based on it,
> as well as the series package.  Cool packages.
>
> These packages all want to do something when faced with EVAL-WHEN
> during expansion.

Which of these packages have a transforming file compiler?

A code walking macro doesn't have to deal with non-top-level EVAL-WHEN
forms; you can design the macro such that if the user wants to control
the compiler with EVAL-WHEN, it has to surround the use of your macro,
e.g.:

  ;; at top level

  (eval-when (situations ...)
    (my-macro ...))  ;; cool!

  (my-macro
    ...
    (eval-when (situations ...) ...) ;; not cool
    )

The second example could be supported. You could say that the forms
passed to your macro as your body are top-level forms if the macro call
is a top-level form. Then if your macro needs to walk those forms, it
perhaps has to worry about EVAL-WHEN's since they are top-level ones.


> So far, the naive approach has been to continue code walking inside
> the body of EVAL-WHEN.  I call it naive because it could fail as the
> required environment may not yet have been set up.
>
> E.g.
> (eval-when (:compile...)
>   (defmacro foo ...))

Assuming this is a top-level form, how would you even get to walk it,
unless you wrote your own file compiler?

> or
> (defmacro foo ... ; macro that expands to some EVAL-WHEN
>   `(eval-when (:compile...) #))

Macros expanding to EVAL-WHEN or any other special operator have to be
dealt with by code walkers, obviously.

If those macro calls are top-level forms, then the expanded EVAL-WHEN
is a top-level form. Otherwise not. Right?

> (iterate
>   (progn (eval-when (:compile...) (foo) #)
>     etc.))

Well, what are the semantics of iterate with respect to top-level use?

If (ITERATE X) is a top-level form, then is X a top level form?

If not, then there is no worry; iterate's code walker can just grok
EVAL-WHEN as a non-top-level form, which means that all it has to do is
check for :EXECUTE. If :EXECUTE is missing, you prune the form right
out, replacing it by NIL. If it's present, you treat it as PROGN.
That's it.