jackfirth / resyntax

A Racket refactoring engine
Apache License 2.0
56 stars 10 forks source link

Suggest using the `#:with` pattern directive instead of `with-syntax` #143

Open jackfirth opened 3 years ago

jackfirth commented 3 years ago

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.

Metaxal commented 3 years ago

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.

jackfirth commented 3 years ago

We could probably do it for provably-safe cases, like when the right-hand-side is a quoted syntax object.

rmculpepper commented 1 year ago

There are a few dangers in this rewriting.

  1. with-syntax and #:with support different languages of patterns. For example, with-syntax interprets a:b as a plain pattern variable, but #:with interprets it as the pattern variable a annotated with the syntax class b.
  2. If the #:with match fails, then it can cause backtracking out of the current clause, but with-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.

jackfirth commented 1 year ago

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.