stxclass: reorganized docs
svn: r13544
This commit is contained in:
parent
e61075a4fd
commit
f2204710fa
|
@ -1,3 +1,4 @@
|
|||
#lang setup/infotab
|
||||
|
||||
(define scribblings '(("stxclass.scrbl")))
|
||||
(define scribblings
|
||||
'(("scribblings/stxclass.scrbl" (multi-page) (experimental))))
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
define-basic-syntax-class
|
||||
define-basic-syntax-class*
|
||||
pattern
|
||||
basic-syntax-class
|
||||
|
||||
syntax-parse
|
||||
syntax-parser
|
||||
|
@ -16,4 +17,7 @@
|
|||
current-expression
|
||||
current-macro-name
|
||||
|
||||
(all-from-out "private/lib.ss"))
|
||||
(all-from-out "private/lib.ss")
|
||||
|
||||
(rename-out [parse-sc syntax-class-parse]
|
||||
[attrs-of syntax-class-attributes]))
|
||||
|
|
|
@ -53,16 +53,6 @@
|
|||
(pattern :define-values-form)
|
||||
(pattern :define-syntaxes-form))
|
||||
|
||||
(define-basic-syntax-class static
|
||||
([value 0])
|
||||
(lambda (x)
|
||||
(if (identifier? x)
|
||||
(let/ec escape
|
||||
(define (bad) (escape #f))
|
||||
(let ([value (syntax-local-value x bad)])
|
||||
(list (syntax-e x) value)))
|
||||
#f)))
|
||||
|
||||
(define-syntax-class (static-of name pred)
|
||||
#:description name
|
||||
#:attributes ([value 0])
|
||||
|
@ -73,9 +63,15 @@
|
|||
(if (identifier? x)
|
||||
(let ([value (syntax-local-value x bad)])
|
||||
(unless (pred value) (bad))
|
||||
(list x value))
|
||||
(list value))
|
||||
(bad))))))
|
||||
|
||||
(define-syntax-class static
|
||||
#:attributes (value)
|
||||
(pattern x
|
||||
#:declare x (static-of "static" (lambda _ #t))
|
||||
#:with value #'x.value))
|
||||
|
||||
(define-basic-syntax-class struct-name
|
||||
([descriptor 0]
|
||||
[constructor 0]
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#lang scheme/base
|
||||
(require (for-template "runtime.ss")
|
||||
(for-template scheme/base)
|
||||
(require (for-template scheme/base)
|
||||
(for-template "runtime.ss")
|
||||
scheme/contract
|
||||
scheme/match
|
||||
syntax/boundmap
|
||||
|
@ -59,14 +59,29 @@
|
|||
(define transparent? (and trans0 #t))
|
||||
(define attributes (and attrs0 (caddr attrs0)))
|
||||
|
||||
(define (parse-rhs*-basic rest)
|
||||
(syntax-case rest (basic-syntax-class)
|
||||
[((basic-syntax-class parser-expr))
|
||||
(make rhs:basic ctx
|
||||
(or attributes null)
|
||||
transparent?
|
||||
description
|
||||
#'parser-expr)]))
|
||||
(define (parse-rhs*-basic rhss)
|
||||
(syntax-case rhss (basic-syntax-class)
|
||||
[((basic-syntax-class . rest))
|
||||
(let-values ([(basic-chunks rest)
|
||||
(chunk-kw-seq/no-dups #'rest basic-rhs-directive-table
|
||||
#:context (stx-car rhss))])
|
||||
(syntax-case rest ()
|
||||
[(parser-expr)
|
||||
(make rhs:basic ctx
|
||||
(or attributes null)
|
||||
transparent?
|
||||
description
|
||||
(if (assq '#:transforming basic-chunks)
|
||||
#'parser-expr
|
||||
#`(let ([parser parser-expr])
|
||||
(lambda (x . args)
|
||||
(let ([result (apply parser x args)])
|
||||
(if (ok? result)
|
||||
(cons x result)
|
||||
result))))))]
|
||||
[_
|
||||
(wrong-syntax (stx-car rhss)
|
||||
"expected parser expression")]))]))
|
||||
|
||||
(define (parse-rhs*-patterns rest)
|
||||
(define (gather-patterns stx)
|
||||
|
@ -359,3 +374,7 @@
|
|||
(list '#:description values)
|
||||
(list '#:transparent)
|
||||
(list '#:attributes check-attr-arity-list)))
|
||||
|
||||
;; basic-rhs-directive-table
|
||||
(define basic-rhs-directive-table
|
||||
(list (list '#:transforming)))
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
(for-syntax "rep-data.ss")
|
||||
(for-syntax "../util/error.ss"))
|
||||
(provide pattern
|
||||
basic-syntax-class
|
||||
...*
|
||||
|
||||
with-enclosing-fail
|
||||
|
@ -35,6 +36,7 @@
|
|||
(raise-syntax-error #f "keyword used out of context" stx))))
|
||||
|
||||
(define-keyword pattern)
|
||||
(define-keyword basic-syntax-class)
|
||||
(define-keyword ...*)
|
||||
(define-keyword ...**)
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
with-patterns
|
||||
|
||||
pattern
|
||||
basic-syntax-class
|
||||
...*
|
||||
|
||||
(struct-out failed)
|
||||
|
@ -118,6 +119,7 @@
|
|||
(define-syntax-class (name arg ...)
|
||||
#:attributes ([attr-name attr-depth] ...)
|
||||
(basic-syntax-class
|
||||
#:transforming
|
||||
(let ([name parser-expr]) name)))]))
|
||||
|
||||
(define-syntax (rhs->parser+description stx)
|
||||
|
@ -137,23 +139,25 @@
|
|||
(define-syntax (parse-sc stx)
|
||||
(syntax-case stx ()
|
||||
[(parse s x arg ...)
|
||||
(let* ([stxclass (get-stxclass #'s)]
|
||||
[attrs (flatten-sattrs (sc-attrs stxclass))])
|
||||
(with-syntax ([parser (sc-parser-name stxclass)]
|
||||
[(name ...) (map attr-name attrs)]
|
||||
[(depth ...) (map attr-depth attrs)])
|
||||
#'(let ([raw (parser x arg ...)])
|
||||
(if (ok? raw)
|
||||
(map vector '(name ...) '(depth ...) (cdr raw))
|
||||
raw))))]))
|
||||
(parameterize ((current-syntax-context stx))
|
||||
(let* ([stxclass (get-stxclass #'s)]
|
||||
[attrs (flatten-sattrs (sc-attrs stxclass))])
|
||||
(with-syntax ([parser (sc-parser-name stxclass)]
|
||||
[(name ...) (map attr-name attrs)]
|
||||
[(depth ...) (map attr-depth attrs)])
|
||||
#'(let ([raw (parser x arg ...)])
|
||||
(if (ok? raw)
|
||||
(map vector '(name ...) '(depth ...) (cdr raw))
|
||||
raw)))))]))
|
||||
|
||||
(define-syntax (attrs-of stx)
|
||||
(syntax-case stx ()
|
||||
[(attrs-of s)
|
||||
(let ([attrs (flatten-sattrs (sc-attrs (get-stxclass #'s)))])
|
||||
(with-syntax ([(a ...) (map attr-name attrs)]
|
||||
[(depth ...) (map attr-depth attrs)])
|
||||
#'(quote ((a depth) ...))))]))
|
||||
(parameterize ((current-syntax-context stx))
|
||||
(let ([attrs (flatten-sattrs (sc-attrs (get-stxclass #'s)))])
|
||||
(with-syntax ([(a ...) (map attr-name attrs)]
|
||||
[(depth ...) (map attr-depth attrs)])
|
||||
#'(quote ((a depth) ...)))))]))
|
||||
|
||||
(define-syntax (debug-rhs stx)
|
||||
(syntax-case stx ()
|
||||
|
@ -186,7 +190,7 @@
|
|||
(let ([fail (syntax-patterns-fail x)])
|
||||
(parameterize ((current-expression (or (current-expression) x)))
|
||||
#,(parse:clauses #'clauses #'x #'fail))))))]))
|
||||
|
||||
|
||||
(define-syntax with-patterns
|
||||
(syntax-rules ()
|
||||
[(with-patterns () . b)
|
||||
|
|
103
collects/stxclass/scribblings/library.scrbl
Normal file
103
collects/stxclass/scribblings/library.scrbl
Normal file
|
@ -0,0 +1,103 @@
|
|||
#lang scribble/doc
|
||||
@(require scribble/manual
|
||||
scribble/struct
|
||||
scribble/decode
|
||||
(for-label scheme/base
|
||||
scheme/contract
|
||||
stxclass
|
||||
stxclass/util))
|
||||
|
||||
@(define ellipses @scheme[...])
|
||||
@(define (TODO . pre-flow)
|
||||
(make-splice
|
||||
(cons (bold "TODO: ")
|
||||
(decode-content pre-flow))))
|
||||
|
||||
@title{Library syntax classes}
|
||||
@declare-exporting[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))
|
||||
|
||||
@defstxclass[expr]{
|
||||
|
||||
Matches anything except a keyword literal (to distinguish expressions
|
||||
from the start of a keyword argument sequence). Does not expand or
|
||||
otherwise inspect the term.
|
||||
|
||||
}
|
||||
|
||||
@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])]{
|
||||
|
||||
Match syntax satisfying the corresponding predicates.
|
||||
|
||||
}
|
||||
|
||||
@defstxclass[id]{ Alias for @scheme[identifier]. }
|
||||
@defstxclass[nat]{ Alias for @scheme[exact-nonnegative-integer]. }
|
||||
|
||||
The following syntax classes mirror parts of the macro API. They may
|
||||
only be used during transformation (when @scheme[syntax-transforming?]
|
||||
returns true). Otherwise they may raise an error.
|
||||
|
||||
@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.
|
||||
|
||||
}
|
||||
|
||||
@defform[(static-of description predicate)]{
|
||||
|
||||
Refines @scheme[static]: matches identifiers that are bound in the
|
||||
syntactic environment to static information satisfying the given
|
||||
@scheme[predicate]. Attribute @scheme[_value] contains the value the
|
||||
name is bound to. The @scheme[description] argument is used for error
|
||||
reporting.
|
||||
|
||||
}
|
||||
|
||||
@;{
|
||||
@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].
|
||||
|
||||
}
|
||||
}
|
239
collects/stxclass/scribblings/parsing-syntax.scrbl
Normal file
239
collects/stxclass/scribblings/parsing-syntax.scrbl
Normal file
|
@ -0,0 +1,239 @@
|
|||
#lang scribble/doc
|
||||
@(require scribble/manual
|
||||
scribble/struct
|
||||
scribble/decode
|
||||
(for-label scheme/base
|
||||
scheme/contract
|
||||
stxclass
|
||||
stxclass/util))
|
||||
|
||||
@(define ellipses @scheme[...])
|
||||
@(define (TODO . pre-flow)
|
||||
(make-splice
|
||||
(cons (bold "TODO: ")
|
||||
(decode-content pre-flow))))
|
||||
|
||||
@title{Parsing Syntax}
|
||||
@declare-exporting[stxclass]
|
||||
|
||||
This section describes @schememodname[stxclass]'s facilities for
|
||||
parsing syntax.
|
||||
|
||||
@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.
|
||||
|
||||
@TODO{Allow literal declarations of form @scheme[(_internal-name
|
||||
_external-name)].}
|
||||
}
|
||||
|
||||
@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-pattern #,ellipses . syntax-pattern)
|
||||
((head ...+) ...* . syntax-pattern)]
|
||||
[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 #,ellipses . 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 or equal to
|
||||
@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 #:when expr)]
|
||||
|
||||
@specsubform[(code:line #:declare pvar-id syntax-class-id)]
|
||||
@specsubform[(code:line #:declare pvar-id (syntax-class-id expr ...))]{
|
||||
|
||||
The first form is 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 cause the same
|
||||
clause to be tried multiple times before the next clause is reached.
|
||||
|
||||
}
|
||||
@specsubform[(code:line #:when 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.
|
||||
|
||||
}
|
||||
|
88
collects/stxclass/scribblings/stxclass.scrbl
Normal file
88
collects/stxclass/scribblings/stxclass.scrbl
Normal file
|
@ -0,0 +1,88 @@
|
|||
#lang scribble/doc
|
||||
@(require scribble/manual
|
||||
scribble/struct
|
||||
scribble/decode
|
||||
(for-label scheme/base
|
||||
scheme/contract
|
||||
stxclass
|
||||
stxclass/util))
|
||||
|
||||
@(define ellipses @scheme[...])
|
||||
@(define (TODO . pre-flow)
|
||||
(make-splice
|
||||
(cons (bold "TODO: ")
|
||||
(decode-content pre-flow))))
|
||||
|
||||
@title{Parsing Syntax and Syntax Classes}
|
||||
|
||||
@bold{Warning: This library is still very volatile! Its interface and
|
||||
behavior are subject to frequent change. I highly recommend that you
|
||||
avoid creating PLaneT packages that depend on this library.}
|
||||
|
||||
The @schememodname[stxclass] library provides a framework for
|
||||
describing and parsing syntax. Using @schememodname[stxclass], macro
|
||||
writers can define new syntactic categories, specify their legal
|
||||
syntax, and use them to write clear, concise, and robust macros.
|
||||
|
||||
To load the library:
|
||||
@defmodule[stxclass]
|
||||
|
||||
@;{The first section is an overview with examples that illustrate
|
||||
@schememodname[stxclass] features.}
|
||||
|
||||
The following sections are a reference for @schememodname[stxclass]
|
||||
features.
|
||||
|
||||
@include-section["parsing-syntax.scrbl"]
|
||||
@include-section["syntax-classes.scrbl"]
|
||||
@include-section["library.scrbl"]
|
||||
@include-section["util.scrbl"]
|
||||
|
||||
@local-table-of-contents[]
|
||||
|
||||
@;{
|
||||
|
||||
|
||||
1 How to abstract over similar patterns:
|
||||
|
||||
(syntax-parse stx #:literals (blah bleh blaz kwA kwX)
|
||||
[(blah (bleh (kwX y z)) blaz)
|
||||
___]
|
||||
[(blah (bleh (kwA (b c))) blaz)
|
||||
___])
|
||||
|
||||
=>
|
||||
|
||||
(define-syntax-class common
|
||||
#:attributes (inner)
|
||||
#:literals (blah bleh blaz)
|
||||
(pattern (blah (bleh inner) blaz)))
|
||||
(syntax-parse stx #:literals (kwA kwX)
|
||||
[c:common
|
||||
#:with (kwX y z) #'c.inner
|
||||
___]
|
||||
[c:common
|
||||
#:with (kwA (b c)) #'c.inner
|
||||
___])
|
||||
|
||||
|
||||
OR =>
|
||||
|
||||
(define-syntax-class (common expected-kw)
|
||||
#:attributes (inner)
|
||||
#:literals (blah bleh blaz)
|
||||
(pattern (blah (bleh (kw . inner)) blaz)
|
||||
#:when (free-identifier=? #'kw expected-kw)))
|
||||
(syntax-parse stx
|
||||
[c
|
||||
#:declare c (common #'kwX)
|
||||
#:with (y z) #'c.inner
|
||||
___]
|
||||
[c
|
||||
#:declare c (common #'kwA)
|
||||
#:with ((b c)) #'c.inner
|
||||
___])
|
||||
|
||||
|
||||
}
|
||||
|
210
collects/stxclass/scribblings/syntax-classes.scrbl
Normal file
210
collects/stxclass/scribblings/syntax-classes.scrbl
Normal file
|
@ -0,0 +1,210 @@
|
|||
#lang scribble/doc
|
||||
@(require scribble/manual
|
||||
scribble/struct
|
||||
scribble/decode
|
||||
(for-label scheme/base
|
||||
scheme/contract
|
||||
stxclass
|
||||
stxclass/util))
|
||||
|
||||
@(define ellipses @scheme[...])
|
||||
@(define (TODO . pre-flow)
|
||||
(make-splice
|
||||
(cons (bold "TODO: ")
|
||||
(decode-content pre-flow))))
|
||||
|
||||
@title{Syntax Classes}
|
||||
@declare-exporting[stxclass]
|
||||
|
||||
Syntax classes provide an abstraction mechanism for the specification
|
||||
of syntax. Basic syntax classes include @scheme[identifier] and
|
||||
@scheme[keyword]. More generally, a programmer can define a ``basic''
|
||||
syntax from an arbitrary predicate, although syntax classes thus
|
||||
defined lose some of the benefits of declarative specification of
|
||||
syntactic structure.
|
||||
|
||||
Programmers can also compose basic syntax classes to build
|
||||
specifications of more complex syntax, such as lists of distinct
|
||||
identifiers and formal arguments with keywords. Macros that manipulate
|
||||
the same syntactic structures can share syntax class definitions. The
|
||||
structure of syntax classes and patterns also allows
|
||||
@scheme[syntax-parse] to automatically generate error messages for
|
||||
syntax errors.
|
||||
|
||||
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 basic-syntax-class)
|
||||
[(define-syntax-class name-id stxclass-option ...
|
||||
stxclass-body)
|
||||
(define-syntax-class (name-id arg-id ...) stxclass-option ...
|
||||
stxclass-body)]
|
||||
([stxclass-options
|
||||
(code:line #:attributes (attr-arity-decl ...))
|
||||
(code:line #:description description)
|
||||
(code:line #:transparent)]
|
||||
[attr-arity-decl
|
||||
attr-name-id
|
||||
(attr-name-id depth)]
|
||||
[stxclass-body
|
||||
(code:line (pattern syntax-pattern stxclass-pattern-directive ...) ...+)
|
||||
(code:line (basic-syntax-class parser-expr))])]{
|
||||
|
||||
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 either one
|
||||
@scheme[basic-syntax-class] clause or a non-empty sequence of
|
||||
@scheme[pattern] clauses.
|
||||
|
||||
@specsubform[(code:line #:attributes (attr-arity-decl ...))]{
|
||||
|
||||
Declares the attributes of the syntax class. An attribute arity
|
||||
declaration consists of the attribute name and optionally its ellipsis
|
||||
depth (zero if not explicitly specified).
|
||||
|
||||
If the attributes are not explicitly listed, they are computed using
|
||||
@techlink{attribute inference}.
|
||||
|
||||
}
|
||||
|
||||
@specsubform[(code:line #:description description)]{
|
||||
|
||||
The @scheme[description] argument is an expression (with the
|
||||
syntax-class's parameters in scope) that should evaluate to a
|
||||
string. It is used 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 stxclass-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].
|
||||
|
||||
The attributes of the pattern are the pattern variables within the
|
||||
@scheme[pattern] form together with all pattern variables bound by
|
||||
@scheme[#:with] clauses, including nested attributes produced by
|
||||
syntax classes associated with the pattern variables.
|
||||
|
||||
The name of an attribute is the symbolic name of the pattern variable,
|
||||
except when the name is explicitly given via a @scheme[#:rename]
|
||||
clause.
|
||||
|
||||
@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].
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@specsubform[#:literals (basic-syntax-class)
|
||||
(basic-syntax-class parser-expr)]{
|
||||
|
||||
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 (the parameter names given at
|
||||
the @scheme[define-syntax-class] level are not bound within the
|
||||
@scheme[parser-expr]). 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 @scheme[#f].
|
||||
|
||||
The parser procedure should avoid side-effects, as they interfere with
|
||||
the parsing process's backtracking and error reporting.
|
||||
|
||||
@TODO{Add support for better error reporting within basic syntax
|
||||
class.}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@defidform[pattern]{
|
||||
|
||||
Keyword recognized by @scheme[define-syntax-class]. It may not be
|
||||
used as an expression.
|
||||
}
|
||||
@defidform[basic-syntax-class]{
|
||||
|
||||
Keyword recognized by @scheme[define-syntax-class]. It may not be used
|
||||
as an expression.
|
||||
|
||||
}
|
||||
|
||||
@section{Attributes}
|
||||
|
||||
A syntax class has a set of @deftech{attribute}s. Each attribute has a
|
||||
name, an ellipsis depth, and a set of nested attributes. When an
|
||||
instance of the syntax class is parsed and bound to a pattern
|
||||
variable, additional pattern variables are bound for each of the
|
||||
syntax class's attributes. The name of these additional pattern
|
||||
variables is the dotted concatenation of the the primary pattern
|
||||
variable with the name of the attribute.
|
||||
|
||||
For example, if pattern variable @scheme[p] is bound to an instance of
|
||||
a syntax class with attribute @scheme[a], then the pattern variable
|
||||
@scheme[p.a] is bound to the value of that attribute. The ellipsis
|
||||
depth of @scheme[p.a] is the sum of the depths of @scheme[p] and
|
||||
attribute @scheme[a].
|
||||
|
||||
If the attributes are not declared explicitly, they are computed via
|
||||
@deftech{attribute inference}. For ``basic'' syntax classes, the
|
||||
inferred attribute list is always empty. For compound syntax classes,
|
||||
each @scheme[pattern] form is analyzed to determine its candiate
|
||||
attributes. The attributes of the syntax class are the attributes
|
||||
common to all of the variants (that is, the intersection of the
|
||||
candidate attributes). An attribute must have the same ellipsis-depth
|
||||
in each of the variants; otherwise, an error is raised.
|
||||
|
||||
The candidate attributes of a @scheme[pattern] variant are the pattern
|
||||
variables bound by the variant's pattern (including nested attributes
|
||||
contributed by their associated syntax classes) together with the
|
||||
pattern variables (and nested attributes) from @scheme[#:with]
|
||||
clauses.
|
||||
|
||||
For the purpose of attribute inference, recursive references to the
|
||||
same syntax class and forward references to syntax classes not yet
|
||||
defined do not contribute any nested attributes. This avoids various
|
||||
problems in computing attributes, including infinitely nested
|
||||
attributes.
|
||||
|
||||
@section{Inspection tools}
|
||||
|
||||
The following special forms are for debugging syntax classes.
|
||||
|
||||
@defform[(syntax-class-attributes syntax-class-id)]{
|
||||
|
||||
Returns a list of the syntax class's attributes in flattened
|
||||
form. Each attribute is listed by its name and ellipsis depth.
|
||||
|
||||
}
|
||||
|
||||
@defform[(syntax-class-parse syntax-class-id stx-expr arg-expr ...)]{
|
||||
|
||||
Runs the parser for the syntax class (parameterized by the
|
||||
@scheme[arg-expr]s) on the syntax object produced by
|
||||
@scheme[stx-expr]. On success, the result is a list of vectors
|
||||
representing the attribute bindings of the syntax class. Each vector
|
||||
contains the attribute name, depth, and associated value. On failure,
|
||||
the result is some internal representation of the failure.
|
||||
|
||||
}
|
232
collects/stxclass/scribblings/util.scrbl
Normal file
232
collects/stxclass/scribblings/util.scrbl
Normal file
|
@ -0,0 +1,232 @@
|
|||
#lang scribble/doc
|
||||
@(require scribble/manual
|
||||
scribble/struct
|
||||
scribble/decode
|
||||
(for-label scheme/base
|
||||
scheme/contract
|
||||
stxclass
|
||||
stxclass/util))
|
||||
|
||||
@(define ellipses @scheme[...])
|
||||
@(define (TODO . pre-flow)
|
||||
(make-splice
|
||||
(cons (bold "TODO: ")
|
||||
(decode-content pre-flow))))
|
||||
|
||||
@title{Utilities}
|
||||
|
||||
The @schememodname[stxclass] collection includes several utility
|
||||
modules. They are documented individually below.
|
||||
|
||||
As a shortcut, the @schememodname[stxclass/util] module provides all
|
||||
of the contents of the separate utility modules:
|
||||
|
||||
@defmodule[stxclass/util]
|
||||
|
||||
The contents of the utility modules are not provided by the main
|
||||
@schememodname[stxclass] module.
|
||||
|
||||
@section{Error reporting}
|
||||
|
||||
@defmodule[stxclass/util/error]
|
||||
|
||||
The @schememodname[scheme/base] and @schememodname[scheme] languages
|
||||
provide the @scheme[raise-syntax-error] procedure for reporting syntax
|
||||
errors. Using @scheme[raise-syntax-error] effectively requires passing
|
||||
around either a symbol indicating the special form that signals the
|
||||
error or else a ``contextual'' syntax object from which the special
|
||||
form's name can be extracted. This library helps manage the contextual
|
||||
syntax for reporting errors.
|
||||
|
||||
@defparam[current-syntax-context stx (or/c syntax? false/c)]{
|
||||
|
||||
The current contextual syntax object, defaulting to @scheme[#f]. It
|
||||
determines the special form name that prefixes syntax errors created
|
||||
by @scheme[wrong-syntax], as follows:
|
||||
|
||||
If it is a syntax object with a @scheme['report-error-as] syntax
|
||||
property whose value is a symbol, then that symbol is used as the
|
||||
special form name. Otherwise, the same rules apply as in
|
||||
@scheme[raise-syntax-error].
|
||||
|
||||
}
|
||||
|
||||
@defproc[(wrong-syntax [stx syntax?] [format-string string?] [v any/c] ...)
|
||||
any]{
|
||||
|
||||
Raises a syntax error using the result of
|
||||
@scheme[(current-syntax-context)] as the ``major'' syntax object and
|
||||
the provided @scheme[stx] as the specific syntax object. (The latter,
|
||||
@scheme[stx], is usually the one highlighted by DrScheme.) The error
|
||||
message is constructed using the format string and arguments, and it
|
||||
is prefixed with the special form name as described under
|
||||
@scheme[current-syntax-context].
|
||||
|
||||
}
|
||||
|
||||
A macro using this system might set the syntax context at the very
|
||||
beginning of its transformation as follows:
|
||||
@SCHEMEBLOCK[
|
||||
(define-syntax (my-macro stx)
|
||||
(parameterize ((current-syntax-context stx))
|
||||
(syntax-case stx ()
|
||||
___)))
|
||||
]
|
||||
Then any calls to @scheme[wrong-syntax] during the macro's
|
||||
transformation will refer to @scheme[my-macro] (more precisely, the name that
|
||||
referred to @scheme[my-macro] where the macro was used, which may be
|
||||
different due to renaming, prefixing, etc).
|
||||
|
||||
A macro that expands into a helper macro can insert its own name into
|
||||
syntax errors raised by the helper macro by installing a
|
||||
@scheme['report-error-as] syntax property on the helper macro
|
||||
expression. For example:
|
||||
@SCHEMEBLOCK[
|
||||
(define-syntax (public-macro stx)
|
||||
(syntax-case stx ()
|
||||
[(public-macro stuff)
|
||||
(syntax-property
|
||||
(syntax/loc stx (my-macro stuff other-internal-stuff))
|
||||
'report-error-as
|
||||
(syntax-e #'public-macro))]))
|
||||
]
|
||||
|
||||
@;{
|
||||
@section[Expand]
|
||||
|
||||
@defmodule[stxclass/util/expand]
|
||||
|
||||
TODO
|
||||
}
|
||||
|
||||
@section{Miscellaneous utilities}
|
||||
|
||||
@defmodule[stxclass/util/misc]
|
||||
|
||||
@defform[(define-pattern-variable id expr)]{
|
||||
|
||||
Evaluates @scheme[expr] and binds it to @scheme[id] as a pattern
|
||||
variable, so @scheme[id] can be used in subsequent @scheme[syntax]
|
||||
patterns.
|
||||
|
||||
}
|
||||
|
||||
@defform[(with-temporaries (temp-id ...) . body)]{
|
||||
|
||||
Evaluates @scheme[body] with each @scheme[temp-id] bound as a pattern
|
||||
variable to a freshly generated identifier.
|
||||
|
||||
For example, the following are equivalent:
|
||||
@SCHEMEBLOCK[
|
||||
(with-temporaries (x) #'(lambda (x) x))
|
||||
(with-syntax ([(x) (generate-temporaries '(x))])
|
||||
#'(lambda (x) x))
|
||||
]
|
||||
|
||||
}
|
||||
|
||||
@defproc[(generate-temporary) identifier?]{
|
||||
|
||||
Generates one fresh identifier. Singular form of
|
||||
@scheme[generate-temporaries].
|
||||
|
||||
}
|
||||
|
||||
@defproc[(generate-n-temporaries [n exact-nonnegative-integer?])
|
||||
(listof identifier?)]{
|
||||
|
||||
Generates a list of @scheme[n] fresh identifiers.
|
||||
|
||||
}
|
||||
|
||||
@defform[(with-catching-disappeared-uses body-expr)]{
|
||||
|
||||
Evaluates the @scheme[body-expr], catching identifiers looked up using
|
||||
@scheme[syntax-local-value/catch]. Returns two values: the result of
|
||||
@scheme[body-expr] and the list of caught identifiers.
|
||||
|
||||
}
|
||||
|
||||
@defform[(with-disappeared-uses stx-expr)]{
|
||||
|
||||
Evaluates the @scheme[stx-expr], catching identifiers looked up using
|
||||
@scheme[syntax-local-value/catch]. Adds the caught identifiers to the
|
||||
@scheme['disappeared-uses] syntax property of the resulting syntax
|
||||
object.
|
||||
|
||||
}
|
||||
|
||||
@defproc[(syntax-local-value/catch [id identifier?] [predicate (-> any/c boolean?)])
|
||||
any/c]{
|
||||
|
||||
Looks up @scheme[id] in the syntactic environment (as
|
||||
@scheme[syntax-local-value]). If the lookup succeeds and returns a
|
||||
value satisfying the predicate, the value is returned and @scheme[id]
|
||||
is recorded (``caught'') as a disappeared use. If the lookup fails or
|
||||
if the value does not satisfy the predicate, @scheme[#f] is returned
|
||||
and the identifier is not recorded as a disappeared use.
|
||||
|
||||
}
|
||||
|
||||
|
||||
@defproc[(chunk-kw-seq [stx syntax?]
|
||||
[table
|
||||
(listof (cons/c keyword?
|
||||
(listof (-> syntax? any))))]
|
||||
[context (or/c syntax? false/c) #f])
|
||||
(values (listof (cons/c keyword? (cons/c (syntax/c keyword?) list?)))
|
||||
syntax?)]{
|
||||
|
||||
Parses a syntax list into keyword-argument ``chunks'' and a syntax
|
||||
list tail (the remainder of the syntax list). The syntax of the
|
||||
keyword arguments is specified by @scheme[table], an association list
|
||||
mapping keywords to lists of checker procedures. The length of the
|
||||
checker list is the number of ``arguments'' expected to follow the
|
||||
keyword, and each checker procedure is applied to the corresponding
|
||||
argument. The result of the checker procedure is entered into the
|
||||
chunk for that keyword sequence. The same keyword can appear multiple
|
||||
times in the result list.
|
||||
|
||||
The @scheme[context] is used to report errors.
|
||||
|
||||
}
|
||||
|
||||
@defproc[(chunk-kw-seq/no-dups
|
||||
[stx syntax?]
|
||||
[table
|
||||
(listof (cons/c keyword?
|
||||
(listof (-> syntax? any))))]
|
||||
[context (or/c syntax? false/c) #f])
|
||||
(values (listof (cons/c keyword? (cons/c (syntax/c keyword?) list?)))
|
||||
syntax?)]{
|
||||
|
||||
Like @scheme[chunk-kw-seq] filtered by @scheme[reject-duplicate-chunks].
|
||||
|
||||
The @scheme[context] is used to report errors.
|
||||
|
||||
}
|
||||
|
||||
@defproc[(reject-duplicate-chunks
|
||||
[chunks (listof (cons/c keyword? (cons/c (syntax/c keyword?) list?)))])
|
||||
void?]{
|
||||
|
||||
Raises a syntax error if it encounters the same keyword more than once
|
||||
in the @scheme[chunks] list.
|
||||
|
||||
The @scheme[context] is used to report errors.
|
||||
|
||||
}
|
||||
|
||||
|
||||
@section{Structs}
|
||||
|
||||
@defmodule[stxclass/util/struct]
|
||||
|
||||
@defform[(make struct-id v ...)]{
|
||||
|
||||
Constructs an instance of @scheme[struct-id], which must be defined
|
||||
as a struct name. If @scheme[struct-id] has a different number of
|
||||
fields than the number of @scheme[v] values provided, @scheme[make]
|
||||
raises a compile-time error.
|
||||
|
||||
}
|
|
@ -1,774 +0,0 @@
|
|||
#lang scribble/doc
|
||||
@(require scribble/manual
|
||||
scribble/struct
|
||||
scribble/decode
|
||||
(for-label scheme/base
|
||||
scheme/contract
|
||||
stxclass
|
||||
stxclass/util))
|
||||
|
||||
@(define ellipses @scheme[...])
|
||||
@(define (TODO . pre-flow)
|
||||
(make-splice
|
||||
(cons (bold "TODO: ")
|
||||
(decode-content pre-flow))))
|
||||
|
||||
@title{Parsing Syntax and Syntax Classes}
|
||||
|
||||
@defmodule[stxclass]
|
||||
|
||||
@bold{Warning: This library is still very volatile! Its interface and
|
||||
behavior are subject to frequent change. I highly recommend that you
|
||||
avoid creating PLaneT packages that depend on this library.}
|
||||
|
||||
@section{Parsing Syntax}
|
||||
@declare-exporting[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.
|
||||
|
||||
@TODO{Allow literal declarations of form @scheme[(_internal-name
|
||||
_external-name)].}
|
||||
}
|
||||
|
||||
@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-pattern #,ellipses . syntax-pattern)
|
||||
((head ...+) ...* . syntax-pattern)]
|
||||
[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 #,ellipses . 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 or equal to
|
||||
@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 #:when expr)]
|
||||
|
||||
@specsubform[(code:line #:declare pvar-id syntax-class-id)]
|
||||
@specsubform[(code:line #:declare pvar-id (syntax-class-id expr ...))]{
|
||||
|
||||
The first form is 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 cause the same
|
||||
clause to be tried multiple times before the next clause is reached.
|
||||
|
||||
}
|
||||
@specsubform[(code:line #:when 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[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 #:attributes (attr-arity-decl ...))
|
||||
(code:line #:description description)
|
||||
(code:line #:transparent)]
|
||||
[attr-arity-decl
|
||||
attr-name-id
|
||||
(attr-name-id depth)]
|
||||
[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 #:attributes (attr-arity-decl ...))]{
|
||||
|
||||
Declares the attributes of the syntax class. An attribute arity
|
||||
declaration consists of the attribute name and optionally its ellipsis
|
||||
depth (zero if not explicitly specified).
|
||||
|
||||
If the attributes are not explicitly listed, they are
|
||||
inferred. Attribute inference does not take into account attributes
|
||||
from the current syntax class and from syntax classes that have not
|
||||
yet been defined. The full set of attributes is available, however, to
|
||||
@scheme[#:with] and @scheme[#:when] expressions. This treatment of
|
||||
recursive and forward references prevents infinitely nested
|
||||
attributes.
|
||||
|
||||
}
|
||||
|
||||
@specsubform[(code:line #:description description)]{
|
||||
|
||||
The @scheme[description] argument is an expression (with the
|
||||
syntax-class's parameters in scope) that should evaluate to a
|
||||
string. It is used 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 stxclass-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].
|
||||
|
||||
The attributes of the pattern are the pattern variables within the
|
||||
@scheme[pattern] form together with all pattern variables bound by
|
||||
@scheme[#:with] clauses, including nested attributes produced by
|
||||
syntax classes associated with the pattern variables.
|
||||
|
||||
The name of an attribute is the symbolic name of the pattern variable,
|
||||
except when the name is explicitly given via a @scheme[#:rename]
|
||||
clause.
|
||||
|
||||
@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].
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@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 @scheme[#f].
|
||||
|
||||
The parser procedure is encouraged to avoid side-effects.
|
||||
|
||||
@TODO{Add support for better error reporting within basic syntax
|
||||
class.}
|
||||
|
||||
@TODO{Remove this form in favor of new stxclass-variant form.}
|
||||
|
||||
}
|
||||
@;{
|
||||
@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[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))
|
||||
|
||||
@defstxclass[expr]{
|
||||
|
||||
Matches anything except a keyword literal (to distinguish expressions
|
||||
from the start of a keyword argument sequence). Does not expand or
|
||||
otherwise inspect the term.
|
||||
|
||||
}
|
||||
|
||||
@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])]{
|
||||
|
||||
Match syntax satisfying the corresponding predicates.
|
||||
|
||||
}
|
||||
|
||||
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 during transformation (when @scheme[syntax-transforming?]
|
||||
returns true). Otherwise they may raise an error.
|
||||
|
||||
@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.
|
||||
|
||||
}
|
||||
|
||||
@defform[(static-of description predicate)]{
|
||||
|
||||
Refines @scheme[static]: matches identifiers that are bound in the
|
||||
syntactic environment to static information satisfying the given
|
||||
@scheme[predicate]. Attribute @scheme[_value] contains the value the
|
||||
name is bound to. The @scheme[description] argument is used for error
|
||||
reporting.
|
||||
|
||||
}
|
||||
|
||||
@;{
|
||||
@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].
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@;{
|
||||
|
||||
|
||||
1 How to abstract over similar patterns:
|
||||
|
||||
(syntax-parse stx #:literals (blah bleh blaz kwA kwX)
|
||||
[(blah (bleh (kwX y z)) blaz)
|
||||
___]
|
||||
[(blah (bleh (kwA (b c))) blaz)
|
||||
___])
|
||||
|
||||
=>
|
||||
|
||||
(define-syntax-class common
|
||||
#:attributes (inner)
|
||||
#:literals (blah bleh blaz)
|
||||
(pattern (blah (bleh inner) blaz)))
|
||||
(syntax-parse stx #:literals (kwA kwX)
|
||||
[c:common
|
||||
#:with (kwX y z) #'c.inner
|
||||
___]
|
||||
[c:common
|
||||
#:with (kwA (b c)) #'c.inner
|
||||
___])
|
||||
|
||||
|
||||
OR =>
|
||||
|
||||
(define-syntax-class (common expected-kw)
|
||||
#:attributes (inner)
|
||||
#:literals (blah bleh blaz)
|
||||
(pattern (blah (bleh (kw . inner)) blaz)
|
||||
#:when (free-identifier=? #'kw expected-kw)))
|
||||
(syntax-parse stx
|
||||
[c
|
||||
#:declare c (common #'kwX)
|
||||
#:with (y z) #'c.inner
|
||||
___]
|
||||
[c
|
||||
#:declare c (common #'kwA)
|
||||
#:with ((b c)) #'c.inner
|
||||
___])
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@section{Utilities}
|
||||
|
||||
The @schememodname[stxclass] collection includes several utility
|
||||
modules. They are documented individually below.
|
||||
|
||||
As a shortcut, the @schememodname[stxclass/util] module provides all
|
||||
of the contents of the separate utility modules:
|
||||
|
||||
@defmodule[stxclass/util]
|
||||
|
||||
@subsection{Error reporting}
|
||||
|
||||
@defmodule[stxclass/util/error]
|
||||
|
||||
The @schememodname[scheme/base] and @schememodname[scheme] languages
|
||||
provide the @scheme[raise-syntax-error] procedure for reporting syntax
|
||||
errors. Using @scheme[raise-syntax-error] effectively requires passing
|
||||
around either a symbol indicating the special form that signals the
|
||||
error or else a ``contextual'' syntax object from which the special
|
||||
form's name can be extracted. This library helps manage the contextual
|
||||
syntax for reporting errors.
|
||||
|
||||
@defparam[current-syntax-context stx (or/c syntax? false/c)]{
|
||||
|
||||
The current contextual syntax object, defaulting to @scheme[#f]. It
|
||||
determines the special form name that prefixes syntax errors created
|
||||
by @scheme[wrong-syntax], as follows:
|
||||
|
||||
If it is a syntax object with a @scheme['report-error-as] syntax
|
||||
property whose value is a symbol, then that symbol is used as the
|
||||
special form name. Otherwise, the same rules apply as in
|
||||
@scheme[raise-syntax-error].
|
||||
|
||||
}
|
||||
|
||||
@defproc[(wrong-syntax [stx syntax?] [format-string string?] [v any/c] ...)
|
||||
any]{
|
||||
|
||||
Raises a syntax error using the result of
|
||||
@scheme[(current-syntax-context)] as the ``major'' syntax object and
|
||||
the provided @scheme[stx] as the specific syntax object. (The latter,
|
||||
@scheme[stx], is usually the one highlighted by DrScheme.) The error
|
||||
message is constructed using the format string and arguments, and it
|
||||
is prefixed with the special form name as described under
|
||||
@scheme[current-syntax-context].
|
||||
|
||||
}
|
||||
|
||||
A macro using this system might set the syntax context at the very
|
||||
beginning of its transformation as follows:
|
||||
@SCHEMEBLOCK[
|
||||
(define-syntax (my-macro stx)
|
||||
(parameterize ((current-syntax-context stx))
|
||||
(syntax-case stx ()
|
||||
___)))
|
||||
]
|
||||
Then any calls to @scheme[wrong-syntax] during the macro's
|
||||
transformation will refer to @scheme[my-macro] (more precisely, the name that
|
||||
referred to @scheme[my-macro] where the macro was used, which may be
|
||||
different due to renaming, prefixing, etc).
|
||||
|
||||
A macro that expands into a helper macro can insert its own name into
|
||||
syntax errors raised by the helper macro by installing a
|
||||
@scheme['report-error-as] syntax property on the helper macro
|
||||
expression. For example:
|
||||
@SCHEMEBLOCK[
|
||||
(define-syntax (public-macro stx)
|
||||
(syntax-case stx ()
|
||||
[(public-macro stuff)
|
||||
(syntax-property
|
||||
(syntax/loc stx (my-macro stuff other-internal-stuff))
|
||||
'report-error-as
|
||||
(syntax-e #'public-macro))]))
|
||||
]
|
||||
|
||||
@;{
|
||||
@subsection[Expand]
|
||||
|
||||
@defmodule[stxclass/util/expand]
|
||||
|
||||
TODO
|
||||
}
|
||||
|
||||
@subsection{Miscellaneous utilities}
|
||||
|
||||
@defmodule[stxclass/util/misc]
|
||||
|
||||
@defform[(define-pattern-variable id expr)]{
|
||||
|
||||
Evaluates @scheme[expr] and binds it to @scheme[id] as a pattern
|
||||
variable, so @scheme[id] can be used in subsequent @scheme[syntax]
|
||||
patterns.
|
||||
|
||||
}
|
||||
|
||||
@defform[(with-temporaries (temp-id ...) . body)]{
|
||||
|
||||
Evaluates @scheme[body] with each @scheme[temp-id] bound as a pattern
|
||||
variable to a freshly generated identifier.
|
||||
|
||||
For example, the following are equivalent:
|
||||
@SCHEMEBLOCK[
|
||||
(with-temporaries (x) #'(lambda (x) x))
|
||||
(with-syntax ([(x) (generate-temporaries '(x))])
|
||||
#'(lambda (x) x))
|
||||
]
|
||||
|
||||
}
|
||||
|
||||
@defproc[(generate-temporary) identifier?]{
|
||||
|
||||
Generates one fresh identifier. Singular form of
|
||||
@scheme[generate-temporaries].
|
||||
|
||||
}
|
||||
|
||||
@defproc[(generate-n-temporaries [n exact-nonnegative-integer?])
|
||||
(listof identifier?)]{
|
||||
|
||||
Generates a list of @scheme[n] fresh identifiers.
|
||||
|
||||
}
|
||||
|
||||
@defform[(with-catching-disappeared-uses body-expr)]{
|
||||
|
||||
Evaluates the @scheme[body-expr], catching identifiers looked up using
|
||||
@scheme[syntax-local-value/catch]. Returns two values: the result of
|
||||
@scheme[body-expr] and the list of caught identifiers.
|
||||
|
||||
}
|
||||
|
||||
@defform[(with-disappeared-uses stx-expr)]{
|
||||
|
||||
Evaluates the @scheme[stx-expr], catching identifiers looked up using
|
||||
@scheme[syntax-local-value/catch]. Adds the caught identifiers to the
|
||||
@scheme['disappeared-uses] syntax property of the resulting syntax
|
||||
object.
|
||||
|
||||
}
|
||||
|
||||
@defproc[(syntax-local-value/catch [id identifier?] [predicate (-> any/c boolean?)])
|
||||
any/c]{
|
||||
|
||||
Looks up @scheme[id] in the syntactic environment (as
|
||||
@scheme[syntax-local-value]). If the lookup succeeds and returns a
|
||||
value satisfying the predicate, the value is returned and @scheme[id]
|
||||
is recorded (``caught'') as a disappeared use. If the lookup fails or
|
||||
if the value does not satisfy the predicate, @scheme[#f] is returned
|
||||
and the identifier is not recorded as a disappeared use.
|
||||
|
||||
}
|
||||
|
||||
|
||||
@defproc[(chunk-kw-seq [stx syntax?]
|
||||
[table
|
||||
(listof (cons/c keyword?
|
||||
(listof (-> syntax? any))))]
|
||||
[context (or/c syntax? false/c) #f])
|
||||
(values (listof (cons/c keyword? (cons/c (syntax/c keyword?) list?)))
|
||||
syntax?)]{
|
||||
|
||||
Parses a syntax list into keyword-argument ``chunks'' and a syntax
|
||||
list tail (the remainder of the syntax list). The syntax of the
|
||||
keyword arguments is specified by @scheme[table], an association list
|
||||
mapping keywords to lists of checker procedures. The length of the
|
||||
checker list is the number of ``arguments'' expected to follow the
|
||||
keyword, and each checker procedure is applied to the corresponding
|
||||
argument. The result of the checker procedure is entered into the
|
||||
chunk for that keyword sequence. The same keyword can appear multiple
|
||||
times in the result list.
|
||||
|
||||
The @scheme[context] is used to report errors.
|
||||
|
||||
}
|
||||
|
||||
@defproc[(chunk-kw-seq/no-dups
|
||||
[stx syntax?]
|
||||
[table
|
||||
(listof (cons/c keyword?
|
||||
(listof (-> syntax? any))))]
|
||||
[context (or/c syntax? false/c) #f])
|
||||
(values (listof (cons/c keyword? (cons/c (syntax/c keyword?) list?)))
|
||||
syntax?)]{
|
||||
|
||||
Like @scheme[chunk-kw-seq] filtered by @scheme[reject-duplicate-chunks].
|
||||
|
||||
The @scheme[context] is used to report errors.
|
||||
|
||||
}
|
||||
|
||||
@defproc[(reject-duplicate-chunks
|
||||
[chunks (listof (cons/c keyword? (cons/c (syntax/c keyword?) list?)))])
|
||||
void?]{
|
||||
|
||||
Raises a syntax error if it encounters the same keyword more than once
|
||||
in the @scheme[chunks] list.
|
||||
|
||||
The @scheme[context] is used to report errors.
|
||||
|
||||
}
|
||||
|
||||
|
||||
@subsection{Structs}
|
||||
|
||||
@defmodule[stxclass/util/struct]
|
||||
|
||||
@defform[(make struct-id v ...)]{
|
||||
|
||||
Constructs an instance of @scheme[struct-id], which must be defined
|
||||
as a struct name. If @scheme[struct-id] has a different number of
|
||||
fields than the number of @scheme[v] values provided, @scheme[make]
|
||||
raises a compile-time error.
|
||||
|
||||
}
|
|
@ -270,3 +270,29 @@
|
|||
(pattern f:frob))
|
||||
(define-syntax-class frob
|
||||
(pattern x:id))
|
||||
|
||||
(syntax-parse #'1
|
||||
[x:nat
|
||||
(define (check d)
|
||||
(unless (positive? d)
|
||||
(error "not positive")))
|
||||
(check #'x.datum)
|
||||
'ok])
|
||||
|
||||
|
||||
(define-syntax-class Opaque
|
||||
(pattern (a:id n:nat)))
|
||||
(define-syntax-class Transparent
|
||||
#:transparent
|
||||
(pattern (a:id n:nat)))
|
||||
|
||||
(with-handlers ([exn? exn-message])
|
||||
(syntax-parse #'(0 1) [_:Opaque 'ok]))
|
||||
(with-handlers ([exn? exn-message])
|
||||
(syntax-parse #'(0 1) [_:Transparent 'ok]))
|
||||
|
||||
#;
|
||||
(syntax-parse #'1
|
||||
[_:Transparent 'ok]
|
||||
[(a b) 'ok])
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user