When the syntax expander sees a form in which the first element is a macro, the whole form gets passed to the macro’s syntax transformer. One may visualize this as:
(define-syntax foo foo-transformer) (foo arg...) ;; expands via (foo-transformer #'(foo arg...))
If, on the other hand, a macro is referenced in some other part of a form, the syntax transformer is invoked with only the macro reference, not the whole form.
(define-syntax foo foo-transformer) foo ;; expands via (foo-transformer #'foo)
This allows bare identifier references to be replaced programmatically via a
macro. syntax-rules
provides some syntax to effect this transformation
more easily.
Returns a macro transformer that will replace occurrences of the macro with exp.
For example, if you are importing external code written in terms of fx+
,
the fixnum addition operator, but Guile doesn’t have fx+
, you may use the
following to replace fx+
with +
:
(define-syntax fx+ (identifier-syntax +))
There is also special support for recognizing identifiers on the
left-hand side of a set!
expression, as in the following:
(define-syntax foo foo-transformer) (set! foo val) ;; expands via (foo-transformer #'(set! foo val)) ;; if foo-transformer is a "variable transformer"
As the example notes, the transformer procedure must be explicitly marked as being a “variable transformer”, as most macros aren’t written to discriminate on the form in the operator position.
Mark the transformer procedure as being a “variable
transformer”. In practice this means that, when bound to a syntactic
keyword, it may detect references to that keyword on the left-hand-side
of a set!
.
(define bar 10) (define-syntax bar-alias (make-variable-transformer (lambda (x) (syntax-case x (set!) ((set! var val) #'(set! bar val)) ((var arg ...) #'(bar arg ...)) (var (identifier? #'var) #'bar))))) bar-alias ⇒ 10 (set! bar-alias 20) bar ⇒ 20 (set! bar 30) bar-alias ⇒ 30
There is an extension to identifier-syntax which allows it to handle the
set!
case as well:
Create a variable transformer. The first clause is used for references to the variable in operator or operand position, and the second for appearances of the variable on the left-hand-side of an assignment.
For example, the previous bar-alias
example could be expressed
more succinctly like this:
(define-syntax bar-alias (identifier-syntax (var bar) ((set! var val) (set! bar val))))
As before, the templates in identifier-syntax
forms do not need
wrapping in #'
syntax forms.