Skip to content

Commit 5f13e17

Browse files
committed
Fix implementation with binding check bypass
1 parent 993b532 commit 5f13e17

File tree

2 files changed

+29
-46
lines changed

2 files changed

+29
-46
lines changed

default-recommendations/syntax-parse-shortcuts.rkt

Lines changed: 16 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,11 @@
99
[syntax-parse-shortcuts refactoring-suite?]))
1010

1111

12-
(require rebellion/private/static-name
12+
(require (for-syntax racket/base
13+
syntax/parse)
14+
rebellion/private/static-name
1315
resyntax/base
16+
resyntax/private/more-syntax-parse-classes
1417
resyntax/private/syntax-traversal
1518
racket/stream
1619
syntax/parse
@@ -24,48 +27,22 @@
2427
#:description
2528
"This `define-syntax` macro with a single `syntax-parse` clause can be replaced with a simpler,
2629
equivalent `define-syntax-parse-rule` macro."
27-
#:literals (define-syntax lambda)
30+
#:literals (define-syntax lambda [syntax-parse syntax-parse #:phase 1] [syntax-id syntax #:phase 1])
2831

2932
(define-syntax macro:id
30-
(lambda (stx-var:id)
31-
(syntax-parse-id:id parsed-stx:id
32-
[(_ . pattern) body ...])))
33+
(lambda (stx-id:id)
34+
(syntax-parse stx-id2:id
35+
[(_ pattern ...) directive:syntax-parse-pattern-directive ... (syntax-id last-form)])))
3336

34-
#:do [(define stx-id (attribute stx-var))
35-
;; Check if stx-var is referenced in the body using syntax-search
36-
(define body-has-stx-ref?
37-
(for/or ([body-part (in-list (attribute body))])
38-
(not (stream-empty?
39-
(syntax-search body-part
40-
[id:id #:when (free-identifier=? #'id stx-id)
41-
(stream this-syntax)])))))
42-
;; Replace references to stx-var with this-syntax and strip syntax wrapper
43-
(define (replace-stx-with-this-syntax stx)
44-
(syntax-parse stx
45-
[id:id #:when (free-identifier=? #'id stx-id)
46-
(datum->syntax #'here 'this-syntax stx)]
47-
[(a . b)
48-
(datum->syntax stx
49-
(cons (replace-stx-with-this-syntax #'a)
50-
(replace-stx-with-this-syntax #'b))
51-
stx
52-
stx)]
53-
[other #'other]))
54-
(define (strip-syntax-wrapper stx)
55-
(syntax-parse stx
56-
#:literals (syntax)
57-
[(syntax body) #'body]
58-
[other #'other]))
59-
(define new-body
60-
(for/list ([body-part (in-list (attribute body))])
61-
(strip-syntax-wrapper (replace-stx-with-this-syntax body-part))))]
62-
63-
#:with (new-body-part ...) new-body
64-
65-
#:when (and (free-identifier=? (attribute stx-var) (attribute parsed-stx))
66-
(equal? (syntax-e (attribute syntax-parse-id)) 'syntax-parse))
37+
#:when (free-identifier=? (attribute stx-id) (attribute stx-id2) 1)
38+
39+
#:with (new-body ...)
40+
(syntax-traverse #'((~@ . directive) ... last-form)
41+
[id-in-body:id
42+
#:when (free-identifier=? (attribute id-in-body) (attribute stx-id) 1)
43+
(syntax-property #'this-syntax 'skip-incorrect-binding-check? #true)])
6744

68-
(define-syntax-parse-rule (macro . pattern) new-body-part ...))
45+
(define-syntax-parse-rule (macro pattern ...) new-body ...))
6946

7047

7148
(define-refactoring-rule define-syntax-parser-to-define-syntax-parse-rule-simple

private/syntax-replacement.rkt

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -360,7 +360,9 @@
360360
;; Without the fix, the formatter would allow the code to exceed the line length limit.
361361
;; With the fix, the formatter either keeps it on one line within the limit, or breaks it
362362
;; across multiple lines if it cannot fit.
363-
(define orig-line " [`(,(and (or '+ '- '* '/ 'and 'or) op) ,as ..2 ,b) `(,op ,(loop `(,op ,@as) env) ,(loop b env))]")
363+
(define orig-line
364+
(string-append " [`(,(and (or '+ '- '* '/ 'and 'or) op) ,as ..2 ,b)"
365+
" `(,op ,(loop `(,op ,@as) env) ,(loop b env))]"))
364366
(check-equal? (string-length orig-line) 102 "Original line should be 102 characters")
365367

366368
;; The quasiquote expression starts at position 57 and ends at position 101
@@ -370,9 +372,10 @@
370372
(define quasiquote-end 101) ; just before the final ]
371373

372374
(define replacement
373-
(string-replacement #:start quasiquote-start
374-
#:end quasiquote-end
375-
#:contents (list (inserted-string "(list op (loop `(,op ,@as) env) (loop b env))"))))
375+
(string-replacement
376+
#:start quasiquote-start
377+
#:end quasiquote-end
378+
#:contents (list (inserted-string "(list op (loop `(,op ,@as) env) (loop b env))"))))
376379

377380
;; Test with Racket's standard line width of 102
378381
(parameterize ([current-width 102])
@@ -383,7 +386,8 @@
383386
;; If it's multi-line, each line should not exceed 102 characters
384387
(for ([line (in-list (string-split result "\n"))])
385388
(check-true (<= (string-length line) 102)
386-
(format "Line exceeds length limit: ~a chars (should be <= 102)" (string-length line)))))))
389+
(format "Line exceeds length limit: ~a chars (should be <= 102)"
390+
(string-length line)))))))
387391

388392

389393
(define (syntax-replacement-introduces-incorrect-bindings? replacement)
@@ -392,7 +396,8 @@
392396
#:introduction-scope intro)
393397
replacement)
394398
(for/and ([new-id (in-syntax-identifiers new)]
395-
#:unless (bound-identifier=? new-id (intro new-id 'remove)))
399+
#:unless (bound-identifier=? new-id (intro new-id 'remove))
400+
#:unless (syntax-property new-id 'skip-incorrect-binding-check?))
396401
(free-identifier=? new-id (datum->syntax orig (syntax->datum new-id)))))
397402

398403

@@ -403,7 +408,8 @@
403408
replacement)
404409
(for/list ([new-id (in-syntax-identifiers new)]
405410
#:unless (bound-identifier=? new-id (intro new-id 'remove))
406-
#:unless (free-identifier=? new-id (datum->syntax orig (syntax->datum new-id))))
411+
#:unless (free-identifier=? new-id (datum->syntax orig (syntax->datum new-id)))
412+
#:unless (syntax-property new-id 'skip-incorrect-binding-check?))
407413
new-id))
408414

409415

0 commit comments

Comments
 (0)