racket/collects/syntax/scribblings/parse/ex-uniform.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

144 lines
5.0 KiB
Racket

#lang scribble/doc
@(require scribble/manual
scribble/struct
scribble/decode
scribble/eval
"parse-common.rkt"
(for-label racket/class))
@title[#:tag "uniform-meanings"]{Variants with uniform meanings}
Syntax classes not only validate syntax, they also extract some
measure of meaning from it. From the perspective of meaning, there are
essentially two kinds of syntax class. In the first, all of the syntax
class's variants have the same kind of meaning. In the second,
variants may have different kinds of meaning.@margin-note*{In other
words, some syntax classes' meanings are products and others' meanings
are sums.} This section discusses the first kind, syntax classes with
uniform meanings. The next section discusses @secref{varied-meanings}.
If all of a syntax class's variants express the same kind of
information, that information can be cleanly represented via
attributes, and it can be concisely processed using ellipses.
One example of a syntax class with uniform meaning: the
@scheme[init-decl] syntax of the @scheme[class] macro. Here is the
specification of @scheme[init-decl]:
@schemegrammar*[[init-decl
id
(maybe-renamed)
(maybe-renamed default-expr)]
[maybe-renamed
id
(internal-id external-id)]]
The @scheme[init-decl] syntax class has three variants, plus an
auxiliary syntax class that has two variants of its own. But all forms
of @scheme[init-decl] ultimately carry just three pieces of
information: an internal name, an external name, and a default
configuration of some sort. The simpler syntactic variants are just
abbreviations for the full information.
The three pieces of information determine the syntax class's
attributes. It is useful to declare the attributes explicitly using
the @scheme[#:attributes] keyword; the declaration acts both as
in-code documentation and as a check on the variants.
@schemeblock[
(define-syntax-class init-decl
#:attributes (internal external default)
___)
]
Next we fill in the syntactic variants, deferring the computation of
the attributes:
@schemeblock[
(define-syntax-class init-decl
#:attributes (internal external default)
(pattern ???:id
___)
(pattern (???:maybe-renamed)
___)
(pattern (???:maybe-renamed ???:expr)
___))
]
We perform a similar analysis of @scheme[maybe-renamed]:
@schemeblock[
(define-syntax-class maybe-renamed
#:attributes (internal external)
(pattern ???:id
___)
(pattern (???:id ???:id)
___))
]
Here's one straightforward way of matching syntactic structure with
attributes for @scheme[maybe-renamed]:
@schemeblock[
(define-syntax-class maybe-renamed
#:attributes (internal external)
(pattern internal:id
#:with external #'internal)
(pattern (internal:id external:id)))
]
Given that definition of @scheme[maybe-renamed], we can fill in most
of the definition of @scheme[init-decl]:
@schemeblock[
(define-syntax-class init-decl
#:attributes (internal external default)
(pattern internal:id
#:with external #:internal
#:with default ???)
(pattern (mr:maybe-renamed)
#:with internal #'mr.internal
#:with external #'mr.external
#:with default ???)
(pattern (mr:maybe-renamed default0:expr)
#:with internal #'mr.internal
#:with external #'mr.external
#:with default ???))
]
At this point we realize we have not decided on a representation for
the default configuration. In fact, it is an example of
@seclink["varied-meanings"]{syntax with varied meanings} (aka sum or
disjoint union). The following section discusses representation
options in greater detail; for the sake of completeness, we present
one of them here.
There are two kinds of default configuration. One indicates that the
initialization argument is optional, with a default value computed
from the given expression. The other indicates that the initialization
argument is mandatory. We represent the variants as a (syntax) list
containing the default expression and as the empty (syntax) list,
respectively. More precisely:
@schemeblock[
(define-syntax-class init-decl
#:attributes (internal external default)
(pattern internal:id
#:with external #:internal
#:with default #'())
(pattern (mr:maybe-renamed)
#:with internal #'mr.internal
#:with external #'mr.external
#:with default #'())
(pattern (mr:maybe-renamed default0:expr)
#:with internal #'mr.internal
#:with external #'mr.external
#:with default #'(default0)))
]
Another way to look at this aspect of syntax class design is as the
algebraic factoring of sums-of-products (concrete syntax variants)
into products-of-sums (attributes and abstract syntax variants). The
advantages of the latter form are the ``dot'' notation for data
extraction, avoiding or reducing additional case analysis, and the
ability to concisely manipulate sequences using ellipses.