Skip to content

Commit f77d615

Browse files
authored
Use syntax paths instead of srclocs during analysis (#484)
1 parent 3aab87e commit f77d615

File tree

4 files changed

+234
-27
lines changed

4 files changed

+234
-27
lines changed

info.rkt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@
1212

1313

1414
(define deps
15-
(list "compatibility-lib"
15+
(list "data-lib"
16+
"compatibility-lib"
1617
"base"
1718
"br-parser-tools-lib"
1819
"brag-lib"

private/matching-comparator.rkt

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
#lang racket/base
2+
3+
4+
(provide matching-comparator)
5+
6+
7+
(require (for-syntax racket/base
8+
racket/list
9+
racket/match
10+
racket/syntax)
11+
racket/match
12+
rebellion/base/comparator
13+
syntax/parse/define)
14+
15+
16+
;@----------------------------------------------------------------------------------------------------
17+
18+
19+
(begin-for-syntax
20+
(define-splicing-syntax-class compare-directive
21+
#:attributes (comparable-expr comparator-expr comparator-expr-lexical-context)
22+
23+
(pattern (~seq #:compare comparable-expr:expr comparator-expr:expr)
24+
#:with comparator-expr-lexical-context (syntax-local-introduce (attribute comparator-expr)))
25+
26+
(pattern (~seq #:compare comparable-expr:expr)
27+
#:with comparator-expr #'real<=>
28+
#:with comparator-expr-lexical-context (attribute comparator-expr)))
29+
30+
(define-syntax-class matching-comparator-clause
31+
#:attributes (match-pattern
32+
[comparable-expr 1]
33+
[comparator-expr 1]
34+
[comparator-expr-lexical-context 1])
35+
(pattern [match-pattern :compare-directive ...])))
36+
37+
38+
(define (return-comparison-unless-equivalent comparison)
39+
(and (not (equal? comparison equivalent)) comparison))
40+
41+
42+
(begin-for-syntax
43+
(define (build-static-comparison-chain comparisons)
44+
(define/with-syntax (comparison ... last-comparison) comparisons)
45+
#'(or (return-comparison-unless-equivalent comparison) ... last-comparison)))
46+
47+
48+
(define-syntax-parse-rule (matching-comparator clause:matching-comparator-clause ...+)
49+
50+
#:with ((comparator-id ...) ...)
51+
(let ([counts (make-hash '())])
52+
(for/list ([pattern-comparator-exprs (in-list (attribute clause.comparator-expr))]
53+
[pattern-comparator-contexts
54+
(in-list (attribute clause.comparator-expr-lexical-context))]
55+
[pattern-index (in-naturals)])
56+
(for/list ([expr (in-list pattern-comparator-exprs)]
57+
[context (in-list pattern-comparator-contexts)]
58+
[i (in-naturals)])
59+
(cond
60+
[(identifier? expr)
61+
(define occurrence-index (hash-ref! counts (syntax-e expr) 0))
62+
(hash-update! counts (syntax-e expr) add1)
63+
(format-id context "~a-id~a" expr occurrence-index #:subs? #false)]
64+
[else (format-id context "pattern~a-comparator~a" pattern-index i)]))))
65+
66+
#:with (([left-comparable-thunk-id right-comparable-thunk-id] ...) ...)
67+
(for/list ([pattern-comparable-exprs (in-list (attribute clause.comparable-expr))]
68+
[pattern-index (in-naturals)])
69+
(define counts (make-hash))
70+
(for/list ([expr (in-list pattern-comparable-exprs)]
71+
[i (in-naturals)])
72+
(define (make-id side)
73+
(define context (syntax-local-introduce expr))
74+
(cond
75+
[(identifier? expr)
76+
(define occurrence-index (hash-ref! counts (syntax-e expr) 0))
77+
(hash-update! counts (syntax-e expr) add1)
78+
(format-id context "~a-~a~a" side expr (if (zero? occurrence-index) "" occurrence-index)
79+
#:subs? #false)]
80+
[else
81+
(format-id context "~a-pattern~a-comparable~a" side pattern-index i)]))
82+
(list (make-id 'left) (make-id 'right))))
83+
84+
#:with (pattern-index ...)
85+
(for/list ([i (in-range 0 (length (attribute clause.match-pattern)))])
86+
i)
87+
88+
#:with (comparable-values-expr ...)
89+
(for/list ([pattern-comaprable-exprs (in-list (attribute clause.comparable-expr))]
90+
[pattern-index (in-naturals)])
91+
(build-comparable-values-expression pattern-index pattern-comaprable-exprs))
92+
93+
#:with left-comparables-id #'left-comparables
94+
#:with right-comparables-id #'right-comparables
95+
96+
#:with (comparable-values-comparison ...)
97+
(for/list ([pattern-comparator-ids (in-list (attribute comparator-id))]
98+
[pattern-comparable-exprs (in-list (attribute clause.comparable-expr))]
99+
[pattern-left-comparable-ids (in-list (attribute left-comparable-thunk-id))]
100+
[pattern-right-comparable-ids (in-list (attribute right-comparable-thunk-id))])
101+
(build-comparable-values-comparison (attribute left-comparables-id)
102+
(attribute right-comparables-id)
103+
pattern-comparator-ids
104+
pattern-comparable-exprs
105+
pattern-left-comparable-ids
106+
pattern-right-comparable-ids))
107+
108+
(let ([comparator-id clause.comparator-expr] ... ...)
109+
(define (pattern-selector v)
110+
(match v
111+
[clause.match-pattern comparable-values-expr]
112+
...))
113+
(make-comparator
114+
(λ (left right)
115+
(define-values (left-index left-comparables-id) (pattern-selector left))
116+
(define-values (right-index right-comparables-id) (pattern-selector right))
117+
(cond
118+
[(< left-index right-index) lesser]
119+
[(> left-index right-index) greater]
120+
[(equal? left-index 'pattern-index) comparable-values-comparison]
121+
...)))))
122+
123+
124+
(begin-for-syntax
125+
(define (build-comparable-values-expression index comparable-exprs)
126+
(define wrapped-comparable-exprs
127+
(for/list ([e (in-list comparable-exprs)])
128+
(if (identifier? e) e #`(λ () #,e))))
129+
(define wrapped-comparables
130+
(match (length comparable-exprs)
131+
[0 #'#false]
132+
[1 (first wrapped-comparable-exprs)]
133+
[_ #`(λ () (values #,@wrapped-comparable-exprs))]))
134+
#`(values '#,index #,wrapped-comparables)))
135+
136+
137+
(begin-for-syntax
138+
(define (build-comparable-values-comparison left-values-id
139+
right-values-id
140+
comparator-ids
141+
comparable-exprs
142+
left-comparable-ids
143+
right-comparable-ids)
144+
(define comparisons
145+
(for/list ([e (in-list comparable-exprs)]
146+
[comparator-id (in-list comparator-ids)]
147+
[left (in-list left-comparable-ids)]
148+
[right (in-list right-comparable-ids)])
149+
(if (identifier? e)
150+
#`(compare #,comparator-id #,left #,right)
151+
#`(compare #,comparator-id (#,left) (#,right)))))
152+
(match (length comparator-ids)
153+
[0 #'equivalent]
154+
[1 #`(compare #,(first comparator-ids) #,left-values-id #,right-values-id)]
155+
[_
156+
#`(let-values ([(#,@left-comparable-ids) (#,left-values-id)]
157+
[(#,@right-comparable-ids) (#,right-values-id)])
158+
#,(build-static-comparison-chain comparisons))])))

private/source.rkt

Lines changed: 9 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929
[source-code-analysis-visited-forms (-> source-code-analysis? (listof syntax?))]
3030
[source-code-analysis-expansion-time-output (-> source-code-analysis? immutable-string?)]
3131
[source-code-analysis-namespace (-> source-code-analysis? namespace?)]
32-
[syntax-source-location (-> syntax? source-location?)]
3332
[with-input-from-source (-> source? (-> any) any)]))
3433

3534

@@ -52,6 +51,7 @@
5251
resyntax/private/linemap
5352
resyntax/private/logger
5453
resyntax/private/syntax-neighbors
54+
resyntax/private/syntax-path
5555
syntax/id-table
5656
syntax/modread
5757
syntax/parse)
@@ -82,7 +82,6 @@
8282

8383

8484
(define-record-type source-code-analysis (code visited-forms expansion-time-output namespace))
85-
(define-record-type source-location (source line column position span))
8685

8786

8887
(define (with-input-from-source code proc)
@@ -138,11 +137,11 @@
138137
(define program-source-name (syntax-source program-stx))
139138
(define current-expand-observe (dynamic-require ''#%expobs 'current-expand-observe))
140139
(define original-visits (make-vector-builder))
141-
(define expanded-originals-by-location (make-hash))
140+
(define expanded-originals-by-path (make-hash))
142141

143142
(define (add-all-original-subforms! stx)
144143
(when (resyntax-should-analyze-syntax? stx #:as-visit? #false)
145-
(hash-set! expanded-originals-by-location (syntax-source-location stx) stx))
144+
(hash-set! expanded-originals-by-path (syntax-original-path stx) stx))
146145
(syntax-parse stx
147146
[(subform ...) (for-each add-all-original-subforms! (attribute subform))]
148147
[(subform ...+ . tail-form)
@@ -197,25 +196,25 @@
197196

198197
(define output (get-output-string output-port))
199198
(define binding-table (fully-expanded-syntax-binding-table expanded))
200-
(define original-binding-table-by-position
199+
(define original-binding-table-by-path
201200
(for*/fold ([table (hash)])
202201
([phase-table (in-hash-values binding-table)]
203202
[(id uses) (in-free-id-table phase-table)]
204203
#:when (syntax-original-and-from-source? id)
205204
[use (in-list uses)])
206-
(hash-update table (syntax-source-location id) (λ (previous) (cons use previous)) '())))
205+
(hash-update table (syntax-original-path id) (λ (previous) (cons use previous)) '())))
207206

208207
(add-all-original-subforms! expanded)
209208

210209
(define/guard (add-usages stx)
211210
(guard (identifier? stx) #:else stx)
212-
(define usages (hash-ref original-binding-table-by-position (syntax-source-location stx) '()))
211+
(define usages (hash-ref original-binding-table-by-path (syntax-original-path stx) '()))
213212
(syntax-property stx 'identifier-usages usages))
214213

215214
(define (enrich stx)
216215
(define new-context
217216
(add-usages
218-
(or (hash-ref expanded-originals-by-location (syntax-source-location stx) #false) stx)))
217+
(or (hash-ref expanded-originals-by-path (syntax-original-path stx) #false) stx)))
219218
(syntax-parse stx
220219
[(subform ...)
221220
(datum->syntax new-context
@@ -232,9 +231,9 @@
232231

233232
(define visited
234233
(transduce (build-vector original-visits)
235-
(deduplicating #:key syntax-source-location)
234+
(deduplicating #:key syntax-original-path)
236235
(mapping enrich)
237-
(sorting syntax-source-location<=> #:key syntax-source-location)
236+
(sorting syntax-path<=> #:key syntax-original-path)
238237
#:into into-list))
239238

240239
(for ([visit (in-list visited)])
@@ -253,20 +252,6 @@
253252
#:namespace ns)))
254253

255254

256-
(define (syntax-source-location stx)
257-
(source-location
258-
#:source (syntax-source stx)
259-
#:line (syntax-line stx)
260-
#:column (syntax-column stx)
261-
#:position (syntax-position stx)
262-
#:span (syntax-span stx)))
263-
264-
265-
(define syntax-source-location<=>
266-
(comparator-chain (comparator-map real<=> source-location-position)
267-
(comparator-map (comparator-reverse real<=>) source-location-span)))
268-
269-
270255
(define (extract-module-require-spec mod-stx)
271256
(syntax-parse mod-stx
272257
[(_ name _ . _) `',(syntax-e #'name)]))

private/syntax-path.rkt

Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
(struct-out tail-syntax)
1212
(contract-out
1313
[syntax-path? (-> any/c boolean?)]
14+
[syntax-path<=> (comparator/c syntax-path?)]
1415
[nonempty-syntax-path? (-> any/c boolean?)]
1516
[empty-syntax-path syntax-path?]
1617
[syntax-path (-> (sequence/c syntax-path-element?) syntax-path?)]
@@ -25,12 +26,22 @@
2526
[box-element-syntax syntax-path-element?]))
2627

2728

28-
(require racket/sequence
29+
(require (for-syntax racket/base
30+
racket/list
31+
racket/match
32+
racket/sequence
33+
racket/syntax)
34+
data/order
35+
guard
36+
racket/sequence
2937
racket/struct
3038
racket/treelist
3139
racket/list
3240
racket/match
33-
rebellion/type/singleton)
41+
rebellion/base/comparator
42+
rebellion/type/singleton
43+
resyntax/private/matching-comparator
44+
syntax/parse/define)
3445

3546

3647
(module+ test
@@ -229,3 +240,55 @@
229240
(unless (prefab-struct? s)
230241
(raise-argument-error 'prefab-struct-ref "prefab-struct?" s))
231242
(list-ref (struct->list s) i))
243+
244+
245+
246+
(define datum<=>
247+
(make-comparator
248+
(λ (left right)
249+
(match (datum-order left right)
250+
['= equivalent]
251+
['> greater]
252+
['< lesser]))))
253+
254+
255+
(define syntax-path-element<=>
256+
(matching-comparator
257+
[(? exact-nonnegative-integer? i) #:compare i]
258+
[(tail-syntax i) #:compare i]
259+
[(vector-element-syntax i) #:compare i]
260+
[(hash-value-syntax key) #:compare key datum<=>]
261+
[(== box-element-syntax)]
262+
[(prefab-field-syntax i) #:compare i]))
263+
264+
265+
(module+ test
266+
(test-case "syntax-path-element<=>"
267+
(define unsorted
268+
(list 2
269+
(tail-syntax 1)
270+
box-element-syntax
271+
1
272+
3
273+
(hash-value-syntax 'foo)
274+
(tail-syntax 4)
275+
(vector-element-syntax 5)))
276+
277+
(define sorted
278+
(sort unsorted (λ (a b) (compare-infix syntax-path-element<=> a < b))))
279+
280+
(define expected
281+
(list 1
282+
2
283+
3
284+
(tail-syntax 1)
285+
(tail-syntax 4)
286+
(vector-element-syntax 5)
287+
(hash-value-syntax 'foo)
288+
box-element-syntax))
289+
(check-equal? sorted expected)))
290+
291+
292+
(define syntax-path<=>
293+
(comparator-map (lexicographic-comparator syntax-path-element<=>) syntax-path-elements
294+
#:name 'syntax-path<=>))

0 commit comments

Comments
 (0)