resyntax
resyntax copied to clipboard
Suggest using the `#:with` pattern directive instead of `with-syntax`
In uses of syntax-parse
, clauses whose tail expression is a with-syntax
form can be replaced with #:with
pattern directives. For example, given this expression:
(syntax-parse stx
[foo:id
(with-syntax ([bar #'(+ 1 2 3)])
#'(foo bar)])
Resyntax ought to suggest simplifying it to this:
(syntax-parse stx
[foo:id
#:with bar #'(+ 1 2 3)
#'(foo bar)])
This can open up the door for related simplifications of syntax-parse
such as #142.
It appears that there are some important differences between with-syntax
and #:with
:
https://discord.com/channels/571040468092321801/667522224823205889/870065339017330688
and following messages.
So unless there's a way to filter out the bad cases, I guess this fix can only be a suggestion and cannot be applied automatically.
We could probably do it for provably-safe cases, like when the right-hand-side is a quoted syntax object.
There are a few dangers in this rewriting.
-
with-syntax
and#:with
support different languages of patterns. For example,with-syntax
interpretsa:b
as a plain pattern variable, but#:with
interprets it as the pattern variablea
annotated with the syntax classb
. -
If the
#:with
match fails, then it can cause backtracking out of the current clause, butwith-syntax
cannot. Here's a little example:(syntax-parse #'(m 1) [(_ x) #:with y:id #'x 1] [_ 2]) ;; => 2
If you add
#:cut
before the#:with
, you can prevent this particular issue.
Good points. The first point can be addressed by analyzing the pattern and seeing if it would have a different meaning under syntax parse. We could also just restrict it to relatively simple and obviously equivalent patterns. The second point is trickier. For 99% of cases I doubt it would cause an issue, but it's worth calling it out as a possible caveat in the suggestion's description. Also, it wouldn't matter for cases where no backtracking occurs, like syntax-parse
forms with only one clause.