Next: Lisp-style Macro Definitions, Previous: Support for the syntax-case System, Up: Macros [Contents][Index]
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.
Return #t if and only if the syntax objects a and b
are both identifiers with the same symbolic name (that is, the procedure
syntax->datum would return the same symbol on both of them) and
were both created by the same hygienic macro expansion. This means that
if a already has some binding in an outer scope, and another macro
binds b in some inner scope, the binding of a would be
shadowed. The same applies vice versa if b were bound in some
outer scope and a shadowed it.
If the two identifiers have different symbolic names or were created
by different expansion steps, return #f.
This test is used by syntax forms such as let and lambda
to ensure that the code using them isn’t trying to bind the same
identifier more than once.
Return #t if the syntax objects a and b are both
identifiers and refer to the same binding. If neither a nor
b is bound, return #t if both have the same symbolic name.
If the two identifiers have different bindings, if one is bound and the
other unbound, or if neither has a binding and the two have different
symbolic names, return #f.
This test is used by syntax forms such as cond to look for uses
of auxiliary keywords like else. It can also be used by advanced
procedural macros to coalesce references to the same external identifier
in their input into only one reference in their output.
In practice, the fallback case which applies for identifiers without bindings can usually be ignored by programmers. Auxiliary keywords should usually be bound to dummy macros which always raise a syntax violation if they’re used outside of their correct context; also, if an unbound identifier is inserted into expanded code, it will eventually result in an error anyway.
Return a list of temporary identifiers as long as ls is long. Each
temporary identifier will be distinct from every other identifier in the
sense of bound-identifier=? and will have no existing binding
associated with it.
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))
Return the name of the module whose source contains the identifier id.
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.
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:
lexicalA lexically-bound variable. The value is a unique token (in the sense
of eq?) identifying this binding.
macroA syntax transformer, either local or global. The value is the transformer procedure.
syntax-parameterA 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-variableA pattern variable, bound via syntax-case. The value is an
opaque object, internal to the expander.
ellipsisAn internal binding, bound via with-ellipsis. The value is the
(anti-marked) local ellipsis identifier.
displaced-lexicalA 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.
globalA 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.
otherSome 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.
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))
Next: Lisp-style Macro Definitions, Previous: Support for the syntax-case System, Up: Macros [Contents][Index]