[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

How to write macro within macro



    Date: Fri, 22 Dec 89 12:45:37 MST
    From: intvax!gnome!drstrip@unmvax.cs.unm.edu (David R. Strip)


    I would like to write a macro that takes as input the name of a flavor to be defined,
    as well as the names of the instance variables, and defflavors the flavor, and then
    creates a function whose name is the same as the flavor, and sets a variable to
    an instance of the flavor with all fields initialized by keywords.

    Example

    (def-thing foo a b c)
    creates
    (defflavor foo (a b c)() :initable-instance-variables (:contructor MAKE-FOO))
    (defmacro foo (id x y z) `(setq ,id (MAKE-FOO :a ,x :b ,y :c ,z)))

    which then allows me to have expressions like
    (foo a 1 2 (1 2)))
    which after evaluation leaves me with "a" as an instance of a flavor foo,
    with instance-vars a=1, b=1,c=(1 2).

Your example wouldn't have quite that result.  It would try to evaluate
(1 2), which is an error.  I presume you meant (foo a 1 2 '(1 2))

    Hope that makes it clear.
    I can get the defflavor part from a macro, I can't figure out how to
    put a defmacro into a defmacro, (how to get the backquote inside to show up,
    that sort of thing.)

Yes, macro-defining macros are tricky.  There are some idioms that you
have to learn.  Here's the macro that does what you want:

(defmacro def-thing (name &rest instance-vars)
  (let ((constructor (intern (string-append "MAKE-" name))))
    `(progn
       (defmacro ,name ,instance-vars ()
		 :initable-instance-variables
		 (:constructor ,constructor))
       (defmacro ,name (id .,instance-vars)
	 `(setq ,id (,',constructor
		     .,',(loop for var in instance-vars
			       collect (intern (symbol-name var) 'keyword)
			       collect var)))))))

Show Expanded Lisp Code (a Lisp expression to be evaluated or None) (def-thing foo a b c) 
(PROGN
  (DEFMACRO FOO (A B C)
    NIL
    :INITABLE-INSTANCE-VARIABLES
    (:CONSTRUCTOR MAKE-FOO))
  (DEFMACRO FOO (ID A B C)
    `(SETQ ,ID (MAKE-FOO :A A :B B :C C))))

The most important idiom to learn is comma-quote-comma, which is used
inside the internal macro, and is equivalent to a single comma in the
outer macro.  Comma-comma will have a similar result, but leaves a comma
before the expansion (e.g., if I'd writen ",,constructor" instead of
",',constructor", the expansion would have said "(,MAKE-FOO ...)".

                                                barmar