464 lines
16 KiB
Racket
464 lines
16 KiB
Racket
#lang scribble/doc
|
|
|
|
@(require scribble/manual
|
|
scribble/struct
|
|
(for-label macro-debugger/stxclass/stxclass))
|
|
|
|
@title{Parsing Syntax and Syntax Classes}
|
|
|
|
@defmodule[macro-debugger/stxclass/stxclass]
|
|
|
|
@section{Parsing Syntax}
|
|
@declare-exporting[macro-debugger/stxclass/stxclass]
|
|
|
|
@defform/subs[(syntax-parse stx-expr maybe-literals clause ...)
|
|
([maybe-literals code:blank
|
|
(code:line #:literals (literal-id ...))]
|
|
[clause (syntax-pattern pattern-directive ... expr)])]{
|
|
|
|
Evaluates @scheme[stx-expr], which should produce a syntax object, and
|
|
matches it against the patterns in order. If some pattern matches, its
|
|
pattern variables are bound to the corresponding subterms of the
|
|
syntax object and that clause's side conditions and @scheme[expr] is
|
|
evaluated. The result is the result of @scheme[expr].
|
|
|
|
If the syntax object fails to match any of the patterns (or all
|
|
matches fail the corresponding clauses' side conditions), a syntax
|
|
error is raised. The syntax error indicates the first specific subterm
|
|
for which no pattern matches.
|
|
|
|
}
|
|
|
|
@defform[(syntax-parser maybe-literals clause ...)]{
|
|
|
|
Like @scheme[syntax-parse], but produces a matching procedure. The
|
|
procedure accepts a single argument, which should be a syntax object.
|
|
|
|
}
|
|
|
|
The grammar of patterns accepted by @scheme[syntax-parse] and
|
|
@scheme[syntax-parser] follows:
|
|
|
|
@schemegrammar*[#:literals (_ ... ...*)
|
|
[syntax-pattern
|
|
pvar-id
|
|
pvar-id:syntax-class-id
|
|
literal-id
|
|
atomic-datum
|
|
(syntax-pattern . syntax-pattern)
|
|
(syntax-splice-pattern . syntax-pattern)
|
|
(syntax-pattern ... . syntax-pattern)
|
|
((head ...+) ...* . syntax-pattern)]
|
|
[syntax-splice-pattern
|
|
pvar-id:syntax-splice-class-id]
|
|
[pvar-id
|
|
_
|
|
id]]
|
|
|
|
Here are the variants of @scheme[syntax-pattern]:
|
|
|
|
@specsubform[pvar-id]{
|
|
|
|
Matches anything. The pattern variable is bound to the matched
|
|
subterm, unless the pattern variable is the wildcard (@scheme[_]), in
|
|
which case no binding occurs.
|
|
|
|
}
|
|
@specsubform[pvar-id:syntax-class-id]{
|
|
|
|
Matches only subterms specified by the @scheme[_syntax-class-id]. The
|
|
syntax class's attributes are computed for the subterm and bound to
|
|
the pattern variables formed by prefixing @scheme[_pvar-id.] to the
|
|
name of the attribute. @scheme[_pvar-id] is typically bound to the
|
|
matched subterm, but the syntax class can substitute a transformed
|
|
subterm instead (for example, @scheme[expr/c] wraps the matched
|
|
subterm in a @scheme[contract] expression).
|
|
|
|
If @scheme[_pvar-id] is @scheme[_], no pattern variables are bound.
|
|
|
|
}
|
|
@specsubform[literal-id]{
|
|
|
|
An identifier that appears in the literals list is not a pattern
|
|
variable; instead, it is a literal that matches any identifier
|
|
@scheme[free-identifier=?] to it.
|
|
|
|
}
|
|
@specsubform[atomic-datum]{
|
|
|
|
The empty list, numbers, strings, booleans, and keywords match as
|
|
literals.
|
|
|
|
}
|
|
@specsubform[(syntax-pattern . syntax-pattern)]{
|
|
|
|
Matches a syntax pair whose head matches the first pattern and whose
|
|
tail matches the second.
|
|
|
|
}
|
|
@specsubform[(syntax-splice-pattern . syntax-pattern)]{
|
|
|
|
Matches a syntax object which consists of any sequence of syntax
|
|
objects matching the splice pattern followed by a tail matching the
|
|
given tail pattern.
|
|
|
|
}
|
|
@specsubform[(syntax-pattern ... . syntax-pattern)]{
|
|
|
|
Matches a sequence of the first pattern ending in a tail matching the
|
|
second pattern.
|
|
|
|
That is, the sequence pattern matches either the second pattern (which
|
|
need not be a list) or a pair whose head matches the first pattern and
|
|
whose tail recursively matches the whole sequence pattern.
|
|
|
|
}
|
|
@specsubform/subs[#:literals (...*)
|
|
((head ...+) ...* . syntax-pattern)
|
|
([head
|
|
(code:line (syntax-pattern ...+) head-directive ...)]
|
|
[head-directive
|
|
(code:line #:min min-reps)
|
|
(code:line #:max max-reps)
|
|
(code:line #:mand)
|
|
(code:line #:opt)
|
|
(code:line #:occurs occurs-pvar-id)
|
|
(code:line #:default default-form)])]{
|
|
|
|
Matches a sequence of any combination of the heads ending in a tail
|
|
matching the final pattern. The match is subject to constraints
|
|
specified on the heads.
|
|
|
|
@specsubform[(code:line #:min min-reps)]{
|
|
|
|
Requires at least @scheme[min-reps] occurrences of the preceding head
|
|
to match. @scheme[min-reps] must be a literal exact nonnegative
|
|
integer.
|
|
|
|
}
|
|
@specsubform[(code:line #:max max-reps)]{
|
|
|
|
Requires that no more than @scheme[max-reps] occurrences of the
|
|
preceeding head to match. @scheme[max-reps] must be a literal exact
|
|
nonnegative integer, and it must be greater than @scheme[min-reps].
|
|
|
|
}
|
|
@specsubform[#:mand]{
|
|
|
|
Requires that the preceding head occur exactly once. Pattern variables
|
|
in the preceding head are not bound at a higher ellipsis nesting
|
|
depth.
|
|
|
|
}
|
|
@specsubform[#:opt]{
|
|
|
|
(Probably a bad idea.)
|
|
|
|
}
|
|
}
|
|
|
|
The variants of @scheme[_syntax-splice-pattern] follow:
|
|
|
|
@specsubform[pvar-id:syntax-splice-class-id]{
|
|
|
|
Matches a sequence of syntax objects described by
|
|
@scheme[_syntax-splice-class-id].
|
|
|
|
The name @scheme[_pvar-id] is bound, but not allowed within
|
|
expressions or @scheme[syntax] templates (since it does not refer to a
|
|
particular syntax object). Only the prefixed attributes of the splice
|
|
class are usable.
|
|
|
|
}
|
|
|
|
Both @scheme[syntax-parse] and @scheme[syntax-parser] support
|
|
directives for annotating the pattern and specifying side
|
|
conditions. The grammar for pattern directives follows:
|
|
|
|
@schemegrammar[pattern-directive
|
|
(code:line #:declare pattern-id syntax-class-id)
|
|
(code:line #:declare pattern-id (syntax-class-id expr ...))
|
|
(code:line #:with syntax-pattern expr)
|
|
(code:line #:where expr)]
|
|
|
|
@specsubform[(code:line #:declare pvar-id syntax-class-id)]
|
|
@specsubform[(code:line #:declare pvar-id (syntax-class-id expr ...))]{
|
|
|
|
The first form is entirely equivalent to using the
|
|
@scheme[_pvar-id:syntax-class-id] form in the pattern (but it is
|
|
illegal to use both for a single pattern variable). The
|
|
@scheme[#:declare] form may be preferred when writing macro-defining
|
|
macros or to avoid dealing with structured identifiers.
|
|
|
|
The second form allows the use of parameterized syntax classes, which
|
|
cannot be expressed using the ``colon'' notation. The @scheme[expr]s
|
|
are evaluated outside the scope of the pattern variable bindings.
|
|
|
|
}
|
|
@specsubform[(code:line #:with syntax-pattern expr)]{
|
|
|
|
Evaluates the @scheme[expr] in the context of all previous pattern
|
|
variable bindings and matches it against the pattern. If the match
|
|
succeeds, the new pattern variables are added to the environment for
|
|
the evaluation of subsequent side conditions. If the @scheme[#:with]
|
|
match fails, the matching process backtracks. Since a syntax object
|
|
may match a pattern in several ways, backtracking may try the same
|
|
clause multiple times before continuing to the next clause.
|
|
|
|
}
|
|
@specsubform[(code:line #:where expr)]{
|
|
|
|
Evaluates the @scheme[expr] in the context of all previous pattern
|
|
variable bindings. If it produces a false value, the matching process
|
|
backtracks as described above; otherwise, it continues.
|
|
|
|
}
|
|
|
|
@defidform[...*]{
|
|
|
|
Keyword recognized by @scheme[syntax-parse] etc as notation for
|
|
generalized sequences. It may not be used as an expression.
|
|
|
|
}
|
|
|
|
@section{Syntax Classes}
|
|
@declare-exporting[macro-debugger/stxclass/stxclass]
|
|
|
|
Syntax classes provide an abstraction mechanism for the specification
|
|
of syntax. Basic syntax classes include @scheme[identifier] and
|
|
@scheme[keyword]. From these, programmers can build larger
|
|
specifications of syntax, such as @scheme[distinct-identifier-list]
|
|
and @scheme[keyword-formals]. Macros that manipulate the same
|
|
syntactic structures can share syntax class definitions. Syntax
|
|
classes are also the basis of error reporting in
|
|
@scheme[syntax-parse].
|
|
|
|
When a syntax class accepts (matches, includes) a syntax object, it
|
|
computes and provides attributes based on the contents of the matched
|
|
syntax. While the values of the attributes depend on the matched
|
|
syntax, the set of attributes and each attribute's ellipsis nesting
|
|
depth is fixed for each syntax class.
|
|
|
|
@defform*/subs[#:literals (pattern)
|
|
[(define-syntax-class name-id stxclass-option ...
|
|
stxclass-variant ...)
|
|
(define-syntax-class (name-id arg-id ...) stxclass-option ...
|
|
stxclass-variant ...)]
|
|
([stxclass-options
|
|
(code:line #:description string)
|
|
(code:line #:transparent)]
|
|
[stxclass-variant
|
|
(pattern syntax-pattern pattern-directive ...)])]{
|
|
|
|
Defines @scheme[name-id] as a syntax class. When the @scheme[arg-id]s
|
|
are present, they are bound as variables (not pattern variables) in
|
|
the body.
|
|
|
|
The body of the syntax-class definition contains one or more variants
|
|
that specify the syntax it accepts and determines the attributes it
|
|
provides. The syntax class provides only those attributes which are
|
|
present in every variant. Each such attribute must be defined with the
|
|
same ellipsis nesting depth and the same sub-attributes in each
|
|
component.
|
|
|
|
@specsubform[(code:line #:description string)]{
|
|
|
|
Specifies a string to use in error messages involving the syntax
|
|
class. For example, if a term is rejected by the syntax class, an
|
|
error of the form @scheme["expected <description>"] may be generated.
|
|
|
|
If absent, the name of the syntax class is used instead.
|
|
}
|
|
|
|
@specsubform[#:transparent]{
|
|
|
|
Indicates that errors may be reported with respect to the internal
|
|
structure of the syntax class.
|
|
}
|
|
|
|
@specsubform/subs[#:literals (pattern)
|
|
(pattern syntax-pattern pattern-directive ...)
|
|
([stxclass-pattern-directive
|
|
pattern-directive
|
|
(code:line #:rename internal-id external-id)])]{
|
|
|
|
Accepts syntax matching the given pattern with the accompanying
|
|
pattern directives as in @scheme[syntax-parse].
|
|
|
|
Provides an attribute for every pattern variable defined in the
|
|
pattern and the @scheme[#:with] clauses. The name of the attribute is
|
|
the symbolic name of the pattern variable, except when the name is
|
|
explicitly given via a @scheme[#:rename] clause. Pattern variables
|
|
declared with a syntax class yield derived pattern variables for that
|
|
syntax class's attributes. These are propagated as nested attributes.
|
|
|
|
@specsubform[(code:line #:rename internal-id external-id)]{
|
|
|
|
Exports the pattern variable binding named by @scheme[internal-id] as
|
|
the attribute named @scheme[external-id].
|
|
|
|
}
|
|
}
|
|
|
|
Within the syntax-class body, recursive references to the enclosing
|
|
syntax class and forward references to syntax classes defined in the
|
|
same scope are allowed. For the purpose of calculating provided
|
|
attributes, recursive and forward syntax-class references generate no
|
|
nested attributes. The full set of attributes is available, however,
|
|
to @scheme[#:with] and @scheme[#:where] expressions.
|
|
|
|
This treatment of recursive and forward references prevents infinitely
|
|
nested attributes.
|
|
|
|
}
|
|
|
|
@defform*[[(define-syntax-splice-class (name-id arg-id ...) stxclass-body)
|
|
(define-syntax-splice-class name-id stxclass-body)]]{
|
|
|
|
Defines @scheme[name-id] as a syntax splice class. When the
|
|
@scheme[arg-id]s are present, they are bound as variables (not pattern
|
|
variables) in the body.
|
|
|
|
The @scheme[stxclass-body] is like the body of
|
|
@scheme[define-syntax-class], except that all patterns within it must
|
|
match only proper lists:
|
|
|
|
@schemegrammar[#:literals (... ...*)
|
|
proper-list-pattern
|
|
()
|
|
(syntax-pattern . proper-list-pattern)
|
|
(syntax-splice-pattern . proper-list-pattern)
|
|
(syntax-pattern ... . proper-list-pattern)
|
|
((head ...+) ...* . proper-list-pattern)]
|
|
|
|
}
|
|
|
|
@defidform[pattern]{
|
|
|
|
Keyword recognized by @scheme[define-syntax-class]. It may not be
|
|
used as an expression.
|
|
}
|
|
|
|
@defform[(define-basic-syntax-class (name-id arg-id ...)
|
|
([attr-id attr-depth] ...)
|
|
parser-expr)]{
|
|
|
|
Defines @scheme[name] as a syntax class with the given
|
|
attributes. Each @scheme[attr-depth] must be a literal exact
|
|
nonnegative integer (most often @scheme[0]).
|
|
|
|
The @scheme[arg-id]s are placeholders only. They are not bound in any
|
|
part of the syntax-class body.
|
|
|
|
The @scheme[parser-expr] must evaluate to a procedure. This procedure
|
|
is used to parse or reject syntax objects. The arguments to the parser
|
|
procedure consist of the syntax object to parse followed by the
|
|
syntax-class parameterization arguments. To indicate success, the
|
|
parser should return a list of attribute values, one for each
|
|
attribute listed. (For example, a parser for a syntax class that
|
|
defines no attributes returns the empty list when it succeeds.) To
|
|
indicate failure, the parser procedure should return the result of
|
|
calling @scheme[fail-sc].
|
|
|
|
The parser procedure is encouraged to avoid side-effects.
|
|
|
|
}
|
|
|
|
@defform[(define-basic-syntax-class* (name-id arg-id ...)
|
|
([attr-id attr-depth] ...)
|
|
parser-expr)]{
|
|
|
|
Like @scheme[define-basic-syntax-class], except that on success the
|
|
parser expression produces a list with an extra element consed onto
|
|
the attribute value list. This extra element is the transformed
|
|
matched syntax. When a pattern variable annotated with the syntax
|
|
class matches, it is bound to this syntax instead of the subterm of
|
|
the original syntax object.
|
|
|
|
Transforming matched syntax is useful for implementing syntax classes
|
|
that add interpretation or constraints to expressions, such as
|
|
@scheme[expr/c], which imposes run-time contracts on expressions.
|
|
|
|
}
|
|
|
|
@defform[(attrs-of syntax-class-id)]{
|
|
|
|
For debugging. Returns a representation of the attributes provided by
|
|
a syntax class.
|
|
|
|
}
|
|
|
|
@defform[(parse-sc syntax-class-id stx-expr arg-expr ...)]{
|
|
|
|
For debugging. Runs the parser for the syntax class (parameterized by
|
|
the @scheme[arg-expr]s) on the syntax object produced by
|
|
@scheme[stx-expr].
|
|
|
|
}
|
|
|
|
|
|
@section{Library syntax classes}
|
|
@declare-exporting[macro-debugger/stxclass/stxclass]
|
|
|
|
@(define-syntax-rule (defstxclass name . pre-flows)
|
|
(defidform name . pre-flows))
|
|
|
|
@(define-syntax-rule (defstxclass* (name arg ...) . pre-flows)
|
|
(defform (name arg ...) . pre-flows))
|
|
|
|
The following basic syntax classes are defined:
|
|
|
|
@deftogether[(
|
|
@defstxclass[identifier]
|
|
@defstxclass[boolean]
|
|
@defstxclass[str]
|
|
@defstxclass[char]
|
|
@defstxclass[keyword]
|
|
@defstxclass[number]
|
|
@defstxclass[integer]
|
|
@defstxclass[exact-integer]
|
|
@defstxclass[exact-nonnegative-integer]
|
|
@defstxclass[exact-positive-integer])]
|
|
|
|
Two of the above have short aliases:
|
|
|
|
@defstxclass[id]{ Same as @scheme[identifier]. }
|
|
@defstxclass[nat]{ Same as @scheme[exact-nonnegative-integer]. }
|
|
|
|
The following syntax classes mirror parts of the macro API. They
|
|
may only be used in phase 1 expressions.
|
|
|
|
@defstxclass[static]{
|
|
|
|
Matches identifiers that are bound in the syntactic environment to
|
|
static information (see @scheme[syntax-local-value]). Attribute
|
|
@scheme[_value] contains the value the name is bound to.
|
|
|
|
}
|
|
|
|
@defstxclass[struct-name]{
|
|
|
|
Matches identifiers bound to static struct information. Attributes are
|
|
@scheme[_descriptor], @scheme[_constructor], @scheme[_predicate],
|
|
@scheme[(_accessor ...)], @scheme[_super], and @scheme[_complete?].
|
|
|
|
}
|
|
|
|
@defstxclass[expr/local-expand]{
|
|
|
|
Matches any term and @scheme[local-expand]s it as an expression with
|
|
an empty stop list. Attribute @scheme[_expanded] is the expanded form.
|
|
|
|
}
|
|
|
|
@defstxclass[expr/head-local-expand]
|
|
@defstxclass[block/head-local-expand]
|
|
@defstxclass[internal-definitions]
|
|
|
|
@defform[(expr/c contract-expr-stx)]{
|
|
|
|
Accepts any term and returns as the match that term wrapped in a
|
|
@scheme[contract] expression enforcing @scheme[contract-expr-stx].
|
|
|
|
}
|