From: ······@heslin.eclipse.co.uk
Subject: How to introspect the lambda-list of an existing macro?
Date: 
Message-ID: <87lkyi9h1s.fsf@heslin.eclipse.co.uk>
There is a function called ARGLIST in clocc
(clocc/clocc/src/port/sys.lisp) which returns the signature of a
function by calling various implementation-specific extensions.[1]

I need this to work with macros, too, and the implementations I am most
interested in at the moment are Clisp and SBCL.  With SBCL, ARGLIST
works fine with macros, but Clisp throws an error.

Is there a platform-independent way of getting the lambda-list of a
macro?  Failing that, is there a way to get this information out of
Clisp?

I did look at the code in Slime that gets the arglist (in
swank-clisp.lisp), but it just surrounds the call to EXT:ARGLIST in
IGNORE-ERRORS, so no help there.

I have had two ideas.  The first is to parse the information Clisp
returns when you call MACRO-FUNCTION on the macro name.  But this seems
likely to be brittle, and I'm not sure how to convert the function
object it returns into a string for parsing.

The other idea is to shadow defmacro so that it records the lambda-list
in a hash before defining the macro, but I don't want to complicate
matters by doing that unless it is the only way.

Thanks for any help.

Peter


[1] Here is the ARGLIST function from clocc:

(defun arglist (fn)
  "Return the signature of the function."
  #+allegro (excl:arglist fn)
  #+clisp (sys::arglist fn)
  #+(or cmu scl)
  (let ((f (coerce fn 'function)))
    (typecase f
      (STANDARD-GENERIC-FUNCTION (pcl:generic-function-lambda-list f))
      (EVAL:INTERPRETED-FUNCTION (eval:interpreted-function-arglist f))
      (FUNCTION (values (read-from-string (kernel:%function-arglist f))))))
  #+cormanlisp (ccl:function-lambda-list
                (typecase fn (symbol (fdefinition fn)) (t fn)))
  #+gcl (let ((fn (etypecase fn
                    (symbol fn)
                    (function (si:compiled-function-name fn)))))
          (get fn 'si:debug))
  #+lispworks (lw:function-lambda-list fn)
  #+lucid (lcl:arglist fn)
  #+sbcl (progn (require :sb-introspect)
                (sb-introspect:function-arglist fn))
  #-(or allegro clisp cmu cormanlisp gcl lispworks lucid sbcl scl)
  (error 'not-implemented :proc (list 'arglist fn)))

From: ······@heslin.eclipse.co.uk
Subject: Re: How to introspect the lambda-list of an existing macro?
Date: 
Message-ID: <87ek49apgl.fsf@heslin.eclipse.co.uk>
······@heslin.eclipse.co.uk writes:

> Failing that, is there a way to get this information out of
> Clisp?

Following up my own post, here is what I have so far:

(defun clisp-macro-arglist (symbol)
  (let ((def (get symbol 'system::definition)))
    (when (equal 'defmacro (caar def))
      (caddar def))))

It works with some quick tests, but is it robust?

Peter
From: Pascal Bourguignon
Subject: Re: How to introspect the lambda-list of an existing macro?
Date: 
Message-ID: <87zmmx280h.fsf@thalassa.informatimago.com>
······@heslin.eclipse.co.uk writes:

> There is a function called ARGLIST in clocc
> (clocc/clocc/src/port/sys.lisp) which returns the signature of a
> function by calling various implementation-specific extensions.[1]
>
> I need this to work with macros, too, and the implementations I am most
> interested in at the moment are Clisp and SBCL.  With SBCL, ARGLIST
> works fine with macros, but Clisp throws an error.
>
> Is there a platform-independent way of getting the lambda-list of a
> macro?  Failing that, is there a way to get this information out of
> Clisp?

Try:

[20]> (defmacro m (a b &optional c &key d e) `(list ,a ,b ,c ,d ,e))
M
[21]> (function-lambda-expression (macro-function 'm))
(LAMBDA (SYSTEM::<MACRO-FORM> SYSTEM::<ENV-ARG>)
 (DECLARE (CONS SYSTEM::<MACRO-FORM>)) (DECLARE (IGNORE SYSTEM::<ENV-ARG>))
 (IF (< (EXT:LIST-LENGTH-DOTTED SYSTEM::<MACRO-FORM>) 3)
  (SYSTEM::MACRO-CALL-ERROR SYSTEM::<MACRO-FORM>)
  (LET*
   ((A (CADR SYSTEM::<MACRO-FORM>)) (B (CADDR SYSTEM::<MACRO-FORM>))
    (C (CADDDR SYSTEM::<MACRO-FORM>)) (#:G4330 (CDDDDR SYSTEM::<MACRO-FORM>))
    (D (GETF #:G4330 ':D NIL)) (E (GETF #:G4330 ':E NIL)))
   (SYSTEM::KEYWORD-TEST #:G4330 '(:E :D)) (BLOCK M `(LIST ,A ,B ,C ,D ,E))))) ;
#(NIL NIL NIL NIL ((DECLARATION XLIB::CLX-VALUES VALUES OPTIMIZE DECLARATION))) ;
M
[22]> (third (assoc 'defmacro (get 'm 'system::definition)))
(A B &OPTIONAL C &KEY D E)
[23]> (compile 'm)
M ;
NIL ;
NIL
[24]> (function-lambda-expression (macro-function 'm))
(LAMBDA (A B &OPTIONAL C &KEY D E) `(LIST ,A ,B ,C ,D ,E)) ;
T ;
M
[25]> (second (function-lambda-expression (macro-function 'm)))
(A B &OPTIONAL C &KEY D E)
[26]> (third (assoc 'defmacro (get 'm 'system::definition)))
(A B &OPTIONAL C &KEY D E)
[27]> 



> I have had two ideas.  The first is to parse the information Clisp
> returns when you call MACRO-FUNCTION on the macro name.  But this seems
> likely to be brittle, and I'm not sure how to convert the function
> object it returns into a string for parsing.

(function-lambda-expression (macro-function 'm))

Well, this is common, but the result is implementation specific, can
be always NIL, and it's harder to recover the lambda list from the
interpreted macros in clisp.

In clisp 2.35, I'd use:

(third (assoc 'defmacro (get 'm 'system::definition)))


> The other idea is to shadow defmacro so that it records the lambda-list
> in a hash before defining the macro, but I don't want to complicate
> matters by doing that unless it is the only way.

This is the most portable and robust way to do it.  All the rest is
implementation specific.


-- 
__Pascal Bourguignon__                     http://www.informatimago.com/
Litter box not here.
You must have moved it again.
I'll poop in the sink.