Lisp HUG Maillist Archive

Stepper (and debugger)-friendly macros. Case of debugger

Hi Thomas!

>I get much better results working back through the stack...

The same problem occurs, the same remedy applies. If macroexpander
copies the code, source-to-binary position correspondence is lost. Let
me reformulate my example:

(declaim (optimize (debug 3) (speed 0)))

(eval-when (:compile-toplevel :load-toplevel :execute)
  (defmacro breakpointable (&body x) `(progn ,@x))
  (defmacro non-breakpointable (&body x) `(progn ,@(copy-tree x)))
  )

(defun f1 ()
  (breakpointable
     (   ; one can set breakpoint here
    break )))

(defun f2 ()
  (non-breakpointable
     (   ; can't set breakpoint here as source was
    break )))


(defmacro assign-source (literal expanded)
  "Says that, for stepper, expanded code is associated with
 literal source"
  `(setf (car ,literal) (car ,expanded)
         (cdr ,literal) (cdr ,expanded)
         ,expanded ,literal))

(eval-when (:compile-toplevel :load-toplevel :execute)
  (defmacro breakpointable-again (&body x)
    (let ((result `(progn ,@(copy-tree x))))
      (assign-source (first x) (first (cdr result)))
      result))
  )

(defun f3 ()
  (breakpointable-again
    (  ; can set a breakpoint
     break)))
;;; EOF

Put the code into a buffer and compile it. Then run f1, f2, f3 from a listener.
For each function, use "find source" button from debugger when break occurs.

You will see:
In f1 debugger can find (break) position precisely.
It fails to do so in (f2) and shows enclosing
(non-breakpointable). In case of complex macros (e.g. "iterate") this is
nasty as it can be really hard to locate the problem.
In f3, due to call of "assign source" from macroexpander function,
debugger can find (break) again.

_______________________________________________
Lisp Hug - the mailing list for LispWorks users
lisp-hug@lispworks.com
http://www.lispworks.com/support/lisp-hug.html


Re: Stepper (and debugger)-friendly macros. Case of debugger

Hi All,

I wasn't really responding to the use of, or not, the stepper friendly macros. Rather, I was stating that the stepper is occasionally useful and I would not want to see it discarded.

I need to look more closely at your suggestions, but my initial impression is that they affect only a handful of possibly bothersome instances. There are many macros in the system, and more created all the time. Not sure what your desires are?

If it is based on an inability to discern macros from functions then that is the price one pays for such a flexible system. Any attempt to tighten up the macro facility, like they try to do with hygienic macros in Scheme or Dylan, is counterproductive from my perspective. But given the flexibility of Lisp, you are quite free to implement any variations that you like, and it won't destroy the language flexibility for the rest of us.

- DM

On Mar 3, 2013, at 10:49 AM, Denis Budyak <budden73@gmail.com> wrote:

> 
> Hi Thomas!
> 
>> I get much better results working back through the stack...
> 
> The same problem occurs, the same remedy applies. If macroexpander
> copies the code, source-to-binary position correspondence is lost. Let
> me reformulate my example:
> 
> (declaim (optimize (debug 3) (speed 0)))
> 
> (eval-when (:compile-toplevel :load-toplevel :execute)
>  (defmacro breakpointable (&body x) `(progn ,@x))
>  (defmacro non-breakpointable (&body x) `(progn ,@(copy-tree x)))
>  )
> 
> (defun f1 ()
>  (breakpointable
>     (   ; one can set breakpoint here
>    break )))
> 
> (defun f2 ()
>  (non-breakpointable
>     (   ; can't set breakpoint here as source was
>    break )))
> 
> 
> (defmacro assign-source (literal expanded)
>  "Says that, for stepper, expanded code is associated with
> literal source"
>  `(setf (car ,literal) (car ,expanded)
>         (cdr ,literal) (cdr ,expanded)
>         ,expanded ,literal))
> 
> (eval-when (:compile-toplevel :load-toplevel :execute)
>  (defmacro breakpointable-again (&body x)
>    (let ((result `(progn ,@(copy-tree x))))
>      (assign-source (first x) (first (cdr result)))
>      result))
>  )
> 
> (defun f3 ()
>  (breakpointable-again
>    (  ; can set a breakpoint
>     break)))
> ;;; EOF
> 
> Put the code into a buffer and compile it. Then run f1, f2, f3 from a listener.
> For each function, use "find source" button from debugger when break occurs.
> 
> You will see:
> In f1 debugger can find (break) position precisely.
> It fails to do so in (f2) and shows enclosing
> (non-breakpointable). In case of complex macros (e.g. "iterate") this is
> nasty as it can be really hard to locate the problem.
> In f3, due to call of "assign source" from macroexpander function,
> debugger can find (break) again.
> 
> _______________________________________________
> Lisp Hug - the mailing list for LispWorks users
> lisp-hug@lispworks.com
> http://www.lispworks.com/support/lisp-hug.html
> 
> 

Dr. David McClain
CTO & Co-Founder
Acudora (TM)
e-mail: david@acudora.com
Tel: (+1) 520-529-2437




_______________________________________________
Lisp Hug - the mailing list for LispWorks users
lisp-hug@lispworks.com
http://www.lispworks.com/support/lisp-hug.html


Re: Stepper (and debugger)-friendly macros. Case of debugger

I see that my response didn't really address the issue that you were raising. Now that I understand it, this is actually a problem with define-test in lisp-unit. It is not possible to go to source when there is an error in an assertion. While annoying, I've had bigger issues to address and have just let this slide.

Isn't this problem addressed in LispWorks by Dspecs: Tools for Handling Definitions?

----------------------------------------------------------------
Thomas M. Hermann
Odonata Research LLC
http://www.odonata-research.com/
http://www.linkedin.com/in/thomasmhermann


On Sun, Mar 3, 2013 at 11:49 AM, Denis Budyak <budden73@gmail.com> wrote:
Hi Thomas!

>I get much better results working back through the stack...

The same problem occurs, the same remedy applies. If macroexpander
copies the code, source-to-binary position correspondence is lost. Let
me reformulate my example:

(declaim (optimize (debug 3) (speed 0)))

(eval-when (:compile-toplevel :load-toplevel :execute)
  (defmacro breakpointable (&body x) `(progn ,@x))
  (defmacro non-breakpointable (&body x) `(progn ,@(copy-tree x)))
  )

(defun f1 ()
  (breakpointable
     (   ; one can set breakpoint here
    break )))

(defun f2 ()
  (non-breakpointable
     (   ; can't set breakpoint here as source was
    break )))


(defmacro assign-source (literal expanded)
  "Says that, for stepper, expanded code is associated with
 literal source"
  `(setf (car ,literal) (car ,expanded)
         (cdr ,literal) (cdr ,expanded)
         ,expanded ,literal))

(eval-when (:compile-toplevel :load-toplevel :execute)
  (defmacro breakpointable-again (&body x)
    (let ((result `(progn ,@(copy-tree x))))
      (assign-source (first x) (first (cdr result)))
      result))
  )

(defun f3 ()
  (breakpointable-again
    (  ; can set a breakpoint
     break)))
;;; EOF

Put the code into a buffer and compile it. Then run f1, f2, f3 from a listener.
For each function, use "find source" button from debugger when break occurs.

You will see:
In f1 debugger can find (break) position precisely.
It fails to do so in (f2) and shows enclosing
(non-breakpointable). In case of complex macros (e.g. "iterate") this is
nasty as it can be really hard to locate the problem.
In f3, due to call of "assign source" from macroexpander function,
debugger can find (break) again.

Re: Stepper (and debugger)-friendly macros. Case of debugger

Hello Chris,

Thanks for the response. I should have phrased my response better. The issue is not with lisp-unit, lisp-unit is only a good example. If an error is signaled in the actual body of define-test, for example in the bindings of a LET form or some form outside of an assertion, it is not possible to go to the source from the LW debugger.

----------------------------------------------------------------
Thomas M. Hermann
Odonata Research LLC
http://www.odonata-research.com/
http://www.linkedin.com/in/thomasmhermann


On Mon, Mar 4, 2013 at 11:53 AM, Christopher Riesbeck <c-riesbeck@northwestern.edu> wrote:
Re going to source on an error, do you mean because lisp-unit defaults to aborting on failure?

if so, does rebinding lisp-unit:*error-listener* to lisp-unit:debug-error help?



On 3/4/2013 11:16 AM, Thomas M. Hermann wrote:
I see that my response didn't really address the issue that you were raising. Now that I understand it, this is actually a problem with define-test in lisp-unit. It is not possible to go to source when there is an error in an assertion. While annoying, I've had bigger issues to address and have just let this slide.

Isn't this problem addressed in LispWorks by Dspecs: Tools for Handling Definitions?

----------------------------------------------------------------
Thomas M. Hermann
Odonata Research LLC
http://www.odonata-research.com/
http://www.linkedin.com/in/thomasmhermann


On Sun, Mar 3, 2013 at 11:49 AM, Denis Budyak <budden73@gmail.com> wrote:
Hi Thomas!

>I get much better results working back through the stack...

The same problem occurs, the same remedy applies. If macroexpander
copies the code, source-to-binary position correspondence is lost. Let
me reformulate my example:

(declaim (optimize (debug 3) (speed 0)))

(eval-when (:compile-toplevel :load-toplevel :execute)
  (defmacro breakpointable (&body x) `(progn ,@x))
  (defmacro non-breakpointable (&body x) `(progn ,@(copy-tree x)))
  )

(defun f1 ()
  (breakpointable
     (   ; one can set breakpoint here
    break )))

(defun f2 ()
  (non-breakpointable
     (   ; can't set breakpoint here as source was
    break )))


(defmacro assign-source (literal expanded)
  "Says that, for stepper, expanded code is associated with
 literal source"
  `(setf (car ,literal) (car ,expanded)
         (cdr ,literal) (cdr ,expanded)
         ,expanded ,literal))

(eval-when (:compile-toplevel :load-toplevel :execute)
  (defmacro breakpointable-again (&body x)
    (let ((result `(progn ,@(copy-tree x))))
      (assign-source (first x) (first (cdr result)))
      result))
  )

(defun f3 ()
  (breakpointable-again
    (  ; can set a breakpoint
     break)))
;;; EOF

Put the code into a buffer and compile it. Then run f1, f2, f3 from a listener.
For each function, use "find source" button from debugger when break occurs.

You will see:
In f1 debugger can find (break) position precisely.
It fails to do so in (f2) and shows enclosing
(non-breakpointable). In case of complex macros (e.g. "iterate") this is
nasty as it can be really hard to locate the problem.
In f3, due to call of "assign source" from macroexpander function,
debugger can find (break) again.


-- 
.................................................
Christopher Riesbeck
Associate Professor, Electrical Engineering and Computer Science
McCormick School of Engineering
Northwestern University

2145 Sheridan Rd., Evanston, IL 60208

Home page: http://www.cs.northwestern.edu/~riesbeck/
Calendar: http://calendar.yahoo.com/criesbeck

Updated at: 2020-12-10 08:35 UTC