On this page:
4.4.1 Constructing Syntax Property Bundles
syntax-property-bundle?
syntax-property-entry
syntax-property-bundle
sequence->syntax-property-bundle
into-syntax-property-bundle
property-hashes-into-syntax-property-bundle
4.4.2 Querying Syntax Property Bundles
syntax-property-bundle-get-property
syntax-property-bundle-get-immediate-properties
syntax-property-bundle-get-all-properties
syntax-property-bundle-entries
syntax-property-bundle-as-map
4.4.3 Moving Properties Between Bundles and Syntax Objects
syntax-immediate-properties
syntax-all-properties
syntax-add-all-properties
9.2

4.4 Syntax Property Bundles🔗

 (require resyntax/grimoire/syntax-property-bundle)
  package: resyntax

A syntax property bundle is an immutable tree of syntax properties that has been detached from any particular syntax object tree. Each property in a bundle is addressed by the combination of a syntax path, identifying the subform the property belongs to, and a symbol property key. A bundle contains at most one value for each path and key combination. Property bundles are a plain data representation of metadata that can be attached to and extracted from arbitrary syntax objects and their subforms.

Ordinarily, syntax properties live directly on syntax objects. Representing them separately as plain data lets Resyntax manipulate the properties themselves: bundles can be filtered, merged, inspected, and rearranged without ever touching a syntax object. Resyntax’s expansion analyzers work this way — each analyzer examines a fully expanded module and reports its findings as a syntax property bundle. Resyntax then combines each analyzer’s output bundle together, rearranges the combined bundle, and grafts it onto the original, unexpanded syntax object before analyzing it with refactoring rules.

Although syntax objects themselves permit arbitrary property keys, property keys in a bundle are more limited. A syntax property bundle key must be an interned symbol. This is for two reasons, one specific and one general:

  • Interned symbol keys are the only syntax property keys that can be iterated by syntax-property-symbol-keys, so such keys are the only kind that bundles can faithfully transfer between syntax objects. Since the entire purpose of property bundles is to transfer properties between syntax objects, allowing uninterned symbol keys would have no purpose.

  • More generally, syntax objects are not plain serializable data. Syntax objects are not safe to transfer from one Racket process to another. This is relied upon by various layers of the Racket macro system and similar low-level systems for encapsulation purposes. Some syntax properties are only used during macro expansion with opaque keys to provide private communication channels between macros that implement some library abstraction. Exposing such keys directly would allow intermediate macros in client code using that library to violate its abstractions. These sorts of opaque keys are often gensyms or similar unserializable unique values, and the Racket macro system takes care to make sure no API exists that provides uncontrolled access to them.

4.4.1 Constructing Syntax Property Bundles🔗

procedure

(syntax-property-bundle? v)  boolean?

  v : any/c
A predicate that recognizes syntax property bundles.

struct

(struct syntax-property-entry (path key value)
    #:transparent)
  path : syntax-path?
  key : interned-symbol?
  value : any/c
A syntax property entry pairs a syntax property key and value with the syntax path of the subform that the property belongs to. Bundles are built out of these entries.

Constructs a syntax property bundle containing each entry. The entries may be given in any order, but no two entries may share both a path and a key — a contract error is raised if they do.

Like syntax-property-bundle, but the entries are supplied as a sequence instead of as individual arguments.

A reducer that collects a sequence of syntax property entries into a syntax property bundle. Like syntax-property-bundle, no two reduced entries may share both a path and a key.

A reducer that collects a sequence of entry values, each mapping a syntax path to a hash of the properties at that path, into a syntax property bundle. Entries with empty property hashes are ignored. Each path may occur at most once in the reduced sequence — unlike into-syntax-property-bundle, this reducer does not merge multiple entries that refer to the same path, and instead raises a contract error. This is because this reducer is intended to be used when a syntax object and its subforms are iterated, and each syntax object’s properties are all extracted at once using syntax-property-symbol-keys. Such a client would expect to never iterate two syntax objects with the same syntax path, even if they had disjoint property keys.

4.4.2 Querying Syntax Property Bundles🔗

procedure

(syntax-property-bundle-get-property bundle    
  path    
  key    
  [failure-result])  any/c
  bundle : syntax-property-bundle?
  path : syntax-path?
  key : interned-symbol?
  failure-result : failure-result/c
   = (λ () (raise (make-exn:fail:contract ....)))
Returns the value of the property with key key at path within bundle. If no such property exists, then failure-result determines the result: if it’s a procedure, it’s called with no arguments to produce the result, and otherwise it’s returned directly, following the same protocol as hash-ref. If failure-result is omitted, a contract error is raised instead.

procedure

(syntax-property-bundle-get-immediate-properties bundle 
  path) 
  immutable-hash?
  bundle : syntax-property-bundle?
  path : syntax-path?
Returns a hash of every property in bundle located at exactly path, mapping property keys to property values. Properties located at descendants of path are not included. Returns an empty hash, rather than raising an error, if bundle contains no properties at path.

procedure

(syntax-property-bundle-get-all-properties bundle 
  path) 
  syntax-property-bundle?
  bundle : syntax-property-bundle?
  path : syntax-path?
Returns a syntax property bundle of every property in bundle located at path or at any descendant of path. The paths of the returned bundle are made relative to path, as though by syntax-path-remove-prefix: properties located at exactly path appear at root-syntax-path in the returned bundle. Returns the empty bundle, rather than raising an error, if bundle contains no properties at or under path. Passing root-syntax-path returns bundle unchanged.

Returns a lazy sequence of every syntax property entry in bundle. Entries are produced in ascending order of their paths, in the sense of syntax-path<=>. The relative order of multiple entries at the same path is unspecified.

Returns a view of bundle as a sorted map whose keys are syntax paths, ordered by syntax-path<=>, and whose values are hashes mapping property keys to property values. Only paths with at least one property appear in the map.

4.4.3 Moving Properties Between Bundles and Syntax Objects🔗

procedure

(syntax-immediate-properties stx 
  [#:base-path base-path]) 
  syntax-property-bundle?
  stx : syntax?
  base-path : syntax-path? = root-syntax-path
Returns a syntax property bundle of the properties attached directly to stx, ignoring any properties attached to its subforms. Only properties whose keys are interned symbols are extracted, as determined by syntax-property-symbol-keys. The extracted properties are located at base-path in the returned bundle, which is useful when stx is itself a subform of some larger syntax object.

procedure

(syntax-all-properties stx 
  [#:base-path base-path]) 
  syntax-property-bundle?
  stx : syntax?
  base-path : syntax-path? = root-syntax-path
Returns a syntax property bundle of the properties attached to stx and to every subform within it. Only properties whose keys are interned symbols are extracted, as determined by syntax-property-symbol-keys. Each extracted property is located at the syntax path of the subform it was attached to, prefixed with base-path. Subforms of hash datums are not traversed, as syntax paths cannot refer to them — see Original Syntax Paths and Formatting Preservation for further explanation.

procedure

(syntax-add-all-properties stx bundle)  syntax?

  stx : syntax?
  bundle : syntax-property-bundle?
Returns a copy of stx in which, for each syntax property entry in bundle, the subform at the entry’s path is given the entry’s property key and value as though by syntax-property. Properties already attached to stx and its subforms are retained, except where an entry in bundle overwrites them. Every path in bundle must refer to a subform of stx, in the sense of syntax-contains-path? otherwise a contract error is raised.