209 lines
8.1 KiB
Racket
209 lines
8.1 KiB
Racket
#lang scribble/manual
|
|
@require[scribble/example
|
|
"utils.rkt"
|
|
@for-label[phc-toolkit/untyped
|
|
extensible-parser-specifications
|
|
generic-syntax-expanders
|
|
racket/base
|
|
syntax/parse
|
|
(only-in racket/base [... …])]]
|
|
|
|
@title{Matching alternatives in any order}
|
|
|
|
@defform[#:kind "pattern expander"
|
|
#:literals (~mixin ~or)
|
|
(~seq-no-order clause-or-mixin ...)
|
|
#:grammar
|
|
[(clause-or-mixin #,ntax-pattern
|
|
(~mixin #,-alternative-mixin)
|
|
(~or clause-or-mixin ...)
|
|
derived-or)]]{
|
|
Splicing pattern which matches the given @racket[clause-or-mixin]s in any
|
|
order, enforcing the global constraints expressed within each.
|
|
|
|
Nested @racket[~or] directly below @racket[~seq-no-order] are recursively
|
|
inlined. In other words, the @racket[~or] present directly below the
|
|
@racket[~seq-no-order] or below such an @racket[~or] clause do not behave as
|
|
"exclusive or", but instead contain clauses which can appear in any order.
|
|
These clauses are not grouped in any way by the @racket[~or], i.e.
|
|
@racket[(~no-order (~or (~or a b) (~or c d)))] is equivalent to
|
|
@racket[(~no-order a b c d)].
|
|
|
|
The @racket[derived-or] term covers any
|
|
@tech[#:doc '(lib "syntax/scribblings/syntax.scrbl")]{pattern expander} or
|
|
@tech{eh-mixin expander} application which expands to a
|
|
@racket[clause-or-mixin]. The expansion of pattern and eh-mixin expanders
|
|
happens before inlining the top @racket[~or] clauses.}
|
|
|
|
@defform[#:kind "pattern expander"
|
|
#:literals (~mixin ~or)
|
|
(~no-order clause-or-mixin ...)
|
|
#:grammar
|
|
[(clause-or-mixin #,ntax-pattern
|
|
(~mixin #,-alternative-mixin)
|
|
(~or clause-or-mixin ...)
|
|
derived-or)]]{
|
|
|
|
Like @racket[~seq-no-order], except that it matches a syntax list, instead of
|
|
being spliced into the surrounding sequence of patterns. In other words,
|
|
|
|
@racketblock[({~seq-no-order clause-or-mixin ...})]
|
|
|
|
is equivalent to (notice the extra pair of braces above):
|
|
|
|
@racketblock[(~no-order clause-or-mixin ...)]
|
|
|
|
Additionally, @racket[~no-order] can include clauses which use
|
|
@racket[~lift-rest], which lifts a pattern which matches the tail of an
|
|
improper list.}
|
|
|
|
@section{Enforcing a partial order on the alternatives}
|
|
|
|
@defform[#:kind "eh-mixin expander"
|
|
(~order-point point-name #,ntax-pattern ...)]{
|
|
When parsing a sequence of elements, @racket[~seq-no-order] and
|
|
@racket[~no-order] associate an increasing number to each element starting from
|
|
zero.
|
|
|
|
The number associated with the first element matched by
|
|
@racket[#,ntax-pattern ...] is memorised into the attribute
|
|
@racket[point-name].
|
|
|
|
This allows the position of elements matched by otherwise independent mixins to
|
|
be compared using @racket[order-point<] and @racket[order-point>]}
|
|
|
|
@defform[(order-point< a b)
|
|
#:grammar
|
|
[(a #,tribute-name)
|
|
(b #,tribute-name)]]{
|
|
Returns @racket[#t] when the first element matched by
|
|
@racket[(~order-point a #,ntax-pattern ...)] occurs before the first element
|
|
matched by @racket[(~order-point b #,ntax-pattern ...)]. Otherwise, returns
|
|
@racket[#f].
|
|
|
|
This operation does not fail if @racket[a] or @racket[b] are bound to
|
|
@racket[#f] (i.e. their corresponding @racket[_syntax-pattern ...] did not
|
|
match). Instead, in both cases, it returns @racket[#f].}
|
|
|
|
@defform[(order-point> a b)
|
|
#:grammar
|
|
[(a #,tribute-name)
|
|
(b #,tribute-name)]]{
|
|
Returns @racket[#t] when the first element matched by
|
|
@racket[(~order-point a #,ntax-pattern ...)] occurs after the first element
|
|
matched by @racket[(~order-point b #,ntax-pattern ...)]. Otherwise, returns
|
|
@racket[#f].
|
|
|
|
This operation does not fail if @racket[a] or @racket[b] are bound to
|
|
@racket[#f] (i.e. their corresponding @racket[_syntax-pattern ...] did not
|
|
match). Instead, in both cases, it returns @racket[#f].}
|
|
|
|
@defform[(try-order-point< a b)
|
|
#:grammar
|
|
[(a #,tribute-name)
|
|
(b #,tribute-name)]]{
|
|
|
|
Like @racket[order-point<], except that it does not fail if @racket[a] or
|
|
@racket[b] are not attributes, or if they are bound to @racket[#f]. Instead, in
|
|
all those cases, it returns @racket[#f].
|
|
|
|
It can be used as follows:
|
|
|
|
@racketblock[
|
|
(~post-fail "a must appear after b"
|
|
#:when (try-order-point< a b))]
|
|
|
|
The same caveats as for @racket[try-attribute] apply.}
|
|
|
|
@defform[(try-order-point> a b)
|
|
#:grammar
|
|
[(a #,tribute-name)
|
|
(b #,tribute-name)]]{
|
|
|
|
Like @racket[order-point>], except that it does not fail if @racket[a] or
|
|
@racket[b] are not attributes, or if they are bound to @racket[#f]. Instead, in
|
|
all those cases, it returns @racket[#f].
|
|
|
|
It can be used as follows:
|
|
|
|
@racketblock[
|
|
(~post-fail "a must appear before b"
|
|
#:when (try-order-point> a b))]
|
|
|
|
The same caveats as for @racket[try-attribute] apply.}
|
|
|
|
@defform[#:kind "eh-mixin-expander"
|
|
(~before other message pat ...)]{
|
|
|
|
Post-checks that the first element matched by @racket[pat ...] appears before
|
|
the @racket[other] order-point. This is a shorthand for:
|
|
|
|
@racketblock[{~order-point pt
|
|
{~seq pat ...}
|
|
{~post-fail message #:when (order-point> pt other)}}]
|
|
|
|
Note: Hopefully @racket[~before] will be modified in the future so that it
|
|
auto-detects if the @racket[other] order-point is not defined as part of the
|
|
current @racket[~no-order]. Do not rely on comparisons with order points
|
|
somehow defined outside the current @racket[~no-order], as that behaviour may
|
|
change in the future.
|
|
|
|
This is implemented as a @seclink["Pre__global_and_post_operations"]{pre
|
|
operation}.}
|
|
|
|
@defform[#:kind "eh-mixin-expander"
|
|
(~after other message pat ...)]{
|
|
Post-checks that the first element matched by @racket[pat ...] appears after
|
|
the @racket[other] order-point. This is a shorthand for:
|
|
|
|
@racketblock[{~order-point pt
|
|
{~seq pat ...}
|
|
{~post-fail message #:when (order-point< pt other)}}]
|
|
|
|
Note: Hopefully @racket[~after] will be modified in the future so that it
|
|
auto-detects if the @racket[other] order-point is not defined as part of the
|
|
current @racket[~no-order]. Do not rely on comparisons with order points
|
|
somehow defined outside the current @racket[~no-order], as that behaviour may
|
|
change in the future.
|
|
|
|
This is implemented as a @seclink["Pre__global_and_post_operations"]{pre
|
|
operation}.}
|
|
|
|
@defform[#:kind "eh-mixin-expander"
|
|
(~try-before other message pat ...)]{
|
|
|
|
Post-checks that the first element matched by @racket[pat ...] appears before
|
|
the @racket[other] order-point. The @racket[try-] version does not cause an
|
|
error if the order-point @racket[other] is not define (e.g. it was part of
|
|
another mixin which was not included). This is a shorthand for:
|
|
|
|
@racketblock[{~order-point pt
|
|
{~seq pat ...}
|
|
{~post-fail message #:when (try-order-point> pt other)}}]
|
|
|
|
Note: Hopefully @racket[~before] will be modified in the future so that it
|
|
auto-detects if the @racket[other] order-point is missing. This form will then
|
|
be removed.
|
|
|
|
This is implemented as a @seclink["Pre__global_and_post_operations"]{pre
|
|
operation}.}
|
|
|
|
@defform[#:kind "eh-mixin-expander"
|
|
(~try-after other message pat ...)]{
|
|
Post-checks that the first element matched by @racket[pat ...] appears after
|
|
the @racket[other] order-point. The @racket[try-] version does not cause an
|
|
error if the order-point @racket[other] is not define (e.g. it was part of
|
|
another mixin which was not included). This is a shorthand for:
|
|
|
|
@racketblock[{~order-point pt
|
|
{~seq pat ...}
|
|
{~post-fail message #:when (try-order-point< pt other)}}]
|
|
|
|
Note: Hopefully @racket[~after] will be modified in the future so that it
|
|
auto-detects if the @racket[other] order-point is missing. This form will then
|
|
be removed.
|
|
|
|
This is implemented as a @seclink["Pre__global_and_post_operations"]{pre
|
|
operation}.}
|
|
|