Skip to content

Commit 5363288

Browse files
Copilotjackfirth
andauthored
Add in-syntax-paths utility for iterating through syntax paths (#719)
Co-authored-by: copilot-swe-agent[bot] <[email protected]> Co-authored-by: jackfirth <[email protected]> Co-authored-by: Jack Firth <[email protected]>
1 parent eee0116 commit 5363288

File tree

1 file changed

+151
-8
lines changed

1 file changed

+151
-8
lines changed

private/syntax-path.rkt

Lines changed: 151 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@
2626
[syntax-set (-> syntax? syntax-path? syntax? syntax?)]
2727
[syntax-remove-splice (-> syntax? nonempty-syntax-path? exact-nonnegative-integer? syntax?)]
2828
[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?))]))
3031

3132

3233
(require (for-syntax racket/base
@@ -37,6 +38,7 @@
3738
data/order
3839
guard
3940
racket/format
41+
racket/generator
4042
racket/mutability
4143
racket/sequence
4244
racket/string
@@ -871,10 +873,6 @@
871873
(check-equal? (syntax->datum actual) '(a b c FOO e)))))
872874

873875

874-
875-
876-
877-
878876
(define/guard (syntax-remove-splice stx path children-count)
879877
(guard (positive? children-count) #:else stx)
880878
(define parent (syntax-ref stx (syntax-path-parent path)))
@@ -1177,8 +1175,6 @@
11771175
(syntax-property stx-with-children-labeled property-name path)))
11781176

11791177

1180-
1181-
11821178
(module+ test
11831179
(test-case "syntax-label-paths"
11841180
(define stx #'(foo (a b . c) bar (baz) #(x y) #&z #s(point n m)))
@@ -1205,6 +1201,154 @@
12051201
(check-equal? (syntax->datum (syntax-ref stx path)) (syntax->datum id)))))
12061202

12071203

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)))))
12081352

12091353

12101354
(define (prefab-struct? v)
@@ -1217,7 +1361,6 @@
12171361
(list-ref (struct->list s) i))
12181362

12191363

1220-
12211364
(define datum<=>
12221365
(make-comparator
12231366
(λ (left right)

0 commit comments

Comments
 (0)