updated syntax/parse docs
This commit is contained in:
parent
bf5248e3b5
commit
aac8be59ac
|
@ -33,28 +33,19 @@ Here is the specification of @scheme[mylet]'s syntax:
|
||||||
For simplicity, we handle only the first case for now. We return to
|
For simplicity, we handle only the first case for now. We return to
|
||||||
the second case later in the introduction.
|
the second case later in the introduction.
|
||||||
|
|
||||||
First, we import @scheme[syntax-parse] into the @tech[#:doc '(lib
|
The macro can be implemented very simply using
|
||||||
"scribblings/reference/reference.scrbl")]{transformer environment},
|
@racket[define-syntax-rule]:
|
||||||
since we will use it to implement a macro transformer.
|
|
||||||
|
|
||||||
@myinteraction[(require (for-syntax syntax/parse))]
|
|
||||||
|
|
||||||
We get the first version of @scheme[mylet] by essentially
|
|
||||||
transliterating the syntax specification above. The result is similar
|
|
||||||
to what one would write using @scheme[syntax-rules] or perhaps
|
|
||||||
@scheme[syntax-case].
|
|
||||||
|
|
||||||
@myinteraction[
|
@myinteraction[
|
||||||
(define-syntax (mylet stx)
|
(define-syntax-rule (mylet ([var rhs] ...) body ...)
|
||||||
(syntax-parse stx
|
((lambda (var ...) body ...) rhs ...))
|
||||||
[(_ ([var-id rhs-expr] ...) body ...+)
|
|
||||||
#'((lambda (var-id ...) body ...) rhs-expr ...)]))
|
|
||||||
]
|
]
|
||||||
|
|
||||||
Note the use of @scheme[...] and @scheme[...+] in the pattern;
|
When used correctly, the macro works, but it behaves very badly in the
|
||||||
@scheme[...] means match zero or more repetitions of the preceding
|
presence of errors. In some cases, the macro merely fails with an
|
||||||
pattern; @scheme[...+] means match one or more. Only @scheme[...] may
|
uninformative error message; in others, it blithely accepts illegal
|
||||||
be used in the template, however.
|
syntax and passes it along to @scheme[lambda], with strange
|
||||||
|
consequences:
|
||||||
|
|
||||||
@myinteraction[
|
@myinteraction[
|
||||||
(mylet ([a 1] [b 2]) (+ a b))
|
(mylet ([a 1] [b 2]) (+ a b))
|
||||||
|
@ -63,14 +54,9 @@ be used in the template, however.
|
||||||
(mylet ([#:x 1] [y 2]) (* x y))
|
(mylet ([#:x 1] [y 2]) (* x y))
|
||||||
]
|
]
|
||||||
|
|
||||||
When used correctly, the macro works, but it behaves very badly in the
|
|
||||||
presence of errors. In some cases, @scheme[mylet] blithely accepts
|
|
||||||
illegal syntax and passes it along to @scheme[lambda], with strange
|
|
||||||
consequences.
|
|
||||||
|
|
||||||
These examples of illegal syntax are not to suggest that a typical
|
These examples of illegal syntax are not to suggest that a typical
|
||||||
programmer would make such mistakes attempting to use
|
programmer would make such mistakes attempting to use
|
||||||
@scheme[mylet]. At least, not often. After an initial learning
|
@scheme[mylet]. At least, not often, not after an initial learning
|
||||||
curve. But macros are also used by inexpert programmers and as targets
|
curve. But macros are also used by inexpert programmers and as targets
|
||||||
of other macros (or code generators), and many macros are far more
|
of other macros (or code generators), and many macros are far more
|
||||||
complex than @scheme[mylet]. Macros must validate their syntax and
|
complex than @scheme[mylet]. Macros must validate their syntax and
|
||||||
|
@ -78,6 +64,30 @@ report appropriate errors. Furthermore, the macro writer benefits from
|
||||||
the @emph{machine-checked} specification of syntax in the form of more
|
the @emph{machine-checked} specification of syntax in the form of more
|
||||||
readable, maintainable code.
|
readable, maintainable code.
|
||||||
|
|
||||||
|
We can improve the error behavior of the macro by using
|
||||||
|
@racket[syntax-parse]. First, we import @scheme[syntax-parse] into the
|
||||||
|
@tech[#:doc '(lib
|
||||||
|
"scribblings/reference/reference.scrbl")]{transformer environment},
|
||||||
|
since we will use it to implement a macro transformer.
|
||||||
|
|
||||||
|
@myinteraction[(require (for-syntax syntax/parse))]
|
||||||
|
|
||||||
|
The following is the syntax specification above transliterated into a
|
||||||
|
@racket[syntax-parse] macro definition. It behaves no better than the
|
||||||
|
version using @racket[define-syntax-rule] above.
|
||||||
|
|
||||||
|
@myinteraction[
|
||||||
|
(define-syntax (mylet stx)
|
||||||
|
(syntax-parse stx
|
||||||
|
[(_ ([var-id rhs-expr] ...) body ...+)
|
||||||
|
#'((lambda (var-id ...) body ...) rhs-expr ...)]))
|
||||||
|
]
|
||||||
|
|
||||||
|
One minor difference is the use of @scheme[...+] in the pattern;
|
||||||
|
@scheme[...] means match zero or more repetitions of the preceding
|
||||||
|
pattern; @scheme[...+] means match one or more. Only @scheme[...] may
|
||||||
|
be used in the template, however.
|
||||||
|
|
||||||
The first step toward validation and high-quality error reporting is
|
The first step toward validation and high-quality error reporting is
|
||||||
annotating each of the macro's pattern variables with the @tech{syntax
|
annotating each of the macro's pattern variables with the @tech{syntax
|
||||||
class} that describes its acceptable syntax. In @scheme[mylet], each
|
class} that describes its acceptable syntax. In @scheme[mylet], each
|
||||||
|
|
|
@ -679,7 +679,10 @@ terms instead.
|
||||||
@specsubform/subs[(@#,def[~optional h] H-pattern maybe-optional-option)
|
@specsubform/subs[(@#,def[~optional h] H-pattern maybe-optional-option)
|
||||||
([maybe-optional-option
|
([maybe-optional-option
|
||||||
(code:line)
|
(code:line)
|
||||||
(code:line #:defaults ([attr-id expr] ...))])]{
|
(code:line #:defaults ([attr-arity-decl expr] ...))]
|
||||||
|
[attr-arity-decl
|
||||||
|
attr-id
|
||||||
|
(attr-id depth)])]{
|
||||||
|
|
||||||
Matches either the given head subpattern or an empty sequence of
|
Matches either the given head subpattern or an empty sequence of
|
||||||
terms. If the @scheme[#:defaults] option is given, the subsequent
|
terms. If the @scheme[#:defaults] option is given, the subsequent
|
||||||
|
@ -696,8 +699,11 @@ default attributes must be a subset of the subpattern's attributes.
|
||||||
(syntax-parse #'(m a b c)
|
(syntax-parse #'(m a b c)
|
||||||
[(_ (~optional (~seq #:foo x)) y:id ...)
|
[(_ (~optional (~seq #:foo x)) y:id ...)
|
||||||
(attribute x)])
|
(attribute x)])
|
||||||
|
(syntax-parse #'(m #:syms a b c)
|
||||||
|
[(_ (~optional (~seq #:nums n:nat ...) #:defaults ([(n 1) null]))
|
||||||
|
(~optional (~seq #:syms s:id ...) #:defaults ([(s 1) null])))
|
||||||
|
#'((n ...) (s ...))])
|
||||||
]
|
]
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@specsubform[(@#,def[~describe h] expr H-pattern)]{
|
@specsubform[(@#,def[~describe h] expr H-pattern)]{
|
||||||
|
|
Loading…
Reference in New Issue
Block a user