|
26 | 26 | [syntax-set (-> syntax? syntax-path? syntax? syntax?)] |
27 | 27 | [syntax-remove-splice (-> syntax? nonempty-syntax-path? exact-nonnegative-integer? syntax?)] |
28 | 28 | [syntax-insert-splice (-> syntax? nonempty-syntax-path? (sequence/c syntax?) syntax?)] |
29 | | - [syntax-label-paths (-> syntax? symbol? syntax?)])) |
| 29 | + [syntax-label-paths (-> syntax? symbol? syntax?)] |
| 30 | + [in-syntax-paths (->* (syntax?) (#:base-path syntax-path?) (sequence/c syntax-path?))])) |
30 | 31 |
|
31 | 32 |
|
32 | 33 | (require (for-syntax racket/base |
|
37 | 38 | data/order |
38 | 39 | guard |
39 | 40 | racket/format |
| 41 | + racket/generator |
40 | 42 | racket/mutability |
41 | 43 | racket/sequence |
42 | 44 | racket/string |
|
871 | 873 | (check-equal? (syntax->datum actual) '(a b c FOO e))))) |
872 | 874 |
|
873 | 875 |
|
874 | | - |
875 | | - |
876 | | - |
877 | | - |
878 | 876 | (define/guard (syntax-remove-splice stx path children-count) |
879 | 877 | (guard (positive? children-count) #:else stx) |
880 | 878 | (define parent (syntax-ref stx (syntax-path-parent path))) |
|
1177 | 1175 | (syntax-property stx-with-children-labeled property-name path))) |
1178 | 1176 |
|
1179 | 1177 |
|
1180 | | - |
1181 | | - |
1182 | 1178 | (module+ test |
1183 | 1179 | (test-case "syntax-label-paths" |
1184 | 1180 | (define stx #'(foo (a b . c) bar (baz) #(x y) #&z #s(point n m))) |
|
1205 | 1201 | (check-equal? (syntax->datum (syntax-ref stx path)) (syntax->datum id))))) |
1206 | 1202 |
|
1207 | 1203 |
|
| 1204 | +(define (in-syntax-children stx) |
| 1205 | + (match (syntax-e stx) |
| 1206 | + [(? pair? stx-pair) |
| 1207 | + (in-generator |
| 1208 | + (let loop ([stx-pair stx-pair]) |
| 1209 | + (match stx-pair |
| 1210 | + [(list) (void)] |
| 1211 | + [(cons head tail) |
| 1212 | + (yield head) |
| 1213 | + (cond |
| 1214 | + [(and (syntax? tail) |
| 1215 | + (or (pair? (syntax-e tail)) (empty? (syntax-e tail)))) |
| 1216 | + (unless (empty? (syntax-e tail)) |
| 1217 | + (loop (syntax-e tail)))] |
| 1218 | + [else |
| 1219 | + (loop tail)])] |
| 1220 | + [improper-tail |
| 1221 | + (yield improper-tail)])))] |
| 1222 | + [(? vector? vec) (in-vector vec)] |
| 1223 | + [(? box? b) (in-value (unbox b))] |
| 1224 | + [(? prefab-struct? s) (in-list (struct->list s))] |
| 1225 | + [_ (in-list (list))])) |
| 1226 | + |
| 1227 | + |
| 1228 | +(define (in-syntax-paths stx #:base-path [base-path empty-syntax-path]) |
| 1229 | + (in-generator |
| 1230 | + (let traverse ([stx stx] |
| 1231 | + [parent-elems (syntax-path-elements base-path)]) |
| 1232 | + (yield (syntax-path parent-elems)) |
| 1233 | + (for ([child-stx (in-syntax-children stx)] |
| 1234 | + [i (in-naturals)]) |
| 1235 | + (traverse child-stx (treelist-add parent-elems i)))))) |
| 1236 | + |
| 1237 | + |
| 1238 | +(module+ test |
| 1239 | + (test-case "in-syntax-paths" |
| 1240 | + |
| 1241 | + (test-case "simple flat list" |
| 1242 | + (define stx #'(a b c)) |
| 1243 | + (define paths (sequence->list (in-syntax-paths stx))) |
| 1244 | + (check-equal? paths |
| 1245 | + (list |
| 1246 | + (syntax-path (list)) |
| 1247 | + (syntax-path (list 0)) |
| 1248 | + (syntax-path (list 1)) |
| 1249 | + (syntax-path (list 2))))) |
| 1250 | + |
| 1251 | + (test-case "nested list" |
| 1252 | + (define stx #'(a (b0 b1) c)) |
| 1253 | + (define paths (sequence->list (in-syntax-paths stx))) |
| 1254 | + (check-equal? paths |
| 1255 | + (list |
| 1256 | + (syntax-path (list)) |
| 1257 | + (syntax-path (list 0)) |
| 1258 | + (syntax-path (list 1)) |
| 1259 | + (syntax-path (list 1 0)) |
| 1260 | + (syntax-path (list 1 1)) |
| 1261 | + (syntax-path (list 2))))) |
| 1262 | + |
| 1263 | + (test-case "with base-path" |
| 1264 | + (define stx #'(a (b0 b1) c)) |
| 1265 | + (define paths (sequence->list (in-syntax-paths stx #:base-path (syntax-path (list 5 6 7))))) |
| 1266 | + (check-equal? paths |
| 1267 | + (list |
| 1268 | + (syntax-path (list 5 6 7)) |
| 1269 | + (syntax-path (list 5 6 7 0)) |
| 1270 | + (syntax-path (list 5 6 7 1)) |
| 1271 | + (syntax-path (list 5 6 7 1 0)) |
| 1272 | + (syntax-path (list 5 6 7 1 1)) |
| 1273 | + (syntax-path (list 5 6 7 2))))) |
| 1274 | + |
| 1275 | + (test-case "deeply nested structure" |
| 1276 | + (define stx #'(a (b (c (d e))))) |
| 1277 | + (define paths (sequence->list (in-syntax-paths stx))) |
| 1278 | + (check-equal? paths |
| 1279 | + (list |
| 1280 | + (syntax-path (list)) |
| 1281 | + (syntax-path (list 0)) |
| 1282 | + (syntax-path (list 1)) |
| 1283 | + (syntax-path (list 1 0)) |
| 1284 | + (syntax-path (list 1 1)) |
| 1285 | + (syntax-path (list 1 1 0)) |
| 1286 | + (syntax-path (list 1 1 1)) |
| 1287 | + (syntax-path (list 1 1 1 0)) |
| 1288 | + (syntax-path (list 1 1 1 1))))) |
| 1289 | + |
| 1290 | + (test-case "single atom" |
| 1291 | + (define stx #'atom) |
| 1292 | + (define paths (sequence->list (in-syntax-paths stx))) |
| 1293 | + (check-equal? paths |
| 1294 | + (list (syntax-path (list))))) |
| 1295 | + |
| 1296 | + (test-case "empty list" |
| 1297 | + (define stx #'()) |
| 1298 | + (define paths (sequence->list (in-syntax-paths stx))) |
| 1299 | + (check-equal? paths |
| 1300 | + (list (syntax-path (list))))) |
| 1301 | + |
| 1302 | + (test-case "vector" |
| 1303 | + (define stx #'#[a b c]) |
| 1304 | + (define paths (sequence->list (in-syntax-paths stx))) |
| 1305 | + (check-equal? paths |
| 1306 | + (list |
| 1307 | + (syntax-path (list)) |
| 1308 | + (syntax-path (list 0)) |
| 1309 | + (syntax-path (list 1)) |
| 1310 | + (syntax-path (list 2))))) |
| 1311 | + |
| 1312 | + (test-case "box" |
| 1313 | + (define stx #'#&a) |
| 1314 | + (define paths (sequence->list (in-syntax-paths stx))) |
| 1315 | + (check-equal? paths |
| 1316 | + (list |
| 1317 | + (syntax-path (list)) |
| 1318 | + (syntax-path (list 0))))) |
| 1319 | + |
| 1320 | + (test-case "improper lists - all produce same paths" |
| 1321 | + (define expected-paths |
| 1322 | + (list |
| 1323 | + (syntax-path (list)) |
| 1324 | + (syntax-path (list 0)) |
| 1325 | + (syntax-path (list 1)) |
| 1326 | + (syntax-path (list 2)))) |
| 1327 | + |
| 1328 | + (test-case "proper list: #'(a b c)" |
| 1329 | + (define stx #'(a b c)) |
| 1330 | + (define paths (sequence->list (in-syntax-paths stx))) |
| 1331 | + (check-equal? paths expected-paths)) |
| 1332 | + |
| 1333 | + (test-case "improper with tail: #'(a b . c)" |
| 1334 | + (define stx #'(a b . c)) |
| 1335 | + (define paths (sequence->list (in-syntax-paths stx))) |
| 1336 | + (check-equal? paths expected-paths)) |
| 1337 | + |
| 1338 | + (test-case "nested improper: #'(a . (b . (c . ())))" |
| 1339 | + (define stx #'(a . (b . (c . ())))) |
| 1340 | + (define paths (sequence->list (in-syntax-paths stx))) |
| 1341 | + (check-equal? paths expected-paths)) |
| 1342 | + |
| 1343 | + (test-case "dotted syntax: #'(a . (b c))" |
| 1344 | + (define stx #'(a . (b c))) |
| 1345 | + (define paths (sequence->list (in-syntax-paths stx))) |
| 1346 | + (check-equal? paths expected-paths)) |
| 1347 | + |
| 1348 | + (test-case "nested dotted: #'(a . (b . c))" |
| 1349 | + (define stx #'(a . (b . c))) |
| 1350 | + (define paths (sequence->list (in-syntax-paths stx))) |
| 1351 | + (check-equal? paths expected-paths))))) |
1208 | 1352 |
|
1209 | 1353 |
|
1210 | 1354 | (define (prefab-struct? v) |
|
1217 | 1361 | (list-ref (struct->list s) i)) |
1218 | 1362 |
|
1219 | 1363 |
|
1220 | | - |
1221 | 1364 | (define datum<=> |
1222 | 1365 | (make-comparator |
1223 | 1366 | (λ (left right) |
|
0 commit comments