16.2.1 Syntax Objects

16 Macros
top
up

16.2.1Syntax ObjectsπŸ”— i

The input and output of a macro transformer (i.e., source and replacement forms) are represented as syntax objects. A syntax object contains symbols, lists, and constant values (such as numbers) that essentially correspond to the quote d form of the expression. For example, a representation of the expression (+ 12) contains the symbol '+ and the numbers 1 and 2, all in a list. In addition to this quoted content, a syntax object associates source-location and lexical-binding information with each part of the form. The source-location information is used when reporting syntax errors (for example), and the lexical-binding information allows the macro system to maintain lexical scope. To accommodate this extra information, the representation of the expression (+ 12) is not merely '(+12), but a packaging of '(+12) into a syntax object.

To create a literal syntax object, use the syntax form:

> (syntax (+ 12))

#<syntax:eval:1:0 (+ 1 2)>

In the same way that ' abbreviates quote , #' abbreviates syntax :

> #'(+ 12)

#<syntax:eval:1:0 (+ 1 2)>

A syntax object that contains just a symbol is an identifier syntax object. Racket provides some additional operations specific to identifier syntax objects, including the identifier? operation to detect identifiers. Most notably, free-identifier=? determines whether two identifiers refer to the same binding:

#t

> (identifier? #'(+ 12))

#f

#f

#t

> (require (only-in racket/base[car also-car]))
> (free-identifier=? #'car #'also-car)

#t

To see the lists, symbols, numbers, etc. within a syntax object, use syntax->datum :

> (syntax->datum #'(+ 12))

'(+ 1 2)

The syntax-e function is similar to syntax->datum , but it unwraps a single layer of source-location and lexical-context information, leaving sub-forms that have their own information wrapped as syntax objects:

> (syntax-e #'(+ 12))

'(#<syntax:eval:1:0 +> #<syntax:eval:1:0 1> #<syntax:eval:1:0 2>)

The syntax-e function always leaves syntax-object wrappers around sub-forms that are represented via symbols, numbers, and other literal values. The only time it unwraps extra sub-forms is when unwrapping a pair, in which case the cdr of the pair may be recursively unwrapped, depending on how the syntax object was constructed.

The opposite of syntax->datum is, of course, datum->syntax . In addition to a datum like '(+12), datum->syntax needs an existing syntax object to donate its lexical context, and optionally another syntax object to donate its source location:

> (datum->syntax #'lex
'(+12)
#'srcloc )

#<syntax:eval:1:0 (+ 1 2)>

In the above example, the lexical context of #'lex is used for the new syntax object, while the source location of #'srcloc is used.

When the second (i.e., the “datum”) argument to datum->syntax includes syntax objects, those syntax objects are preserved intact in the result. That is, deconstructing the result with syntax-e eventually produces the syntax objects that were given to datum->syntax .

top
up

AltStyle γ«γ‚ˆγ£γ¦ε€‰ζ›γ•γ‚ŒγŸγƒšγƒΌγ‚Έ (->γ‚ͺγƒͺγ‚ΈγƒŠγƒ«) /