Next: , Previous: , Up: expander lexenv   [Index]


15.3.2 Wrapped and unwrapped syntax objects

Under Vicare, we adopt the following definitions:

Wrapped syntax object

An object of type <stx>.

Unwrapped syntax object

A compound object holding: nulls, pairs, vectors, numbers, strings, bytevectors, chars, booleans, keywords, would–block objects, unbound objects, EOF objects, broken weak pointer objects, objects of type <stx>.

An unwrapped symbol object cannot be part of an unwrapped syntax object: an attempt to use an unwrapped syntax object holding an unwrapped symbol will, sooner or later, cause an exception to be raised.

Object Type: <stx>

Disjoint object type representing wrapped syntax objects: source code expressions associated to meta data representing their lexical contour.

Objects of type <stx> have the following fields:

expr

A symbolic expression representing source code, possibly annotated; these expressions are the ones produced by the Scheme source code reader. They can be raw source code expressions or nested hierarchies of annotation objects returned by get-annotated-datum (see iklib reader annotations).

mark*

Null or a proper list of eq?–unique objects, including the symbol ‘src’, used to distinguish between identifiers introduced by the source code and identifiers introduced by applications of macro transformers. Each of these marks can be either a generated mark or an anti–mark.

Two marks must be eq?–comparable, so, by default, we use empty strings as marks and #f as anti–mark: their generation is fast.

rib*

Null or a proper list of rib objects or shift symbols. Every rib represents a nested lexical contour; a shift represents the return from a macro transformer application.

While expanding source code: upon entering a syntactic form representing a lexical contour, a new rib is added to the syntax object representing the syntactic form itself, to allow syntactic identifiers in the form to be captured by the bindings introduced in that contour.

annotated-expr*

Null or a proper list of annotated expressions: #f or input forms of macro transformer calls. This field is used to trace the transformations a form undergoes when it is processed as macro use. The #f items are inserted when this instance is processed as input form of a macro call, but is later discarded.

The following bindings are exported by the library (vicare expander).

Function: syntax-object? stx

Return #t if stx is a wrapped or unwrapped syntax object; otherwise return #f.

Function: stx? stx

Return #t if stx is a wrapped syntax object; else return #f.

Field accessor on <stx>: stx-expr stx

Return a symbolic expression, possibly annotated.

Field accessor on <stx>: stx-mark* stx

Return null or a proper list of eq?–unique objects acting as lexical contour marks, including the symbol ‘src’.

Field accessor on <stx>: stx-rib* stx

Return null or a proper list of rib instances or shift symbols.

Field accessor on <stx>: stx-annotated-expr* stx

Return null or a proper list of annotated expressions: #f or input forms of macro transformer calls.

What are syntax objects

All the syntactic identifiers are <stx> objects with a symbol in their expr field; other objects such as pairs and vectors may be wrapped or unwrapped. A wrapped pair is an <stx> whose expr field is a pair:

(syntax (a . b))

an unwrapped pair is a pair whose car and cdr fields are themselves syntax objects (wrapped or unwrapped):

((syntax a) . (syntax b))

It makes sense to associate lexical contour informations to syntactic identifiers, while associating them to datums is useless from the point of view of expanding source code. For example, in the following code the identifiers ‘var’ belong to different lexical contours, and so have different meanings, while the datum ‘123’ is always the same in all the lexical contours:

(let ((var 123))
  (let ((var 123))
    var))

We can create a syntax object holding a raw expression as follows:

(import (vicare))
(define X 1)
(begin-for-syntax
  (datum->syntax #'X 'ciao))
⇒ #<syntactic-identifier expr=ciao mark*=(src)>

and we can create a syntax object holding an annotated expression as follows:

(import (vicare))
(define X 1)
(begin-for-syntax
  (let* ((port   (open-string-input-port "(list X)"))
         (datum  (get-annotated-datum port))
         (stx    (datum->syntax #'X datum)))
    datum
    ⇒ #[annotation
             expression=#<omitted>
             stripped=(list X)
             textual-position=#[r6rs-record: &source-position
                                   port-id="*string-input-port*"
                                   byte=0
                                   character=0
                                   line=1
                                   column=1]]
    stx)
    ⇒ #<syntax
             expr=(list X)
             mark*=(src)
             line=1 column=1 source=*string-input-port*>

we can unwrap a syntax object by using syntax-case:

(import (vicare))
(define X 1)
(begin-for-syntax
  (let* ((port   (open-string-input-port "(list X)"))
         (datum  (get-annotated-datum port))
         (stx    (datum->syntax #'X datum))
         (stx    (syntax-case stx ()
                   ((?head ?tail)
                    (list #'?head #'?tail)))))
    stx)
⇒ (#<syntactic-identifier expr=list mark*=(src)>
    #<syntactic-identifier expr=X mark*=(src)>)

Next: , Previous: , Up: expander lexenv   [Index]