[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