Skip to content

Commit c56f86e

Browse files
authored
Add analysis-test: to testing language (#552)
1 parent 9a54d6b commit c56f86e

File tree

6 files changed

+204
-18
lines changed

6 files changed

+204
-18
lines changed

main.rkt

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
#:max-modified-sources (or/c exact-nonnegative-integer? +inf.0)
2727
#:max-modified-lines (or/c exact-nonnegative-integer? +inf.0))
2828
resyntax-analysis?)]
29+
[reysntax-analyze-for-properties-only
30+
(->* (source?) (#:suite refactoring-suite?) syntax-property-bundle?)]
2931
[refactor! (-> (sequence/c refactoring-result?) void?)]))
3032

3133

@@ -59,6 +61,7 @@
5961
resyntax/private/source
6062
resyntax/private/string-indent
6163
resyntax/private/string-replacement
64+
resyntax/private/syntax-property-bundle
6265
resyntax/private/syntax-range
6366
resyntax/private/syntax-replacement
6467
(except-in racket/list range)
@@ -148,8 +151,8 @@
148151

149152

150153
(define/guard (resyntax-analyze source
151-
#:suite [suite default-recommendations]
152-
#:lines [lines (range-set (unbounded-range #:comparator natural<=>))])
154+
#:suite [suite default-recommendations]
155+
#:lines [lines (range-set (unbounded-range #:comparator natural<=>))])
153156
(define comments (with-input-from-source source read-comment-locations))
154157
(define source-lang (source-read-language source))
155158
(guard source-lang #:else
@@ -186,6 +189,31 @@
186189
(refactoring-result-set #:base-source source #:results results))
187190

188191

192+
(define/guard (reysntax-analyze-for-properties-only source #:suite [suite default-recommendations])
193+
(define comments (with-input-from-source source read-comment-locations))
194+
(define full-source (source->string source))
195+
(guard (string-prefix? full-source "#lang racket") #:else
196+
(log-resyntax-warning "skipping ~a because it does not start with #lang racket"
197+
(or (source-path source) "string source"))
198+
(syntax-property-bundle))
199+
(log-resyntax-info "analyzing ~a" (or (source-path source) "string source"))
200+
(for ([comment (in-range-set comments)])
201+
(log-resyntax-debug "parsed comment: ~a: ~v" comment (substring-by-range full-source comment)))
202+
203+
(define (skip e)
204+
(log-resyntax-error
205+
"skipping ~a\n encountered an error during macro expansion\n error:\n~a"
206+
(or (source-path source) "string source")
207+
(string-indent (exn-message e) #:amount 3))
208+
(syntax-property-bundle))
209+
210+
(with-handlers ([exn:fail:syntax? skip]
211+
[exn:fail:filesystem:missing-module? skip]
212+
[exn:fail:contract:variable? skip])
213+
(define analysis (source-analyze source))
214+
(source-code-analysis-added-syntax-properties analysis)))
215+
216+
189217
(define (resyntax-analyze-all sources
190218
#:suite [suite default-recommendations]
191219
#:max-fixes [max-fixes +inf.0]

private/source.rkt

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
[source-original (-> source? unmodified-source?)]
1515
[source-read-syntax (-> source? syntax?)]
1616
[source-read-language (-> source? (or/c module-path? #false))]
17+
[source-text-of (-> source? syntax? immutable-string?)]
1718
[source-analyze (->* (source?) (#:lines range-set?) source-code-analysis?)]
1819
[file-source? (-> any/c boolean?)]
1920
[file-source (-> path-string? file-source?)]
@@ -30,6 +31,7 @@
3031
[source-code-analysis-visited-forms (-> source-code-analysis? (listof syntax?))]
3132
[source-code-analysis-expansion-time-output (-> source-code-analysis? immutable-string?)]
3233
[source-code-analysis-namespace (-> source-code-analysis? namespace?)]
34+
[source-code-analysis-added-syntax-properties (-> source-code-analysis? syntax-property-bundle?)]
3335
[with-input-from-source (-> source? (-> any) any)]))
3436

3537

@@ -97,7 +99,8 @@
9799
#:guard (λ (original contents _) (values original (string->immutable-string contents))))
98100

99101

100-
(define-record-type source-code-analysis (code visited-forms expansion-time-output namespace))
102+
(define-record-type source-code-analysis
103+
(code visited-forms expansion-time-output namespace added-syntax-properties))
101104

102105

103106
(define (with-input-from-source code proc)
@@ -169,6 +172,15 @@
169172
(modified-source-original code)))
170173

171174

175+
(define (source-text-of code stx)
176+
(unless (and (syntax-position stx) (syntax-span stx))
177+
(raise-arguments-error 'source-text-of "syntax object does not have source location information"
178+
"syntax" stx))
179+
(define start (sub1 (syntax-position stx)))
180+
(define end (+ start (syntax-span stx)))
181+
(string->immutable-string (substring (source->string code) start end)))
182+
183+
172184
(define (source-analyze code #:lines [lines (range-set (unbounded-range #:comparator natural<=>))])
173185
(define ns (make-base-namespace))
174186
(parameterize ([current-directory (or (source-directory code) (current-directory))]
@@ -307,7 +319,8 @@
307319
(source-code-analysis #:code code
308320
#:visited-forms visited
309321
#:expansion-time-output output
310-
#:namespace ns)))
322+
#:namespace ns
323+
#:added-syntax-properties expansion-analyzer-props-adjusted-for-visits)))
311324

312325

313326
(define (syntax-original-and-from-source? stx source-name)

private/syntax-property-bundle.rkt

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@
1111
[syntax-property-bundle? (-> any/c boolean?)]
1212
[syntax-property-bundle-as-map (-> syntax-property-bundle? immutable-sorted-map?)]
1313
[syntax-property-bundle-entries (-> syntax-property-bundle? (sequence/c syntax-property-entry?))]
14-
[syntax-property-bundle-get-property (-> syntax-property-bundle? syntax-path? any/c any/c)]
14+
[syntax-property-bundle-get-property
15+
(->* (syntax-property-bundle? syntax-path? any/c) (failure-result/c) any/c)]
1516
[syntax-property-bundle-get-immediate-properties
1617
(-> syntax-property-bundle? syntax-path? immutable-hash?)]
1718
[syntax-property-bundle-get-all-properties
@@ -127,7 +128,7 @@
127128
(check-equal? actual expected)))
128129

129130

130-
(define (syntax-property-bundle-get-property prop-bundle path key)
131+
(define (syntax-property-bundle-get-property prop-bundle path key [failure-result #false])
131132
(define props-at-path (sorted-map-get (syntax-property-bundle-as-map prop-bundle) path (hash)))
132133

133134
(define (fail)
@@ -138,7 +139,7 @@
138139
"property key" key
139140
"properties at path" props-at-path))
140141

141-
(hash-ref props-at-path key fail))
142+
(hash-ref props-at-path key (or failure-result fail)))
142143

143144

144145
(module+ test
@@ -161,7 +162,18 @@
161162
(check-regexp-match #rx"syntax-property-bundle-get-property:" (exn-message thrown))
162163
(check-regexp-match #rx"path:" (exn-message thrown))
163164
(check-regexp-match #rx"property key: 'foo" (exn-message thrown))
164-
(check-regexp-match #rx"properties at path: '#hash()" (exn-message thrown)))))
165+
(check-regexp-match #rx"properties at path: '#hash()" (exn-message thrown)))
166+
167+
(test-case "empty bundle with failure value provided"
168+
(define path (syntax-path (list 1 2 3)))
169+
(define actual (syntax-property-bundle-get-property (syntax-property-bundle) path 'foo 42))
170+
(check-equal? actual 42))
171+
172+
(test-case "empty bundle with failure thunk provided"
173+
(define path (syntax-path (list 1 2 3)))
174+
(define actual
175+
(syntax-property-bundle-get-property (syntax-property-bundle) path 'foo (λ () 42)))
176+
(check-equal? actual 42))))
165177

166178

167179
(define (syntax-property-bundle-get-immediate-properties prop-bundle path)

test.rkt

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@
1111
range-set
1212
require:
1313
statement
14-
test:)
14+
test:
15+
analysis-test:)
1516

1617

1718
(require (for-syntax racket/base
@@ -130,6 +131,33 @@
130131
args.check ...))]))))
131132

132133

134+
(begin-for-syntax
135+
(define-syntax-class property-value
136+
#:description "a literal syntax property value (an unquoted symbol, boolean, number, or string)"
137+
(pattern (~or :id :boolean :number :str))))
138+
139+
140+
(define-syntax analysis-test:
141+
(statement-transformer
142+
(λ (stx)
143+
(syntax-parse stx
144+
#:track-literals
145+
#:datum-literals (option @within @inspect @property @assert)
146+
[(_ _ name:str
147+
code:literal-code-block
148+
(~seq (option @within context-block:literal-code-block) ...
149+
(option @inspect target-block:literal-code-block)
150+
(option @property property-key:id)
151+
(~and assert-option (option @assert expected-value:property-value))))
152+
#`(test-case name
153+
#,(syntax/loc this-syntax
154+
(check-suite-analysis code
155+
(list context-block ...)
156+
target-block
157+
'property-key
158+
'expected-value)))]))))
159+
160+
133161
(define (line-range first-line last-line)
134162
(closed-range first-line last-line #:comparator natural<=>))
135163

@@ -185,7 +213,10 @@
185213
(syntax-e line-stx))))
186214
(define joined-srcloc (srcloc-spanning (first (attribute line)) (last (attribute line))))
187215
(define joined-lines-stx (datum->syntax #false joined-lines joined-srcloc #false))
188-
(datum->syntax #false (list normalized-id joined-lines-stx) this-syntax this-syntax)]))
216+
(datum->syntax #false (list normalized-id joined-lines-stx) this-syntax this-syntax)]
217+
#:parent-context-modifier (λ (stx) stx)
218+
#:parent-srcloc-modifier (λ (stx) stx)
219+
#:parent-props-modifier (λ (stx) stx)))
189220
(define module-datum
190221
`(module refactoring-test racket/base
191222
(module test resyntax/test

test/private/grammar.rkt

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,11 @@
33

44
begin: statement*
55
statement: COLON-IDENTIFIER (option | expression | code-block-sequence)+
6-
@expression: range-set | IDENTIFIER | LITERAL-STRING | LITERAL-INTEGER
6+
@expression: standalone-code-block | range-set | IDENTIFIER | LITERAL-STRING | LITERAL-INTEGER
77
option: AT-SIGN-IDENTIFIER expression
88

99

10-
@code-block-sequence: standalone-code-block
11-
| starting-code-block middle-code-block* ending-code-block+
10+
@code-block-sequence: starting-code-block middle-code-block* ending-code-block+
1211
standalone-code-block: (/SINGLE-DASH CODE-LINE) | (/DASH-LINE CODE-LINE* /DASH-LINE)
1312
starting-code-block: /DASH-LINE CODE-LINE* /EQUALS-LINE
1413
middle-code-block: CODE-LINE* /EQUALS-LINE

test/private/rackunit.rkt

Lines changed: 108 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
set-header!
99
add-suite-under-test!
1010
check-suite-refactors
11-
check-suite-does-not-refactor)
11+
check-suite-does-not-refactor
12+
check-suite-analysis)
1213

1314

1415
(require racket/logging
@@ -34,6 +35,9 @@
3435
resyntax/private/source
3536
resyntax/private/string-indent
3637
resyntax/private/string-replacement
38+
resyntax/private/syntax-path
39+
resyntax/private/syntax-property-bundle
40+
resyntax/private/syntax-traversal
3741
syntax/modread
3842
syntax/parse
3943
(except-in racket/list range))
@@ -156,10 +160,11 @@
156160
(with-handlers
157161
([exn:fail?
158162
(λ (e)
159-
(with-check-info (['logs (build-logs-info)]
160-
['original (string-block-info (code-block-raw-string original-program))]
161-
['expected (string-block-info expected-program)]
162-
['exception e])
163+
(with-check-info
164+
(['logs (build-logs-info)]
165+
['original (string-block-info (code-block-raw-string original-program))]
166+
['expected (string-block-info expected-program)]
167+
['exception e])
163168
(fail-check "an error occurred while processing refactoring results")))])
164169
(call-with-logs-captured
165170
(λ () (modified-source-contents (refactoring-result-set-updated-source result-set))))))
@@ -212,6 +217,104 @@
212217
(fail-check "the program was not changed, but no-op fixes were suggested"))))))
213218

214219

220+
(define-check (check-suite-analysis program context-list target property-key expected-value)
221+
(define suite (current-suite-under-test))
222+
(set! program (code-block-append (current-header) program))
223+
(define program-src (string-source (code-block-raw-string program)))
224+
(define-values (call-with-logs-captured build-logs-info) (make-log-capture-utilities))
225+
226+
(define actual-props
227+
(call-with-logs-captured
228+
(λ () (reysntax-analyze-for-properties-only program-src))))
229+
230+
(define target-src (string-source (string-trim (code-block-raw-string target))))
231+
(define context-src-list
232+
(for/list ([ctx (in-list context-list)])
233+
(string-source (string-trim (code-block-raw-string ctx)))))
234+
235+
(define target-path (source-find-path-of program-src target-src #:contexts context-src-list))
236+
237+
(unless target-path
238+
(with-check-info (['logs (build-logs-info)]
239+
['program (string-block-info (string-source-contents program-src))]
240+
['target (string-block-info (string-source-contents target-src))])
241+
(fail-check "could not locate target subform within the given program")))
242+
243+
(define (fail-property-lookup)
244+
(define target-properties
245+
(syntax-property-bundle-get-immediate-properties actual-props target-path))
246+
(with-check-info (['logs (build-logs-info)]
247+
['program (string-block-info (string-source-contents program-src))]
248+
['target (string-block-info (string-source-contents target-src))]
249+
['target-properties target-properties]
250+
['property-key property-key])
251+
(fail-check "analysis did not assign a value for the given syntax property key")))
252+
253+
(define actual-value
254+
(syntax-property-bundle-get-property actual-props target-path property-key fail-property-lookup))
255+
256+
(unless (equal? actual-value expected-value)
257+
(with-check-info (['logs (build-logs-info)]
258+
['program (string-block-info (string-source-contents program-src))]
259+
['target (string-block-info (string-source-contents target-src))]
260+
['property-key property-key]
261+
['actual actual-value]
262+
['expected expected-value])
263+
(fail-check "analysis assigned an incorrect value for the given syntax property key"))))
264+
265+
266+
(define (source-find-path-of src target-src #:contexts [context-srcs '()])
267+
(define stx (syntax-label-paths (source-read-syntax src) 'source-path))
268+
(define target-as-string (string-source-contents target-src))
269+
270+
(define target-stx
271+
(let loop ([stx stx] [context-srcs context-srcs])
272+
(match context-srcs
273+
['()
274+
(syntax-find-first stx subform
275+
#:when (equal? (source-text-of src (attribute subform)) target-as-string))]
276+
[(cons next-context remaining-contexts)
277+
(define next-as-string (string-source-contents next-context))
278+
(define substx
279+
(syntax-find-first stx subform
280+
#:when (equal? (source-text-of src (attribute subform)) next-as-string)))
281+
(and substx (loop substx remaining-contexts))])))
282+
283+
(and target-stx (syntax-property target-stx 'source-path)))
284+
285+
286+
(module+ test
287+
(test-case "source-find-path-of"
288+
289+
(test-case "no #lang"
290+
(define src (string-source "(+ a b c)"))
291+
(define target (string-source "b"))
292+
(check-equal? (source-find-path-of src target) (syntax-path (list 2))))
293+
294+
(test-case "simple #lang"
295+
(define src (string-source "#lang racket (define a 1)"))
296+
(define target (string-source "a"))
297+
(check-equal? (source-find-path-of src target) (syntax-path (list 3 1 1))))
298+
299+
(test-case "single context"
300+
(define src (string-source "(list (+ a) (* a))"))
301+
(define target (string-source "a"))
302+
(define contexts (list (string-source "(* a)")))
303+
(check-equal? (source-find-path-of src target #:contexts contexts) (syntax-path (list 2 1))))
304+
305+
(test-case "multiple contexts"
306+
(define src (string-source "(+ a (+ a (+ a (+ a))))"))
307+
(define target (string-source "a"))
308+
(define contexts
309+
(list (string-source "(+ a (+ a (+ a)))")
310+
(string-source "(+ a (+ a))")
311+
(string-source "(+ a)")))
312+
313+
(define actual-path (source-find-path-of src target #:contexts contexts))
314+
315+
(check-equal? actual-path (syntax-path (list 2 2 2 1))))))
316+
317+
215318
(define (refactoring-result-set-matched-rules-info result-set)
216319
(define matches
217320
(transduce (refactoring-result-set-results result-set)

0 commit comments

Comments
 (0)