Next: stdlib syntax-case identifier, Previous: stdlib syntax-case transformers, Up: stdlib syntax-case [Index]
Transformers can destructure their input with syntax-case
and
rebuild their output with syntax
.
Each ?literal must be an identifier. Each ?syntax-case-clause must take one of the following two forms.
(?pattern ?output-expression) (?pattern ?fender ?output-expression)
?fender and ?output-expression must be ?expressions.
A ?pattern is an identifier, constant, or one of the following.
(?pattern …) (?pattern ?pattern … . ?pattern) (?pattern … ?pattern ?ellipsis ?pattern …) (?pattern … ?pattern ?ellipsis ?pattern … . ?pattern) #(?pattern …) #(?pattern … ?pattern ?ellipsis ?pattern …)
An ?ellipsis is the identifier ‘...’ (three periods).
An identifier appearing within a ?pattern may be an underscore ‘_’, an ellipsis ‘...’ or a literal identifier listed in the list of literals ‘(?literal …)’. All other identifiers appearing within a ?pattern are pattern variables. It is a syntax violation if an ellipsis or underscore appears in ‘(?literal …)’.
‘_’ and ‘...’ are the same as in the (rnrs base (6))
library.
Pattern variables match arbitrary input subforms and are used to refer to elements of the input. It is a syntax violation if the same pattern variable appears more than once in a ?pattern.
Underscores also match arbitrary input subforms but are not pattern variables and so cannot be used to refer to those elements. Multiple underscores may appear in a ?pattern.
A literal identifier matches an input subform if and only if the input subform is an identifier and either both its occurrence in the input expression and its occurrence in the list of literals have the same lexical binding, or the two identifiers have the same name and both have no lexical binding.
A subpattern followed by an ellipsis can match zero or more elements of the input.
More formally, an input form F matches a pattern P if and only if one of the following holds:
free-identifier=?
.
(P_1 ... P_n)
and F is a list of n elements that match P_1 through P_n.
(P_1 ... P_n . P_x)
and F is a list or improper list of n or more elements whose first n elements match P_1 through P_n and whose nth cdr matches P_x.
(P_1 ... P_k P_e ?ellipsis P_(m+1) ... P_n)
where ?ellipsis is the identifier ‘...’ and F is a proper list of n elements whose first k elements match P_1 through P_k, whose next m-k elements each match P_e, and whose remaining n-m elements match P_(m+1) through P_n.
(P_1 ... P_k P_e ?ellipsis P_(m+1) ... P_n . P_x)
where ?ellipsis is the identifier ‘...’ and F is a list or improper list of n elements whose first k elements match P_1 through P_k, whose next m-k elements each match P_e, whose next n-m elements match P_(m+1) through P_n, and whose nth and final cdr matches P_x.
#(P_1 ... P_n)
and F is a vector of n elements that match P_1 through P_n.
#(P_1 ... P_k P_e ?ellipsis P_(m+1) ... P_n)
where ?ellipsis is the identifier ‘...’ and F is a vector of n or more elements whose first k elements match P_1 through P_k, whose next m-k elements each match P_e, and whose remaining n-m elements match P_(m+1) through P_n.
equal?
procedure.
A syntax-case
expression first evaluates ?expression. It
then attempts to match the ?pattern from the first
?syntax-case-clause against the resulting value, which is
unwrapped as necessary to perform the match. If the pattern matches the
value and no ?fender is present, ?output-expression is
evaluated and its value returned as the value of the syntax-case
expression. If the pattern does not match the value, syntax-case
tries the second ?syntax-case-clause, then the third, and so on.
It is a syntax violation if the value does not match any of the
patterns.
If the optional ?fender is present, it serves as an additional constraint on acceptance of a clause. If the ?pattern of a given ?syntax-case-clause matches the input value, the corresponding ?fender is evaluated. If ?fender evaluates to a true value, the clause is accepted; otherwise, the clause is rejected as if the pattern had failed to match the value. Fenders are logically a part of the matching process, i.e., they specify additional matching constraints beyond the basic structure of the input.
Pattern variables contained within a clause’s ?pattern are bound
to the corresponding pieces of the input value within the clause’s
?fender (if present) and ?output-expression. Pattern
variables can be referenced only within syntax
expressions (see
below). Pattern variables occupy the same name space as program
variables and keywords.
If the syntax-case
form is in tail context, the
?output-expressions are also in tail position.
A syntax
expression is similar to a quote
expression
except that:
syntax
expression is a syntax object.
The following sharp–quote expression:
#'?template
is equivalent to:
(syntax ?template)
scheme lex datum abbreviations for the other abbreviations.
A ?template can be one among: a pattern variable, an identifier that is not a pattern variable, a pattern datum, or one of the following.
(?subtemplate …) (?subtemplate … . ?template) #(?subtemplate …)
A ?subtemplate is a ?template followed by zero or more ellipses.
The value of a syntax
form is a copy of ?template in which
the pattern variables appearing within the template are replaced with
the input subforms to which they are bound:
It is a syntax violation if the above constraints are not met.
A template of the form ‘(?ellipsis ?template)’ is identical to ?template, except that ellipses within the template have no special meaning. That is, any ellipses contained within ?template are treated as ordinary identifiers. In particular, the template ‘(... ...)’ produces a single ellipsis. This allows macro uses to expand into forms containing ellipses.
The output produced by syntax
is wrapped or unwrapped according
to the following rules:
The input subforms inserted in place of the pattern variables are wrapped if and only if the corresponding input subforms are wrapped.
The following definitions of or
illustrate syntax-case
and
syntax
; the second is equivalent to the first but uses the
sharp–quote prefix instead of the full syntax
form:
(define-syntax or (lambda (x) (syntax-case x () ((_) (syntax #f)) ((_ e) (syntax e)) ((_ e1 e2 e3 ...) (syntax (let ((t e1)) (if t t (or e2 e3 ...)))))))) (define-syntax or (lambda (x) (syntax-case x () ((_) #'#f) ((_ e) #'e) ((_ e1 e2 e3 ...) #'(let ((t e1)) (if t t (or e2 e3 ...)))))))
The examples below define identifier macros, macro uses supporting
keyword references that do not necessarily appear in the first position
of a list–structured form; the second example uses
make-variable-transformer
to handle the case where the keyword
appears on the left-hand side of a set!
expression:
(define p (cons 4 5)) (define-syntax p.car (lambda (x) (syntax-case x () ((_ . rest) #'((car p) . rest)) (_ #'(car p))))) p.car ⇒ 4 (set! p.car 15) error→ exception &syntax (define p (cons 4 5)) (define-syntax p.car (make-variable-transformer (lambda (x) (syntax-case x (set!) ((set! _ e) #'(set-car! p e)) ((_ . rest) #'((car p) . rest)) (_ #'(car p)))))) (set! p.car 15) p.car ⇒ 15 p ⇒ (15 . 5)
Any syntax-rules
form can be expressed with syntax-case
by
making the lambda
expression and syntax
expressions
explicit, and syntax-rules
may be defined in terms of
syntax-case
as follows.
(define-syntax syntax-rules (lambda (x) (syntax-case x () ((_ (lit ...) ((k . p) t) ...) (for-all identifier? #'(lit ... k ...)) #'(lambda (x) (syntax-case x (lit ...) ((_ . p) #'t) ...))))))
The identifier-syntax
form of the base library (see baselib transformers) may be defined in terms of syntax-case
,
syntax
, and make-variable-transformer
as follows.
(define-syntax identifier-syntax (syntax-rules (set!) ((_ e) (lambda (x) (syntax-case x () (id (identifier? #'id) #'e) ((_ x (... ...)) #'(e x (... ...)))))) ((_ (id exp1) ((set! var val) exp2)) (and (identifier? #'id) (identifier? #'var)) (make-variable-transformer (lambda (x) (syntax-case x (set!) ((set! var val) #'exp2) ((id x (... ...)) #'(exp1 x (... ...))) (id (identifier? #'id) #'exp1)))))))
Next: stdlib syntax-case identifier, Previous: stdlib syntax-case transformers, Up: stdlib syntax-case [Index]