|
15 | 15 |
|
16 | 16 | (provide |
17 | 17 | (contract-out |
18 | | - [syntax-original-leading-neighbor (-> syntax? (or/c syntax? #false))] |
19 | | - [syntax-original-trailing-neighbor (-> syntax? (or/c syntax? #false))] |
| 18 | + [syntax-original-path (-> syntax? (or/c syntax-path? #false))] |
| 19 | + [syntax-label-original-paths (-> syntax? syntax?)] |
20 | 20 | [syntax-originally-neighbors? (-> syntax? syntax? boolean?)] |
21 | | - [syntax-mark-original-neighbors (-> syntax? syntax?)] |
22 | 21 | [syntax-extract-originals-from-pair (-> syntax? syntax? (values syntax? syntax?))])) |
23 | 22 |
|
24 | 23 |
|
25 | 24 | (require guard |
| 25 | + racket/match |
| 26 | + racket/struct |
26 | 27 | racket/syntax-srcloc |
27 | 28 | resyntax/private/logger |
| 29 | + resyntax/private/syntax-path |
28 | 30 | syntax/parse |
29 | 31 | syntax/parse/experimental/template) |
30 | 32 |
|
|
38 | 40 | ;@---------------------------------------------------------------------------------------------------- |
39 | 41 |
|
40 | 42 |
|
41 | | -(define (syntax-mark-original-neighbors stx) |
42 | | - (syntax-parse stx |
43 | | - [(~and (subform ...+) (_ trailing-neighbor ...) (leading-neighbor ... _)) |
44 | | - (define leading-neighbors (cons #false (attribute leading-neighbor))) |
45 | | - (define trailing-neighbors (append (attribute trailing-neighbor) (list #false))) |
46 | | - (define results |
47 | | - (for/list ([leading (in-list leading-neighbors)] |
48 | | - [trailing (in-list trailing-neighbors)] |
49 | | - [subform-stx (in-list (attribute subform))]) |
50 | | - (define leading-pos (and leading (syntax-position leading))) |
51 | | - (define trailing-pos (and trailing (syntax-position trailing))) |
52 | | - (define subform-pos (syntax-position subform-stx)) |
53 | | - (mark-neighbors (syntax-mark-original-neighbors subform-stx) |
54 | | - #:leading-neighbor (and leading (< leading-pos subform-pos) leading) |
55 | | - #:trailing-neighbor (and trailing (< subform-pos trailing-pos) trailing)))) |
56 | | - (datum->syntax stx results stx stx)] |
57 | | - [_ stx])) |
| 43 | +(define original-syntax-path-key 'original-syntax-path) |
58 | 44 |
|
59 | 45 |
|
60 | | -(define (mark-neighbors stx #:leading-neighbor leading-stx #:trailing-neighbor trailing-stx) |
61 | | - (define stx-with-leading |
62 | | - (if leading-stx |
63 | | - (syntax-property stx 'original-leading-neighbor leading-stx) |
64 | | - stx)) |
65 | | - (if trailing-stx |
66 | | - (syntax-property stx-with-leading |
67 | | - 'original-trailing-neighbor |
68 | | - trailing-stx) |
69 | | - stx-with-leading)) |
| 46 | +(define (syntax-label-original-paths stx) |
| 47 | + (syntax-label-paths stx original-syntax-path-key)) |
70 | 48 |
|
71 | 49 |
|
72 | | -(define (syntax-original-leading-neighbor stx) |
73 | | - (syntax-property stx 'original-leading-neighbor)) |
74 | | - |
75 | | - |
76 | | -(define (syntax-original-trailing-neighbor stx) |
77 | | - (syntax-property stx 'original-trailing-neighbor)) |
| 50 | +(define (syntax-original-path stx) |
| 51 | + ; The property value will be a cons tree if a macro produced a syntax object with the path property |
| 52 | + ; set. The main way this occurs is via `(begin x ...)`, as each of the `x` subforms counts as an |
| 53 | + ; "expansion" of the surrounding `(begin ...)` and therefore has its properties merged. In such a |
| 54 | + ; case, each `x` counts as the "result" and the `(begin ...)` counts as the "original", so if an |
| 55 | + ; `x` and the `(begin ...)` both have their paths set, the resulting property path will be |
| 56 | + ; `(cons <path-of-x> <path-of-(begin...)>)`. We therefore want to pick the *head* of any cons cells |
| 57 | + ; we encounter when looking up the original syntax path property value. There might be other cases |
| 58 | + ; where we want to look at the tail for some reason, but if those cases exist I haven't found them |
| 59 | + ; yet and they don't cause any of Resyntax's tests to fail. |
| 60 | + (let loop ([possible-cons-tree (syntax-property stx original-syntax-path-key)]) |
| 61 | + (if (pair? possible-cons-tree) |
| 62 | + (loop (car possible-cons-tree)) |
| 63 | + possible-cons-tree))) |
78 | 64 |
|
79 | 65 |
|
80 | 66 | (define (syntax-extract-originals-from-pair left-stx right-stx) |
|
89 | 75 | (define (syntax-originally-neighbors? left-stx* right-stx*) |
90 | 76 | (define-values (left-stx right-stx) (syntax-extract-originals-from-pair left-stx* right-stx*)) |
91 | 77 | (guarded-block |
92 | | - (define left-trailer (syntax-original-trailing-neighbor left-stx)) |
93 | | - (define right-leader (syntax-original-leading-neighbor right-stx)) |
| 78 | + (define left-path (syntax-original-path left-stx)) |
| 79 | + (define right-path (syntax-original-path right-stx)) |
94 | 80 | ;; If either of the above is missing, then they're not neighbors. We log a debug message in that |
95 | | - ;; case aide in debugging test failures caused by dropped comments. |
96 | | - (guard left-trailer #:else |
97 | | - (log-resyntax-debug (string-append "not neighbors because left-trailer is missing\n" |
| 81 | + ;; case to aide in debugging test failures caused by dropped comments. |
| 82 | + (guard left-path #:else |
| 83 | + (log-resyntax-debug (string-append "not neighbors because left-path is missing\n" |
98 | 84 | " original left syntax: ~a\n" |
99 | 85 | " original right syntax: ~a\n" |
100 | 86 | " replacement left syntax: ~a\n" |
|
104 | 90 | (syntax->datum left-stx*) |
105 | 91 | (syntax->datum right-stx*)) |
106 | 92 | #false) |
107 | | - (guard right-leader #:else |
108 | | - (log-resyntax-debug (string-append "not neighbors because right-leader is missing\n" |
| 93 | + (guard right-path #:else |
| 94 | + (log-resyntax-debug (string-append "not neighbors because right-path is missing\n" |
109 | 95 | " original left syntax: ~a\n" |
110 | 96 | " original right syntax: ~a\n" |
111 | 97 | " replacement left syntax: ~a\n" |
|
115 | 101 | (syntax->datum left-stx*) |
116 | 102 | (syntax->datum right-stx*)) |
117 | 103 | #false) |
118 | | - (define left-srcloc (syntax-srcloc left-stx)) |
119 | | - (define left-trailer-srcloc (syntax-srcloc left-trailer)) |
120 | | - (define right-srcloc (syntax-srcloc right-stx)) |
121 | | - (define right-leader-srcloc (syntax-srcloc right-leader)) |
122 | | - (guard (and left-srcloc left-trailer-srcloc right-srcloc right-leader-srcloc) #:else #false) |
123 | | - (and (equal? left-trailer-srcloc right-srcloc) (equal? right-leader-srcloc left-srcloc)))) |
| 104 | + (define neighbors? (syntax-path-neighbors? left-path right-path)) |
| 105 | + (unless neighbors? |
| 106 | + (log-resyntax-debug (string-append "not neighbors because syntax-path-neighbors? says so\n" |
| 107 | + " original left path: ~a\n" |
| 108 | + " original right path: ~a\n" |
| 109 | + " original left syntax: ~a\n" |
| 110 | + " original right syntax: ~a\n" |
| 111 | + " replacement left syntax: ~a\n" |
| 112 | + " replacement right syntax: ~a") |
| 113 | + left-path |
| 114 | + right-path |
| 115 | + (syntax->datum left-stx) |
| 116 | + (syntax->datum right-stx) |
| 117 | + (syntax->datum left-stx*) |
| 118 | + (syntax->datum right-stx*))) |
| 119 | + neighbors?)) |
124 | 120 |
|
125 | 121 |
|
126 | 122 | (module+ test |
127 | | - (test-case "syntax-mark-original-neighbors" |
| 123 | + (test-case "syntax-originally-neighbors?" |
128 | 124 | (define stx #'(foo (a b c) bar (baz))) |
129 | | - (define marked (syntax-mark-original-neighbors stx)) |
130 | | - (check-equal? (syntax->datum marked) (syntax->datum stx)) |
131 | | - (define/with-syntax (foo* (a* b* c*) bar* (baz*)) marked) |
132 | | - (check-false (syntax-original-leading-neighbor #'foo*)) |
133 | | - (check-equal? (syntax->datum (syntax-original-trailing-neighbor #'foo*)) '(a b c)) |
134 | | - (check-false (syntax-original-leading-neighbor #'a*)) |
135 | | - (check-equal? (syntax->datum (syntax-original-trailing-neighbor #'a*)) 'b) |
136 | | - (check-equal? (syntax->datum (syntax-original-leading-neighbor #'b*)) 'a) |
137 | | - (check-equal? (syntax->datum (syntax-original-trailing-neighbor #'b*)) 'c) |
138 | | - (check-equal? (syntax->datum (syntax-original-leading-neighbor #'c*)) 'b) |
139 | | - (check-false (syntax-original-trailing-neighbor #'c*)) |
140 | | - (check-equal? (syntax->datum (syntax-original-leading-neighbor #'bar*)) '(a b c)) |
141 | | - (check-equal? (syntax->datum (syntax-original-trailing-neighbor #'bar*)) '(baz)) |
142 | | - (check-false (syntax-original-leading-neighbor #'baz*)) |
143 | | - (check-false (syntax-original-trailing-neighbor #'baz*)) |
| 125 | + (define labeled (syntax-label-original-paths stx)) |
| 126 | + (check-equal? (syntax->datum labeled) (syntax->datum stx)) |
| 127 | + (define/with-syntax (foo* (a* b* c*) bar* (baz*)) labeled) |
144 | 128 | (check-false (syntax-originally-neighbors? #'foo* #'b*)) |
145 | 129 | (check-true (syntax-originally-neighbors? #'a* #'b*)) |
146 | 130 | (check-true (syntax-originally-neighbors? #'b* #'c*)) |
147 | 131 | (check-false (syntax-originally-neighbors? #'c* #'bar*)) |
148 | 132 | (check-false (syntax-originally-neighbors? #'bar* #'baz*)))) |
| 133 | + |
| 134 | + |
| 135 | +(define (improper-list-drop-tail improper-list) |
| 136 | + (cons (car improper-list) |
| 137 | + (let loop ([improper-list (cdr improper-list)]) |
| 138 | + (if (pair? improper-list) |
| 139 | + (cons (car improper-list) (loop (cdr improper-list))) |
| 140 | + '())))) |
| 141 | + |
| 142 | + |
| 143 | +(module+ test |
| 144 | + (test-case "improper-list-drop-tail" |
| 145 | + (check-equal? (improper-list-drop-tail '(1 2 3 . 4)) '(1 2 3)))) |
0 commit comments