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)) (recurse))))))
(get-list-to-expand '(symbol-macrolet ((s a)) s) '(2))
(defun nsubst-list (source substitution list-indexes) (if (null list-indexes) substitution (progn (setf (nth (car list-indexes) source) (nsubst-list (nth (car list-indexes) source) substitution (cdr list-indexes))) source)))
(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) obj-b i))) tree))
(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)) list-indexes))
(expand-part '(macrolet ((x (m) `(y ,m))) (x z)) 2)
(expand-part '(let ((x 50)) (destructuring-bind (x y z) f (dolist (q y) x))) 2) ;; or "2 3)" for the dolist