views:

97

answers:

1

I need to write a macro (with-hooks (monster method who what) &body body) for a game I'm writing. Monster is a CLOS object, method and who are strings and what is a function (#' notation). The macroexpansion would be something to the effect of

(add-hook monster method who what)
,@body
(remove-hook monster method who)

I have absolutely no idea how to write such a macro, and I would appreciate some help. I have the creepy feeling that this is easy and I'm a bit ignorant.

+8  A: 

I'd write it like this:

(defmacro with-hooks ((monster method who what) &body body)
  (let ((monster-var (gensym))
        (method-var (gensym))
        (who-var (gensym))
        (what-var (gensym)))
    `(let ((,monster-var ,monster) ; dummy comment
           (,method-var ,method)
           (,who-var ,who)
           (,what-var ,what))
        (add-hook ,monster-var ,method-var ,who-var ,what-var)
        (unwind-protect
           (progn ,@body)
          (remove-hook ,monster-var ,method-var ,who-var)))))

Some notes:

  1. something-vars are used to ensure that expressions for monster, method, who, what are evaluated only once (because these expressions are referenced multiple times in macro body) and in left-to-right order.
  2. gensyms are used to ensure that variables have guaranteed unique names
  3. unwind-protect is used to ensure that remove-hook is called even in case of non-local exits (e.g., stack unwind due to exception being thrown).
dmitry_vk
funny, I had written the same code almost line-by-line
Rainer Joswig
Thank you. I'm working on a GPL roguelike game called Menace of the Mines (http://motm.sourceforge.net) and just want to make sure this being in there is OK with you. (I have an attributing comment (It's been there for a while))
krzysz00
I don't mind if you include this macro in any project in any way.
dmitry_vk