What does #:track-literals
do in syntax-parse
? Why doesn't define-syntax-class
also have #:track-literals
?
Literals and disappeared-uses
Suppose you have a macro like cond
that recognizes the literal identifier else
and treats it specially. In Racket, literal identifiers are recognized by binding, so else
is defined somewhere and exported from the racket
language, etc.
When you use cond
and have an else
clause, you'd like DrRacket to tell you that else
comes from racket
. On the other hand, DrRacket should not say else
comes from racket
in the program (let ([else 5]) (add1 else))
or in the program (quote (if then else))
---neither of those are references to Racket's else
. So how should DrRacket decide what to say?
It has to look at the expanded program, because in Racket expansion is when scoping and references get figured out. So it looks at the expanded program, and whenever it sees a reference to a variable (like add1
) or primitive syntax (like quote
) that corresponds to an original identifier, it records the source of the identifier and its origin (see identifier-binding
). But cond
and else
aren't in the expanded program. So there's a convention: when the macro expander expands cond
, it adds the cond
identifier to a syntax property named 'origin
on the result expression, and DrRacket looks there too. So that's how it knows to talk about cond
. There's another convention: the cond
macro records the else
identifier in a different syntax property called 'disappeared-uses
on the syntax it expands to, and DrRacket looks there too.
syntax-parse and #:track-literals
If a macro doesn't bother to add the 'disappeared-uses
property for a literal, DrRacket doesn't see it. The macro expander cannot automatically track literals like else
, because the knowledge of their interpretation is inside of the individual macros, but syntax-parse
has patterns and features dedicated to literals, so it can automatically record literals that occur in the input, in a backtracking-safe way. If you include #:track-literals
directive, then it adds those recorded literals to the 'disappeared-uses
property on the result. (It doesn't do so by default because the result of a syntax-parse
expression does not have to be syntax, even though that's the most common use.) The define-syntax-class
form doesn't have the option because the 'disappeared-use
property is customarily only placed on the macro's final result.
tl,dr: Typically, a syntax-parse
form that implements a macro should use #:track-literals
.
Lucid. This would be a great addition to the syntax-parse documentation. Thank you.