Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to write (simple) macro?

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.

like image 977
krzysz00 Avatar asked May 23 '10 16:05

krzysz00


1 Answers

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).
like image 177
dmitry_vk Avatar answered Nov 15 '22 10:11

dmitry_vk