syntax/parse: fix use of evaluators in docs
This commit is contained in:
parent
808a6ca266
commit
4f5c54db54
|
@ -6,6 +6,8 @@
|
|||
"parse-common.rkt"
|
||||
(for-label syntax/parse/define))
|
||||
|
||||
@(define the-eval (make-sp-eval))
|
||||
|
||||
@title{Defining Simple Macros}
|
||||
|
||||
@defmodule[syntax/parse/define]
|
||||
|
@ -22,7 +24,7 @@ Defines a macro named @racket[macro-id]; equivalent to the following:
|
|||
]
|
||||
|
||||
@(the-eval '(require syntax/parse/define))
|
||||
@myexamples[
|
||||
@examples[#:eval the-eval
|
||||
(define-simple-macro (fn x:id rhs:expr) (lambda (x) rhs))
|
||||
((fn x x) 17)
|
||||
(fn 1 2)
|
||||
|
@ -47,7 +49,7 @@ Defines a macro named @racket[macro-id]; equivalent to:
|
|||
(syntax-parser parse-option ... clause ...))
|
||||
]
|
||||
|
||||
@myexamples[
|
||||
@examples[#:eval the-eval
|
||||
(define-syntax-parser fn3
|
||||
[(fn3 x:id rhs:expr)
|
||||
#'(lambda (x) rhs)]
|
||||
|
@ -59,3 +61,4 @@ Defines a macro named @racket[macro-id]; equivalent to:
|
|||
(fn3 a #:b 'c)
|
||||
]}
|
||||
|
||||
@(close-eval the-eval)
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
"parse-common.rkt"
|
||||
(for-label racket/class))
|
||||
|
||||
@(define the-eval (make-sp-eval))
|
||||
|
||||
@title[#:tag "exprc"]{Contracts on Macro Sub-expressions}
|
||||
|
||||
Just as procedures often expect certain kinds of values as arguments,
|
||||
|
@ -17,7 +19,7 @@ For example, here is a macro @racket[myparameterize] that behaves like
|
|||
@racket[parameterize] but enforces the @racket[parameter?] contract on
|
||||
the parameter expressions.
|
||||
|
||||
@myinteraction[
|
||||
@interaction[#:eval the-eval
|
||||
(define-syntax (myparameterize stx)
|
||||
(syntax-parse stx
|
||||
[(_ ((p v:expr) ...) body:expr)
|
||||
|
@ -37,3 +39,5 @@ template, the expansion would have used the raw, unchecked
|
|||
expressions. The @racket[expr/c] syntax class does not change how
|
||||
pattern variables are bound; it only computes an attribute that
|
||||
represents the checked expression.
|
||||
|
||||
@(close-eval the-eval)
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
"parse-common.rkt"
|
||||
(for-label racket/class))
|
||||
|
||||
@(define the-eval (make-sp-eval))
|
||||
|
||||
@title{Optional Keyword Arguments}
|
||||
|
||||
This section explains how to write a macro that accepts (simple)
|
||||
|
@ -22,7 +24,7 @@ head-pattern forms are @racket[~seq], @racket[~or], and
|
|||
|
||||
Here's one way to do it:
|
||||
|
||||
@myinteraction[
|
||||
@interaction[#:eval the-eval
|
||||
(define-syntax (mycond stx)
|
||||
(syntax-parse stx
|
||||
[(mycond (~or (~seq #:error-on-fallthrough who:expr) (~seq))
|
||||
|
@ -47,7 +49,7 @@ argument is omitted. Instead we must write @racket[(attribute who)],
|
|||
which produces @racket[#f] if matching did not assign a value to the
|
||||
attribute.
|
||||
|
||||
@myinteraction[
|
||||
@interaction[#:eval the-eval
|
||||
(mycond [(even? 13) 'blue]
|
||||
[(odd? 4) 'red])
|
||||
(mycond #:error-on-fallthrough 'myfun
|
||||
|
@ -62,7 +64,7 @@ There's a simpler way of writing the @racket[~or] pattern above:
|
|||
|
||||
Yet another way is to introduce a @tech{splicing syntax class}, which
|
||||
is like an ordinary syntax class but for head patterns.
|
||||
@myinteraction[
|
||||
@interaction[#:eval the-eval
|
||||
(define-syntax (mycond stx)
|
||||
|
||||
(define-splicing-syntax-class maybe-fallthrough-option
|
||||
|
@ -84,3 +86,5 @@ syntax class's variants. (This is possible to do in the inline pattern
|
|||
version too, using @racket[~and] and @racket[~parse], just less
|
||||
convenient.) Splicing syntax classes also closely parallel the style
|
||||
of grammars in macro documentation.
|
||||
|
||||
@(close-eval the-eval)
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
"parse-common.rkt"
|
||||
(for-label racket/class))
|
||||
|
||||
@(define the-eval (make-sp-eval))
|
||||
|
||||
@title{More Keyword Arguments}
|
||||
|
||||
This section shows how to express the syntax of @racket[struct]'s
|
||||
|
@ -15,7 +17,7 @@ The part of @racket[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[
|
||||
@interaction[#:eval the-eval
|
||||
(define-splicing-syntax-class maybe-super
|
||||
(pattern (~seq super:id))
|
||||
(pattern (~seq)))
|
||||
|
@ -135,3 +137,5 @@ both @racket[#:guard] and @racket[#:property]. Repetition constraints
|
|||
cannot express arbitrary incompatibility relations. The best way to
|
||||
handle such constraints is with a side condition using
|
||||
@racket[#:fail-when].
|
||||
|
||||
@(close-eval the-eval)
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
"parse-common.rkt"
|
||||
(for-label racket/class))
|
||||
|
||||
@(define the-eval (make-sp-eval))
|
||||
|
||||
@title{Phases and Reusable Syntax Classes}
|
||||
|
||||
As demonstrated in the @secref{stxparse-intro}, the simplest place to
|
||||
|
@ -17,7 +19,7 @@ classes requires some awareness of the Racket @tech[#:doc '(lib
|
|||
syntax class defined immediately within a module cannot be used by
|
||||
macros in the same module; it is defined at the wrong phase.
|
||||
|
||||
@myinteraction[
|
||||
@interaction[#:eval the-eval
|
||||
(module phase-mismatch-mod racket
|
||||
(require syntax/parse (for-syntax syntax/parse))
|
||||
(define-syntax-class foo
|
||||
|
@ -37,7 +39,7 @@ phase level incompatibility.)
|
|||
The phase level mismatch is easily remedied by putting the syntax
|
||||
class definition within a @racket[begin-for-syntax] block:
|
||||
|
||||
@myinteraction[
|
||||
@interaction[#:eval the-eval
|
||||
(module phase-ok-mod racket
|
||||
(require (for-syntax syntax/parse))
|
||||
(begin-for-syntax
|
||||
|
@ -55,7 +57,7 @@ An alternative to @racket[begin-for-syntax] is to define the syntax
|
|||
class in a separate module and require that module
|
||||
@racket[for-syntax].
|
||||
|
||||
@myinteraction[
|
||||
@interaction[#:eval the-eval
|
||||
(module stxclass-mod racket
|
||||
(require syntax/parse)
|
||||
(define-syntax-class foo
|
||||
|
@ -77,7 +79,7 @@ expressions via syntax templates, then the module containing the
|
|||
syntax class must generally require @racket[for-template] the bindings
|
||||
referred to in the patterns and templates.
|
||||
|
||||
@myinteraction[
|
||||
@interaction[#:eval the-eval
|
||||
(module arith-keywords-mod racket
|
||||
(define-syntax plus (syntax-rules ()))
|
||||
(define-syntax times (syntax-rules ()))
|
||||
|
@ -124,3 +126,5 @@ implicit syntax @racket[#%app]) must be bound at ``absolute'' phase
|
|||
level 0. Since the module @racket['arith-stxclass-mod] is required
|
||||
with a phase level offset of 1 (that is, @racket[for-syntax]), it must
|
||||
compensate with a phase level offset of -1, or @racket[for-template].
|
||||
|
||||
@(close-eval the-eval)
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
scribble/eval
|
||||
"parse-common.rkt")
|
||||
|
||||
@(define the-eval (make-sp-eval))
|
||||
|
||||
@title{Experimental}
|
||||
|
||||
The following facilities are experimental.
|
||||
|
@ -118,7 +120,7 @@ must be specified explicitly.
|
|||
Like @racket[~reflect] but for reified splicing syntax classes.
|
||||
}
|
||||
|
||||
@myexamples[
|
||||
@examples[#:eval the-eval
|
||||
(define-syntax-class (nat> x)
|
||||
#:description (format "natural number greater than ~s" x)
|
||||
#:attributes (diff)
|
||||
|
@ -216,7 +218,7 @@ Includes the alternatives of @racket[eh-alternative-set-id], prefixing
|
|||
their attributes with @racket[name].
|
||||
}
|
||||
|
||||
@myexamples[
|
||||
@examples[#:eval the-eval
|
||||
(define-eh-alternative-set options
|
||||
(pattern (~once (~seq #:a a:expr) #:name "#:a option"))
|
||||
(pattern (~seq #:b b:expr)))
|
||||
|
@ -443,3 +445,5 @@ If @racket[join] were defined as a macro, it would not be usable in
|
|||
the context above; instead, @racket[let-values] would report an
|
||||
invalid binding list.
|
||||
}
|
||||
|
||||
@(close-eval the-eval)
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
"parse-common.rkt"
|
||||
(for-label (only-in syntax/parse ...+)))
|
||||
|
||||
@(define the-eval (make-sp-eval #f))
|
||||
|
||||
@(define-syntax-rule (defdummy id)
|
||||
(defidentifier (quote-syntax id)
|
||||
#:form? #t #:index? #f #:show-libs? #f))
|
||||
|
@ -36,7 +38,7 @@ the second case later in the introduction.
|
|||
The macro can be implemented very simply using
|
||||
@racket[define-syntax-rule]:
|
||||
|
||||
@myinteraction[
|
||||
@interaction[#:eval the-eval
|
||||
(define-syntax-rule (mylet ([var rhs] ...) body ...)
|
||||
((lambda (var ...) body ...) rhs ...))
|
||||
]
|
||||
|
@ -47,7 +49,7 @@ uninformative error message; in others, it blithely accepts illegal
|
|||
syntax and passes it along to @racket[lambda], with strange
|
||||
consequences:
|
||||
|
||||
@myinteraction[
|
||||
@interaction[#:eval the-eval
|
||||
(mylet ([a 1] [b 2]) (+ a b))
|
||||
(mylet (b 2) (sub1 b))
|
||||
(mylet ([1 a]) (add1 a))
|
||||
|
@ -70,13 +72,15 @@ We can improve the error behavior of the macro by using
|
|||
"scribblings/reference/reference.scrbl")]{transformer environment},
|
||||
since we will use it to implement a macro transformer.
|
||||
|
||||
@myinteraction[(require (for-syntax syntax/parse))]
|
||||
@interaction[#:eval the-eval
|
||||
(require (for-syntax syntax/parse))
|
||||
]
|
||||
|
||||
The following is the syntax specification above transliterated into a
|
||||
@racket[syntax-parse] macro definition. It behaves no better than the
|
||||
version using @racket[define-syntax-rule] above.
|
||||
|
||||
@myinteraction[
|
||||
@interaction[#:eval the-eval
|
||||
(define-syntax (mylet stx)
|
||||
(syntax-parse stx
|
||||
[(_ ([var-id rhs-expr] ...) body ...+)
|
||||
|
@ -98,7 +102,7 @@ pattern variable name, a colon character, and the syntax class
|
|||
name.@margin-note*{For an alternative to the ``colon'' syntax, see the
|
||||
@racket[~var] pattern form.}
|
||||
|
||||
@myinteraction[
|
||||
@interaction[#:eval the-eval
|
||||
(define-syntax (mylet stx)
|
||||
(syntax-parse stx
|
||||
[(_ ((var:id rhs:expr) ...) body ...+)
|
||||
|
@ -108,24 +112,24 @@ Note that the syntax class annotations do not appear in the template
|
|||
(i.e., @racket[var], not @racket[var:id]).
|
||||
|
||||
The syntax class annotations are checked when we use the macro.
|
||||
@myinteraction[
|
||||
@interaction[#:eval the-eval
|
||||
(mylet ([a 1] [b 2]) (+ a b))
|
||||
(mylet (["a" 1]) (add1 a))
|
||||
]
|
||||
The @racket[expr] syntax class does not actually check that the term
|
||||
it matches is a valid expression---that would require calling that
|
||||
macro expander. Instead, @racket[expr] just means not a keyword.
|
||||
@myinteraction[
|
||||
@interaction[#:eval the-eval
|
||||
(mylet ([a #:whoops]) 1)
|
||||
]
|
||||
Also, @racket[syntax-parse] knows how to report a few kinds of errors
|
||||
without any help:
|
||||
@myinteraction[
|
||||
@interaction[#:eval the-eval
|
||||
(mylet ([a 1 2]) (* a a))
|
||||
]
|
||||
There are other kinds of errors, however, that this macro does not
|
||||
handle gracefully:
|
||||
@myinteraction[
|
||||
@interaction[#:eval the-eval
|
||||
(mylet (a 1) (+ a 2))
|
||||
]
|
||||
It's too much to ask for the macro to respond, ``This expression is
|
||||
|
@ -140,7 +144,7 @@ syntactic categories. One way of doing that is by defining new syntax
|
|||
classes:@margin-note*{Another way is the @racket[~describe] pattern
|
||||
form.}
|
||||
|
||||
@myinteraction[
|
||||
@interaction[#:eval the-eval
|
||||
(define-syntax (mylet stx)
|
||||
|
||||
(define-syntax-class binding
|
||||
|
@ -158,11 +162,11 @@ Note that we write @racket[b.var] and @racket[b.rhs] now. They are the
|
|||
syntax class @racket[binding].
|
||||
|
||||
Now the error messages can talk about ``binding pairs.''
|
||||
@myinteraction[
|
||||
@interaction[#:eval the-eval
|
||||
(mylet (a 1) (+ a 2))
|
||||
]
|
||||
Errors are still reported in more specific terms when possible:
|
||||
@myinteraction[
|
||||
@interaction[#:eval the-eval
|
||||
(mylet (["a" 1]) (+ a 2))
|
||||
]
|
||||
|
||||
|
@ -170,13 +174,13 @@ There is one other constraint on the legal syntax of
|
|||
@racket[mylet]. The variables bound by the different binding pairs
|
||||
must be distinct. Otherwise the macro creates an illegal
|
||||
@racket[lambda] form:
|
||||
@myinteraction[
|
||||
@interaction[#:eval the-eval
|
||||
(mylet ([a 1] [a 2]) (+ a a))
|
||||
]
|
||||
|
||||
Constraints such as the distinctness requirement are expressed as side
|
||||
conditions, thus:
|
||||
@myinteraction[
|
||||
@interaction[#:eval the-eval
|
||||
(define-syntax (mylet stx)
|
||||
|
||||
(define-syntax-class binding
|
||||
|
@ -190,7 +194,7 @@ conditions, thus:
|
|||
"duplicate variable name"
|
||||
#'((lambda (b.var ...) body ...) b.rhs ...)]))
|
||||
]
|
||||
@myinteraction[
|
||||
@interaction[#:eval the-eval
|
||||
(mylet ([a 1] [a 2]) (+ a a))
|
||||
]
|
||||
The @racket[#:fail-when] keyword is followed by two expressions: the
|
||||
|
@ -202,7 +206,7 @@ pinpoint the cause of the failure.
|
|||
Syntax classes can have side conditions, too. Here is the macro
|
||||
rewritten to include another syntax class representing a ``sequence of
|
||||
distinct binding pairs.''
|
||||
@myinteraction[
|
||||
@interaction[#:eval the-eval
|
||||
(define-syntax (mylet stx)
|
||||
|
||||
(define-syntax-class binding
|
||||
|
@ -238,7 +242,7 @@ offered by Racket's @racket[let]. We must add the
|
|||
``named-@racket[let]'' form. That turns out to be as simple as adding
|
||||
a new clause:
|
||||
|
||||
@myinteraction[
|
||||
@interaction[#:eval the-eval
|
||||
(define-syntax (mylet stx)
|
||||
|
||||
(define-syntax-class binding
|
||||
|
@ -267,7 +271,7 @@ lines.
|
|||
|
||||
But does adding this new case affect @racket[syntax-parse]'s ability
|
||||
to pinpoint and report errors?
|
||||
@myinteraction[
|
||||
@interaction[#:eval the-eval
|
||||
(mylet ([a 1] [b 2]) (+ a b))
|
||||
(mylet (["a" 1]) (add1 a))
|
||||
(mylet ([a #:whoops]) 1)
|
||||
|
@ -278,7 +282,7 @@ to pinpoint and report errors?
|
|||
The error reporting for the original syntax seems intact. We should
|
||||
verify that the named-@racket[let] syntax is working, that
|
||||
@racket[syntax-parse] is not simply ignoring that clause.
|
||||
@myinteraction[
|
||||
@interaction[#:eval the-eval
|
||||
(mylet loop ([a 1] [b 2]) (+ a b))
|
||||
(mylet loop (["a" 1]) (add1 a))
|
||||
(mylet loop ([a #:whoops]) 1)
|
||||
|
@ -300,7 +304,7 @@ potential errors (including ones like @racket[loop] not matching
|
|||
each error. Only the error with the most progress is reported.
|
||||
|
||||
For example, in this bad use of the macro,
|
||||
@myinteraction[
|
||||
@interaction[#:eval the-eval
|
||||
(mylet loop (["a" 1]) (add1 a))
|
||||
]
|
||||
there are two potential errors: expected @racket[distinct-bindings] at
|
||||
|
@ -309,7 +313,7 @@ second error occurs further in the term than the first, so it is
|
|||
reported.
|
||||
|
||||
For another example, consider this term:
|
||||
@myinteraction[
|
||||
@interaction[#:eval the-eval
|
||||
(mylet (["a" 1]) (add1 a))
|
||||
]
|
||||
Again, there are two potential errors: expected @racket[identifier] at
|
||||
|
@ -319,7 +323,7 @@ if you prefer), but the second error occurs deeper in the
|
|||
term. Progress is based on a left-to-right traversal of the syntax.
|
||||
|
||||
A final example: consider the following:
|
||||
@myinteraction[
|
||||
@interaction[#:eval the-eval
|
||||
(mylet ([a 1] [a 2]) (+ a a))
|
||||
]
|
||||
There are two errors again: duplicate variable name at @racket[([a 1]
|
||||
|
@ -339,7 +343,7 @@ the term.
|
|||
|
||||
It is, however, possible for multiple potential errors to occur with
|
||||
the same progress. Here's one example:
|
||||
@myinteraction[
|
||||
@interaction[#:eval the-eval
|
||||
(mylet "not-even-close")
|
||||
]
|
||||
In this case @racket[syntax-parse] reports both errors.
|
||||
|
@ -347,7 +351,7 @@ In this case @racket[syntax-parse] reports both errors.
|
|||
Even with all of the annotations we have added to our macro, there are
|
||||
still some misuses that defy @racket[syntax-parse]'s error reporting
|
||||
capabilities, such as this example:
|
||||
@myinteraction[
|
||||
@interaction[#:eval the-eval
|
||||
(mylet)
|
||||
]
|
||||
The philosophy behind @racket[syntax-parse] is that in these
|
||||
|
@ -363,3 +367,5 @@ conditions, and progress-ordered error reporting. But
|
|||
@secref{stxparse-examples} section for samples of other features in
|
||||
working code, or skip to the subsequent sections for the complete
|
||||
reference documentation.
|
||||
|
||||
@(close-eval the-eval)
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
scribble/eval
|
||||
"parse-common.rkt")
|
||||
|
||||
@(define the-eval (make-sp-eval))
|
||||
|
||||
@title{Literal Sets and Conventions}
|
||||
|
||||
Sometimes the same literals are recognized in a number of different
|
||||
|
@ -38,7 +40,7 @@ identifiers the literal matches. If the @racket[#:literal-sets] option
|
|||
is present, the contents of the given @racket[imported-litset-id]s are
|
||||
included.
|
||||
|
||||
@myexamples[
|
||||
@examples[#:eval the-eval
|
||||
(define-literal-set def-litset
|
||||
(define-values define-syntaxes))
|
||||
(syntax-parse #'(define-syntaxes (x) 12)
|
||||
|
@ -56,7 +58,7 @@ given, then @racket[phase-level] is @racket[0].
|
|||
|
||||
For example:
|
||||
|
||||
@myexamples[
|
||||
@interaction[#:eval the-eval
|
||||
(module common racket/base
|
||||
(define x 'something)
|
||||
(provide x))
|
||||
|
@ -74,7 +76,7 @@ module @racketmodname['common].
|
|||
The following module defines an equivalent literal set, but imports
|
||||
the @racket['common] module for-template instead:
|
||||
|
||||
@myexamples[
|
||||
@interaction[#:eval the-eval
|
||||
(module lits racket/base
|
||||
(require syntax/parse (for-template 'common))
|
||||
(define-literal-set common-lits #:for-template (x))
|
||||
|
@ -85,7 +87,7 @@ When a literal set is @emph{used} with the @racket[#:phase phase-expr]
|
|||
option, the literals' fixed bindings are compared against the binding of
|
||||
the input literal at the specified phase. Continuing the example:
|
||||
|
||||
@myexamples[
|
||||
@interaction[#:eval the-eval
|
||||
(require syntax/parse 'lits (for-syntax 'common))
|
||||
(syntax-parse #'x #:literal-sets ([common-lits #:phase 1])
|
||||
[x 'yes]
|
||||
|
@ -106,7 +108,7 @@ phase @racket[_phase] at which to examine the binding of @racket[_id];
|
|||
the @racket[_phase] argument defaults to
|
||||
@racket[(syntax-local-phase-level)].
|
||||
|
||||
@myexamples[
|
||||
@examples[#:eval the-eval
|
||||
(define kernel? (literal-set->predicate kernel-literals))
|
||||
(kernel? #'lambda)
|
||||
(kernel? #'#%plain-lambda)
|
||||
|
@ -130,7 +132,7 @@ that matches determines the syntax class for the pattern. If no
|
|||
@racket[name-pattern] matches, then the pattern variable has no syntax
|
||||
class.
|
||||
|
||||
@myexamples[
|
||||
@examples[#:eval the-eval
|
||||
(define-conventions xyz-as-ids
|
||||
[x id] [y id] [z id])
|
||||
(syntax-parse #'(a b c 1 2 3)
|
||||
|
@ -149,7 +151,7 @@ Local conventions, introduced with the @racket[#:local-conventions]
|
|||
keyword argument of @racket[syntax-parse] and syntax class
|
||||
definitions, may refer to local bindings:
|
||||
|
||||
@myexamples[
|
||||
@examples[#:eval the-eval
|
||||
(define-syntax-class (nat> bound)
|
||||
(pattern n:nat
|
||||
#:fail-unless (> (syntax-e #'n) bound)
|
||||
|
@ -168,3 +170,5 @@ definitions, may refer to local bindings:
|
|||
]
|
||||
|
||||
}
|
||||
|
||||
@(close-eval the-eval)
|
||||
|
|
|
@ -1,16 +1,14 @@
|
|||
#lang racket/base
|
||||
(require scribble/manual
|
||||
scribble/eval
|
||||
racket/string
|
||||
racket/sandbox)
|
||||
|
||||
(provide ellipses
|
||||
the-eval
|
||||
myexamples
|
||||
myinteraction)
|
||||
make-sp-eval)
|
||||
|
||||
(define ellipses (racket ...))
|
||||
|
||||
(define (fixup exn)
|
||||
(define (fixup/short exn)
|
||||
(let ([src (ormap values (exn:fail:syntax-exprs exn))])
|
||||
(if src
|
||||
(make-exn:fail:syntax
|
||||
|
@ -21,37 +19,46 @@
|
|||
(exn-continuation-marks exn)
|
||||
(exn:fail:syntax-exprs exn))
|
||||
exn)))
|
||||
(define the-eval
|
||||
(call-with-trusted-sandbox-configuration
|
||||
(lambda ()
|
||||
(parameterize ([sandbox-output 'string]
|
||||
[sandbox-error-output 'string]
|
||||
[sandbox-propagate-breaks #f]
|
||||
[sandbox-eval-handlers
|
||||
(list #f
|
||||
(lambda (thunk)
|
||||
(with-handlers ([exn:fail:syntax?
|
||||
(lambda (e) (raise (fixup e)))])
|
||||
(thunk))))])
|
||||
(make-evaluator 'racket/base
|
||||
#:requires (let ([mods '(racket/promise
|
||||
syntax/parse
|
||||
syntax/parse/debug
|
||||
syntax/parse/experimental/splicing
|
||||
syntax/parse/experimental/contract
|
||||
syntax/parse/experimental/reflect
|
||||
syntax/parse/experimental/specialize
|
||||
syntax/parse/experimental/template
|
||||
syntax/parse/experimental/eh)])
|
||||
`((for-syntax racket/base ,@mods)
|
||||
,@mods)))))))
|
||||
(the-eval '(error-print-source-location #f))
|
||||
|
||||
(define-syntax-rule (myexamples e ...)
|
||||
(examples #:eval the-eval e ...))
|
||||
(define (fixup/long exn)
|
||||
(let ([src (ormap values (exn:fail:syntax-exprs exn))])
|
||||
(if src
|
||||
(make-exn:fail:syntax
|
||||
(string-trim (exn-message exn)
|
||||
#rx"[^ ]*[ ]"
|
||||
#:left? #t #:right? #f)
|
||||
(exn-continuation-marks exn)
|
||||
(exn:fail:syntax-exprs exn))
|
||||
exn)))
|
||||
|
||||
(define-syntax-rule (myinteraction e ...)
|
||||
(interaction #:eval the-eval e ...))
|
||||
(define (make-sp-eval [short? #f])
|
||||
(define fixup (if short? fixup/short fixup/long))
|
||||
(define the-eval
|
||||
(call-with-trusted-sandbox-configuration
|
||||
(lambda ()
|
||||
(parameterize ([sandbox-output 'string]
|
||||
[sandbox-error-output 'string]
|
||||
[sandbox-propagate-breaks #f]
|
||||
[sandbox-eval-handlers
|
||||
(list #f
|
||||
(lambda (thunk)
|
||||
(with-handlers ([exn:fail:syntax?
|
||||
(lambda (e) (raise (fixup e)))])
|
||||
(thunk))))])
|
||||
(make-evaluator 'racket/base
|
||||
#:requires (let ([mods '(racket/promise
|
||||
syntax/parse
|
||||
syntax/parse/debug
|
||||
syntax/parse/experimental/splicing
|
||||
syntax/parse/experimental/contract
|
||||
syntax/parse/experimental/reflect
|
||||
syntax/parse/experimental/specialize
|
||||
syntax/parse/experimental/template
|
||||
syntax/parse/experimental/eh)])
|
||||
`((for-syntax racket/base ,@mods)
|
||||
,@mods)))))))
|
||||
(when short? (the-eval '(error-print-source-location #f)))
|
||||
the-eval)
|
||||
|
||||
;; ----
|
||||
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
"parse-common.rkt"
|
||||
(for-label racket/syntax))
|
||||
|
||||
@(define the-eval (make-sp-eval))
|
||||
|
||||
@title{Parsing Syntax}
|
||||
|
||||
This section describes @racket[syntax-parse], the
|
||||
|
@ -79,15 +81,16 @@ is inferred as with @racket[raise-syntax-error].
|
|||
The @racket[current-syntax-context] parameter is also set to the
|
||||
syntax object @racket[_context-stx].
|
||||
|
||||
@(myexamples
|
||||
(syntax-parse #'(a b 3)
|
||||
[(x:id ...) 'ok])
|
||||
(syntax-parse #'(a b 3)
|
||||
#:context #'(lambda (a b 3) (+ a b))
|
||||
[(x:id ...) 'ok])
|
||||
(syntax-parse #'(a b 3)
|
||||
#:context 'check-id-list
|
||||
[(x:id ...) 'ok]))
|
||||
@examples[#:eval the-eval
|
||||
(syntax-parse #'(a b 3)
|
||||
[(x:id ...) 'ok])
|
||||
(syntax-parse #'(a b 3)
|
||||
#:context #'(lambda (a b 3) (+ a b))
|
||||
[(x:id ...) 'ok])
|
||||
(syntax-parse #'(a b 3)
|
||||
#:context 'check-id-list
|
||||
[(x:id ...) 'ok])
|
||||
]
|
||||
}
|
||||
|
||||
@specsubform[(code:line #:literals (literal ...))
|
||||
|
@ -172,7 +175,7 @@ bindings. See the section on @tech{conventions} for examples.
|
|||
|
||||
Suppresses the ``colon notation'' for annotated pattern variables.
|
||||
|
||||
@myexamples[
|
||||
@examples[#:eval the-eval
|
||||
(syntax-parse #'(a b c)
|
||||
[(x:y ...) 'ok])
|
||||
(syntax-parse #'(a b c) #:disable-colon-notation
|
||||
|
@ -195,7 +198,7 @@ syntax object result of @racket[stx-expr] against
|
|||
@racket[syntax-pattern] and creates pattern variable definitions for
|
||||
the attributes of @racket[syntax-pattern].
|
||||
|
||||
@myexamples[
|
||||
@examples[#:eval the-eval
|
||||
(define/syntax-parse ((~seq kw:keyword arg:expr) ...)
|
||||
#'(#:a 1 #:b 2 #:c 3))
|
||||
#'(kw ...)
|
||||
|
@ -204,3 +207,5 @@ the attributes of @racket[syntax-pattern].
|
|||
Compare with @racket[define/with-syntax], a similar definition form
|
||||
that uses the simpler @racket[syntax-case] patterns.
|
||||
}
|
||||
|
||||
@(close-eval the-eval)
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
scribble/eval
|
||||
"parse-common.rkt")
|
||||
|
||||
@(define the-eval (make-sp-eval))
|
||||
|
||||
@(define-syntax-rule (define-dotsplus-names dotsplus def-dotsplus)
|
||||
(begin (require (for-label (only-in syntax/parse ...+)))
|
||||
(define dotsplus (racket ...+))
|
||||
|
@ -200,7 +202,7 @@ An identifier can be either a @tech{pattern variable}, an
|
|||
literals list, it is a @tech{literal} pattern that behaves
|
||||
like @racket[(~literal id)].
|
||||
|
||||
@myexamples[
|
||||
@examples[#:eval the-eval
|
||||
(syntax-parse #'(define x 12)
|
||||
#:literals (define)
|
||||
[(define var:id body:expr) 'ok])
|
||||
|
@ -221,7 +223,7 @@ An identifier can be either a @tech{pattern variable}, an
|
|||
@tech{annotated pattern variable}, and the pattern is equivalent to
|
||||
@racket[(~var _pvar-id _syntax-class-id)].
|
||||
|
||||
@myexamples[
|
||||
@examples[#:eval the-eval
|
||||
(syntax-parse #'a
|
||||
[var:id (syntax-e #'var)])
|
||||
(syntax-parse #'12
|
||||
|
@ -246,7 +248,7 @@ An identifier can be either a @tech{pattern variable}, an
|
|||
where @racket[_literal-id] is in the literals list, then it is
|
||||
equivalent to @racket[(~and (~var _pvar-id) literal-id)].
|
||||
|
||||
@myexamples[
|
||||
@examples[#:eval the-eval
|
||||
(require (only-in racket/base [define def]))
|
||||
(syntax-parse #'(def x 7)
|
||||
#:literals (define)
|
||||
|
@ -299,7 +301,7 @@ If @svar[pvar-id] is @racket[_], no attributes are bound. If
|
|||
If @racket[role-expr] is given and evaluates to a string, it is
|
||||
combined with the syntax class's description in error messages.
|
||||
|
||||
@myexamples[
|
||||
@examples[#:eval the-eval
|
||||
(syntax-parse #'a
|
||||
[(~var var id) (syntax-e #'var)])
|
||||
(syntax-parse #'12
|
||||
|
@ -327,7 +329,7 @@ combined with the syntax class's description in error messages.
|
|||
A @deftech{literal} identifier pattern. Matches any identifier
|
||||
@racket[free-identifier=?] to @racket[literal-id].
|
||||
|
||||
@myexamples[
|
||||
@examples[#:eval the-eval
|
||||
(syntax-parse #'(define x 12)
|
||||
[((~literal define) var:id body:expr) 'ok])
|
||||
(syntax-parse #'(lambda x 12)
|
||||
|
@ -344,7 +346,7 @@ The identifiers are compared at the phase given by
|
|||
Numbers, strings, booleans, keywords, and the empty list match as
|
||||
literals.
|
||||
|
||||
@myexamples[
|
||||
@examples[#:eval the-eval
|
||||
(syntax-parse #'(a #:foo bar)
|
||||
[(x #:foo y) (syntax->datum #'y)])
|
||||
(syntax-parse #'(a foo bar)
|
||||
|
@ -358,7 +360,7 @@ Matches syntax whose S-expression contents (obtained by
|
|||
@racket[syntax->datum]) is @racket[equal?] to the given
|
||||
@racket[datum].
|
||||
|
||||
@myexamples[
|
||||
@examples[#:eval the-eval
|
||||
(syntax-parse #'(a #:foo bar)
|
||||
[(x (~datum #:foo) y) (syntax->datum #'y)])
|
||||
(syntax-parse #'(a foo bar)
|
||||
|
@ -369,7 +371,7 @@ The @racket[~datum] form is useful for recognizing identifiers
|
|||
symbolically, in contrast to the @racket[~literal] form, which
|
||||
recognizes them by binding.
|
||||
|
||||
@myexamples[
|
||||
@examples[#:eval the-eval
|
||||
(syntax-parse (let ([define 'something-else]) #'(define x y))
|
||||
[((~datum define) var:id e:expr) 'yes]
|
||||
[_ 'no])
|
||||
|
@ -435,7 +437,7 @@ That is, the following patterns are equivalent:
|
|||
@item[@racket[((~between H 1 +inf.0) ... . S)]]
|
||||
]
|
||||
|
||||
@myexamples[
|
||||
@examples[#:eval the-eval
|
||||
(syntax-parse #'(1 2 3)
|
||||
[(n:nat ...+) 'ok])
|
||||
(syntax-parse #'()
|
||||
|
@ -461,7 +463,7 @@ term (including its lexical context, source location, etc) while also
|
|||
examining its structure. Syntax classes are useful for the same
|
||||
purpose, but @racket[~and] can be lighter weight.
|
||||
|
||||
@myexamples[
|
||||
@examples[#:eval the-eval
|
||||
(define-syntax (import stx)
|
||||
(raise-syntax-error #f "illegal use of import" stx))
|
||||
(eval:alts
|
||||
|
@ -490,7 +492,7 @@ of @racket[#f]. The same attribute may be bound by multiple
|
|||
subpatterns, and if it is bound by all of the subpatterns, it is sure
|
||||
to have a value if the whole pattern matches.
|
||||
|
||||
@myexamples[
|
||||
@examples[#:eval the-eval
|
||||
(syntax-parse #'a
|
||||
[(~or x:id y:nat) (values (attribute x) (attribute y))])
|
||||
(syntax-parse #'(a 1)
|
||||
|
@ -506,7 +508,7 @@ Matches any term that does not match the subpattern. None of the
|
|||
subpattern's attributes are bound outside of the
|
||||
@racket[~not]-pattern.
|
||||
|
||||
@myexamples[
|
||||
@examples[#:eval the-eval
|
||||
(syntax-parse #'(x y z => u v)
|
||||
#:literals (=>)
|
||||
[((~and before (~not =>)) ... => after ...)
|
||||
|
@ -520,7 +522,7 @@ Matches a term that is a vector whose elements, when considered as a
|
|||
list, match the @tech{@Spattern} corresponding to
|
||||
@racket[(pattern-part ...)].
|
||||
|
||||
@myexamples[
|
||||
@examples[#:eval the-eval
|
||||
(syntax-parse #'#(1 2 3)
|
||||
[#(x y z) (syntax->datum #'z)])
|
||||
(syntax-parse #'#(1 2 3)
|
||||
|
@ -536,7 +538,7 @@ Matches a term that is a prefab struct whose key is exactly the given
|
|||
key and whose sequence of fields, when considered as a list, match the
|
||||
@tech{@Spattern} corresponding to @racket[(pattern-part ...)].
|
||||
|
||||
@myexamples[
|
||||
@examples[#:eval the-eval
|
||||
(syntax-parse #'#s(point 1 2 3)
|
||||
[#s(point x y z) 'ok])
|
||||
(syntax-parse #'#s(point 1 2 3)
|
||||
|
@ -551,7 +553,7 @@ key and whose sequence of fields, when considered as a list, match the
|
|||
Matches a term that is a box whose contents matches the inner
|
||||
@tech{@Spattern}.
|
||||
|
||||
@myexamples[
|
||||
@examples[#:eval the-eval
|
||||
(syntax-parse #'#&5
|
||||
[#&n:nat 'ok])
|
||||
]
|
||||
|
@ -564,7 +566,7 @@ is useful in positions where improper (``dotted'') lists are not
|
|||
allowed by the reader, such as vector and structure patterns (see
|
||||
above).
|
||||
|
||||
@myexamples[
|
||||
@examples[#:eval the-eval
|
||||
(syntax-parse #'(1 2 3)
|
||||
[(x ~rest y) (syntax->datum #'y)])
|
||||
(syntax-parse #'#(1 2 3)
|
||||
|
@ -594,7 +596,7 @@ terms of the description given.
|
|||
If @racket[role-expr] is given and produces a string, its value is
|
||||
combined with the description in error messages.
|
||||
|
||||
@myexamples[
|
||||
@examples[#:eval the-eval
|
||||
(syntax-parse #'(m 1)
|
||||
[(_ (~describe "id pair" (x:id y:id))) 'ok])
|
||||
(syntax-parse #'(m (a 2))
|
||||
|
@ -681,7 +683,7 @@ matches a head pattern.
|
|||
Matches a sequence of terms whose elements, if put in a list, would
|
||||
match @racket[L-pattern].
|
||||
|
||||
@myexamples[
|
||||
@examples[#:eval the-eval
|
||||
(syntax-parse #'(1 2 3 4)
|
||||
[((~seq 1 2 3) 4) 'ok])
|
||||
]
|
||||
|
@ -695,7 +697,7 @@ examples of @racket[~seq].
|
|||
Like the @Spattern version, @ref[~and s], but matches a sequence of
|
||||
terms instead.
|
||||
|
||||
@myexamples[
|
||||
@examples[#:eval the-eval
|
||||
(syntax-parse #'(#:a 1 #:b 2 3 4 5)
|
||||
[((~and (~seq (~seq k:keyword e:expr) ...)
|
||||
(~seq keyword-stuff ...))
|
||||
|
@ -708,7 +710,7 @@ subpatterns be @tech{proper @Hpatterns} (not @tech{@Spatterns}). This
|
|||
is to prevent typos like the following, a variant of the previous
|
||||
example with the second @racket[~seq] omitted:
|
||||
|
||||
@myexamples[
|
||||
@examples[#:eval the-eval
|
||||
(syntax-parse #'(#:a 1 #:b 2 3 4 5)
|
||||
[((~and (~seq (~seq k:keyword e:expr) ...)
|
||||
(keyword-stuff ...))
|
||||
|
@ -728,7 +730,7 @@ example with the second @racket[~seq] omitted:
|
|||
Like the @Spattern version, @ref[~or s], but matches a sequence of
|
||||
terms instead.
|
||||
|
||||
@myexamples[
|
||||
@examples[#:eval the-eval
|
||||
(syntax-parse #'(m #:foo 2 a b c)
|
||||
[(_ (~or (~seq #:foo x) (~seq)) y:id ...)
|
||||
(attribute x)])
|
||||
|
@ -752,7 +754,7 @@ terms. If the @racket[#:defaults] option is given, the subsequent
|
|||
attribute bindings are used if the subpattern does not match. The
|
||||
default attributes must be a subset of the subpattern's attributes.
|
||||
|
||||
@myexamples[
|
||||
@examples[#:eval the-eval
|
||||
(syntax-parse #'(m #:foo 2 a b c)
|
||||
[(_ (~optional (~seq #:foo x) #:defaults ([x #'#f])) y:id ...)
|
||||
(attribute x)])
|
||||
|
@ -812,7 +814,7 @@ matching position, so the pattern consumes no input. Used to look
|
|||
ahead in a sequence. None of the subpattern's attributes are bound
|
||||
outside of the @racket[~peek-not]-pattern.
|
||||
|
||||
@myexamples[
|
||||
@examples[#:eval the-eval
|
||||
(define-splicing-syntax-class final (code:comment "final term")
|
||||
(pattern (~seq x (~peek-not _))))
|
||||
|
||||
|
@ -841,7 +843,7 @@ repetition. They are useful for matching, for example, keyword
|
|||
arguments where the keywords may come in any order. Multiple
|
||||
alternatives are grouped together via @ref[~or eh].
|
||||
|
||||
@myexamples[
|
||||
@examples[#:eval the-eval
|
||||
(define parser1
|
||||
(syntax-parser
|
||||
[((~or (~once (~seq #:a x) #:name "#:a keyword")
|
||||
|
@ -1041,7 +1043,7 @@ There is currently no way to bind attributes using a @racket[~do]
|
|||
pattern. It is an error to shadow an attribute binding with a
|
||||
definition in a @racket[~do] block.
|
||||
|
||||
@myexamples[
|
||||
@examples[#:eval the-eval
|
||||
(syntax-parse #'(1 2 3)
|
||||
[(a b (~do (printf "a was ~s\n" #'a)) c:id) 'ok])
|
||||
]
|
||||
|
@ -1065,7 +1067,7 @@ forms by rewriting them into existing pattern forms.
|
|||
|
||||
Returns a @tech{pattern expander} that uses @racket[proc] to transform the pattern.
|
||||
|
||||
@myexamples[
|
||||
@examples[#:eval the-eval
|
||||
(define-syntax ~maybe
|
||||
(pattern-expander
|
||||
(syntax-rules ()
|
||||
|
@ -1100,3 +1102,5 @@ Returns @racket[#t] if @racket[v] is a @tech{pattern expander},
|
|||
|
||||
Like @racket[syntax-local-introduce], but for @tech{pattern expanders}.
|
||||
}
|
||||
|
||||
@(close-eval the-eval)
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
scribble/eval
|
||||
"parse-common.rkt")
|
||||
|
||||
@(define the-eval (make-sp-eval))
|
||||
|
||||
@title[#:tag "stxparse-specifying"]{Specifying Syntax with Syntax Classes}
|
||||
|
||||
@declare-exporting[syntax/parse]
|
||||
|
@ -204,7 +206,7 @@ If a @racket[#:with] directive appears between the main pattern (e.g., in a
|
|||
@racket[#:declare], then only pattern variables from the @racket[#:with]
|
||||
pattern may be declared.
|
||||
|
||||
@myexamples[
|
||||
@examples[#:eval the-eval
|
||||
(syntax-parse #'P
|
||||
[x
|
||||
#:declare x id
|
||||
|
@ -322,7 +324,7 @@ subterm. A non-syntax-valued attribute should be bound using the
|
|||
and @racket[~parse] will convert the right-hand side to a (possibly
|
||||
3D) syntax object.
|
||||
|
||||
@myexamples[
|
||||
@examples[#:eval the-eval
|
||||
(define-syntax-class table
|
||||
(pattern ((key value) ...)
|
||||
#:attr hashtable
|
||||
|
@ -347,7 +349,7 @@ used in a syntax template.
|
|||
|
||||
Syntax-valued attributes can be used in syntax templates:
|
||||
|
||||
@myinteraction[
|
||||
@interaction[#:eval the-eval
|
||||
(syntax-parse #'((a 3) (b 2) (c 1))
|
||||
[t:table
|
||||
#'(t.key ...)])
|
||||
|
@ -357,7 +359,7 @@ Syntax-valued attributes can be used in syntax templates:
|
|||
|
||||
But non-syntax-valued attributes cannot:
|
||||
|
||||
@myinteraction[
|
||||
@interaction[#:eval the-eval
|
||||
(syntax-parse #'((a 3) (b 2) (c 1))
|
||||
[t:table
|
||||
#'t.hashtable])
|
||||
|
@ -366,7 +368,7 @@ But non-syntax-valued attributes cannot:
|
|||
Use the @racket[attribute] form to get the value of an attribute
|
||||
(syntax-valued or not).
|
||||
|
||||
@myinteraction[
|
||||
@interaction[#:eval the-eval
|
||||
(syntax-parse #'((a 1) (b 2) (c 3))
|
||||
[t:table
|
||||
(attribute t.hashtable)])
|
||||
|
@ -409,7 +411,7 @@ it is syntax-valued. In particular, @racket[~or] and
|
|||
expected levels of list nesting, and @racket[#:attr] and
|
||||
@racket[~bind] can be used to bind attributes to arbitrary values.
|
||||
|
||||
@myexamples[
|
||||
@examples[#:eval the-eval
|
||||
(syntax-parse #'(a b 3)
|
||||
[(~or (x:id ...) _)
|
||||
(attribute x)])
|
||||
|
@ -421,3 +423,5 @@ Returns the value associated with the @tech{attribute} named
|
|||
@racket[attr-id]. If @racket[attr-id] is not bound as an attribute, an
|
||||
error is raised.
|
||||
}
|
||||
|
||||
@(close-eval the-eval)
|
||||
|
|
Loading…
Reference in New Issue
Block a user