|
21 | 21 | [into-syntax-property-bundle (reducer/c syntax-property-entry? syntax-property-bundle?)] |
22 | 22 | [property-hashes-into-syntax-property-bundle |
23 | 23 | (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?)])) |
25 | 27 |
|
26 | 28 |
|
27 | 29 | (require guard |
|
244 | 246 | (syntax-set stx path new-subform)) |
245 | 247 |
|
246 | 248 |
|
| 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 | + |
247 | 270 | (module+ test |
248 | 271 | (test-case "syntax-add-all-properties" |
249 | 272 | (define stx #'(a (b c) d)) |
|
266 | 289 | (define/syntax-parse (b* c*) #'bc*) |
267 | 290 | (check-equal? (syntax-property #'b* 'headphone-shaped?) #true) |
268 | 291 | (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