I'm not sure if this grievance falls to CLISP or to SLIME. When I land in the debugger, there are way too many frames present. Most of them are just noise, and I usually can't find the interesting frames -- such as those corresponding to named functions that I wrote -- with lexical bindings to inspect.
Playing around with CLISP outside of SLIME, I see that one can set the mode used by the ":bt" command in the debugger. This can help to simplify the output, though I haven't yet figured out which of the five modes corresponds to what I'd /like/ to see.
Consider this contrived example:
,---- | CL-USER> (defun foo (n) | (/ 3 n)) | FOO | CL-USER> (foo 0) `----
Evaluating that second form provokes this view in the debugger: (Take a deep breath.)
,---- | /: division by zero | [Condition of type SYSTEM::SIMPLE-DIVISION-BY-ZERO] | | Restarts: | 0: [RETRY] Retry SLIME REPL evaluation request. | 1: [ABORT] Return to SLIME's top level. | 2: [CLOSE-CONNECTION] Close SLIME connection | 3: [ABORT] Abort main loop | | Backtrace: | 0: [366] frame binding variables (~ = dynamically): | | ~ SWANK::*SLDB-STEPPING-P* <--> NIL | 1: [363] frame binding variables (~ = dynamically): | | ~ SWANK::*SLDB-LEVEL* <--> 0 | 2: [360] frame binding variables (~ = dynamically): | | ~ *PACKAGE* <--> #<PACKAGE COMMON-LISP-USER> | 3: <1/354> #<COMPILED-FUNCTION SWANK::DEBUG-IN-EMACS> | [353] frame binding variables (~ = dynamically): | | ~ SWANK::*SLIME-INTERRUPTS-ENABLED* <--> T | 4: <1/347> #<COMPILED-FUNCTION SWANK:INVOKE-SLIME-DEBUGGER> | - #<COMPILED-FUNCTION SWANK::SWANK-DEBUGGER-HOOK-1> | 5: <1/345> #<COMPILED-FUNCTION SWANK::SWANK-DEBUGGER-HOOK-1> | - #<COMPILED-FUNCTION SWANK::SWANK-DEBUGGER-HOOK-1> | 6: [344] frame binding variables (~ = dynamically): | | ~ *DEBUGGER-HOOK* <--> NIL | 7: <1/340> #<COMPILED-FUNCTION #:|624 629 (DEFINTERFACE CALL-WITH-DEBUGGER-HOOK (HOOK FUN) ...)-61-3-1|> | - #<COMPILED-FUNCTION #:|624 629 (DEFINTERFACE CALL-WITH-DEBUGGER-HOOK (HOOK FUN) ...)-61-3-1|> | 8: <1/335> #<COMPILED-FUNCTION SWANK-BACKEND:CALL-WITH-DEBUGGER-HOOK> | - #(NIL #<SYSTEM::SIMPLE-DIVISION-BY-ZERO #x10140B4D>) | 9: <1/331> #<COMPILED-FUNCTION SWANK:SWANK-DEBUGGER-HOOK> | [329] frame binding variables (~ = dynamically): | | ~ *DEBUGGER-HOOK* <--> #<COMPILED-FUNCTION SWANK:SWANK-DEBUGGER-HOOK> | 10: <1/326> #<SYSTEM-FUNCTION INVOKE-DEBUGGER> 1 | [325] frame binding variables (~ = dynamically): | | ~ SYSTEM::*PRIN-STREAM* <--> #<UNBOUND> | 11: [322] frame binding variables (~ = dynamically): | | ~ *PRINT-READABLY* <--> NIL | 12: [319] frame binding variables (~ = dynamically): | | ~ *PRINT-ESCAPE* <--> T | 13: <1/315> #<SYSTEM-FUNCTION /> 2 | - 3 | 14: [313] EVAL frame for form (/ 3 N) | Locals: | N = 0 | 15: [309] frame binding environments | VAR_ENV <--> NIL | FUN_ENV <--> NIL | BLOCK_ENV <--> NIL | GO_ENV <--> NIL | DECL_ENV <--> ((DECLARATION OPTIMIZE DECLARATION)) | 16: [303] frame binding variables #<ADDRESS #x7FF404FC> binds (~ = dynamically): | | N <--> 0 | Next environment: NIL | 17: [297] APPLY frame for call (FOO '0) | 18: <1/293> #<FUNCTION FOO (N) (DECLARE (SYSTEM::IN-DEFUN FOO)) (BLOCK FOO (/ 3 N))> 1 | - #<FUNCTION FOO (N) (DECLARE (SYSTEM::IN-DEFUN FOO)) (BLOCK FOO (/ 3 N))> | 19: [292] EVAL frame for form (FOO 0) | 20: [289] frame binding environments | VAR_ENV <--> NIL | FUN_ENV <--> NIL | BLOCK_ENV <--> NIL | GO_ENV <--> NIL | DECL_ENV <--> ((DECLARATION OPTIMIZE DECLARATION)) | 21: <1/284> #<SYSTEM-FUNCTION EVAL> | - (FOO 0) `----
If I ran across this output in a large program, I'd probably be most interested in frame 14, where the division operator is being evaluated. Expanding it shows that "N" was bound to 3.
Is there some way to configure SLIME to sift through these frames and reduce them to something more "interesting"? For instance, by my criteria, everything in frames 1 through 12 above is irrelevant to the debugging intent, unless I was trying to debug the debugger.
As an aside, I'd appreciate any comparison in the output to other implementations besides CLISP. Are they less chatty?
"Steven E. Harris" seh@panix.com writes:
Expanding it shows that "N" was bound to 3.
By which I mean "N" was bound to zero.
* Steven E. Harris [2008-10-27 00:37+0100] writes:
[...]
If I ran across this output in a large program, I'd probably be most interested in frame 14, where the division operator is being evaluated. Expanding it shows that "N" was bound to 3.
Is there some way to configure SLIME to sift through these frames and reduce them to something more "interesting"? For instance, by my criteria, everything in frames 1 through 12 above is irrelevant to the debugging intent, unless I was trying to debug the debugger.
Not unless you are willing to improve the CLISP backend. E.g. the backend could skip over the top frames until the frame for invoke-debugger, break, or something like that. There is also a function swank-backend::boring-frame-p which could possibly be customized.
Problem is, CLISP doesn't have a debugger API (or something that would be worth the name API), and currently the backend only prints the "frames" to strings and does some regexp matching on those strings. That's no fun.
As an aside, I'd appreciate any comparison in the output to other implementations besides CLISP. Are they less chatty?
CMUCL:
Arithmetic error division-by-zero signalled. Operation was kernel::division, operands (3 0). [Condition of type division-by-zero]
Restarts: 0: [retry] Retry SLIME REPL evaluation request. 1: [abort] Return to SLIME's top level. 2: [abort] Return to Top-Level.
Backtrace: 0: (kernel::integer-/-integer 3 0) 1: (/ 3 0) 2: (swank::eval-region "(foo 0)\n") 3: ("defun repl-eval") 4: (swank::track-package #<Closure Over Function "defun repl-eval" {587FA8B1}>) 5: (swank::call-with-retry-restart "Retry SLIME REPL evaluation request." #<Closure Over Function "defun repl-eval" {587FA841}>) ...
Lispworks:
Division-by-zero caused by / of (3 0). [Condition of type division-by-zero]
Restarts: 0: [value] Return a value to use. 1: [new-args] Supply new arguments to use. 2: [retry] Retry SLIME REPL evaluation request. 3: [abort] Return to SLIME's top level. 4: [abort] Quit process.
Backtrace: 0: conditions::conditions-error (:invisiblep t #<division-by-zero 200B8AA7> nil) 1: system::division-by-zero-error (/ 3 0) 2: / (3 &rest (0)) 3: foo nil 4: system::*%apply-interpreted-function-proper-function (:invisiblep t &rest (0)) 5: system::%invoke nil 6: system::%eval ((foo 0)) 7: eval ((foo 0)) 8: swank::eval-region ("(foo 0)\n") 9: (subfunction 1 swank::repl-eval) nil 10: swank::track-package (#<Closure (swank::repl-eval . 1) 200B071A>) 11: swank::call-with-retry-restart ("Retry SLIME REPL evaluation request." #<Closure (swank::repl-eval . 1) 200B0702>) ...
Clozure CL:
DIVISION-BY-ZERO detected [Condition of type DIVISION-BY-ZERO]
Restarts: 0: [RETRY] Retry SLIME REPL evaluation request. 1: [ABORT] Return to SLIME's top level. 2: [ABORT-BREAK] Reset this process 3: [ABORT] Kill this process
Backtrace: 0: (CCL::%FIXNUM-TRUNCATE) 1: (CCL::INTEGER-/-INTEGER 3 0) 2: (CCL::CALL-CHECK-REGS FOO 0) 3: (SWANK::EVAL-REGION "(foo 0)\n") 4: ((:INTERNAL SWANK::REPL-EVAL)) 5: (SWANK::TRACK-PACKAGE #<COMPILED-LEXICAL-CLOSURE (:INTERNAL SWANK::REPL-EV$ 6: (SWANK::CALL-WITH-RETRY-RESTART "Retry SLIME REPL evaluation request." #<C$