6.8.4 Syntax Transformer Helpers

As noted in the previous section, Guile’s syntax expander operates on syntax objects. Procedural macros consume and produce syntax objects. This section describes some of the auxiliary helpers that procedural macros can use to compare, generate, and query objects of this data type.

Scheme Procedure: bound-identifier=? a b

Return #t if the syntax objects a and b refer to the same lexically-bound identifier, or #f otherwise.

Scheme Procedure: free-identifier=? a b

Return #t if the syntax objects a and b refer to the same free identifier, or #f otherwise.

Scheme Procedure: generate-temporaries ls

Return a list of temporary identifiers as long as ls is long.

Scheme Procedure: syntax-source x

Return the source properties that correspond to the syntax object x. See Source Properties, for more information.

Guile also offers some more experimental interfaces in a separate module. As was the case with the Large Hadron Collider, it is unclear to our senior macrologists whether adding these interfaces will result in awesomeness or in the destruction of Guile via the creation of a singularity. We will preserve their functionality through the 2.0 series, but we reserve the right to modify them in a future stable series, to a more than usual degree.

(use-modules (system syntax))
Scheme Procedure: syntax-module id

Return the name of the module whose source contains the identifier id.

Scheme Procedure: syntax-sourcev stx

Like syntax-source, but returns its result in a more compact #(filename line column) format. This format is used as the internal representation of source locations for syntax objects.

Scheme Procedure: syntax-local-binding id [#:resolve-syntax-parameters?=#t]

Resolve the identifier id, a syntax object, within the current lexical environment, and return two values, the binding type and a binding value. The binding type is a symbol, which may be one of the following:

lexical

A lexically-bound variable. The value is a unique token (in the sense of eq?) identifying this binding.

macro

A syntax transformer, either local or global. The value is the transformer procedure.

syntax-parameter

A syntax parameter (see Syntax Parameters). By default, syntax-local-binding will resolve syntax parameters, so that this value will not be returned. Pass #:resolve-syntax-parameters? #f to indicate that you are interested in syntax parameters. The value is the default transformer procedure, as in macro.

pattern-variable

A pattern variable, bound via syntax-case. The value is an opaque object, internal to the expander.

ellipsis

An internal binding, bound via with-ellipsis. The value is the (anti-marked) local ellipsis identifier.

displaced-lexical

A lexical variable that has gone out of scope. This can happen if a badly-written procedural macro saves a syntax object, then attempts to introduce it in a context in which it is unbound. The value is #f.

global

A global binding. The value is a pair, whose head is the symbol, and whose tail is the name of the module in which to resolve the symbol.

other

Some other binding, like lambda or other core bindings. The value is #f.

This is a very low-level procedure, with limited uses. One case in which it is useful is to build abstractions that associate auxiliary information with macros:

(define aux-property (make-object-property))
(define-syntax-rule (with-aux aux value)
  (let ((trans value))
    (set! (aux-property trans) aux)
    trans))
(define-syntax retrieve-aux
  (lambda (x)
    (syntax-case x ()
      ((x id)
       (call-with-values (lambda () (syntax-local-binding #'id))
         (lambda (type val)
           (with-syntax ((aux (datum->syntax #'here
                                             (and (eq? type 'macro)
                                                  (aux-property val)))))
             #''aux)))))))
(define-syntax foo
  (with-aux 'bar
    (syntax-rules () ((_) 'foo))))
(foo)
⇒ foo
(retrieve-aux foo)
⇒ bar

syntax-local-binding must be called within the dynamic extent of a syntax transformer; to call it otherwise will signal an error.

Scheme Procedure: syntax-locally-bound-identifiers id

Return a list of identifiers that were visible lexically when the identifier id was created, in order from outermost to innermost.

This procedure is intended to be used in specialized procedural macros, to provide a macro with the set of bound identifiers that the macro can reference.

As a technical implementation detail, the identifiers returned by syntax-locally-bound-identifiers will be anti-marked, like the syntax object that is given as input to a macro. This is to signal to the macro expander that these bindings were present in the original source, and do not need to be hygienically renamed, as would be the case with other introduced identifiers. See the discussion of hygiene in section 12.1 of the R6RS, for more information on marks.

(define (local-lexicals id)
  (filter (lambda (x)
            (eq? (syntax-local-binding x) 'lexical))
          (syntax-locally-bound-identifiers id)))
(define-syntax lexicals
  (lambda (x)
    (syntax-case x ()
      ((lexicals) #'(lexicals lexicals))
      ((lexicals scope)
       (with-syntax (((id ...) (local-lexicals #'scope)))
         #'(list (cons 'id id) ...))))))

(let* ((x 10) (x 20)) (lexicals))
⇒ ((x . 10) (x . 20))