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? 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?
Thanks,
Mark
* 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
Thanks. That is all a great start at an 80% solution (meta-.).
For the PC stuff, do you recommend I cross post this to SBCL/CCL lists, or are the compiler folks here?
Thanks again,
Mark
Helmut Eller wrote:
- 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
[0] http://trac.clozure.com/ccl/changeset/11373
slime-devel site list slime-devel@common-lisp.net http://common-lisp.net/mailman/listinfo/slime-devel
* Mark H. David [2010-11-11 01:54] writes:
Thanks. That is all a great start at an 80% solution (meta-.).
For the PC stuff, do you recommend I cross post this to SBCL/CCL lists, or are the compiler folks here?
Some SBCL people seem to read this list but I don't think that the Clozure folks do.
Helmut
On 11 November 2010 09:09, Helmut Eller heller@common-lisp.net wrote:
For the PC stuff, do you recommend I cross post this to SBCL/CCL lists, or are the compiler folks here?
Some SBCL people seem to read this list but I don't think that the Clozure folks do.
I created https://bugs.launchpad.net/sbcl/+bug/675913 to track this in SBCL. No promises, but I think this should be supported sooner or later.
Cheers,
-- Nikodemus