From: Damyan Pepper
Subject: Installing my own defmacro
Date: 
Message-ID: <ufyidv4ek.fsf@gmail.com>
I want to install my own version of defmacro.

I'm sure this sounds pretty silly - and maybe there's a better way to
do what I want to do, so I'll explain why I want to do it.

I'm trying to get slime / clisp to recognise macro arguments, mainly
so that its semantic indenting feature will work properly for me.  So
what I'm trying to do is to store the argument list in the
symbol-plist for the macro's symbol.  I can then quite easily modify
the swank backend code to look up the arglist from there.  It strikes
me that this could also be used to fix the annoying "arg0 arg1"
arglists that clisp reports for compiled functions.

So I've got:

(defmacro defmymacro (name params &body body)
  `(progn
	 (setf (get ',name 'swank::arglist) ',params)
	 (defmacro ,name ,params ,@body)
	 ',name))


And this seems to work ok:

CL-USER> (defmymacro flibble (foo) foo)
FLIBBLE
CL-USER> (flibble 1)
1
CL-USER> (get 'flibble 'swank::arglist)
(FOO)

So now I'd like to make it so I don't have to write 'defmymacro' but
can write 'defmacro' instead.  I've done some fiddling with
macro-function, copy-symbol, *macroexpand-hook* but haven't really got
anywhere sensible.


I'm taking this sort of approach:

(defvar *old-defmacro* (copy-symbol 'common-lisp:defmacro t))

(defun install-mymacro ()
  (setf *old-defmacro* (copy-symbol 'common-lisp:defmacro t))
  (setf (macro-function 'common-lisp:defmacro) (macro-function 'defmymacro)))

My thinking here is that in order to keep things as transparent as
possible I don't want to lose any of the other data for 'defmacro,
hence just (setf macro-function ...) rather than trying to generate an
entirely new symbol.


Then the fun thing is what I should do in defmymacro - since I can't
have it calling 'defmacro' any more because that'll just end up
calling itself.  So somehow I need to get (macro-function
*old-defmacro*) to do the expansion for me.

My latest defmymacro looks like this, but it doesn't seem to actually
define the macro:

(defmacro defmymacro (&environment env &whole whole name params &body body)
  `(progn
	 (setf (get ',name 'swank::arglist) ',params)
	 (funcall (macro-function *old-defmacro*) ',whole ,env)
	 ',name))


It does seem to be calling defmacro at some level - if I replace
',whole with ',(cdr whole) then I get an error that I presume was
generate by defmacro complaining that the arglist (in the example
above, (foo)) is an invalid name for the macro.

Does anyone have any pointers on what might help here?  Is my approach
totally bogus?


Thanks,

Damyan.

From: Alexander
Subject: Re: Installing my own defmacro
Date: 
Message-ID: <1149933344.803955.259370@f6g2000cwb.googlegroups.com>
Hi
1. At first CLHS doesn't allow to redefine macros in CL package
2. May be shadowing cl:defmacro in your package solve your problem.
3. (defmacro defmymacro (&environment env &whole whole name params
&body body)
   `(progn
 	 (setf (get ',name 'swank::arglist) ',params)
         (eval-when (:compile-toplevel :load-toplevel :execute)
 	 (funcall (macro-function *old-defmacro*) ',whole ,env))
 	 ',name))
From: Damyan Pepper
Subject: Re: Installing my own defmacro
Date: 
Message-ID: <ubqswrq0p.fsf@gmail.com>
"Alexander" <········@gmail.com> writes:

> Hi

Thanks for the reply!

> 1. At first CLHS doesn't allow to redefine macros in CL package

That puts a bit of a downer on the whole plan really!  It took me a
while to find the relevant bit of CLHS which specified this
(11.1.2.1.2 I belive if anyone else is following.)

I can see why that restriction is there, although I suspect some
implementations may let me do it anyway, I guess it's probably not a
good thing to rely on.


> 2. May be shadowing cl:defmacro in your package solve your problem.

I think this is part of the approach I'll have to take - I'm having a
look through the code Pascal pointed me at the moment which looks like
it takes this approach.

The other option of course is to modify CLISP itself.  *shudder*.  I
think I've managed to track down where it sets up defmacro, but don't
quite understand it yet.

> 3. (defmacro defmymacro (&environment env &whole whole name params
> &body body)
>    `(progn
>  	 (setf (get ',name 'swank::arglist) ',params)
>          (eval-when (:compile-toplevel :load-toplevel :execute)
>  	 (funcall (macro-function *old-defmacro*) ',whole ,env))
>  	 ',name))

This snippet has prodded me into trying to find out what eval-when
does!  I think I'm slowly getting there.  Unfortunately this
suggestion doesn't seem to have any effect on the behaviour of my
code, but it did make me think about it a bit more and to come up with
the following:

(defmacro defmymacro (&environment env &whole whole name params &body body)
  `(progn
	 (setf (get ',name 'swank::arglist) ',params)
	 (eval-when (:compile-toplevel :load-toplevel :execute)
	   ,(funcall (macro-function *old-defmacro*) whole env))
	 ',name))

The difference here being that I'm expanding the equivelant
(cl:defmacro name params body) into my expansion.  This seems to do
the trick.  The expansion also includes eval-when statements that I'm
guessing at the moment wouldn't have got evaluated when called through
funcall since it wouldn't have been a top-level form.  Maybe?

Thanks again!

Damyan.
From: Alexander
Subject: Re: Installing my own defmacro
Date: 
Message-ID: <1150285456.222185.69980@c74g2000cwc.googlegroups.com>
Damyan Pepper wrote:

> This snippet has prodded me into trying to find out what eval-when
> does!  I think I'm slowly getting there.  Unfortunately this
> suggestion doesn't seem to have any effect on the behaviour of my
> code, but it did make me think about it a bit more and to come up with
> the following:
>
> (defmacro defmymacro (&environment env &whole whole name params &body body)
>   `(progn
> 	 (setf (get ',name 'swank::arglist) ',params)
> 	 (eval-when (:compile-toplevel :load-toplevel :execute)
> 	   ,(funcall (macro-function *old-defmacro*) whole env))
> 	 ',name))

May be here eval-when is not necessary ?

 (defmacro defmymacro (&environment env &whole whole name params &body
body)
   `(progn
 	 (setf (get ',name 'swank::arglist) ',params)
 	  ,(funcall (macro-function *old-defmacro*) whole env)
 	 ',name))
From: Damyan Pepper
Subject: Re: Installing my own defmacro
Date: 
Message-ID: <uy7w0q76r.fsf@gmail.com>
"Alexander" <········@gmail.com> writes:

> May be here eval-when is not necessary ?
>
>  (defmacro defmymacro (&environment env &whole whole name params &body
> body)
>    `(progn
>  	 (setf (get ',name 'swank::arglist) ',params)
>  	  ,(funcall (macro-function *old-defmacro*) whole env)
>  	 ',name))

You're right, it isn't. :)
From: Pascal Bourguignon
Subject: Re: Installing my own defmacro
Date: 
Message-ID: <87r71x2lr6.fsf@thalassa.informatimago.com>
Damyan Pepper <·······@gmail.com> writes:

> I want to install my own version of defmacro.
>
> I'm sure this sounds pretty silly - and maybe there's a better way to
> do what I want to do, so I'll explain why I want to do it.
>
> I'm trying to get slime / clisp to recognise macro arguments, mainly
> so that its semantic indenting feature will work properly for me.  So
> what I'm trying to do is to store the argument list in the
> symbol-plist for the macro's symbol.  I can then quite easily modify
> the swank backend code to look up the arglist from there.  It strikes
> me that this could also be used to fix the annoying "arg0 arg1"
> arglists that clisp reports for compiled functions.
>
> So I've got:
>
> (defmacro defmymacro (name params &body body)
>   `(progn
> 	 (setf (get ',name 'swank::arglist) ',params)
> 	 (defmacro ,name ,params ,@body)
> 	 ',name))
>
> And this seems to work ok:
> [...]
> So now I'd like to make it so I don't have to write 'defmymacro' but
> can write 'defmacro' instead.  I've done some fiddling with
> macro-function, copy-symbol, *macroexpand-hook* but haven't really got
> anywhere sensible.
>
>
> I'm taking this sort of approach:
>
> (defvar *old-defmacro* (copy-symbol 'common-lisp:defmacro t))
> [...]
> Does anyone have any pointers on what might help here?  Is my approach
> totally bogus?

Not totally, but it's not exactly the right approach.
Have a look at http://paste.lisp.org/display/20035#1
to see how you can write your own defmacro.

Notice also how we define a new defpackage to substitute the new "CL"
package for the standard CL package in the unsuspecting packages...

Some more functions or macros would need to be redefined similarly:
make-package, import, use-package, etc, to force the new definitions
on unsuspecting packages.


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

HEALTH WARNING: Care should be taken when lifting this product,
since its mass, and thus its weight, is dependent on its velocity
relative to the user.
From: Damyan Pepper
Subject: Re: Installing my own defmacro
Date: 
Message-ID: <uslm8q6vs.fsf@gmail.com>
Pascal Bourguignon <···@informatimago.com> writes:

> Not totally, but it's not exactly the right approach.  Have a look
> at http://paste.lisp.org/display/20035#1 to see how you can write
> your own defmacro.
>
> Notice also how we define a new defpackage to substitute the new "CL"
> package for the standard CL package in the unsuspecting packages...
>
> Some more functions or macros would need to be redefined similarly:
> make-package, import, use-package, etc, to force the new definitions
> on unsuspecting packages.

Oh, that's very cool!  Thanks for the link, it was a very interesting
read.