Expanding Guile macros one step at a time

Expanding Guile macros one step at a time

Published by Arun Isaac on

In other languages: தமிழ்

Tags: lisp, scheme, software

When debugging Guile macros, sometimes one expansion step is all you need. Here’s a small tool I wrote to scratch that itch.

I’ve always found Guile’s macroexpand confusing and hard to understand. Sometimes, it seems to expand too much—down to the lowest level primitives. That’s not what I want to see when I’m debugging a macro I wrote. All I want to see is an expansion of the first level. So, I wrote me1 (stands for macroexpand-1), and have been using it successfully for a while. Here I share it with you.

(define (me1 x)
  (syntax->datum
   (syntax-case x ()
     ((head _ ...)
      (and=> (module-variable (current-module)
                              (syntax->datum #'head))
             (compose macro? variable-ref))
      ((macro-transformer (module-ref (current-module)
                                      (syntax->datum #'head)))
       x))
     (_ x))))

Here’s a simple or macro definition from the Guile manual.

(define-syntax my-or
  (syntax-rules ()
    ((my-or)
     #f)
    ((my-or exp)
     exp)
    ((my-or exp rest ...)
     (let ((t exp))
       (if t
           t
           (my-or rest ...))))))

And here’s how you use me1 on it:

(me1 #'(my-or 1 2 3))

which produces:

(let ((t 1)) (if t t (my-or 2 3)))

Note that me1 takes a syntax object (defined using #' ). And, a caveat: me1 only works with macros defined in the current module.