Skip to content

Commit 6ad3371

Browse files
Copilotjackfirth
andauthored
Add syntax property extraction utilities (#731)
Co-authored-by: copilot-swe-agent[bot] <[email protected]> Co-authored-by: jackfirth <[email protected]>
1 parent 3354f02 commit 6ad3371

File tree

1 file changed

+143
-1
lines changed

1 file changed

+143
-1
lines changed

private/syntax-property-bundle.rkt

Lines changed: 143 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@
2121
[into-syntax-property-bundle (reducer/c syntax-property-entry? syntax-property-bundle?)]
2222
[property-hashes-into-syntax-property-bundle
2323
(reducer/c (entry/c syntax-path? immutable-hash?) syntax-property-bundle?)]
24-
[syntax-add-all-properties (-> syntax? syntax-property-bundle? syntax?)]))
24+
[syntax-add-all-properties (-> syntax? syntax-property-bundle? syntax?)]
25+
[syntax-immediate-properties (->* (syntax?) (#:base-path syntax-path?) syntax-property-bundle?)]
26+
[syntax-all-properties (->* (syntax?) (#:base-path syntax-path?) syntax-property-bundle?)]))
2527

2628

2729
(require guard
@@ -244,6 +246,27 @@
244246
(syntax-set stx path new-subform))
245247

246248

249+
(define (syntax-immediate-properties stx #:base-path [base-path empty-syntax-path])
250+
(define keys (syntax-property-symbol-keys stx))
251+
(transduce keys
252+
(mapping (λ (key)
253+
(define value (syntax-property stx key))
254+
(syntax-property-entry base-path key value)))
255+
#:into into-syntax-property-bundle))
256+
257+
258+
(define (syntax-all-properties stx #:base-path [base-path empty-syntax-path])
259+
(transduce (in-syntax-paths stx #:base-path base-path)
260+
(append-mapping
261+
(λ (path)
262+
(define subform (syntax-ref stx (syntax-path-remove-prefix path base-path)))
263+
(define keys (syntax-property-symbol-keys subform))
264+
(for/list ([key (in-list keys)])
265+
(define value (syntax-property subform key))
266+
(syntax-property-entry path key value))))
267+
#:into into-syntax-property-bundle))
268+
269+
247270
(module+ test
248271
(test-case "syntax-add-all-properties"
249272
(define stx #'(a (b c) d))
@@ -266,3 +289,122 @@
266289
(define/syntax-parse (b* c*) #'bc*)
267290
(check-equal? (syntax-property #'b* 'headphone-shaped?) #true)
268291
(check-equal? (syntax-property #'c* 'headphone-shaped?) #false)))
292+
293+
294+
(module+ test
295+
(test-case "syntax-immediate-properties"
296+
297+
(test-case "syntax with no properties"
298+
(define stx #'(a b c))
299+
(define props (syntax-immediate-properties stx))
300+
(check-true (syntax-property-bundle? props))
301+
(check-equal? (syntax-property-bundle-get-immediate-properties props empty-syntax-path)
302+
(hash)))
303+
304+
(test-case "syntax with single property"
305+
(define stx (syntax-property #'(a b c) 'foo 42))
306+
(define props (syntax-immediate-properties stx))
307+
(check-true (syntax-property-bundle? props))
308+
(define immediate (syntax-property-bundle-get-immediate-properties props empty-syntax-path))
309+
(check-equal? (hash-ref immediate 'foo) 42))
310+
311+
(test-case "syntax with multiple properties"
312+
(define stx
313+
(syntax-property
314+
(syntax-property
315+
(syntax-property #'(a b c) 'foo 42)
316+
'bar #true)
317+
'baz "hello"))
318+
(define props (syntax-immediate-properties stx))
319+
(check-true (syntax-property-bundle? props))
320+
(define immediate (syntax-property-bundle-get-immediate-properties props empty-syntax-path))
321+
(check-equal? (hash-ref immediate 'foo) 42)
322+
(check-equal? (hash-ref immediate 'bar) #true)
323+
(check-equal? (hash-ref immediate 'baz) "hello"))
324+
325+
(test-case "only extracts immediate properties, not from subforms"
326+
(define inner-stx (syntax-property #'x 'inner-prop 123))
327+
(define outer-stx
328+
(syntax-property
329+
(datum->syntax #f (list inner-stx #'y) #f)
330+
'outer-prop 456))
331+
(define props (syntax-immediate-properties outer-stx))
332+
(define immediate (syntax-property-bundle-get-immediate-properties props empty-syntax-path))
333+
(check-equal? (hash-ref immediate 'outer-prop #false) 456)
334+
(check-equal? (hash-ref immediate 'inner-prop #false) #false))))
335+
336+
337+
(module+ test
338+
(test-case "syntax-all-properties"
339+
340+
(test-case "syntax with no properties"
341+
(define stx #'(a b c))
342+
(define props (syntax-all-properties stx))
343+
(check-true (syntax-property-bundle? props))
344+
(check-equal? (sequence-length (syntax-property-bundle-entries props)) 0))
345+
346+
(test-case "syntax with property only on root"
347+
(define stx (syntax-property #'(a b c) 'root-prop 42))
348+
(define props (syntax-all-properties stx))
349+
(check-true (syntax-property-bundle? props))
350+
(define root-props (syntax-property-bundle-get-immediate-properties props empty-syntax-path))
351+
(check-equal? (hash-ref root-props 'root-prop) 42))
352+
353+
(test-case "syntax with properties on multiple subforms"
354+
(define a-stx (syntax-property #'a 'a-prop 1))
355+
(define b-stx (syntax-property #'b 'b-prop 2))
356+
(define c-stx (syntax-property #'c 'c-prop 3))
357+
(define stx (datum->syntax #f (list a-stx b-stx c-stx) #f))
358+
(define stx-with-root (syntax-property stx 'root-prop 0))
359+
(define props (syntax-all-properties stx-with-root))
360+
(check-true (syntax-property-bundle? props))
361+
362+
(define root-props (syntax-property-bundle-get-immediate-properties props empty-syntax-path))
363+
(check-equal? (hash-ref root-props 'root-prop) 0)
364+
365+
(define a-props (syntax-property-bundle-get-immediate-properties props (syntax-path (list 0))))
366+
(check-equal? (hash-ref a-props 'a-prop) 1)
367+
368+
(define b-props (syntax-property-bundle-get-immediate-properties props (syntax-path (list 1))))
369+
(check-equal? (hash-ref b-props 'b-prop) 2)
370+
371+
(define c-props (syntax-property-bundle-get-immediate-properties props (syntax-path (list 2))))
372+
(check-equal? (hash-ref c-props 'c-prop) 3))
373+
374+
(test-case "nested syntax with properties"
375+
(define inner-b (syntax-property #'b 'inner-prop 42))
376+
(define inner-c (syntax-property #'c 'inner-prop 99))
377+
(define inner-list (datum->syntax #f (list inner-b inner-c) #f))
378+
(define inner-with-prop (syntax-property inner-list 'list-prop 10))
379+
(define outer (datum->syntax #f (list #'a inner-with-prop #'d) #f))
380+
(define props (syntax-all-properties outer))
381+
382+
(define inner-list-props (syntax-property-bundle-get-immediate-properties props (syntax-path (list 1))))
383+
(check-equal? (hash-ref inner-list-props 'list-prop) 10)
384+
385+
(define b-props (syntax-property-bundle-get-immediate-properties props (syntax-path (list 1 0))))
386+
(check-equal? (hash-ref b-props 'inner-prop) 42)
387+
388+
(define c-props (syntax-property-bundle-get-immediate-properties props (syntax-path (list 1 1))))
389+
(check-equal? (hash-ref c-props 'inner-prop) 99))
390+
391+
(test-case "with base-path parameter"
392+
(define stx (syntax-property #'(a b c) 'root-prop 42))
393+
(define base (syntax-path (list 5 10)))
394+
(define props (syntax-immediate-properties stx #:base-path base))
395+
(check-true (syntax-property-bundle? props))
396+
(define base-props (syntax-property-bundle-get-immediate-properties props base))
397+
(check-equal? (hash-ref base-props 'root-prop) 42))
398+
399+
(test-case "syntax-all-properties with base-path"
400+
(define a-stx (syntax-property #'a 'a-prop 1))
401+
(define b-stx (syntax-property #'b 'b-prop 2))
402+
(define stx (datum->syntax #f (list a-stx b-stx) #f))
403+
(define base (syntax-path (list 3 7)))
404+
(define props (syntax-all-properties stx #:base-path base))
405+
406+
(define a-props (syntax-property-bundle-get-immediate-properties props (syntax-path (list 3 7 0))))
407+
(check-equal? (hash-ref a-props 'a-prop) 1)
408+
409+
(define b-props (syntax-property-bundle-get-immediate-properties props (syntax-path (list 3 7 1))))
410+
(check-equal? (hash-ref b-props 'b-prop) 2))))

0 commit comments

Comments
 (0)