► |  | The Racket Reference

1 | Language Model
2 | Notation for Documentation
3 | Syntactic Forms
4 | Datatypes
5 | Structures
6 | Classes and Objects
7 | Units
8 | Contracts
9 | Pattern Matching
10 | Control Flow
11 | Concurrency and Parallelism
12 | Macros
13 | Input and Output
14 | Reflection and Security
15 | Operating System
16 | Memory Management
17 | Unsafe Operations
18 | Running Racket
| Bibliography
| Index

▼ | 12 | Macros

12.1 | Pattern-Based Syntax Matching
12.2 | Syntax Object Content
12.3 | Syntax Object Bindings
12.4 | Syntax Transformers
12.5 | Syntax Parameters
12.6 | Local Binding with Splicing Body
12.7 | Syntax Object Properties
12.8 | Syntax Taints
12.9 | Expanding Top-Level Forms
12.10 | Serializing Syntax
12.11 | File Inclusion
12.12 | Syntax Utilities

On this page:

syntax-property
syntax-property-remove
syntax-property-preserved?
syntax-property-symbol-keys
syntax-track-origin

top ← prev up next →

#### 12.7`` Syntax Object Properties

Every syntax object has an associated syntax property list, which can be queried or extended with syntax-property. A property is set as preserved or not; a preserved property is maintained for a syntax object in a compiled form that is marshaled to a byte string or ".zo" file, and other properties are discarded when marshaling.

In read-syntax, the reader attaches a preserved 'paren-shape property to any pair or vector syntax object generated from parsing a pair [ and ] or { and }; the property value is #\[ in the former case, and #\{ in the latter case. The syntax form copies any 'paren-shape property from the source of a template to corresponding generated syntax.

Both the syntax input to a transformer and the syntax result of a transformer may have associated properties. The two sets of properties are merged by the syntax expander: each property in the original and not present in the result is copied to the result, and the values of properties present in both are combined with cons (result value first, original value second) and the consed value is preserved if either of the values were preserved.

Before performing the merge, however, the syntax expander automatically adds a property to the original syntax object using the key 'origin. If the source syntax has no 'origin property, it is set to the empty list. Then, still before the merge, the identifier that triggered the macro expansion (as syntax) is consed onto the 'origin property so far. The 'origin property thus records (in reverse order) the sequence of macro expansions that produced an expanded expression. Usually, the 'origin value is a list of identifiers, but a transformer might return syntax that has already been expanded, in which case an 'origin list can contain other lists after a merge. The syntax-track-origin procedure implements this tracking. The 'origin property is added as non-preserved.

Besides 'origin tracking for general macro expansion, Racket adds properties to expanded syntax (often using syntax-track-origin) to record additional expansion details:

- When a begin form is spliced into a sequence with internal definitions (see Internal Definitions), syntax-track-origin is applied to every spliced element from the begin body. The second argument to syntax-track-origin is the begin form, and the third argument is the begin keyword (extracted from the spliced form).

- When an internal define-values or define-syntaxes form is converted into a letrec-syntaxes+values form (see Internal Definitions), syntax-track-origin is applied to each generated binding clause. The second argument to syntax-track-origin is the converted form, and the third argument is the define-values or define-syntaxes keyword form the converted form.

- When a letrec-syntaxes+values expression is fully expanded, syntax bindings disappear, and the result is either a letrec-values form (if the unexpanded form contained non-syntax bindings), or only the body of the letrec-syntaxes+values form (wrapped with begin if the body contained multiple expressions). To record the disappeared syntax bindings, a property is added to the expansion result: an immutable list of identifiers from the disappeared bindings, as a 'disappeared-binding property.

- When a subtyping struct form is expanded, the identifier used to reference the base type does not appear in the expansion. Therefore, the struct transformer adds the identifier to the expansion result as a 'disappeared-use property.

- When a rename transformer is used to replace a set! target, syntax-track-origin is used on the target identifier (the same as when the identifier is used as an expression).

- When a reference to an unexported or protected identifier from a module is discovered, the 'protected property is added to the identifier with a #t value.

- When read-syntax generates a syntax object, it attaches a property to the object (using a private key) to mark the object as originating from a read. The syntax-original? predicate looks for the property to recognize such syntax objects. (See Syntax Object Content for more information.)

See also Check Syntax for one client of the 'disappeared-use and 'disappeared-binding properties.

See Information on Expanded Modules for information about properties generated by the expansion of a module declaration. See lambda and Inferred Value Names for information about properties recognized when compiling a procedure. See current-compile for information on properties and byte codes.

> > procedure

> > (syntax-property stx key v [preserved?]) → syntax?

> stx : syntax?
> key : (if preserved? (and/c symbol? symbol-interned?) any/c)
> v : any/c
> preserved? : any/c = (eq? key 'paren-shape)
> (syntax-property stx key) → any
> stx : syntax?
> key : any/c

The three- or four-argument form extends stx by associating an arbitrary property value v with the key key; the result is a new syntax object with the association (while stx itself is unchanged). The property is added as preserved if preserved? is true, in which case key must be an interned symbol, and v should be a value as described below that can be saved in marshaled bytecode.

The two-argument form returns an arbitrary property value associated to stx with the key key, or #f if no value is associated to stx for key.

To support marshaling to bytecode, a value for a preserved syntax property must be a non-cyclic value that is either

- a pair containing allowed preserved-property values;

- a vector (unmarshaled as immutable) containing allowed preserved-property values;

- a box (unmarshaled as immutable) containing allowed preserved-property values;

- an immutable prefab structure containing allowed preserved-property values;

- an immutable hash table whose keys and values are allowed preserved-property values;

- a syntax object; or

- an empty list, symbol, number, character, string, byte string, or regexp value.

Any other value for a preserved property triggers an exception at an attempt to marshal the owning syntax object to bytecode form.

Changed in version 6.4.0.14 of package base: Added the preserved? argument.

> > procedure

> > (syntax-property-remove stx key) → syntax?

> stx : syntax?
> key : any/c

Returns a syntax object like stx, but without a property (if any) for key.

Added in version 6.90.0.20 of package base.

> > procedure

> > (syntax-property-preserved? stx key) → boolean?

> stx : syntax?
> key : (and/c symbol? symbol-interned?)

Returns #t if stx has a preserved property value for key, #f otherwise.

Added in version 6.4.0.14 of package base.

> > procedure

> > (syntax-property-symbol-keys stx) → list?

> stx : syntax?

Returns a list of all symbols that as keys have associated properties in stx. Uninterned symbols (see Symbols) are not included in the result list.

> > procedure

> > (syntax-track-origin |  | new-stx |  |  |  |
> > |  | orig-stx |  |  |  |
> > |  | id-stx) |  | → |  | any

> new-stx : syntax?
> orig-stx : syntax?
> id-stx : identifier?

Adds properties to new-stx in the same way that macro expansion adds properties to a transformer result. In particular, it merges the properties of orig-stx into new-stx, first adding id-stx as an 'origin property, and it returns the property-extended syntax object. Use the syntax-track-origin procedure in a macro transformer that discards syntax (corresponding to orig-stx with a keyword id-stx) leaving some other syntax in its place (corresponding to new-stx).

For example, the expression

> (or x y)

expands to

> (let ([or-part x]) (if or-part or-part (or y)))

which, in turn, expands to

> (let-values ([(or-part) x]) (if or-part or-part y))

The syntax object for the final expression will have an 'origin property whose value is (list (quote-syntax let) (quote-syntax or)).

top ← prev up next →