|
15 | 15 | [in-expanded-id-table |
16 | 16 | (-> expanded-id-table? (sequence/c (entry/c expanded-identifier? any/c)))] |
17 | 17 | [in-expanded-id-table-phase |
18 | | - (-> expanded-id-table? (or/c exact-nonnegative-integer? #false) (sequence/c (entry/c expanded-identifier? any/c)))])) |
| 18 | + (-> expanded-id-table? (or/c exact-nonnegative-integer? #false) (sequence/c (entry/c expanded-identifier? any/c)))] |
| 19 | + [syntax-label-id-phases (-> syntax? syntax?)] |
| 20 | + [binding-site-identifiers (-> syntax? stream?)] |
| 21 | + [fully-expanded-syntax-id-table (-> syntax? expanded-id-table?)])) |
19 | 22 |
|
20 | 23 |
|
21 | 24 | (require guard |
22 | 25 | racket/contract/base |
23 | 26 | racket/dict |
| 27 | + racket/list |
24 | 28 | racket/match |
25 | 29 | racket/sequence |
26 | 30 | racket/stream |
27 | 31 | rebellion/base/result |
28 | 32 | rebellion/collection/entry |
29 | | - syntax/id-table) |
| 33 | + resyntax/private/syntax-traversal |
| 34 | + syntax/id-table |
| 35 | + syntax/parse) |
30 | 36 |
|
31 | 37 |
|
32 | 38 | (module+ test |
|
87 | 93 | ;@---------------------------------------------------------------------------------------------------- |
88 | 94 |
|
89 | 95 |
|
| 96 | +;; Label syntax with phase information |
| 97 | +(define (syntax-label-id-phases expanded-stx) |
| 98 | + (let loop ([expanded-stx expanded-stx] [phase 0] [skip? #false]) |
| 99 | + (syntax-traverse expanded-stx |
| 100 | + #:skip-root? skip? |
| 101 | + #:literal-sets ([kernel-literals #:phase phase]) |
| 102 | + |
| 103 | + [:id (syntax-property this-syntax 'phase phase)] |
| 104 | + [(begin-for-syntax _ ...) (loop this-syntax (add1 phase) #true)] |
| 105 | + |
| 106 | + [(define-syntaxes-id:define-syntaxes ids expr) |
| 107 | + (define new-define-syntaxes (loop (attribute define-syntaxes-id) phase #false)) |
| 108 | + (define new-ids (loop (attribute ids) phase #true)) |
| 109 | + (define new-expr (loop (attribute expr) (add1 phase) #false)) |
| 110 | + (define new-datum (list new-define-syntaxes new-ids new-expr)) |
| 111 | + (datum->syntax this-syntax new-datum this-syntax this-syntax)] |
| 112 | + |
| 113 | + [((~or module module*) _ ...) (loop this-syntax 0 #true)] |
| 114 | + |
| 115 | + #:parent-context-modifier (λ (stx) stx) |
| 116 | + #:parent-srcloc-modifier (λ (stx) stx) |
| 117 | + #:parent-props-modifier (λ (stx) stx)))) |
| 118 | + |
| 119 | + |
| 120 | +;; Find all binding sites and return them as a stream of identifiers |
| 121 | +(define (binding-site-identifiers expanded-stx) |
| 122 | + (let loop ([expanded-stx expanded-stx] [phase 0]) |
| 123 | + (define (recur stx) |
| 124 | + (loop stx phase)) |
| 125 | + (syntax-search expanded-stx |
| 126 | + #:literal-sets ([kernel-literals #:phase phase]) |
| 127 | + |
| 128 | + [(id:id _ ...) |
| 129 | + #:do [(define id-phase (syntax-property (attribute id) 'phase))] |
| 130 | + #:when (not (equal? id-phase phase)) |
| 131 | + (loop this-syntax id-phase)] |
| 132 | + |
| 133 | + [(quote-syntax _ ...) (stream)] |
| 134 | + |
| 135 | + [(define-values (id ...) body) |
| 136 | + (stream-append (attribute id) (recur (attribute body)))] |
| 137 | + |
| 138 | + [(define-syntaxes (id ...) body) |
| 139 | + (stream-append (attribute id) (loop (attribute body) (add1 phase)))] |
| 140 | + |
| 141 | + [((~or let-values letrec-values) ([(id ...) rhs] ...) body ...) |
| 142 | + (define inner-exprs (append (attribute rhs) (attribute body))) |
| 143 | + (define ids (append* (attribute id))) |
| 144 | + (apply stream-append ids (map recur inner-exprs))] |
| 145 | + |
| 146 | + [(#%plain-lambda formals body ...) |
| 147 | + (apply stream-append |
| 148 | + (syntax-search (attribute formals) [:id]) |
| 149 | + (map recur (attribute body)))] |
| 150 | + |
| 151 | + [(case-lambda [formals body ...] ...) |
| 152 | + (apply stream-append |
| 153 | + (syntax-search #'(formals ...) [:id]) |
| 154 | + (map recur (append* (attribute body))))]))) |
| 155 | + |
| 156 | + |
| 157 | +;; Builds an expanded-id-table from phase-labeled syntax. |
| 158 | +;; The input syntax should already have phase labels added via syntax-label-id-phases. |
| 159 | +;; Returns an expanded-id-table mapping expanded-identifiers to empty lists, |
| 160 | +;; with one entry for each binding site in the syntax. |
| 161 | +(define (fully-expanded-syntax-id-table stx) |
| 162 | + ;; stx is expected to already have phase labels via syntax-label-id-phases |
| 163 | + (define table (make-expanded-id-table)) |
| 164 | + (for ([id (in-stream (binding-site-identifiers stx))]) |
| 165 | + (define id-phase (syntax-property id 'phase)) |
| 166 | + (expanded-id-table-set! table (expanded-identifier id id-phase) '())) |
| 167 | + table) |
| 168 | + |
| 169 | + |
| 170 | +;@---------------------------------------------------------------------------------------------------- |
| 171 | + |
| 172 | + |
90 | 173 | (module+ test |
91 | 174 | (test-case "expanded-id-table" |
92 | 175 |
|
|
118 | 201 | (expanded-id-table-set! table id2 'val2) |
119 | 202 | (expanded-id-table-set! table id3 'val3) |
120 | 203 | (define entries (for/list ([e (in-expanded-id-table table)]) e)) |
121 | | - (check-equal? (length entries) 3)))) |
| 204 | + (check-equal? (length entries) 3))) |
| 205 | + |
| 206 | + (test-case "fully-expanded-syntax-id-table" |
| 207 | + |
| 208 | + (test-case "creates table with binding sites from expanded module" |
| 209 | + (define stx #'(module test racket/base (define x 1) (define y 2))) |
| 210 | + (define expanded-stx (expand stx)) |
| 211 | + (define labeled-stx (syntax-label-id-phases expanded-stx)) |
| 212 | + (define table (fully-expanded-syntax-id-table labeled-stx)) |
| 213 | + (check-pred expanded-id-table? table) |
| 214 | + ;; The table should contain bindings |
| 215 | + (define entries (for/list ([e (in-expanded-id-table table)]) e)) |
| 216 | + (check > (length entries) 0)) |
| 217 | + |
| 218 | + (test-case "creates table with phase 0 bindings" |
| 219 | + (define stx #'(module test racket/base (define a 1))) |
| 220 | + (define expanded-stx (expand stx)) |
| 221 | + (define labeled-stx (syntax-label-id-phases expanded-stx)) |
| 222 | + (define table (fully-expanded-syntax-id-table labeled-stx)) |
| 223 | + (define phase0-entries (for/list ([e (in-expanded-id-table-phase table 0)]) e)) |
| 224 | + (check > (length phase0-entries) 0)) |
| 225 | + |
| 226 | + (test-case "creates table with phase 1 bindings" |
| 227 | + (define stx #'(module test racket/base |
| 228 | + (require (for-syntax racket/base)) |
| 229 | + (begin-for-syntax (define a 1)))) |
| 230 | + (define expanded-stx (expand stx)) |
| 231 | + (define labeled-stx (syntax-label-id-phases expanded-stx)) |
| 232 | + (define table (fully-expanded-syntax-id-table labeled-stx)) |
| 233 | + (define phase1-entries (for/list ([e (in-expanded-id-table-phase table 1)]) e)) |
| 234 | + (check > (length phase1-entries) 0)))) |
0 commit comments