Skip to content

Commit e05681a

Browse files
Copilotjackfirth
andauthored
Store visited paths instead of syntaxes in source-code-analysis (#712)
Co-authored-by: copilot-swe-agent[bot] <[email protected]> Co-authored-by: jackfirth <[email protected]> Co-authored-by: Jack Firth <[email protected]>
1 parent 6e4206d commit e05681a

File tree

1 file changed

+63
-62
lines changed

1 file changed

+63
-62
lines changed

private/analysis.rkt

Lines changed: 63 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
source-code-analysis?)]
1212
[source-code-analysis? (-> any/c boolean?)]
1313
[source-code-analysis-code (-> source-code-analysis? source?)]
14+
[source-code-analysis-enriched-syntax (-> source-code-analysis? syntax?)]
15+
[source-code-analysis-visited-paths (-> source-code-analysis? (listof syntax-path?))]
1416
[source-code-analysis-visited-forms (-> source-code-analysis? (listof syntax?))]
1517
[source-code-analysis-expansion-time-output (-> source-code-analysis? immutable-string?)]
1618
[source-code-analysis-namespace (-> source-code-analysis? namespace?)]
@@ -33,6 +35,7 @@
3335
rebellion/collection/sorted-map
3436
rebellion/collection/sorted-set
3537
rebellion/collection/vector/builder
38+
rebellion/streaming/reducer
3639
rebellion/streaming/transducer
3740
rebellion/type/record
3841
resyntax/default-recommendations/analyzers/identifier-usage
@@ -55,7 +58,14 @@
5558

5659

5760
(define-record-type source-code-analysis
58-
(code visited-forms expansion-time-output namespace added-syntax-properties))
61+
(code enriched-syntax visited-paths expansion-time-output namespace added-syntax-properties))
62+
63+
64+
(define (source-code-analysis-visited-forms analysis)
65+
(define stx (source-code-analysis-enriched-syntax analysis))
66+
(define paths (source-code-analysis-visited-paths analysis))
67+
(for/list ([path (in-sorted-set paths)])
68+
(syntax-ref stx path)))
5969

6070

6171
(define (source-analyze code
@@ -76,8 +86,8 @@
7686
(log-resyntax-debug "original source name: ~a" program-source-name)
7787
(log-resyntax-debug "original syntax:\n ~a" program-stx)
7888
(define current-expand-observe (dynamic-require ''#%expobs 'current-expand-observe))
79-
(define original-visits (make-vector-builder))
80-
(define most-recent-visits-by-original-path (make-hash))
89+
(define visited-syntaxes (make-mutable-sorted-map #:key-comparator syntax-path<=>))
90+
(define context-syntaxes (make-mutable-sorted-map #:key-comparator syntax-path<=>))
8191

8292
(define/guard (resyntax-should-analyze-syntax? stx #:as-visit? [as-visit? #true])
8393
(guard (syntax-original-and-from-source? stx program-source-name) #:else #false)
@@ -98,12 +108,17 @@
98108
(define/match (observe-event! sig val)
99109
[('visit (? syntax? visited))
100110
(when (resyntax-should-analyze-syntax? visited)
101-
(vector-builder-add original-visits visited))
111+
(define visited-path (syntax-original-path visited))
112+
(unless visited-path
113+
(raise-arguments-error
114+
'source-analyze "visit is missing original path"
115+
"visited syntax" visited))
116+
(sorted-map-put-if-absent! visited-syntaxes visited-path visited))
102117
(for ([visit-subform (in-stream (syntax-search-everything visited))]
103118
#:when (and (resyntax-should-analyze-syntax? visit-subform #:as-visit? #false)
104119
(syntax-has-original-path? visit-subform)))
105120
(define path (syntax-original-path visit-subform))
106-
(hash-set! most-recent-visits-by-original-path path visit-subform))]
121+
(sorted-map-put! context-syntaxes path visit-subform))]
107122
[(_ _) (void)])
108123

109124
(define output-port (open-output-string))
@@ -112,6 +127,8 @@
112127
[current-output-port output-port])
113128
(expand program-stx)))
114129

130+
(define visited-paths (sorted-set->immutable-sorted-set (sorted-map-keys visited-syntaxes)))
131+
115132
;; We evaluate the module in order to ensure it's declared in the namespace, then we attach it at
116133
;; expansion time to ensure the module is visited (but not instantiated). This allows refactoring
117134
;; rules to access expansion-time values reflectively via the analysis namespace.
@@ -121,6 +138,36 @@
121138
(define output (get-output-string output-port))
122139
(define movement-table (syntax-movement-table expanded))
123140

141+
;; Here we search the expanded syntax for unambiguously original syntax objects and insert them
142+
;; into the context table. This ensures that any identifiers which survive expansion will contain
143+
;; all their post-expansion scopes when being analyzed by rules.
144+
(for ([e (in-sorted-map movement-table)])
145+
(match-define (entry orig-path exp-paths) e)
146+
(define num-orig-paths
147+
(transduce exp-paths
148+
(filtering (λ (path) (syntax-original? (syntax-ref expanded path))))
149+
#:into into-count))
150+
(when (>= num-orig-paths 2)
151+
(log-resyntax-debug
152+
(string-append
153+
"ignoring expansion lexical context for original path ~a because"
154+
" multiple expanded forms claim to originate from that path and be original"
155+
" syntax.")
156+
orig-path))
157+
(when (equal? num-orig-paths 1)
158+
(define exp-path (present-value (sorted-set-least-element exp-paths)))
159+
(sorted-map-put! context-syntaxes orig-path (syntax-ref expanded exp-path))))
160+
161+
(define enriched-program-stx-without-analyzer-props
162+
(for/fold ([program-stx program-stx])
163+
([e (in-sorted-map context-syntaxes)])
164+
(match-define (entry orig-path context-stx) e)
165+
(define child-stx (syntax-ref program-stx orig-path))
166+
(define stx-to-use-for-props (sorted-map-get visited-syntaxes orig-path child-stx))
167+
(define enriched-child
168+
(datum->syntax context-stx (syntax-e child-stx) child-stx stx-to-use-for-props))
169+
(syntax-set program-stx orig-path enriched-child)))
170+
124171
(define property-selection-table
125172
(transduce movement-table
126173
(filtering
@@ -151,7 +198,10 @@
151198
(define valid? (syntax-contains-path? expanded path))
152199
(unless valid?
153200
(log-resyntax-warning
154-
"ignoring property with out-of-syntax path returned by analyzer~n path: ~a~n property key: ~a"
201+
(string-append
202+
"ignoring property with out-of-syntax path returned by analyzer\n"
203+
" path: ~a\n"
204+
" property key: ~a")
155205
path
156206
key))
157207
valid?))
@@ -170,63 +220,14 @@
170220
(string-indent (pretty-format expansion-analyzer-props-adjusted-for-visits) #:amount 2))
171221
(log-resyntax-debug "syntax properties from expansion analyzers:\n~a" props-str))
172222

173-
(define (enrich stx #:skip-root? [skip-root? #false])
174-
(syntax-traverse stx
175-
#:skip-root? skip-root?
176-
[child
177-
#:do [(define child-stx (attribute child))
178-
(define orig-path (syntax-original-path child-stx))]
179-
#:when (and orig-path (sorted-map-contains-key? movement-table orig-path))
180-
#:do [(define expansions
181-
(transduce (sorted-map-get movement-table orig-path)
182-
(mapping (λ (p) (syntax-ref expanded p)))
183-
(filtering syntax-original?)
184-
#:into into-list))]
185-
#:when (equal? (length expansions) 1)
186-
(match-define (list expanded-child) expansions)
187-
(log-resyntax-debug "enriching ~a with scopes from expansion" child-stx)
188-
(enrich (datum->syntax expanded-child (syntax-e child-stx) child-stx child-stx)
189-
#:skip-root? #true)]
190-
[child
191-
#:do [(define child-stx (attribute child))
192-
(define orig-path (syntax-original-path child-stx))]
193-
#:when (and orig-path (hash-has-key? most-recent-visits-by-original-path orig-path))
194-
#:do [(define visit (hash-ref most-recent-visits-by-original-path orig-path))]
195-
(log-resyntax-debug "enriching ~a with scopes from visit" child-stx)
196-
(enrich (datum->syntax visit (syntax-e child-stx) child-stx child-stx) #:skip-root? #true)]
197-
#:parent-context-modifier values
198-
#:parent-srcloc-modifier values
199-
#:parent-props-modifier values))
200-
201-
(define visited
202-
(transduce (build-vector original-visits)
203-
(peeking
204-
(λ (visit)
205-
(unless (syntax-original-path visit)
206-
(raise-arguments-error
207-
'source-analyze "pre-enriched visit is missing original path"
208-
"visited syntax" visit))))
209-
(deduplicating #:key syntax-original-path)
210-
(mapping
211-
(λ (visit)
212-
(define path (syntax-original-path visit))
213-
(define visit-props
214-
(syntax-property-bundle-get-all-properties
215-
expansion-analyzer-props-adjusted-for-visits path))
216-
(syntax-add-all-properties visit visit-props)))
217-
(mapping enrich)
218-
(peeking
219-
(λ (visit)
220-
(unless (syntax-original-path visit)
221-
(raise-arguments-error
222-
'source-analyze "post-enriched visit is missing original path"
223-
"visited syntax" visit))))
224-
(sorting syntax-path<=> #:key syntax-original-path)
225-
#:into into-list))
226-
227-
(log-resyntax-debug "visited ~a forms" (length visited))
223+
(define enriched-program-stx
224+
(syntax-add-all-properties enriched-program-stx-without-analyzer-props
225+
expansion-analyzer-props-adjusted-for-visits))
226+
227+
(log-resyntax-debug "visited ~a forms" (sorted-set-size visited-paths))
228228
(source-code-analysis #:code code
229-
#:visited-forms visited
229+
#:enriched-syntax enriched-program-stx
230+
#:visited-paths visited-paths
230231
#:expansion-time-output output
231232
#:namespace ns
232233
#:added-syntax-properties expansion-analyzer-props-adjusted-for-visits)))

0 commit comments

Comments
 (0)