* Mark H. David [2010-11-10 19:49] writes:
I have a fancy def type of macro -- lets call it DEFOPERATION, which takes a function name, args, and body, and eventually emits a corresponding DEFUN form to get the function defined. It gets sprinkled throughout the sources, but doesn't immediately invoke DEFUN. Instead, at some later point, another macro form is invoked -- lets say it's (DEFINE-DEFS-NOW), and that actually emits all the defuns.
The problem is that when I do meta-. on any so-defined function, it takes me to the line in the source containing (DEFINE-DEFS-NOW). Not too interesting a place to go. What I really want is for it to take me to the corresponding DEFOPERATION.
How can I make this work better in SLIME?
The only portable way handle this is a TAGS file or grep.
Or, if it's an implementation thing, or partially so, what can I do specifically in my Lisps, specifically CCL and/or SBCL, to make this work better?
With implementation specific tricks we can get a bit further but it's not easy. For example in CCL:
(eval-when (:compile-toplevel) (defparameter *compile-time-stuff* nil)
(defmacro defop (&whole whole name args &body body) (push (list name args body (ccl::fcomp-source-note whole)) *compile-time-stuff*) nil)
(defmacro defnow () (prog1 `(progn . ,(loop for (name args body srcloc) in *compile-time-stuff* collect `(progn (defun ,name ,args . ,body) (ccl::record-definition-source ccl::*function-definition-type* ',name ',srcloc)))) (setq *compile-time-stuff* nil)))
)
(defop foo () (break) 12) (defop bar () (break) 34)
(defnow)
CCL's reader has a special hack which inserts source-notes[0] in a hash table. You can retrieve them whith ccl::fcomp-source-note. In the defnow macro we generate code that associates the name with that source-note.
Note this only specifies the source location for the name and doesn't deal with the more interesting problem of how to preserve source locations of all subforms of body. That would be needed for pc-to-source mapping, but is not necessary for M-.
The same idea for SBCL could look like so:
(eval-when (:compile-toplevel) (defparameter *compile-time-stuff* nil)
(defmacro defop (&whole whole name args &body body) (push (list name args body (cddr (sb-c::get-source-path whole))) *compile-time-stuff*) nil)
(defmacro defnow (&whole whole) (prog1 `(progn . ,(loop for (name args body srcloc) in *compile-time-stuff* for defun = `(defun ,name ,args . ,body) do (setf (gethash defun sb-c::*source-paths*) (append (sb-c::get-source-path whole) srcloc)) collect defun)) (setq *compile-time-stuff* nil)))
)
(defop foo () (break) 12) (defop bar () (break) 34)
(defnow)
SBCL numbers the cons in a sexp and uses those numbers to specify the source location. Our stuff will end up in the debug info of function objects.
All those are obviously just hacks. Ask the compiler guys for the proper way to do it.
Helmut