From: His Holiness the Reverend Doktor Xenophon Fenderson, the Carbon(d)ated
Subject: Macro argument lists
Date: 
Message-ID: <w4osnzc2164.fsf@nemesis.irtnog.org>
I'm trying to write a macro that looks like Common Lisp's DEFUN
macro.  The macro is called DEFINE-INSTRUCTION; a typical call looks
like this:

(define-instruction stq memory dc21064 (ra rb &optional (offset 0))
  "Store quadword from register to memory."
  (declare (type (gp-register dc21064 (quadword-integer dc21064)) ra)
	   (type (gp-register dc21064) rb)
	   (type (signed-byte 16) offset))
  :opcode #x2D :ra ra :rb rb :offset offset)

Right now, the macro definition looks something like the following:

(defmacro define-instruction (instruction-name instruction-format
			      machine-name lambda-list
			      &rest opcode-description)
  ...)

and I manually parse OPCODE-DESCRIPTION to extract the docstring and
the DECLARE form.  I would prefer that there were two optional and
interchangable parameters, DOCUMENTATION and DECLARATIONS, but I don't
know how to do it, even after reading up on macro lambda lists.  Is it
possible, or am I stuck doing my own parsing on the body
(OPCODE-DESCRIPTION) form?

-- 
JOHN CAGE (strapped to table): Do you really expect me to conduct this
 antiquated tonal system? 
LEONARD BERNSTEIN: No, Mr. Cage, I expect you to die!

From: Barry Margolin
Subject: Re: Macro argument lists
Date: 
Message-ID: <mmHl4.30$xI3.530@burlma1-snr2>
In article <···············@nemesis.irtnog.org>,
His Holiness the Reverend Doktor Xenophon Fenderson, the Carbon(d)ated <········@irtnog.org> wrote:
>I'm trying to write a macro that looks like Common Lisp's DEFUN
>macro.  The macro is called DEFINE-INSTRUCTION; a typical call looks
>like this:
>
>(define-instruction stq memory dc21064 (ra rb &optional (offset 0))
>  "Store quadword from register to memory."
>  (declare (type (gp-register dc21064 (quadword-integer dc21064)) ra)
>	   (type (gp-register dc21064) rb)
>	   (type (signed-byte 16) offset))
>  :opcode #x2D :ra ra :rb rb :offset offset)
>
>Right now, the macro definition looks something like the following:
>
>(defmacro define-instruction (instruction-name instruction-format
>			      machine-name lambda-list
>			      &rest opcode-description)
>  ...)
>
>and I manually parse OPCODE-DESCRIPTION to extract the docstring and
>the DECLARE form.  I would prefer that there were two optional and
>interchangable parameters, DOCUMENTATION and DECLARATIONS, but I don't
>know how to do it, even after reading up on macro lambda lists.  Is it
>possible, or am I stuck doing my own parsing on the body
>(OPCODE-DESCRIPTION) form?

Unfortunately, there's no built-in way to handle documentation and
declarations at the beginning of a body.  Everyone rolls their own body
parser for this.  Luckily, it's not very complex.

-- 
Barry Margolin, ······@bbnplanet.com
GTE Internetworking, Powered by BBN, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
From: Thomas A. Russ
Subject: Re: Macro argument lists
Date: 
Message-ID: <ymihffr1nlb.fsf@sevak.isi.edu>
"His Holiness the Reverend Doktor Xenophon Fenderson, the Carbon(d)ated" <········@irtnog.org> writes:

> 
> I'm trying to write a macro that looks like Common Lisp's DEFUN
> macro.
[snip]
> and I manually parse OPCODE-DESCRIPTION to extract the docstring and
> the DECLARE form.  I would prefer that there were two optional and
> interchangable parameters, DOCUMENTATION and DECLARATIONS, but I don't
> know how to do it, even after reading up on macro lambda lists.  Is it
> possible, or am I stuck doing my own parsing on the body
> (OPCODE-DESCRIPTION) form?

If you want to mix optional parameters and keywords, then you are on
your own as far as the parsing goes.  That is because keywords do not
interact well with optional parameters.  It is generally easiest to have
either one or the other, but not both.

One approach to your macro would be to make the documentation and the
declarations keywords as well.  Then you could have Lisp do the parsing
for you:

 (defmacro define-instruction (instruction-name instruction-format
 			      machine-name lambda-list
 			      &key documenation declare opcode ...)
   ...)
 
and call it like this:
 
 (define-instruction stq memory dc21064 (ra rb &optional (offset 0))
   :documentation "Store quadword from register to memory."
   :declare ((type (gp-register dc21064 (quadword-integer dc21064)) ra)
 	     (type (gp-register dc21064) rb)
 	     (type (signed-byte 16) offset))
   :opcode #x2D :ra ra :rb rb :offset offset)

You might want to allow the outer parentheses to be left off of the
declare argument if there is only a single declaration.  Assuming that
all declaration clauses start with an atom (or symbol) would allow you
to test for that case.

You might also want to shorten :documentation to :doc, so as not to
discourage the writing of documenation by increasing the typing too much
:)

-- 
Thomas A. Russ,  USC/Information Sciences Institute          ···@isi.edu    
From: Fernando D. Mato Mira
Subject: Re: Macro argument lists
Date: 
Message-ID: <38998058.75C35CA@iname.com>
"Thomas A. Russ" wrote:

> One approach to your macro would be to make the documentation and the
> declarations keywords as well.  Then you could have Lisp do the parsing
> for you:

I'd go with just :documentation and parsing the declarations myself, to be more consistent
with everything else.

Doc strings have a funny flavor anyway, eg:

(defun foo ()
  "Returns NIL"
  )


--
Fernando D. Mato Mira
Real-Time SW Eng & Networking
Advanced Systems Engineering Division
CSEM
Jaquet-Droz 1                   email: matomira AT acm DOT org
CH-2007 Neuchatel                 tel:       +41 (32) 720-5157
Switzerland                       FAX:       +41 (32) 720-5720

www.csem.ch      www.vrai.com     ligwww.epfl.ch/matomira.html
From: Robert Monfera
Subject: Re: Macro argument lists
Date: 
Message-ID: <3899A908.740FCA29@fisec.com>
Hi Barry,

You wrote:
>
> In article <·················@fisec.com>,
> Robert Monfera  <·······@fisec.com> wrote:
[...]
> >Sometimes I want to do this:
> >
> >(defun foo (u &key x y z) ...)
> >
> >(defun bar (w &rest args &key a &allow-other-keys)
> >   ...
> >   (apply #'foo w :x (if a :left :right) args)
> >   ...)
> >
> >(defun baz (...)
> >   ...
> >   (bar 3748 :a t :z 'fixnum)
> >   ...)
> >
> >expecting that keyword A and its value (T) does not get into ARGS
[...]
>
> That's the purpose of the :ALLOW-OTHER-KEYS T option -- it tells a
> function
> you're calling to ignore the extra keywords that are included in the
> argument list because of this.  So you should do:
>
> (apply #'foo w ... :allow-other-keys t args)

This solves most of the problems, and this recommendation is better than
what I would have considered (an :ALLOW-OTHER-KEYS in FOO), because it
covers the case when FOO is a built-in function.

Both ways cause a problem if FOO itself has a &KEY A, but is used
differently or for another purpose relative to BAR's one.  This should
be rare (accidental) if I use keyword names in a disciplined manner and
respect standard keywords in case FOO is a built-in function, but the
price of a collision is a possibly hard to find bug.

By other words, this would more accurately express the intention that
ARGS will have only those keys that are left unmentioned in the lambda
list of the caller function, while avoiding a collision and preserving
keyword error checking:

(apply #'foo w :x (if a :left :right) :remove-specified-keys t args)

(This removal refers to &KEY A, because even if &KEY X was left among
ARGS, the callee would still take (if a :left :right), because it is to
the left.)

Or better yet:

(defun bar (w &unspecified-rest args &key a &allow-other-keys)
   ...
   (apply #'foo w :x (if a :left :right) args)
   ...)

so that ARGS does not even contain a value associated with A.

I thought I can remove &KEY A from ARGS with DESTRUCTURING-BIND, but I
found this one:

> (destructuring-bind (&rest r &key a &allow-other-keys)
     '(:a 1 :b 2 :c 3) r)
=> (:A 1 :B 2 :C 3)      [instead of (:B 2 :C 3)]

out of line with

> (destructuring-bind (a &rest r) '(1 2 3) r)
=> (2 3)


Thanks for the hint of using :ALLOW-OTHER-KEYS in a function call and
the backgrounder.

[Disclaimer: I am just pursuing it out of curiosity and desire to
understand rather than a burning need.  I'm not dependent on it at all
and even if I wanted to, I could write a macro DEFFUN that ensures that
keyword-value pairs are removed from ARGS for keywords listed after
&KEY:

(defmacro deffun (name lambda-list &body body)
  `(defun ,name ,lambda-list
     (let ((,(extract-rest-binding lambda-list)
            (remove-apairs ',(extract-keys lambda-list)
                           ,(extract-rest-binding lambda-list)))))
       ,@body)))

; which expands

(deffun bar (w &rest args &key a &allow-other-keys)
   ...
   (apply #'foo w :x (if a :left :right) args)
   ...)

; to

(defun bar (w &rest args &key a &allow-other-keys)
  (let ((args (remove-apairs '(a) args)))
   ...
   (apply #'foo w :x (if a :left :right) args)
   ...))

(This macro unduly contains multiple evaluations and maybe the EXTRACT-*
functions exist in CL.)]

Robert