updated syntax/parse docs

This commit is contained in:
Ryan Culpepper 2011-04-20 20:57:14 -06:00
parent bf5248e3b5
commit aac8be59ac
2 changed files with 42 additions and 26 deletions

View File

@ -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
the second case later in the introduction.
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))]
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].
The macro can be implemented very simply using
@racket[define-syntax-rule]:
@myinteraction[
(define-syntax (mylet stx)
(syntax-parse stx
[(_ ([var-id rhs-expr] ...) body ...+)
#'((lambda (var-id ...) body ...) rhs-expr ...)]))
(define-syntax-rule (mylet ([var rhs] ...) body ...)
((lambda (var ...) body ...) rhs ...))
]
Note the use of @scheme[...] and @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.
When used correctly, the macro works, but it behaves very badly in the
presence of errors. In some cases, the macro merely fails with an
uninformative error message; in others, it blithely accepts illegal
syntax and passes it along to @scheme[lambda], with strange
consequences:
@myinteraction[
(mylet ([a 1] [b 2]) (+ a b))
@ -63,14 +54,9 @@ be used in the template, however.
(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
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
of other macros (or code generators), and many macros are far more
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
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
annotating each of the macro's pattern variables with the @tech{syntax
class} that describes its acceptable syntax. In @scheme[mylet], each

View File

@ -679,7 +679,10 @@ terms instead.
@specsubform/subs[(@#,def[~optional h] H-pattern maybe-optional-option)
([maybe-optional-option
(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
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)
[(_ (~optional (~seq #:foo x)) y:id ...)
(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)]{