[slime-devel] suggested macroexpansion feature (and volunteer)

Chris Capel pdf23ds at gmail.com
Wed Apr 13 03:25:53 UTC 2005

I've been thinking about a neat feature I think could be implemented in a
pretty straightforward way to help with the debugging of macros. There
would be a new minor mode for a buffer containing some random form.
Selecting any given subform of the buffer's form would macroexpand that
one form, in place. Of course, it would have to respect macrolet's and
symbol-macrolet's (which isn't that hard, really).

I already have the code written (included below) to expand such forms
(perhaps buggy, perhaps incomplete). (One thing I know it doesn't do
is find and respect macrolets that aren't present in the form until after
some expansion. I don't know that this is a big deal.)

What's missing is the hooks into slime and Emacs. I don't want to bother
with these (because they'd be a lot more effort for me) until I find
whether there are any similar features currently available for SLIME. So
has anyone done anything like this yet? If not, I suppose SLIME would need
another minor mode with some cool keybindings and code to figure out what
to pass as the list-indexes variable based on the position in the buffer
(perhaps the hardest part?).

Chris Capel

(defmacro expand (form &environment e)
 (list 'quote (macroexpand-1 form e)))

(defun get-list-to-expand (list list-indexes)
 (flet ((recurse ()
          (get-list-to-expand (nth (car list-indexes) list)
                              (cdr list-indexes))))
   (if (null list-indexes)
       (list 'expand list)
       (let ((sym (find (car list) '(macrolet symbol-macrolet))))
         (if sym
             (list sym (cadr list) (recurse))

(get-list-to-expand '(symbol-macrolet ((s a)) s) '(2))

(defun nsubst-list (source substitution list-indexes)
 (if (null list-indexes)
       (setf (nth (car list-indexes) source)
             (nsubst-list (nth (car list-indexes) source)
                              (cdr list-indexes)))

(nsubst-list '(a b (c d)) '(e f) '(2 1))

(defun subst-all-tree (tree obj-a obj-b &key (test #'equal))
 (mapcar (lambda (i)
           (if (consp i)
               (subst-all-tree i obj-a obj-b :test test)
               (if (funcall test obj-a i)

(subst-all-tree '(a b (c d)) 'd 'e)

(defun expand-part (list &rest list-indexes)
 (nsubst-list list
              (eval (get-list-to-expand list list-indexes))

 '(macrolet ((x (m) `(y ,m)))
   (x z))

 '(let ((x 50))
   (destructuring-bind (x y z) f
     (dolist (q y)
 2) ;; or "2 3)" for the dolist

More information about the slime-devel mailing list