racket/collects/syntax/scribblings/parse/ex-many-kws.scrbl
Ryan Culpepper d7a87c79e0 Merged changes to syntax/parse
Changed backtracking algorithm, runtime representations
    - syntax classes, ~describe no longer implicitly commit
    - ~describe no longer delimits effect of cut
  Added keyword & optional args for stxclasses
  Added ~do and #:do, ~post, ~commit and #:commit,
    ~delimit-cut and #:no-delimit-cut
  Added syntax/parse/debug, syntax/parse/experimental/*
    - expr/c for contracting macro sub-expressions
      moved from syntax/parse to syntax/parse/experimental/contract
    - syntax class reflection (~reflect, ~splicing-reflect)
    - eh-alternative-sets (~eh-var)
    - provide-syntax-class/contract
      (only for params, not attrs so far)
  Changed ~fail to not include POST progress (#:fail still does)
    old (~fail _) is now (~post (~fail _))
  Made msg argument of ~fail optional
  Removed generic "repetition constraint violated" msg
  Removed atom-in-list stxclass
  Removed unnecessary datum->syntax on cdr of pair pattern
    massive improvements to long-list microbenchmarks
  Optimization: integrable syntax classes (id, expr, keyword)
    need better measurements
  Optimization: ad hoc elimination of head/tail choice point
    for (EH ... . ()) patterns
  Added unstable/wrapc (proc version of expr/c)
2010-08-31 10:55:58 -06:00

138 lines
5.4 KiB
Racket

#lang scribble/doc
@(require scribble/manual
scribble/struct
scribble/decode
scribble/eval
"parse-common.rkt"
(for-label racket/class))
@title{More keyword arguments}
This section shows how to express the syntax of @scheme[struct]'s
optional keyword arguments using @scheme[syntax-parse] patterns.
The part of @scheme[struct]'s syntax that is difficult to specify is
the sequence of struct options. Let's get the easy part out of the way
first.
@myinteraction[
(define-splicing-syntax-class maybe-super
(pattern (~seq super:id))
(pattern (~seq)))
(define-syntax-class field-option
(pattern #:mutable)
(pattern #:auto))
(define-syntax-class field
(pattern field:id
#:with (option ...) '())
(pattern [field:id option:field-option ...]))
]
Given those auxiliary syntax classes, here is a first approximation of
the main pattern, including the struct options:
@schemeblock[
(struct name:id super:maybe-super (field:field ...)
(~or (~seq #:mutable)
(~seq #:super super-expr:expr)
(~seq #:inspector inspector:expr)
(~seq #:auto-value auto:expr)
(~seq #:guard guard:expr)
(~seq #:property prop:expr prop-val:expr)
(~seq #:transparent)
(~seq #:prefab)
(~seq #:constructor-name constructor-name:id)
(~seq #:extra-constructor-name extra-constructor-name:id)
(~seq #:omit-define-syntaxes)
(~seq #:omit-define-values))
...)
]
The fact that @scheme[expr] does not match keywords helps in the case
where the programmer omits a keyword's argument; instead of accepting
the next keyword as the argument expression, @scheme[syntax-parse]
reports that an expression was expected.
There are two main problems with the pattern above:
@itemize[
@item{There's no way to tell whether a zero-argument keyword like
@scheme[#:mutable] was seen.}
@item{Some options, like @scheme[#:mutable], should appear at most
once.}
]
The first problem can be remedied using @scheme[~and] patterns to bind
a pattern variable to the keyword itself, as in this sub-pattern:
@schemeblock[
(~seq (~and #:mutable mutable-kw))
]
The second problem can be solved using @emph{repetition constraints}:
@schemeblock[
(struct name:id super:maybe-super (field:field ...)
(~or (~optional (~seq (~and #:mutable) mutable-kw))
(~optional (~seq #:super super-expr:expr))
(~optional (~seq #:inspector inspector:expr))
(~optional (~seq #:auto-value auto:expr))
(~optional (~seq #:guard guard:expr))
(~seq #:property prop:expr prop-val:expr)
(~optional (~seq (~and #:transparent transparent-kw)))
(~optional (~seq (~and #:prefab prefab-kw)))
(~optional (~seq #:constructor-name constructor-name:id))
(~optional
(~seq #:extra-constructor-name extra-constructor-name:id))
(~optional
(~seq (~and #:omit-define-syntaxes omit-def-stxs-kw)))
(~optional (~seq (~and #:omit-define-values omit-def-vals-kw))))
...)
]
The @scheme[~optional] repetition constraint indicates that an
alternative can appear at most once. (There is a @scheme[~once] form
that means it must appear exactly once.) In @scheme[struct]'s keyword
options, only @scheme[#:property] may occur any number of times.
There are still some problems, though. Without additional help,
@scheme[~optional] does not report particularly good errors. We must
give it the language to use, just as we had to give descriptions to
sub-patterns via syntax classes. Also, some related options are
mutually exclusive, such as @scheme[#:inspector],
@scheme[#:transparent], and @scheme[#:prefab].
@schemeblock[
(struct name:id super:maybe-super (field:field ...)
(~or (~optional
(~or (~seq #:inspector inspector:expr)
(~seq (~and #:transparent transparent-kw))
(~seq (~and #:prefab prefab-kw)))
#:name "#:inspector, #:transparent, or #:prefab option")
(~optional (~seq (~and #:mutable) mutable-kw)
#:name "#:mutable option")
(~optional (~seq #:super super-expr:expr)
#:name "#:super option")
(~optional (~seq #:auto-value auto:expr)
#:name "#:auto-value option")
(~optional (~seq #:guard guard:expr)
#:name "#:guard option")
(~seq #:property prop:expr prop-val:expr)
(~optional (~seq #:constructor-name constructor-name:id)
#:name "#:constructor-name option")
(~optional
(~seq #:extra-constructor-name extra-constructor-name:id)
#:name "#:extra-constructor-name option")
(~optional (~seq (~and #:omit-define-syntaxes omit-def-stxs-kw))
#:name "#:omit-define-syntaxes option")
(~optional (~seq (~and #:omit-define-values omit-def-vals-kw))
#:name "#:omit-define-values option"))
...)
]
Here we have grouped the three incompatible options together under a
single @scheme[~optional] constraint. That means that at most one of
any of those options is allowed. We have given names to the optional
clauses. See @scheme[~optional] for other customization options.
Note that there are other constraints that we have not represented in
the pattern. For example, @scheme[#:prefab] is also incompatible with
both @scheme[#:guard] and @scheme[#:property]. Repetition constraints
cannot express arbitrary incompatibility relations. The best way to
handle such contraints is with a side condition using
@scheme[#:fail-when].