[slime-devel] Re: suggested macroexpansion feature (and volunteer)

Chris Capel pdf23ds at gmail.com
Wed Apr 13 15:04:36 UTC 2005


On Wed, 13 Apr 2005 12:42:09 +0200, Helmut Eller wrote:

> Chris Capel <pdf23ds at gmail.com> writes:
> 
>> I already have the code written (included below) to expand such forms
>> (perhaps buggy, perhaps incomplete). (One thing I know it doesn't do is
>> find and respect macrolets that aren't present in the form until after
>> some expansion. I don't know that this is a big deal.)
> 
> I suspect that your code doesn't pass down the environment correctly.
> Every macro can potentially call macroexpand itself and I think you have
> to expand every macro and pass the proper environemnt.  I think in the
> general case you need a full codewalker.  Of course, a lot of useful stuff
> can be done with something much simpler.

Do you mean that the environment passed to macroexpand-1 up there in my
EXPAND isn't correct?

Now, what could be done to be more general is to actually do the full
expansion for every parent form before expanding the selected form, but
only show the selected form's expansion in the buffer. The challenge here
would be keeping dibs on the selected form during the macroexpansion of
its parents. Since the form isn't necessarily preserved in a way congruent
with the users expectations (or even in a way we can locate it again after
a call to macroexpand-1) this problem has no general solution.

> Suppose you have:
> 
>   (defmacro bar (x) `(1+ ,x))
>   (defmacro foo (&rest body) '())
>   (defun baz (y) (foo (bar y)))
> 
> and now you select (bar y) and let it expand.  What's the result?

Yeah, my code was definitely built on the assumption that you know what
you're doing when you try to start expanding stuff. There could be a
warning somewhere that "You should only expand forms nested under
other macros when those other macros include a , at body somewhere and the
forms you're expanding a part of that body. Otherwise, you're pretty much
guaranteed to get something completely different than what will actually
be compiled."

But since these are uncommon cases, and since macros with full
code-walkers and transformers rarely have regular lisp macro calls that
are eradicated by the time macroexpansion is complete (but instead some
domain-specific language or parameter list that couldn't be meaningfully
macroexpanded anyway) I think the potential for confusion is minimal.

Perhaps sufficient would be to allow the list of forms kept for
environment purposes to be expanded from '(macrolet symbol-macrolet) by
the user, as some sort of configuration. Of course, the configuration
would include which parts of the form to keep (while it's the first two
items of macrolet or symbol-macrolet, that's not general principle).

>> If not, I suppose SLIME would need
>> another minor mode with some cool keybindings and code to figure out
>> what to pass as the list-indexes variable based on the position in the
>> buffer (perhaps the hardest part?).
> 
> I have the impression that your list-indexes are similar to what CMUCL
> calls "source-path".  You could use the code in SLIME's
> source-path-parser.  Basically you can pass in a string (or stream) and
> you get the corresponding sexp and a table which maps each (sub)form to
> the start and the end position in the string.  So you could give it the
> toplevel expression from the buffer as a string, search the interval in
> the table which matches the buffer position best and you know which
> subform to expand.  If you know the subform (comparable with eq) you can
> compute the source-path.  But you probably don't need that, since you
> already have the subform.
> 
> Hm... sounds like a lot of work.  Maybe there's something simpler.

Here's one idea I had. Emacs passes in the position of the point and a
string representation of the whole buffer, which Lisp proceeds to read
with a locally rebound #\( read macro that keeps up with the position in
the list during every recursive call to read in some global variable. When
it gets to the position in the string stream where the point was in Emacs,
it saves its current list position to some other variable, which is then
passed to the expanders. But this sounds like a reimplementation of
source-path-parser to me, so I doubt any effort would be saved.

Well, I'll look into getting a patch for this in the coming week, then.

Chris Capel




More information about the slime-devel mailing list