Skip to content

Commit cedd860

Browse files
authored
Add syntax movement library (#491)
This will make it much easier to gather data from expanded syntax and propagate it backwards to visited syntax.
1 parent 86859d7 commit cedd860

File tree

1 file changed

+96
-0
lines changed

1 file changed

+96
-0
lines changed

private/syntax-movement.rkt

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
#lang racket/base
2+
3+
4+
(require racket/contract/base)
5+
6+
7+
(provide
8+
(contract-out
9+
; Returns a map of sorted sets of syntax paths. Unfortunately I haven't implemented sorted map and
10+
; set contracts.
11+
[syntax-movement-table (-> syntax? immutable-sorted-map?)]))
12+
13+
14+
(require racket/stream
15+
rebellion/collection/entry
16+
rebellion/collection/sorted-map
17+
rebellion/collection/sorted-set
18+
rebellion/streaming/transducer
19+
resyntax/private/syntax-neighbors
20+
resyntax/private/syntax-path
21+
resyntax/private/syntax-traversal
22+
syntax/parse)
23+
24+
25+
(module+ test
26+
(require (submod "..")
27+
rackunit))
28+
29+
30+
;@----------------------------------------------------------------------------------------------------
31+
32+
33+
; Traverses a syntax object `result-stx`, searching for all syntax objects that have a
34+
; syntax-original-path, then returns a table mapping each original path to the set of paths in
35+
; `result-stx` that corresponded to that original path. If `result-stx` is fully expanded syntax, this
36+
; amounts to returning a table mapping each (path-based) position in the original unexpanded syntax to
37+
; the set of positions in the fully expanded syntax which that original syntax expanded into. Note
38+
; that each input path maps to a set of output paths instead of a single path because macros can
39+
; duplicate forms. The returned table is in the form of an immutable sorted map of syntax paths to
40+
; sorted sets of syntax paths.
41+
(define (syntax-movement-table result-stx)
42+
43+
(define (search parent-stx [include-self? #true])
44+
(syntax-search parent-stx
45+
[child
46+
#:do [(define child-stx (attribute child))]
47+
#:when (syntax-original-path child-stx)
48+
#:when (or include-self? (not (equal? child-stx parent-stx)))
49+
(stream-cons child-stx (search child-stx #false))]))
50+
51+
(transduce (search (syntax-label-paths result-stx 'final-syntax-path))
52+
(bisecting syntax-original-path
53+
(λ (stx) (syntax-property stx 'final-syntax-path)))
54+
(grouping (into-sorted-set syntax-path<=>))
55+
#:into (into-sorted-map syntax-path<=>)))
56+
57+
58+
(module+ test
59+
(test-case "syntax-movement-table smoke test"
60+
(define orig-stx
61+
(syntax-label-original-paths
62+
#'(module foo racket/base
63+
(void))))
64+
(define expanded-stx (expand orig-stx))
65+
66+
(define table (syntax-movement-table expanded-stx))
67+
68+
(define expected-table
69+
(sorted-map
70+
#:key-comparator syntax-path<=>
71+
72+
; (module ...)
73+
empty-syntax-path
74+
(sorted-set empty-syntax-path (syntax-path (list 3)) #:comparator syntax-path<=>)
75+
76+
; module
77+
(syntax-path (list 0))
78+
(sorted-set (syntax-path (list 0)) #:comparator syntax-path<=>)
79+
80+
; foo
81+
(syntax-path (list 1))
82+
(sorted-set (syntax-path (list 1)) #:comparator syntax-path<=>)
83+
84+
; racket/base
85+
(syntax-path (list 2))
86+
(sorted-set (syntax-path (list 2)) #:comparator syntax-path<=>)
87+
88+
; (void)
89+
(syntax-path (list 3))
90+
(sorted-set (syntax-path (list 3 2)) #:comparator syntax-path<=>)
91+
92+
; void
93+
(syntax-path (list 3 0))
94+
(sorted-set (syntax-path (list 3 2 (tail-syntax 1) 0)) #:comparator syntax-path<=>)))
95+
96+
(check-equal? table expected-table)))

0 commit comments

Comments
 (0)