collect-macro-forms.lisp (2425B)
1 ;;; collect-macro-forms.lisp -- helper macros for slynk-macrostep.lisp 2 ;; 3 ;; Authors: Luís Oliveira <luismbo@gmail.com> 4 ;; Jon Oddie <j.j.oddie@gmail.com> 5 ;; João Távora <joaotavora@gmail.com> 6 ;; 7 ;; License: Public Domain 8 9 (in-package #:slynk-macrostep) 10 11 ;;; JT: These definitions brought into this contrib from SLIME's 12 ;;; backend.lisp. They could/should go into SLY if they prove to be useful 13 ;;; enough for writing other contribs, meanwhile keep them here. 14 ;;; 15 (defmacro with-collected-macro-forms 16 ((forms &optional result) instrumented-form &body body) 17 "Collect macro forms by locally binding *MACROEXPAND-HOOK*. 18 Evaluates INSTRUMENTED-FORM and collects any forms which undergo 19 macro-expansion into a list. Then evaluates BODY with FORMS bound to 20 the list of forms, and RESULT (optionally) bound to the value of 21 INSTRUMENTED-FORM." 22 (assert (and (symbolp forms) (not (null forms)))) 23 (assert (symbolp result)) 24 ;; JT: Added conditional ignore spec 25 ;; 26 (let ((result-var (or result 27 (gensym)))) 28 `(call-with-collected-macro-forms 29 (lambda (,forms ,result-var) 30 (declare (ignore ,@(unless result 31 `(,result-var)))) 32 ,@body) 33 (lambda () ,instrumented-form)))) 34 35 (defun call-with-collected-macro-forms (body-fn instrumented-fn) 36 (let ((return-value nil) 37 (collected-forms '())) 38 (let* ((real-macroexpand-hook *macroexpand-hook*) 39 (*macroexpand-hook* 40 (lambda (macro-function form environment) 41 (let ((result (funcall real-macroexpand-hook 42 macro-function form environment))) 43 (unless (eq result form) 44 (push form collected-forms)) 45 result)))) 46 (setf return-value (funcall instrumented-fn))) 47 (funcall body-fn collected-forms return-value))) 48 49 (defun collect-macro-forms (form &optional env) 50 "Collect subforms of FORM which undergo (compiler-)macro expansion. 51 Returns two values: a list of macro forms and a list of compiler macro 52 forms." 53 (with-collected-macro-forms (macro-forms expansion) 54 (ignore-errors (macroexpand-all form env)) 55 (with-collected-macro-forms (compiler-macro-forms) 56 (handler-bind ((warning #'muffle-warning)) 57 (ignore-errors 58 (compile nil `(lambda () ,expansion)))) 59 (values macro-forms compiler-macro-forms))))