[racket] Can not set breakpoints on macro calls that do not expand into a single command

From: Dmitry Pavlov (dmitry.pavlov at gmail.com)
Date: Fri Nov 18 08:56:30 EST 2011


OK, I will reply to my own question.
Good news: problem solved, two solutions available.
Bad news: one solution is clumsy, another is unclear.

The problem here is not just the debugging.
The problem is that the source-location info
is lost during macro expansion. Besides debugging,
that breaks stacktraces of errors.

syntax/loc seems to be the most natural solution:

(define-syntax (my-print2 stx)
 (syntax-case stx ()
   ((_ x)
    (syntax/loc stx
      (begin (printf "~a\n" x))))))

But it does not work. Debugger does not stop at
my-print2 calls, not are errors traced back to
my-print2. Try inserting (/ 1 0) after the printf
call, run the code, and press "backtrace" to see
what I mean.

OK, let us move on: there is also datum->syntax
that accepts optional srcloc parameter:

(define-syntax (my-print3 stx)
 (syntax-case stx ()
   ((_ x)
    (datum->syntax stx
                   `(begin (printf "~a\n" ,#'x))

That works! Unless the macro is done for some custom
language, which does not have its own "begin" and
"printf". That is my case. My language is not even
a s-exp language.The code does not compile, saying

compile: bad syntax; function application is not allowed, because no
#%app syntax transformer is bound

So we must pass a different ctxt parameter to
datum->syntax, keeping the srcloc parameter in place.
What we need for ctxt is actually the "current"
compiler context. (syntax anything) should suffice,
and we take #'here for clarity. Also, instead of begin
and printf, we should take the corresponding syntax objects:

(define-syntax (my-print4 stx)
 (syntax-case stx ()
   ((_ x)
    (datum->syntax #'here
                   `(,#'begin (,#'printf "~a\n" ,#'x))

That works for my case. But the final code looks very unnatural.
Also, my-print3, my-print4, and my-print do NOT allow to debug
inside their definitions. The debugger just skips over the whole
(printf) part. On the other hand, my-print1 and my-print2 DO
allow to debug inside their definitions, but, as said before, the
debugger does not see where did it come here from.

I shockingly revealed (by an accident) how to write the macro
code that works perfectly, not losing any of the source location info.
The trick is to put the whole thing into (let):

(define-syntax-rule (my-print5 x)
  (let ()
      (printf "~a\n" x))))

I am happy with my-print5, but things are unclear to me.
Maybe I am missing something fundamental here. Any comments?

To summarize:

1. It is not clear why define-syntax-rule preserves the
source location info without "begin" and loses it with "begin".
>From my point of view, it should either preserve the location
always or lose it always.

2. I do not understand why "syntax/loc" does not work for me.

3. It is not clear why wrapping the code with (let) solves the
problem with source location of the macro and also preserves
the source location info of the inner S-expressions of the macro.

I still use Racket 5.1.3.

Best regards,


On 11/14/2011 12:24 PM, Dmitry Pavlov wrote:
> Hello,
> I am having trouble debugging Racket code that contains macros.
> Here is the simplest example:
> #lang racket
> (define-syntax-rule (my-print x)
>   (printf "~a\n" x))
> (define-syntax-rule (my-print1 x)
>   (begin
>     (printf "~a\n" x)))
> (my-print  10)
> (my-print1 20)
> (my-print  30)
> (my-print1 40)
> When I enter the above code in DrRacket and press "Debug",
> I find out that I can set breakpoints on (my-print  10)
> and (my-print  30), but can not set breakpoints on
> (my-print1 20) and (my-print1 40).
> How does the "begin" in my-print1 affect the debugger?
> Is there a way to set breakpoints for complex macros?
> I would appreciate any pointers.
> I use Racket 5.1.3.
> Best regards,
> Dmitry
> _________________________________________________
>   For list-related administrative tasks:
>   http://lists.racket-lang.org/listinfo/users

Posted on the users mailing list.