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 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

View File

@ -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)]{