syntax/parse:
separated ~!, ~bind, ~fail as "action patterns", documented docs use eg "single-term pattern" instead of "S-pattern" in text svn: r16089
This commit is contained in:
parent
6387797aa4
commit
491808e717
|
@ -227,6 +227,8 @@
|
||||||
(fail x
|
(fail x
|
||||||
#:expect (expectation pattern0)
|
#:expect (expectation pattern0)
|
||||||
#:fce fc))]
|
#:fce fc))]
|
||||||
|
[#s(pat:ghost attrs ghost subpattern)
|
||||||
|
#'(parse:G x fc ghost (parse:S x fc subpattern k))]
|
||||||
[#s(pat:head attrs head tail)
|
[#s(pat:head attrs head tail)
|
||||||
#`(parse:H x fc head rest index
|
#`(parse:H x fc head rest index
|
||||||
(parse:S rest #,(frontier:add-index (wash #'fc) #'index) tail k))]
|
(parse:S rest #,(frontier:add-index (wash #'fc) #'index) tail k))]
|
||||||
|
@ -269,9 +271,6 @@
|
||||||
(fail x
|
(fail x
|
||||||
#:expect (expectation pattern0)
|
#:expect (expectation pattern0)
|
||||||
#:fce fc))))))]
|
#:fce fc))))))]
|
||||||
[#s(pat:cut attrs pattern)
|
|
||||||
#`(with-enclosing-fail enclosing-cut-fail
|
|
||||||
(parse:S x fc pattern k))]
|
|
||||||
[#s(pat:describe attrs description transparent? pattern)
|
[#s(pat:describe attrs description transparent? pattern)
|
||||||
#`(let ([previous-fail enclosing-fail]
|
#`(let ([previous-fail enclosing-fail]
|
||||||
[previous-cut-fail enclosing-cut-fail])
|
[previous-cut-fail enclosing-cut-fail])
|
||||||
|
@ -283,15 +282,7 @@
|
||||||
(parse:S x #,(empty-frontier #'x) pattern
|
(parse:S x #,(empty-frontier #'x) pattern
|
||||||
(with-enclosing-cut-fail previous-cut-fail
|
(with-enclosing-cut-fail previous-cut-fail
|
||||||
(with-enclosing-fail previous-fail
|
(with-enclosing-fail previous-fail
|
||||||
k)))))]
|
k)))))])]))
|
||||||
[#s(pat:bind _ clauses)
|
|
||||||
#'(convert-sides x clauses (clause-success () k))]
|
|
||||||
[#s(pat:fail _ condition message)
|
|
||||||
#`(if condition
|
|
||||||
(fail x
|
|
||||||
#:expect (expectation pattern0)
|
|
||||||
#:fce fc)
|
|
||||||
k)])]))
|
|
||||||
|
|
||||||
;; (parse:S* (id ...) (FCE ...) (SinglePattern ...) expr) : expr
|
;; (parse:S* (id ...) (FCE ...) (SinglePattern ...) expr) : expr
|
||||||
(define-syntax parse:S*
|
(define-syntax parse:S*
|
||||||
|
@ -323,6 +314,23 @@
|
||||||
(let ([sub-id alt-sub-id] ...)
|
(let ([sub-id alt-sub-id] ...)
|
||||||
(success pre ... id ...))))))]))
|
(success pre ... id ...))))))]))
|
||||||
|
|
||||||
|
|
||||||
|
;; (parse:G id FCE SinglePattern expr) : expr
|
||||||
|
(define-syntax (parse:G stx)
|
||||||
|
(syntax-case stx ()
|
||||||
|
[(parse:G x fc pattern0 k)
|
||||||
|
(syntax-case #'pattern0 ()
|
||||||
|
[#s(ghost:cut _)
|
||||||
|
#`(with-enclosing-fail enclosing-cut-fail k)]
|
||||||
|
[#s(ghost:bind _ clauses)
|
||||||
|
#`(convert-sides x clauses (clause-success () k))]
|
||||||
|
[#s(ghost:fail _ condition message)
|
||||||
|
#`(if condition
|
||||||
|
(fail x
|
||||||
|
#:expect (expectation pattern0)
|
||||||
|
#:fce fc)
|
||||||
|
k)])]))
|
||||||
|
|
||||||
(begin-for-syntax
|
(begin-for-syntax
|
||||||
;; convert-list-pattern : ListPattern id -> SinglePattern
|
;; convert-list-pattern : ListPattern id -> SinglePattern
|
||||||
;; Converts '() datum pattern at end of list to bind (cons stx index)
|
;; Converts '() datum pattern at end of list to bind (cons stx index)
|
||||||
|
@ -560,11 +568,10 @@
|
||||||
;; #'(make-expect:pair)]
|
;; #'(make-expect:pair)]
|
||||||
[(_ #s(pat:compound attrs kind0 (part-pattern ...)))
|
[(_ #s(pat:compound attrs kind0 (part-pattern ...)))
|
||||||
#''ineffable]
|
#''ineffable]
|
||||||
[(_ #s(pat:fail _ condition message))
|
|
||||||
#'(expectation-of-message message)]
|
|
||||||
[(_ #s(pat:not _ pattern))
|
[(_ #s(pat:not _ pattern))
|
||||||
#''ineffable]
|
#''ineffable]
|
||||||
))
|
[(_ #s(ghost:fail _ condition message))
|
||||||
|
#'(expectation-of-message message)]))
|
||||||
|
|
||||||
;; ----
|
;; ----
|
||||||
|
|
||||||
|
|
|
@ -7,77 +7,85 @@
|
||||||
(provide (all-defined-out))
|
(provide (all-defined-out))
|
||||||
|
|
||||||
#|
|
#|
|
||||||
A PBase/HPBase/EHPBase is (listof IAttr)
|
A Base is (listof IAttr)
|
||||||
If P = (make-pattern Attrs ...) and A is in Attrs,
|
If P = (make-pattern Attrs ...) and A is in Attrs,
|
||||||
the depth of A is with respect to P,
|
the depth of A is with respect to P,
|
||||||
not with respect to the entire enclosing pattern.
|
not with respect to the entire enclosing pattern.
|
||||||
|
|
||||||
An IdPrefix is an identifier/#f
|
|
||||||
If #f, it means bind no attributes
|
|
||||||
If identifier, it already includes the colon part, unless epsilon
|
|
||||||
|#
|
|#
|
||||||
|
|
||||||
|
|
||||||
#|
|
#|
|
||||||
A SinglePattern is one of
|
A SinglePattern is one of
|
||||||
(make-pat:any SPBase)
|
(make-pat:any Base)
|
||||||
(make-pat:var SPBase id id (listof stx) (listof IAttr))
|
(make-pat:var Base id id (listof stx) (listof IAttr))
|
||||||
(make-pat:datum SPBase datum)
|
(make-pat:literal Base identifier)
|
||||||
(make-pat:literal SPBase identifier)
|
(make-pat:datum Base datum)
|
||||||
(make-pat:head SPBase HeadPattern SinglePattern)
|
(make-pat:ghost Base GhostPattern SinglePattern)
|
||||||
(make-pat:dots SPBase (listof EllipsisHeadPattern) SinglePattern)
|
(make-pat:head Base HeadPattern SinglePattern)
|
||||||
(make-pat:and SPBase (listof SinglePattern))
|
(make-pat:dots Base (listof EllipsisHeadPattern) SinglePattern)
|
||||||
(make-pat:or SPBase (listof SinglePattern))
|
(make-pat:and Base (listof SinglePattern))
|
||||||
(make-pat:not SPBase SinglePattern)
|
(make-pat:or Base (listof SinglePattern))
|
||||||
(make-pat:compound SPBase Kind (listof SinglePattern))
|
(make-pat:not Base SinglePattern)
|
||||||
(make-pat:cut SPBase SinglePattern)
|
(make-pat:compound Base Kind (listof SinglePattern))
|
||||||
(make-pat:describe SPBase stx boolean SinglePattern)
|
(make-pat:describe Base stx boolean SinglePattern)
|
||||||
(make-pat:fail SPBase stx stx)
|
|
||||||
(make-pat:bind SPBase (listof clause:attr))
|
|
||||||
|
|
||||||
A ListPattern is a subtype of SinglePattern; one of
|
A ListPattern is a subtype of SinglePattern; one of
|
||||||
(make-pat:datum SPBase '())
|
(make-pat:datum Base '())
|
||||||
(make-pat:head SPBase HeadPattern ListPattern)
|
(make-pat:ghost Base GhostPattern ListPattern)
|
||||||
(make-pat:compound SPBase '#:pair (list SinglePattern ListPattern))
|
(make-pat:head Base HeadPattern ListPattern)
|
||||||
(make-pat:dots SPBase EllipsisHeadPattern SinglePattern)
|
(make-pat:compound Base '#:pair (list SinglePattern ListPattern))
|
||||||
(make-pat:cut SPBase ListPattern)
|
(make-pat:dots Base EllipsisHeadPattern SinglePattern)
|
||||||
|#
|
|#
|
||||||
|
|
||||||
(define-struct pat:any (attrs) #:prefab)
|
(define-struct pat:any (attrs) #:prefab)
|
||||||
(define-struct pat:var (attrs name parser args nested-attrs) #:prefab)
|
(define-struct pat:var (attrs name parser args nested-attrs) #:prefab)
|
||||||
(define-struct pat:datum (attrs datum) #:prefab)
|
|
||||||
(define-struct pat:literal (attrs id) #:prefab)
|
(define-struct pat:literal (attrs id) #:prefab)
|
||||||
|
(define-struct pat:datum (attrs datum) #:prefab)
|
||||||
|
(define-struct pat:ghost (attrs ghost inner) #:prefab)
|
||||||
(define-struct pat:head (attrs head tail) #:prefab)
|
(define-struct pat:head (attrs head tail) #:prefab)
|
||||||
(define-struct pat:dots (attrs heads tail) #:prefab)
|
(define-struct pat:dots (attrs heads tail) #:prefab)
|
||||||
(define-struct pat:and (attrs patterns) #:prefab)
|
(define-struct pat:and (attrs patterns) #:prefab)
|
||||||
(define-struct pat:or (attrs patterns) #:prefab)
|
(define-struct pat:or (attrs patterns) #:prefab)
|
||||||
(define-struct pat:not (attrs pattern) #:prefab)
|
(define-struct pat:not (attrs pattern) #:prefab)
|
||||||
(define-struct pat:compound (attrs kind patterns) #:prefab)
|
(define-struct pat:compound (attrs kind patterns) #:prefab)
|
||||||
(define-struct pat:cut (attrs pattern) #:prefab)
|
|
||||||
(define-struct pat:describe (attrs description transparent? pattern) #:prefab)
|
(define-struct pat:describe (attrs description transparent? pattern) #:prefab)
|
||||||
(define-struct pat:fail (attrs when message) #:prefab)
|
|
||||||
(define-struct pat:bind (attrs clauses) #:prefab)
|
#|
|
||||||
|
A GhostPattern is one of
|
||||||
|
(make-ghost:cut Base)
|
||||||
|
(make-ghost:fail Base stx stx)
|
||||||
|
(make-ghost:bind Base (listof clause:attr))
|
||||||
|
* (make-ghost:and Base (listof GhostPattern))
|
||||||
|
|
||||||
|
ghost:and is desugared below in create-* procedures
|
||||||
|
|#
|
||||||
|
|
||||||
|
(define-struct ghost:cut (attrs) #:prefab)
|
||||||
|
(define-struct ghost:fail (attrs when message) #:prefab)
|
||||||
|
(define-struct ghost:bind (attrs clauses) #:prefab)
|
||||||
|
(define-struct ghost:and (attrs patterns) #:prefab)
|
||||||
|
|
||||||
#|
|
#|
|
||||||
A HeadPattern is one of
|
A HeadPattern is one of
|
||||||
(make-hpat:var SPBase id id (listof stx) (listof IAttr))
|
(make-hpat:var Base id id (listof stx) (listof IAttr))
|
||||||
(make-hpat:seq HPBase ListPattern)
|
(make-hpat:seq Base ListPattern)
|
||||||
(make-hpat:and HPBase HeadPattern SinglePattern)
|
(make-hpat:ghost Base GhostPattern HeadPattern)
|
||||||
(make-hpat:or HPBase (listof HeadPattern))
|
(make-hpat:and Base HeadPattern SinglePattern)
|
||||||
(make-hpat:describe HPBase stx/#f boolean HeadPattern)
|
(make-hpat:or Base (listof HeadPattern))
|
||||||
(make-hpat:optional HPBase HeadPattern (listof clause:attr))
|
(make-hpat:optional Base HeadPattern (listof clause:attr))
|
||||||
|
(make-hpat:describe Base stx/#f boolean HeadPattern)
|
||||||
|#
|
|#
|
||||||
|
|
||||||
(define-struct hpat:var (attrs name parser args nested-attrs) #:prefab)
|
(define-struct hpat:var (attrs name parser args nested-attrs) #:prefab)
|
||||||
(define-struct hpat:seq (attrs inner) #:prefab)
|
(define-struct hpat:seq (attrs inner) #:prefab)
|
||||||
(define-struct hpat:or (attrs patterns) #:prefab)
|
(define-struct hpat:ghost (attrs ghost inner) #:prefab)
|
||||||
(define-struct hpat:and (attrs head single) #:prefab)
|
(define-struct hpat:and (attrs head single) #:prefab)
|
||||||
(define-struct hpat:describe (attrs description transparent? pattern) #:prefab)
|
(define-struct hpat:or (attrs patterns) #:prefab)
|
||||||
(define-struct hpat:optional (attrs inner defaults) #:prefab)
|
(define-struct hpat:optional (attrs inner defaults) #:prefab)
|
||||||
|
(define-struct hpat:describe (attrs description transparent? pattern) #:prefab)
|
||||||
|
|
||||||
#|
|
#|
|
||||||
An EllipsisHeadPattern is
|
An EllipsisHeadPattern is
|
||||||
(make-ehpat EHPBase HeadPattern RepConstraint)
|
(make-ehpat Base HeadPattern RepConstraint)
|
||||||
|
|
||||||
A RepConstraint is one of
|
A RepConstraint is one of
|
||||||
(make-rep:once stx stx stx)
|
(make-rep:once stx stx stx)
|
||||||
|
@ -85,6 +93,7 @@ A RepConstraint is one of
|
||||||
(make-rep:bounds nat/#f nat/#f stx stx stx)
|
(make-rep:bounds nat/#f nat/#f stx stx stx)
|
||||||
#f
|
#f
|
||||||
|#
|
|#
|
||||||
|
|
||||||
(define-struct ehpat (attrs head repc) #:prefab)
|
(define-struct ehpat (attrs head repc) #:prefab)
|
||||||
(define-struct rep:once (name under-message over-message) #:prefab)
|
(define-struct rep:once (name under-message over-message) #:prefab)
|
||||||
(define-struct rep:optional (name over-message defaults) #:prefab)
|
(define-struct rep:optional (name over-message defaults) #:prefab)
|
||||||
|
@ -102,26 +111,31 @@ A Kind is one of
|
||||||
(define (pattern? x)
|
(define (pattern? x)
|
||||||
(or (pat:any? x)
|
(or (pat:any? x)
|
||||||
(pat:var? x)
|
(pat:var? x)
|
||||||
(pat:datum? x)
|
|
||||||
(pat:literal? x)
|
(pat:literal? x)
|
||||||
|
(pat:datum? x)
|
||||||
|
(pat:ghost? x)
|
||||||
(pat:head? x)
|
(pat:head? x)
|
||||||
(pat:dots? x)
|
(pat:dots? x)
|
||||||
(pat:and? x)
|
(pat:and? x)
|
||||||
(pat:or? x)
|
(pat:or? x)
|
||||||
(pat:not? x)
|
(pat:not? x)
|
||||||
(pat:compound? x)
|
(pat:compound? x)
|
||||||
(pat:cut? x)
|
(pat:describe? x)))
|
||||||
(pat:describe? x)
|
|
||||||
(pat:bind? x)
|
(define (ghost-pattern? x)
|
||||||
(pat:fail? x)))
|
(or (ghost:cut? x)
|
||||||
|
(ghost:bind? x)
|
||||||
|
(ghost:fail? x)
|
||||||
|
(ghost:and? x)))
|
||||||
|
|
||||||
(define (head-pattern? x)
|
(define (head-pattern? x)
|
||||||
(or (hpat:var? x)
|
(or (hpat:var? x)
|
||||||
(hpat:seq? x)
|
(hpat:seq? x)
|
||||||
|
(hpat:ghost? x)
|
||||||
(hpat:and? x)
|
(hpat:and? x)
|
||||||
(hpat:or? x)
|
(hpat:or? x)
|
||||||
(hpat:describe? x)
|
(hpat:optional? x)
|
||||||
(hpat:optional? x)))
|
(hpat:describe? x)))
|
||||||
|
|
||||||
(define (ellipsis-head-pattern? x)
|
(define (ellipsis-head-pattern? x)
|
||||||
(ehpat? x))
|
(ehpat? x))
|
||||||
|
@ -147,10 +161,10 @@ A Kind is one of
|
||||||
#'(lambda (x)
|
#'(lambda (x)
|
||||||
(cond [(pred x) (accessor x)] ...
|
(cond [(pred x) (accessor x)] ...
|
||||||
[else (raise-type-error 'pattern-attrs "pattern" x)])))]))
|
[else (raise-type-error 'pattern-attrs "pattern" x)])))]))
|
||||||
(mk-get-attrs pat:any pat:var pat:datum pat:literal pat:head pat:dots
|
(mk-get-attrs pat:any pat:var pat:datum pat:literal pat:ghost pat:head
|
||||||
pat:and pat:or pat:not pat:compound
|
pat:dots pat:and pat:or pat:not pat:compound pat:describe
|
||||||
pat:cut pat:describe pat:bind pat:fail
|
ghost:cut ghost:bind ghost:fail ghost:and
|
||||||
hpat:var hpat:seq hpat:and hpat:or hpat:describe
|
hpat:var hpat:seq hpat:ghost hpat:and hpat:or hpat:describe
|
||||||
hpat:optional
|
hpat:optional
|
||||||
ehpat)))
|
ehpat)))
|
||||||
|
|
||||||
|
@ -174,12 +188,21 @@ A Kind is one of
|
||||||
(define (create-pat:literal literal)
|
(define (create-pat:literal literal)
|
||||||
(make pat:literal null literal))
|
(make pat:literal null literal))
|
||||||
|
|
||||||
|
(define (create-pat:ghost g sp)
|
||||||
|
(cond [(ghost:and? g)
|
||||||
|
(for/fold ([sp sp]) ([g (reverse (ghost:and-patterns g))])
|
||||||
|
(create-pat:ghost g sp))]
|
||||||
|
[else
|
||||||
|
(let ([attrs (append-iattrs (map pattern-attrs (list g sp)))])
|
||||||
|
(make pat:ghost attrs g sp))]))
|
||||||
|
|
||||||
|
(define (create-pat:head headp tailp)
|
||||||
|
(let ([attrs (append-iattrs (map pattern-attrs (list headp tailp)))])
|
||||||
|
(make pat:head attrs headp tailp)))
|
||||||
|
|
||||||
(define (create-pat:compound kind ps)
|
(define (create-pat:compound kind ps)
|
||||||
(make pat:compound (append-iattrs (map pattern-attrs ps)) kind ps))
|
(make pat:compound (append-iattrs (map pattern-attrs ps)) kind ps))
|
||||||
|
|
||||||
(define (create-pat:cut inner)
|
|
||||||
(make pat:cut (pattern-attrs inner) inner))
|
|
||||||
|
|
||||||
(define (create-pat:describe description transparent? p)
|
(define (create-pat:describe description transparent? p)
|
||||||
(make pat:describe (pattern-attrs p) description transparent? p))
|
(make pat:describe (pattern-attrs p) description transparent? p))
|
||||||
|
|
||||||
|
@ -198,12 +221,17 @@ A Kind is one of
|
||||||
(let ([attrs (append-iattrs (map pattern-attrs (cons tailp headps)))])
|
(let ([attrs (append-iattrs (map pattern-attrs (cons tailp headps)))])
|
||||||
(make pat:dots attrs headps tailp)))
|
(make pat:dots attrs headps tailp)))
|
||||||
|
|
||||||
(define (create-pat:fail condition message)
|
;; ----
|
||||||
(make pat:fail null condition message))
|
|
||||||
|
|
||||||
(define (create-pat:head headp tailp)
|
(define (create-ghost:cut)
|
||||||
(let ([attrs (append-iattrs (map pattern-attrs (list headp tailp)))])
|
(make ghost:cut null))
|
||||||
(make pat:head attrs headp tailp)))
|
|
||||||
|
(define (create-ghost:fail condition message)
|
||||||
|
(make ghost:fail null condition message))
|
||||||
|
|
||||||
|
(define (create-ghost:and patterns)
|
||||||
|
(let ([attrs (append-iattrs (map pattern-attrs patterns))])
|
||||||
|
(make ghost:and attrs patterns)))
|
||||||
|
|
||||||
;; ----
|
;; ----
|
||||||
|
|
||||||
|
@ -215,6 +243,14 @@ A Kind is one of
|
||||||
(define (create-hpat:seq lp)
|
(define (create-hpat:seq lp)
|
||||||
(make hpat:seq (pattern-attrs lp) lp))
|
(make hpat:seq (pattern-attrs lp) lp))
|
||||||
|
|
||||||
|
(define (create-hpat:ghost g hp)
|
||||||
|
(cond [(ghost:and? g)
|
||||||
|
(for/fold ([hp hp]) ([g (reverse (ghost:and-patterns g))])
|
||||||
|
(create-hpat:ghost g hp))]
|
||||||
|
[else
|
||||||
|
(let ([attrs (append-iattrs (map pattern-attrs (list g hp)))])
|
||||||
|
(make hpat:ghost attrs g hp))]))
|
||||||
|
|
||||||
(define (create-hpat:describe description transparent? p)
|
(define (create-hpat:describe description transparent? p)
|
||||||
(make hpat:describe (pattern-attrs p) description transparent? p))
|
(make hpat:describe (pattern-attrs p) description transparent? p))
|
||||||
|
|
||||||
|
@ -227,8 +263,14 @@ A Kind is one of
|
||||||
|
|
||||||
;; ----
|
;; ----
|
||||||
|
|
||||||
(define (head-pattern->list-pattern hp)
|
(define (ghost/head-pattern->list-pattern p)
|
||||||
;; simplification: just extract list pattern from hpat:seq
|
(cond [(ghost-pattern? p)
|
||||||
(if (hpat:seq? hp)
|
(create-pat:ghost p (create-pat:any))]
|
||||||
(hpat:seq-inner hp)
|
[(hpat:seq? p)
|
||||||
(create-pat:head hp (create-pat:datum '()))))
|
;; simplification: just extract list pattern from hpat:seq
|
||||||
|
(hpat:seq-inner p)]
|
||||||
|
[else
|
||||||
|
(create-pat:head p (create-pat:datum '()))]))
|
||||||
|
|
||||||
|
(define (ghost-pattern->single-pattern gp)
|
||||||
|
(create-pat:ghost gp (create-pat:any)))
|
||||||
|
|
|
@ -259,50 +259,84 @@
|
||||||
|
|
||||||
;; parse-single-pattern : stx DeclEnv -> SinglePattern
|
;; parse-single-pattern : stx DeclEnv -> SinglePattern
|
||||||
(define (parse-single-pattern stx decls)
|
(define (parse-single-pattern stx decls)
|
||||||
|
;; FIXME: allow ghosts, convert to single-term pattern???
|
||||||
|
(let ([p (parse-*-pattern stx decls #f #f)])
|
||||||
|
p))
|
||||||
|
|
||||||
|
;; parse-head-pattern : stx DeclEnv -> HeadPattern
|
||||||
|
(define (parse-head-pattern stx decls)
|
||||||
|
(parse-*-pattern stx decls #t #f))
|
||||||
|
|
||||||
|
;; parse-*-pattern : stx DeclEnv boolean boolean -> Pattern
|
||||||
|
(define (parse-*-pattern stx decls allow-head? allow-ghost?)
|
||||||
|
(define (check-head! x)
|
||||||
|
(unless allow-head?
|
||||||
|
(wrong-syntax stx "head pattern not allowed here"))
|
||||||
|
x)
|
||||||
|
(define (check-ghost! x)
|
||||||
|
;; Coerce to S-pattern IF only S-patterns allowed
|
||||||
|
(cond [allow-ghost? x]
|
||||||
|
[(not allow-head?) (ghost-pattern->single-pattern x)]
|
||||||
|
[else
|
||||||
|
(wrong-syntax stx "action pattern not allowed here")]))
|
||||||
(syntax-case stx (~var ~literal ~and ~or ~not ~rest ~struct
|
(syntax-case stx (~var ~literal ~and ~or ~not ~rest ~struct
|
||||||
~! ~describe ~bind ~fail)
|
~! ~describe ~bind ~fail ~seq ~optional)
|
||||||
[wildcard
|
[wildcard
|
||||||
(wildcard? #'wildcard)
|
(wildcard? #'wildcard)
|
||||||
(create-pat:any)]
|
(create-pat:any)]
|
||||||
|
[~!
|
||||||
|
(check-ghost!
|
||||||
|
(create-ghost:cut))]
|
||||||
[reserved
|
[reserved
|
||||||
(reserved? #'reserved)
|
(reserved? #'reserved)
|
||||||
(wrong-syntax stx "not allowed here")]
|
(wrong-syntax stx "pattern keyword not allowed here")]
|
||||||
[id
|
[id
|
||||||
(identifier? #'id)
|
(identifier? #'id)
|
||||||
(parse-pat:id stx decls #f)]
|
(parse-pat:id stx decls allow-head?)]
|
||||||
[datum
|
[datum
|
||||||
(atomic-datum? #'datum)
|
(atomic-datum? #'datum)
|
||||||
(create-pat:datum (syntax->datum #'datum))]
|
(create-pat:datum (syntax->datum #'datum))]
|
||||||
[(~var . rest)
|
[(~var . rest)
|
||||||
(parse-pat:var stx decls #f)]
|
(parse-pat:var stx decls allow-head?)]
|
||||||
[(~literal . rest)
|
[(~literal . rest)
|
||||||
(parse-pat:literal stx decls)]
|
(parse-pat:literal stx decls)]
|
||||||
[(~and . rest)
|
[(~and . rest)
|
||||||
(parse-pat:and stx decls #f)]
|
(parse-pat:and stx decls allow-head? allow-ghost?)]
|
||||||
[(~or . rest)
|
[(~or . rest)
|
||||||
(parse-pat:or stx decls #f)]
|
(parse-pat:or stx decls allow-head?)]
|
||||||
[(~not . rest)
|
[(~not . rest)
|
||||||
(parse-pat:not stx decls)]
|
(parse-pat:not stx decls)]
|
||||||
|
[(~rest . rest)
|
||||||
|
(parse-pat:rest stx decls)]
|
||||||
|
[(~describe . rest)
|
||||||
|
(parse-pat:describe stx decls allow-head?)]
|
||||||
|
[(~seq . rest)
|
||||||
|
(check-head!
|
||||||
|
(parse-hpat:seq stx #'rest decls))]
|
||||||
|
[(~optional . rest)
|
||||||
|
(check-head!
|
||||||
|
(parse-hpat:optional stx decls))]
|
||||||
|
[(~bind . rest)
|
||||||
|
(check-ghost!
|
||||||
|
(parse-pat:bind stx decls))]
|
||||||
|
[(~fail . rest)
|
||||||
|
(check-ghost!
|
||||||
|
(parse-pat:fail stx decls))]
|
||||||
[(head dots . tail)
|
[(head dots . tail)
|
||||||
(dots? #'dots)
|
(dots? #'dots)
|
||||||
(parse-pat:dots stx #'head #'tail decls)]
|
(parse-pat:dots stx #'head #'tail decls)]
|
||||||
[(~struct key . contents)
|
|
||||||
(let ([lp (parse-single-pattern (syntax/loc stx contents) decls)]
|
|
||||||
[key (syntax->datum #'key)])
|
|
||||||
(create-pat:compound `(#:pstruct ,key) (list lp)))]
|
|
||||||
[(~! . rest)
|
|
||||||
(let ([inner (parse-single-pattern (syntax/loc stx rest) decls)])
|
|
||||||
(create-pat:cut inner))]
|
|
||||||
[(~describe . rest)
|
|
||||||
(parse-pat:describe stx decls #f)]
|
|
||||||
[(~bind . rest)
|
|
||||||
(parse-pat:bind stx decls)]
|
|
||||||
[(~fail . rest)
|
|
||||||
(parse-pat:fail stx decls)]
|
|
||||||
[(~rest . rest)
|
|
||||||
(parse-pat:rest stx decls)]
|
|
||||||
[(head . tail)
|
[(head . tail)
|
||||||
(parse-pat:pair stx #'head #'tail decls)]
|
(let ([headp (parse-*-pattern #'head decls #t #t)]
|
||||||
|
[tailp (parse-single-pattern #'tail decls)])
|
||||||
|
;; Only make pat:head if head is complicated;
|
||||||
|
;; otherwise simple compound/pair
|
||||||
|
;; FIXME: Could also inline ~seq patterns from head...?
|
||||||
|
(cond [(ghost-pattern? headp)
|
||||||
|
(create-pat:ghost headp tailp)]
|
||||||
|
[(head-pattern? headp)
|
||||||
|
(create-pat:head headp tailp)]
|
||||||
|
[else
|
||||||
|
(create-pat:compound '#:pair (list headp tailp))]))]
|
||||||
[#(a ...)
|
[#(a ...)
|
||||||
(let ([lp (parse-single-pattern (syntax/loc stx (a ...)) decls)])
|
(let ([lp (parse-single-pattern (syntax/loc stx (a ...)) decls)])
|
||||||
(create-pat:compound '#:vector (list lp)))]
|
(create-pat:compound '#:vector (list lp)))]
|
||||||
|
@ -318,27 +352,6 @@
|
||||||
(let ([lp (parse-single-pattern (datum->syntax #f contents #'s) decls)])
|
(let ([lp (parse-single-pattern (datum->syntax #f contents #'s) decls)])
|
||||||
(create-pat:compound `(#:pstruct ,key) (list lp))))]))
|
(create-pat:compound `(#:pstruct ,key) (list lp))))]))
|
||||||
|
|
||||||
;; parse-head-pattern : stx DeclEnv -> HeadPattern
|
|
||||||
(define (parse-head-pattern stx decls)
|
|
||||||
(syntax-case stx (~var ~and ~or ~seq ~describe ~optional)
|
|
||||||
[id
|
|
||||||
(and (identifier? #'id) (not (reserved? #'id)))
|
|
||||||
(parse-pat:id stx decls #t)]
|
|
||||||
[(~var . rest)
|
|
||||||
(parse-pat:var stx decls #t)]
|
|
||||||
[(~and . rest)
|
|
||||||
(parse-pat:and stx decls #t)]
|
|
||||||
[(~or . rest)
|
|
||||||
(parse-pat:or stx decls #t)]
|
|
||||||
[(~seq . rest)
|
|
||||||
(parse-hpat:seq stx #'rest decls)]
|
|
||||||
[(~describe . rest)
|
|
||||||
(parse-pat:describe stx decls #t)]
|
|
||||||
[(~optional . rest)
|
|
||||||
(parse-hpat:optional stx decls)]
|
|
||||||
[_
|
|
||||||
(parse-single-pattern stx decls)]))
|
|
||||||
|
|
||||||
;; parse-ellipsis-head-pattern : stx DeclEnv number -> EllipsisHeadPattern
|
;; parse-ellipsis-head-pattern : stx DeclEnv number -> EllipsisHeadPattern
|
||||||
(define (parse-ellipsis-head-pattern stx decls)
|
(define (parse-ellipsis-head-pattern stx decls)
|
||||||
(syntax-case stx (~bounds ~optional ~once)
|
(syntax-case stx (~bounds ~optional ~once)
|
||||||
|
@ -374,10 +387,9 @@
|
||||||
[(list 'splicing-parser parser description attrs)
|
[(list 'splicing-parser parser description attrs)
|
||||||
(parse-pat:id/h id parser null attrs)]
|
(parse-pat:id/h id parser null attrs)]
|
||||||
[#f
|
[#f
|
||||||
#|
|
(when #f ;; FIXME: enable?
|
||||||
(unless (safe-name? id)
|
(unless (safe-name? id)
|
||||||
(wrong-syntax id "expected identifier not starting with ~ character"))
|
(wrong-syntax id "expected identifier not starting with ~ character")))
|
||||||
|#
|
|
||||||
(let-values ([(name sc) (split-id/get-stxclass id decls)])
|
(let-values ([(name sc) (split-id/get-stxclass id decls)])
|
||||||
(if sc
|
(if sc
|
||||||
(parse-pat:var* id allow-head? name sc null)
|
(parse-pat:var* id allow-head? name sc null)
|
||||||
|
@ -486,11 +498,60 @@
|
||||||
(define transparent? (and (assq '#:transparent chunks) #t))
|
(define transparent? (and (assq '#:transparent chunks) #t))
|
||||||
(syntax-case rest ()
|
(syntax-case rest ()
|
||||||
[(description pattern)
|
[(description pattern)
|
||||||
(let ([p (parse-some-pattern #'pattern decls allow-head?)])
|
(let ([p (parse-*-pattern #'pattern decls allow-head? #f)])
|
||||||
(if (head-pattern? p)
|
(if (head-pattern? p)
|
||||||
(create-hpat:describe #'description transparent? p)
|
(create-hpat:describe #'description transparent? p)
|
||||||
(create-pat:describe #'description transparent? p)))]))]))
|
(create-pat:describe #'description transparent? p)))]))]))
|
||||||
|
|
||||||
|
(define (split-prefix xs pred)
|
||||||
|
(let loop ([xs xs] [rprefix null])
|
||||||
|
(cond [(and (pair? xs) (pred (car xs)))
|
||||||
|
(loop (cdr xs) (cons (car xs) rprefix))]
|
||||||
|
[else
|
||||||
|
(values (reverse rprefix) xs)])))
|
||||||
|
|
||||||
|
(define (parse-pat:and stx decls allow-head? allow-ghost?)
|
||||||
|
;; allow-ghost? = allowed to *return* pure ghost pattern;
|
||||||
|
;; all ~and patterns are allowed to *contain* ghost patterns
|
||||||
|
(define patterns0 (parse-cdr-patterns stx decls allow-head? #t))
|
||||||
|
(define-values (ghosts patterns) (split-prefix patterns0 ghost-pattern?))
|
||||||
|
(cond [(null? patterns)
|
||||||
|
(cond [allow-ghost?
|
||||||
|
(create-ghost:and ghosts)]
|
||||||
|
[allow-head?
|
||||||
|
(wrong-syntax stx "expected at least one head pattern")]
|
||||||
|
[else
|
||||||
|
(wrong-syntax stx "expected at least one single-term pattern")])]
|
||||||
|
[else
|
||||||
|
(let ([p (parse-pat:and* stx patterns)])
|
||||||
|
(if (head-pattern? p)
|
||||||
|
(for/fold ([p p]) ([ghost (reverse ghosts)])
|
||||||
|
(create-hpat:ghost ghost p))
|
||||||
|
(for/fold ([p p]) ([ghost (reverse ghosts)])
|
||||||
|
(create-pat:ghost ghost p))))]))
|
||||||
|
|
||||||
|
(define (parse-pat:and* stx patterns)
|
||||||
|
;; patterns is non-empty (empty case handled above)
|
||||||
|
(cond [(null? (cdr patterns))
|
||||||
|
(car patterns)]
|
||||||
|
[(ormap head-pattern? patterns)
|
||||||
|
;; Check to make sure *all* are head patterns
|
||||||
|
(for ([pattern patterns]
|
||||||
|
[pattern-stx (stx->list (stx-cdr stx))])
|
||||||
|
(unless (or (ghost-pattern? pattern) (head-pattern? pattern))
|
||||||
|
(wrong-syntax
|
||||||
|
pattern-stx
|
||||||
|
"single-term pattern not allowed after head pattern")))
|
||||||
|
(let ([p0 (car patterns)]
|
||||||
|
[lps (map ghost/head-pattern->list-pattern (cdr patterns))])
|
||||||
|
(create-hpat:and p0 (create-pat:and lps)))]
|
||||||
|
[else
|
||||||
|
(create-pat:and
|
||||||
|
(for/list ([p patterns])
|
||||||
|
(if (ghost-pattern? p)
|
||||||
|
(ghost-pattern->single-pattern p)
|
||||||
|
p)))]))
|
||||||
|
|
||||||
(define (parse-pat:or stx decls allow-head?)
|
(define (parse-pat:or stx decls allow-head?)
|
||||||
(define patterns (parse-cdr-patterns stx decls allow-head? #f))
|
(define patterns (parse-cdr-patterns stx decls allow-head? #f))
|
||||||
(cond [(null? (cdr patterns))
|
(cond [(null? (cdr patterns))
|
||||||
|
@ -501,24 +562,6 @@
|
||||||
[else
|
[else
|
||||||
(create-pat:or patterns)])]))
|
(create-pat:or patterns)])]))
|
||||||
|
|
||||||
(define (parse-pat:and stx decls allow-head?)
|
|
||||||
(define patterns (parse-cdr-patterns stx decls allow-head? #t))
|
|
||||||
(cond [(null? (cdr patterns))
|
|
||||||
(car patterns)]
|
|
||||||
[(ormap head-pattern? patterns)
|
|
||||||
;; Check to make sure *all* are head patterns
|
|
||||||
(for ([pattern patterns]
|
|
||||||
[pattern-stx (stx->list (stx-cdr stx))])
|
|
||||||
(unless (head-pattern? pattern)
|
|
||||||
(wrong-syntax
|
|
||||||
pattern-stx
|
|
||||||
"single-term pattern not allowed after head pattern")))
|
|
||||||
(let ([p0 (car patterns)]
|
|
||||||
[lps (map head-pattern->list-pattern (cdr patterns))])
|
|
||||||
(create-hpat:and p0 (create-pat:and lps)))]
|
|
||||||
[else
|
|
||||||
(create-pat:and patterns)]))
|
|
||||||
|
|
||||||
(define (parse-pat:not stx decls)
|
(define (parse-pat:not stx decls)
|
||||||
(syntax-case stx (~not)
|
(syntax-case stx (~not)
|
||||||
[(~not pattern)
|
[(~not pattern)
|
||||||
|
@ -532,31 +575,16 @@
|
||||||
(check-list-pattern pattern stx)
|
(check-list-pattern pattern stx)
|
||||||
(create-hpat:seq pattern))
|
(create-hpat:seq pattern))
|
||||||
|
|
||||||
(define (parse-cdr-patterns stx decls allow-head? allow-cut?)
|
(define (parse-cdr-patterns stx decls allow-head? allow-ghost?)
|
||||||
(unless (stx-list? stx)
|
(unless (stx-list? stx)
|
||||||
(wrong-syntax stx "expected sequence of patterns"))
|
(wrong-syntax stx "expected sequence of patterns"))
|
||||||
(let ([result
|
(let ([result
|
||||||
(for/list ([sub (cdr (stx->list stx))])
|
(for/list ([sub (cdr (stx->list stx))])
|
||||||
(if allow-cut?
|
(parse-*-pattern sub decls allow-head? allow-ghost?))])
|
||||||
(or (parse-cut-in-and sub)
|
|
||||||
(parse-some-pattern sub decls allow-head?))
|
|
||||||
(parse-some-pattern sub decls allow-head?)))])
|
|
||||||
(when (null? result)
|
(when (null? result)
|
||||||
(wrong-syntax stx "expected at least one pattern"))
|
(wrong-syntax stx "expected at least one pattern"))
|
||||||
result))
|
result))
|
||||||
|
|
||||||
(define (parse-cut-in-and stx)
|
|
||||||
(syntax-case stx (~!)
|
|
||||||
[~! (create-pat:cut (create-pat:any))]
|
|
||||||
[_ #f]))
|
|
||||||
|
|
||||||
(define (parse-some-pattern stx decl allow-head?)
|
|
||||||
(define p (parse-head-pattern stx decl))
|
|
||||||
(when (head-pattern? p)
|
|
||||||
(unless allow-head?
|
|
||||||
(wrong-syntax stx "head pattern not allowed here")))
|
|
||||||
p)
|
|
||||||
|
|
||||||
(define (parse-pat:dots stx head tail decls)
|
(define (parse-pat:dots stx head tail decls)
|
||||||
(define headps
|
(define headps
|
||||||
(syntax-case head (~or)
|
(syntax-case head (~or)
|
||||||
|
@ -577,7 +605,7 @@
|
||||||
(syntax-case stx ()
|
(syntax-case stx ()
|
||||||
[(_ clause ...)
|
[(_ clause ...)
|
||||||
(let ([clauses (check-bind-clause-list #'(clause ...) stx)])
|
(let ([clauses (check-bind-clause-list #'(clause ...) stx)])
|
||||||
(make pat:bind
|
(make ghost:bind
|
||||||
(append-iattrs (side-clauses-attrss clauses))
|
(append-iattrs (side-clauses-attrss clauses))
|
||||||
clauses))]))
|
clauses))]))
|
||||||
|
|
||||||
|
@ -598,7 +626,7 @@
|
||||||
#`(not #,(caddr chunk)))))])
|
#`(not #,(caddr chunk)))))])
|
||||||
(syntax-case rest ()
|
(syntax-case rest ()
|
||||||
[(message)
|
[(message)
|
||||||
(create-pat:fail condition #'message)]
|
(create-ghost:fail condition #'message)]
|
||||||
[()
|
[()
|
||||||
(wrong-syntax stx "missing message expression")]
|
(wrong-syntax stx "missing message expression")]
|
||||||
[_
|
[_
|
||||||
|
@ -609,15 +637,6 @@
|
||||||
[(_ pattern)
|
[(_ pattern)
|
||||||
(parse-single-pattern #'pattern decls)]))
|
(parse-single-pattern #'pattern decls)]))
|
||||||
|
|
||||||
(define (parse-pat:pair stx head tail decls)
|
|
||||||
(define headp (parse-head-pattern head decls))
|
|
||||||
(define tailp (parse-single-pattern tail decls))
|
|
||||||
;; Only make pat:head if head is complicated; otherwise simple compound/pair
|
|
||||||
;; FIXME: Could also inline ~seq patterns from head...?
|
|
||||||
(if (head-pattern? headp)
|
|
||||||
(create-pat:head headp tailp)
|
|
||||||
(create-pat:compound '#:pair (list headp tailp))))
|
|
||||||
|
|
||||||
(define (check-list-pattern pattern stx)
|
(define (check-list-pattern pattern stx)
|
||||||
(match pattern
|
(match pattern
|
||||||
[(struct pat:datum (_base '()))
|
[(struct pat:datum (_base '()))
|
||||||
|
|
|
@ -12,6 +12,18 @@
|
||||||
@(define ellipses @scheme[...])
|
@(define ellipses @scheme[...])
|
||||||
@(define-syntax-rule (defhere id) (defidentifier #'id #:form? #t))
|
@(define-syntax-rule (defhere id) (defidentifier #'id #:form? #t))
|
||||||
|
|
||||||
|
@(define Spattern "single-term pattern")
|
||||||
|
@(define Lpattern "list pattern")
|
||||||
|
@(define Hpattern "head pattern")
|
||||||
|
@(define EHpattern "ellipsis-head pattern")
|
||||||
|
@(define Apattern "action pattern")
|
||||||
|
|
||||||
|
@(define Spatterns "single-term patterns")
|
||||||
|
@(define Lpatterns "list patterns")
|
||||||
|
@(define Hpatterns "head patterns")
|
||||||
|
@(define EHpatterns "ellipsis-head patterns")
|
||||||
|
@(define Apatterns "action patterns")
|
||||||
|
|
||||||
@(begin
|
@(begin
|
||||||
(define-syntax ref
|
(define-syntax ref
|
||||||
(syntax-rules ()
|
(syntax-rules ()
|
||||||
|
@ -56,15 +68,20 @@
|
||||||
|
|
||||||
The grammar of @deftech{syntax patterns} used by
|
The grammar of @deftech{syntax patterns} used by
|
||||||
@schememodname[syntax/parse] facilities is given in the following
|
@schememodname[syntax/parse] facilities is given in the following
|
||||||
table. There are three main kinds of syntax pattern: @tech{S-patterns}
|
table. There are four main kinds of syntax pattern:
|
||||||
(for ``single-term patterns''), @tech{H-patterns} (for ``head
|
@itemize[
|
||||||
patterns''), and @tech{EH-patterns} (for ``ellipsis head
|
@item{@tech{@Spatterns}, abbreviated @svar[S-pattern]}
|
||||||
patterns''). A fourth kind, @tech{L-patterns} (for ``list patterns''),
|
@item{@tech{@Hpatterns}, abbreviated @svar[H-pattern]}
|
||||||
is a restricted subset of @tech{S-patterns}.
|
@item{@tech{@EHpatterns}, abbreviated @svar[EH-pattern]}
|
||||||
|
@item{@tech{@Apatterns}, abbreviated @svar[A-pattern]}
|
||||||
|
]
|
||||||
|
A fifth kind, @tech{@Lpatterns} (abbreviated
|
||||||
|
@svar[L-pattern]), is a just a syntactically restricted subset of
|
||||||
|
@tech{@Spatterns}.
|
||||||
|
|
||||||
When a special form in this manual refers to @svar[syntax-pattern]
|
When a special form in this manual refers to @svar[syntax-pattern]
|
||||||
(eg, the description of the @scheme[syntax-parse] special form), it
|
(eg, the description of the @scheme[syntax-parse] special form), it
|
||||||
means specifically @tech{S-pattern}.
|
means specifically @tech{@Spattern}.
|
||||||
|
|
||||||
@schemegrammar*[#:literals (_ ~var ~literal ~or ~and ~not ~seq
|
@schemegrammar*[#:literals (_ ~var ~literal ~or ~and ~not ~seq
|
||||||
~rep ~once ~optional
|
~rep ~once ~optional
|
||||||
|
@ -78,81 +95,118 @@ means specifically @tech{S-pattern}.
|
||||||
(~literal literal-id)
|
(~literal literal-id)
|
||||||
atomic-datum
|
atomic-datum
|
||||||
(H-pattern . S-pattern)
|
(H-pattern . S-pattern)
|
||||||
|
(A-pattern . S-pattern)
|
||||||
((@#,ref[~or eh] EH-pattern ...+) #,ellipses . S-pattern)
|
((@#,ref[~or eh] EH-pattern ...+) #,ellipses . S-pattern)
|
||||||
(EH-pattern #,ellipses . S-pattern)
|
(EH-pattern #,ellipses . S-pattern)
|
||||||
(@#,ref[~and s] S-pattern ...+)
|
(@#,ref[~and s] proper-S/A-pattern ...+)
|
||||||
(@#,ref[~or s] S-pattern ...+)
|
(@#,ref[~or s] S-pattern ...+)
|
||||||
(~not S-pattern)
|
(~not S-pattern)
|
||||||
#((unsyntax @svar[pattern-part]) ...)
|
#((unsyntax @svar[pattern-part]) ...)
|
||||||
#s(prefab-struct-key (unsyntax @svar[pattern-part]) ...)
|
#s(prefab-struct-key (unsyntax @svar[pattern-part]) ...)
|
||||||
(~rest S-pattern)
|
(~rest S-pattern)
|
||||||
(@#,ref[~describe s] expr S-pattern)
|
(@#,ref[~describe s] expr S-pattern)
|
||||||
(~! . S-pattern)
|
A-pattern]
|
||||||
(~bind [attr-id expr] ...)
|
|
||||||
(~fail maybe-fail-condition message-expr)]
|
|
||||||
[L-pattern
|
[L-pattern
|
||||||
()
|
()
|
||||||
|
(A-pattern . L-pattern)
|
||||||
(H-pattern . L-pattern)
|
(H-pattern . L-pattern)
|
||||||
((@#,ref[~or eh] EH-pattern ...+) #,ellipses . L-pattern)
|
((@#,ref[~or eh] EH-pattern ...+) #,ellipses . L-pattern)
|
||||||
(EH-pattern #,ellipses . L-pattern)
|
(EH-pattern #,ellipses . L-pattern)
|
||||||
(~rest L-pattern)
|
(~rest L-pattern)]
|
||||||
(~! . L-pattern)]
|
|
||||||
[H-pattern
|
[H-pattern
|
||||||
pvar-id:splicing-syntax-class-id
|
pvar-id:splicing-syntax-class-id
|
||||||
(@#,ref[~var h] id splicing-syntax-class)
|
(@#,ref[~var h] id splicing-syntax-class)
|
||||||
(~seq . L-pattern)
|
(~seq . L-pattern)
|
||||||
(@#,ref[~and h] strict-H-pattern ...+)
|
(@#,ref[~and h] proper-H/A-pattern ...+)
|
||||||
(@#,ref[~or h] H-pattern ...+)
|
(@#,ref[~or h] H-pattern ...+)
|
||||||
(@#,ref[~optional h] H-pattern maybe-optional-option)
|
(@#,ref[~optional h] H-pattern maybe-optional-option)
|
||||||
(@#,ref[~describe h] expr H-pattern)
|
(@#,ref[~describe h] expr H-pattern)
|
||||||
S-pattern]
|
proper-S-pattern]
|
||||||
[EH-pattern
|
[EH-pattern
|
||||||
(~once H-pattern once-option ...)
|
(~once H-pattern once-option ...)
|
||||||
(@#,ref[~optional eh] H-pattern optional-option ...)
|
(@#,ref[~optional eh] H-pattern optional-option ...)
|
||||||
H-pattern]]
|
H-pattern]
|
||||||
|
[A-pattern
|
||||||
|
~!
|
||||||
|
(~bind [attr-id expr] ...)
|
||||||
|
(~fail maybe-fail-condition message-expr)
|
||||||
|
(@#,ref[~and a] A-pattern ...+)]
|
||||||
|
[proper-S-pattern
|
||||||
|
#, @elem{a @svar{S-pattern} that is not a @svar{A-pattern}}]
|
||||||
|
[proper-H-pattern
|
||||||
|
#, @elem{a @svar{H-pattern} that is not a @svar{S-pattern}}]]
|
||||||
|
|
||||||
The following pattern keywords can be used in multiple pattern
|
The following pattern keywords can be used in multiple pattern
|
||||||
variants:
|
variants:
|
||||||
|
|
||||||
@defidform[~var]{
|
@defidform[~var]{
|
||||||
|
|
||||||
Pattern keyword; see @ref[~var s-], @ref[~var s+], or @ref[~var h].
|
One of @ref[~var s-], @ref[~var s+], or @ref[~var h].
|
||||||
}
|
}
|
||||||
|
|
||||||
@defidform[~and]{
|
@defidform[~and]{
|
||||||
|
|
||||||
Pattern keyword; see @ref[~and s] or @ref[~and h].
|
One of @ref[~and s], @ref[~and h], or @ref[~and a]:
|
||||||
|
@itemize[
|
||||||
|
@item{@ref[~and a] if all of the conjuncts are @tech{@Apatterns}}
|
||||||
|
@item{@ref[~and h] if any of the conjuncts is a @tech{proper
|
||||||
|
@Hpattern}}
|
||||||
|
@item{@ref[~and s] otherwise}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@defidform[~or]{
|
@defidform[~or]{
|
||||||
|
|
||||||
Pattern keyword; see @ref[~or s], @ref[~or h]), or @ref[~or eh].
|
One of @ref[~or s], @ref[~or h]), or @ref[~or eh]:
|
||||||
|
@itemize[
|
||||||
|
@item{@ref[~or eh] if the pattern occurs directly before ellipses
|
||||||
|
(@ellipses)}
|
||||||
|
@item{@ref[~or h] if any of the disjuncts is a @tech{proper @Hpattern}}
|
||||||
|
@item{@ref[~or s] otherwise}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@defidform[~describe]{
|
@defidform[~describe]{
|
||||||
|
|
||||||
Pattern keyword; see @ref[~describe s] or @ref[~describe h].
|
One of @ref[~describe s] or @ref[~describe h]:
|
||||||
|
@itemize[
|
||||||
|
@item{@ref[~describe h] if the subpattern is a @tech{proper @Hpattern}}
|
||||||
|
@item{@ref[~describe s] otherwise}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@defidform[~optional]{
|
@defidform[~optional]{
|
||||||
|
|
||||||
Pattern keyword; see @ref[~optional h] or @ref[~optional eh].
|
One of @ref[~optional h] or @ref[~optional eh]:
|
||||||
|
@itemize[
|
||||||
|
@item{@ref[~optional eh] if it is an immediate disjunct of a @ref[~or
|
||||||
|
eh] pattern}
|
||||||
|
@item{@ref[~optional h] otherwise}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@;{--------}
|
@;{--------}
|
||||||
|
|
||||||
@section{S-pattern variants}
|
@section{Single-term patterns}
|
||||||
|
|
||||||
An @deftech{S-pattern} (for ``single-term pattern'') is a pattern that
|
A @deftech{@Spattern} (abbreviated @svar[S-pattern]) is a pattern that
|
||||||
describes a single term. The pattern may, of course, consist of other
|
describes a single term. These are like the traditional patterns used
|
||||||
parts. For example, @scheme[(17 ...)] is an @tech{S-pattern}
|
in @scheme[syntax-rules] and @scheme[syntax-case], but with additional
|
||||||
that matches any term that is a proper list of repeated
|
variants that make them more expressive.
|
||||||
@schemeresult[17] numerals. The @deftech{L-pattern}s (for ``list
|
|
||||||
pattern'') are @tech{S-pattern} having a restricted structure that
|
|
||||||
constrains it to match only terms that are proper lists.
|
|
||||||
|
|
||||||
Here are the variants of @tech{S-pattern}:
|
``Single-term'' does not mean ``atomic''; a @Spattern can have
|
||||||
|
complex structure, and it can match terms that have many parts. For
|
||||||
|
example, @scheme[(17 ...)] is a @Spattern that matches any
|
||||||
|
term that is a proper list of repeated @schemeresult[17] numerals.
|
||||||
|
|
||||||
|
A @deftech{proper @Spattern} is one that is not an @tech{@Apattern}.
|
||||||
|
|
||||||
|
The @deftech{@Lpatterns} (for ``list pattern'') are @Spatterns
|
||||||
|
having a restricted structure that guarantees that they match only
|
||||||
|
terms that are proper lists.
|
||||||
|
|
||||||
|
Here are the variants of @elem{@Spattern}:
|
||||||
|
|
||||||
@specsubform[id]{
|
@specsubform[id]{
|
||||||
|
|
||||||
|
@ -285,32 +339,46 @@ literals.
|
||||||
@specsubform[(H-pattern . S-pattern)]{
|
@specsubform[(H-pattern . S-pattern)]{
|
||||||
|
|
||||||
Matches any term that can be decomposed into a list prefix matching
|
Matches any term that can be decomposed into a list prefix matching
|
||||||
the @tech{H-pattern} and a suffix matching the S-pattern.
|
@scheme[H-pattern] and a suffix matching @scheme[S-pattern].
|
||||||
|
|
||||||
Note that the pattern may match terms that are not even improper
|
Note that the pattern may match terms that are not even improper
|
||||||
lists; if the head pattern can match a zero-length head, then the
|
lists; if the head pattern can match a zero-length head, then the
|
||||||
whole pattern matches whatever the tail pattern accepts.
|
whole pattern matches whatever the tail pattern accepts.
|
||||||
|
|
||||||
The first pattern can be an @tech{S-pattern}, in which case the whole
|
The first pattern can be a @tech{@Spattern}, in which case the whole
|
||||||
pattern matches any pair whose first element matches the first pattern
|
pattern matches any pair whose first element matches the first pattern
|
||||||
and whose rest matches the second.
|
and whose rest matches the second.
|
||||||
|
|
||||||
See @tech{H-patterns} for more information.
|
See @tech{@Hpatterns} for more information.
|
||||||
|
}
|
||||||
|
|
||||||
|
@specsubform[(A-pattern . S-pattern)]{
|
||||||
|
|
||||||
|
Performs the actions specified by @scheme[A-pattern], then matches
|
||||||
|
any term that matches @scheme[S-pattern].
|
||||||
|
|
||||||
|
Pragmatically, one can throw an @tech{@Apattern} into any list
|
||||||
|
pattern. Thus, @scheme[(x y z)] is a pattern matching a list of three
|
||||||
|
terms, and @scheme[(x y ~! z)] is a pattern matching a list of three
|
||||||
|
terms, with a @tech{cut} performed after the second one. In other
|
||||||
|
words, @Apatterns ``don't take up space.''
|
||||||
|
|
||||||
|
See @tech{@Apatterns} for more information.
|
||||||
}
|
}
|
||||||
|
|
||||||
@specsubform[((@#,def[~or eh] EH-pattern ...+) #,ellipses . S-pattern)]{
|
@specsubform[((@#,def[~or eh] EH-pattern ...+) #,ellipses . S-pattern)]{
|
||||||
|
|
||||||
Matches any term that can be decomposed into a list head matching some
|
Matches any term that can be decomposed into a list head matching some
|
||||||
number of repetitions of the @tech{EH-pattern} alternatives (subject
|
number of repetitions of @scheme[EH-pattern] alternatives (subject to
|
||||||
to its repetition constraints) followed by a list tail matching the
|
its repetition constraints) followed by a list tail matching
|
||||||
S-pattern.
|
@scheme[S-pattern].
|
||||||
|
|
||||||
In other words, the whole pattern matches either the second pattern
|
In other words, the whole pattern matches either the second pattern
|
||||||
(which need not be a list) or a term whose head matches one of the
|
(which need not be a list) or a term whose head matches one of the
|
||||||
alternatives of the first pattern and whose tail recursively matches
|
alternatives of the first pattern and whose tail recursively matches
|
||||||
the whole sequence pattern.
|
the whole sequence pattern.
|
||||||
|
|
||||||
See @tech{EH-patterns} for more information.
|
See @tech{@EHpatterns} for more information.
|
||||||
}
|
}
|
||||||
|
|
||||||
@specsubform[(EH-pattern #,ellipses . S-pattern)]{
|
@specsubform[(EH-pattern #,ellipses . S-pattern)]{
|
||||||
|
@ -319,10 +387,13 @@ The @scheme[~or]-free variant of ellipses (@ellipses) pattern is
|
||||||
equivalent to the @scheme[~or] variant with just one alternative.
|
equivalent to the @scheme[~or] variant with just one alternative.
|
||||||
}
|
}
|
||||||
|
|
||||||
@specsubform[(@#,def[~and s] S-pattern ...)]{
|
@specsubform[(@#,def[~and s] S/A-pattern ...)]{
|
||||||
|
|
||||||
Matches any term that matches all of the subpatterns.
|
Matches any term that matches all of the subpatterns.
|
||||||
|
|
||||||
|
The subpatterns can contain a mixture of @tech{@Spatterns} and
|
||||||
|
@tech{@Apatterns}, but must contain at least one @tech{@Spattern}.
|
||||||
|
|
||||||
Attributes bound in subpatterns are available to subsequent
|
Attributes bound in subpatterns are available to subsequent
|
||||||
subpatterns. The whole pattern binds all of the subpatterns'
|
subpatterns. The whole pattern binds all of the subpatterns'
|
||||||
attributes.
|
attributes.
|
||||||
|
@ -348,7 +419,6 @@ purpose, but @scheme[~and] can be lighter weight.
|
||||||
#f "bad import" #'import-clause bad))
|
#f "bad import" #'import-clause bad))
|
||||||
'ok)])
|
'ok)])
|
||||||
]
|
]
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@specsubform[(@#,def[~or s] S-pattern ...)]{
|
@specsubform[(@#,def[~or s] S-pattern ...)]{
|
||||||
|
@ -372,8 +442,9 @@ to have a value if the whole pattern matches.
|
||||||
|
|
||||||
@specsubform[(@#,defhere[~not] S-pattern)]{
|
@specsubform[(@#,defhere[~not] S-pattern)]{
|
||||||
|
|
||||||
Matches any term that does not match the subpattern. The subpattern's
|
Matches any term that does not match the subpattern. None of the
|
||||||
attributes are @emph{not} bound outside of the @scheme[~not]-pattern.
|
subpattern's attributes are bound outside of the
|
||||||
|
@scheme[~not]-pattern.
|
||||||
|
|
||||||
@myexamples[
|
@myexamples[
|
||||||
(syntax-parse #'(x y z => u v)
|
(syntax-parse #'(x y z => u v)
|
||||||
|
@ -386,7 +457,7 @@ attributes are @emph{not} bound outside of the @scheme[~not]-pattern.
|
||||||
@specsubform[#(#, @svar[pattern-part] ...)]{
|
@specsubform[#(#, @svar[pattern-part] ...)]{
|
||||||
|
|
||||||
Matches a term that is a vector whose elements, when considered as a
|
Matches a term that is a vector whose elements, when considered as a
|
||||||
list, match the @tech{S-pattern} corresponding to
|
list, match the @tech{@Spattern} corresponding to
|
||||||
@scheme[(pattern-part ...)].
|
@scheme[(pattern-part ...)].
|
||||||
|
|
||||||
@myexamples[
|
@myexamples[
|
||||||
|
@ -397,14 +468,13 @@ list, match the @tech{S-pattern} corresponding to
|
||||||
(syntax-parse #'#(1 2 3)
|
(syntax-parse #'#(1 2 3)
|
||||||
[#(x ~rest y) (syntax->datum #'y)])
|
[#(x ~rest y) (syntax->datum #'y)])
|
||||||
]
|
]
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@specsubform[#s(prefab-struct-key #, @svar[pattern-part] ...)]{
|
@specsubform[#s(prefab-struct-key #, @svar[pattern-part] ...)]{
|
||||||
|
|
||||||
Matches a term that is a prefab struct whose key is exactly the given
|
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
|
key and whose sequence of fields, when considered as a list, match the
|
||||||
@tech{S-pattern} corresponding to @scheme[(pattern-part ...)].
|
@tech{@Spattern} corresponding to @scheme[(pattern-part ...)].
|
||||||
|
|
||||||
@myexamples[
|
@myexamples[
|
||||||
(syntax-parse #'#s(point 1 2 3)
|
(syntax-parse #'#s(point 1 2 3)
|
||||||
|
@ -418,10 +488,10 @@ key and whose sequence of fields, when considered as a list, match the
|
||||||
|
|
||||||
@specsubform[(#, @defhere[~rest] S-pattern)]{
|
@specsubform[(#, @defhere[~rest] S-pattern)]{
|
||||||
|
|
||||||
Matches just like the inner @scheme[S-pattern]. The @scheme[~rest]
|
Matches just like @scheme[S-pattern]. The @scheme[~rest] pattern form
|
||||||
pattern form is useful in positions where improper lists (``dots'')
|
is useful in positions where improper (``dotted'') lists are not
|
||||||
are not allowed by the reader, such as vector and structure patterns
|
allowed by the reader, such as vector and structure patterns (see
|
||||||
(see above).
|
above).
|
||||||
|
|
||||||
@myexamples[
|
@myexamples[
|
||||||
(syntax-parse #'(1 2 3)
|
(syntax-parse #'(1 2 3)
|
||||||
|
@ -442,19 +512,234 @@ A describe-pattern also affects backtracking in two ways:
|
||||||
|
|
||||||
@itemize{
|
@itemize{
|
||||||
|
|
||||||
@item{A cut-pattern (@scheme[~!]) within a describe-pattern only
|
@item{A cut (@scheme[~!]) within a describe-pattern only
|
||||||
eliminates choice-points created within the describe-pattern.}
|
eliminates choice-points created within the describe-pattern.}
|
||||||
|
|
||||||
@item{If a describe-pattern succeeds, then all choice points created
|
@item{If a describe-pattern succeeds, then all choice points
|
||||||
within the describe-pattern are discarded, and a failure @emph{after}
|
created within the describe-pattern are discarded, and a failure
|
||||||
the describe-pattern backtracks to a choice point @emph{before} the
|
@emph{after} the describe-pattern backtracks to a choice point
|
||||||
describe-pattern, never one @emph{within} it.}}}
|
@emph{before} the describe-pattern, never one @emph{within} it.}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@specsubform[(@#,defhere[~!] . S-pattern)]{
|
@specsubform[A-pattern]{
|
||||||
|
|
||||||
The @scheme[~!] operator, pronounced ``cut'', eliminates backtracking
|
An @tech{@Apattern} is considered a @Spattern when there is no
|
||||||
choice points and commits parsing to the current branch of the pattern
|
ambiguity; it matches any term.
|
||||||
it is exploring.
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@section{Head patterns}
|
||||||
|
|
||||||
|
A @deftech{@Hpattern} (abbreviated @svar[H-pattern]) is a pattern that
|
||||||
|
describes some number of terms that occur at the head of some list
|
||||||
|
(possibly an improper list). A @Hpattern's usefulness comes from being
|
||||||
|
able to match heads of different lengths, such as optional forms like
|
||||||
|
keyword arguments.
|
||||||
|
|
||||||
|
A @deftech{proper @Hpattern} is a @Hpattern that is not a @elem{@Spattern}.
|
||||||
|
|
||||||
|
Here are the variants of @elem{@Hpattern}:
|
||||||
|
|
||||||
|
@specsubform[pvar-id:splicing-syntax-class-id]{
|
||||||
|
|
||||||
|
Equivalent to @scheme[(~var pvar-id splicing-syntax-class-id)].
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@specsubform/subs[(@#,def[~var h] pvar-id splicing-syntax-class)
|
||||||
|
([splicing-syntax-class splicing-syntax-class-id
|
||||||
|
(splicing-syntax-class-id arg-expr ...)])]{
|
||||||
|
|
||||||
|
Pattern variable annotated with a @tech{splicing syntax
|
||||||
|
class}. Similar to a normal @tech{annotated pattern variable}, except
|
||||||
|
matches a head pattern.
|
||||||
|
}
|
||||||
|
|
||||||
|
@specsubform[(@#,defhere[~seq] . L-pattern)]{
|
||||||
|
|
||||||
|
Matches a head whose elements, if put in a list, would match
|
||||||
|
@scheme[L-pattern].
|
||||||
|
|
||||||
|
@myexamples[
|
||||||
|
(syntax-parse #'(1 2 3 4)
|
||||||
|
[((~seq 1 2 3) 4) 'ok])
|
||||||
|
]
|
||||||
|
|
||||||
|
See also the section on @tech{@EHpatterns} for more interesting
|
||||||
|
examples of @scheme[~seq].
|
||||||
|
}
|
||||||
|
|
||||||
|
@specsubform[(@#,def[~and h] H-pattern ...)]{
|
||||||
|
|
||||||
|
Like the @Spattern version of @scheme[~and], but matches a term head
|
||||||
|
instead.
|
||||||
|
|
||||||
|
@myexamples[
|
||||||
|
(syntax-parse #'(#:a 1 #:b 2 3 4 5)
|
||||||
|
[((~and (~seq (~seq k:keyword e:expr) ...)
|
||||||
|
(~seq keyword-stuff ...))
|
||||||
|
positional-stuff ...)
|
||||||
|
(syntax->datum #'((k ...) (e ...) (keyword-stuff ...)))])
|
||||||
|
]
|
||||||
|
|
||||||
|
The @Hpattern variant of @scheme[~and] requires that all of the
|
||||||
|
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 @scheme[~seq] omitted:
|
||||||
|
|
||||||
|
@myexamples[
|
||||||
|
(syntax-parse #'(#:a 1 #:b 2 3 4 5)
|
||||||
|
[((~and (~seq (~seq k:keyword e:expr) ...)
|
||||||
|
(keyword-stuff ...))
|
||||||
|
positional-stuff ...)
|
||||||
|
(syntax->datum #'((k ...) (e ...) (keyword-stuff ...)))])
|
||||||
|
(code:comment "If the example above were allowed, it would be equivalent to this:")
|
||||||
|
(syntax-parse #'(#:a 1 #:b 2 3 4 5)
|
||||||
|
[((~and (~seq (~seq k:keyword e:expr) ...)
|
||||||
|
(~seq (keyword-stuff ...)))
|
||||||
|
positional-stuff ...)
|
||||||
|
(syntax->datum #'((k ...) (e ...) (keyword-stuff ...)))])
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
@specsubform[(@#,def[~or h] H-pattern ...)]{
|
||||||
|
|
||||||
|
Like the @Spattern version of @scheme[~or], but matches a term head
|
||||||
|
instead.
|
||||||
|
|
||||||
|
@myexamples[
|
||||||
|
(syntax-parse #'(m #:foo 2 a b c)
|
||||||
|
[(_ (~or (~seq #:foo x) (~seq)) y:id ...)
|
||||||
|
(attribute x)])
|
||||||
|
(syntax-parse #'(m a b c)
|
||||||
|
[(_ (~or (~seq #:foo x) (~seq)) y:id ...)
|
||||||
|
(attribute x)])
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
@specsubform/subs[(@#,def[~optional h] H-pattern maybe-optional-option)
|
||||||
|
([maybe-optional-option
|
||||||
|
(code:line)
|
||||||
|
(code:line #:defaults ([attr-id expr] ...))])]{
|
||||||
|
|
||||||
|
Matches either the given head subpattern or an empty head. If the
|
||||||
|
@scheme[#: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[
|
||||||
|
(syntax-parse #'(m #:foo 2 a b c)
|
||||||
|
[(_ (~optional (~seq #:foo x) #:defaults ([x #'#f])) y:id ...)
|
||||||
|
(attribute x)])
|
||||||
|
(syntax-parse #'(m a b c)
|
||||||
|
[(_ (~optional (~seq #:foo x) #:defaults ([x #'#f])) y:id ...)
|
||||||
|
(attribute x)])
|
||||||
|
(syntax-parse #'(m a b c)
|
||||||
|
[(_ (~optional (~seq #:foo x)) y:id ...)
|
||||||
|
(attribute x)])
|
||||||
|
]
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@specsubform[(@#,def[~describe h] expr H-pattern)]{
|
||||||
|
|
||||||
|
Like the @Spattern version of @scheme[~describe], but matches a head
|
||||||
|
pattern instead.
|
||||||
|
}
|
||||||
|
|
||||||
|
@specsubform[S-pattern]{
|
||||||
|
|
||||||
|
Matches a head of one element, which must be a term matching
|
||||||
|
@scheme[S-pattern].
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@;{--------}
|
||||||
|
|
||||||
|
@section{Ellipsis-head patterns}
|
||||||
|
|
||||||
|
An @deftech{@EHpattern} (abbreviated @svar[EH-pattern]) is pattern
|
||||||
|
that describes some number of terms, like a @tech{@Hpattern}, but may
|
||||||
|
also place contraints on the number of times it occurs in a
|
||||||
|
repetition. They are useful for matching keyword arguments where the
|
||||||
|
keywords may come in any order.
|
||||||
|
|
||||||
|
@myexamples[
|
||||||
|
(define parser1
|
||||||
|
(syntax-parser
|
||||||
|
[((~or (~once (~seq #:a x) #:name "#:a keyword")
|
||||||
|
(~optional (~seq #:b y) #:name "#:b keyword")
|
||||||
|
(~seq #:c z)) ...)
|
||||||
|
'ok]))
|
||||||
|
(parser1 #'(#:a 1))
|
||||||
|
(parser1 #'(#:b 2 #:c 3 #:c 25 #:a 'hi))
|
||||||
|
(parser1 #'(#:a 1 #:a 2))
|
||||||
|
]
|
||||||
|
|
||||||
|
The pattern requires exactly one occurrence of the @scheme[#:a]
|
||||||
|
keyword and argument, at most one occurrence of the @scheme[#:b]
|
||||||
|
keyword and argument, and any number of @scheme[#:c] keywords and
|
||||||
|
arguments. The ``pieces'' can occur in any order.
|
||||||
|
|
||||||
|
Here are the variants of @elem{@EHpattern}:
|
||||||
|
|
||||||
|
@specsubform/subs[(@#,defhere[~once] H-pattern once-option ...)
|
||||||
|
([once-option (code:line #:name name-expr)
|
||||||
|
(code:line #:too-few too-few-message-expr)
|
||||||
|
(code:line #:too-many too-many-message-expr)])]{
|
||||||
|
|
||||||
|
Matches if the inner @scheme[H-pattern] matches. This pattern must be
|
||||||
|
selected exactly once in the match of the entire repetition sequence.
|
||||||
|
|
||||||
|
If the pattern is not chosen in the repetition sequence, then an error
|
||||||
|
is raised with a message, either @scheme[too-few-message-expr] or
|
||||||
|
@schemevalfont{"missing required occurrence of @scheme[name-expr]"}.
|
||||||
|
|
||||||
|
If the pattern is chosen more than once in the repetition sequence,
|
||||||
|
then an error is raised with a message, either
|
||||||
|
@scheme[too-many-message-expr] or @schemevalfont{"too many occurrences
|
||||||
|
of @scheme[name-expr]"}.
|
||||||
|
}
|
||||||
|
|
||||||
|
@specsubform/subs[(@#,def[~optional eh] H-pattern optional-option ...)
|
||||||
|
([optional-option (code:line #:name name-expr)
|
||||||
|
(code:line #:too-many too-many-message-expr)
|
||||||
|
(code:line #:defaults ([attr-id expr] ...))])]{
|
||||||
|
|
||||||
|
Matches if the inner @scheme[H-pattern] matches. This pattern may be used at
|
||||||
|
most once in the match of the entire repetition.
|
||||||
|
|
||||||
|
If the pattern is chosen more than once in the repetition sequence,
|
||||||
|
then an error is raised with a message, either
|
||||||
|
@scheme[too-many-message-expr] or @schemevalfont{"too many occurrences
|
||||||
|
of @scheme[name-expr]"}.
|
||||||
|
|
||||||
|
If the @scheme[#:defaults] option is given, the following attribute
|
||||||
|
bindings are used if the subpattern does not match at all in the
|
||||||
|
sequence. The default attributes must be a subset of the subpattern's
|
||||||
|
attributes.
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@;{--------}
|
||||||
|
|
||||||
|
@section{Action patterns}
|
||||||
|
|
||||||
|
An @deftech{@Apattern} (abbreviated @svar[A-pattern]) does not
|
||||||
|
describe any syntax; rather, it has an effect such as the binding of
|
||||||
|
attributes or the modification of the matching process.
|
||||||
|
|
||||||
|
The grammar describing where an @Apattern may occur may look
|
||||||
|
complicated, but the essence is this: ``@Apatterns don't take up
|
||||||
|
space.'' They can be freely added to a list pattern or inserted into
|
||||||
|
an @scheme[~and] pattern.
|
||||||
|
|
||||||
|
@specsubform[@#,defhere[~!]]{
|
||||||
|
|
||||||
|
The @deftech{cut} operator, written @scheme[~!], eliminates
|
||||||
|
backtracking choice points and commits parsing to the current branch
|
||||||
|
of the pattern it is exploring.
|
||||||
|
|
||||||
Common opportunities for cut-patterns come from recognizing special
|
Common opportunities for cut-patterns come from recognizing special
|
||||||
forms based on keywords. Consider the following expression:
|
forms based on keywords. Consider the following expression:
|
||||||
|
@ -496,9 +781,8 @@ are discarded.
|
||||||
|
|
||||||
@specsubform[(@#,defhere[~bind] [attr-id expr] ...)]{
|
@specsubform[(@#,defhere[~bind] [attr-id expr] ...)]{
|
||||||
|
|
||||||
This pattern matches any term. Its effect is to evaluate the
|
Evaluates the @scheme[expr]s and binds them to the given
|
||||||
@scheme[expr]s and bind them to the given @scheme[attr-id]s as
|
@scheme[attr-id]s as attributes.
|
||||||
attributes.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@specsubform/subs[(@#,defhere[~fail] maybe-fail-condition message-expr)
|
@specsubform/subs[(@#,defhere[~fail] maybe-fail-condition message-expr)
|
||||||
|
@ -506,206 +790,17 @@ attributes.
|
||||||
(code:line #:when condition-expr)
|
(code:line #:when condition-expr)
|
||||||
(code:line #:unless condition-expr)])]{
|
(code:line #:unless condition-expr)])]{
|
||||||
|
|
||||||
This pattern succeeds or fails independent of the term being matched
|
If the condition is absent, or if the @scheme[#:when]
|
||||||
against. If the condition is absent, or if the @scheme[#:when]
|
|
||||||
condition evaluates to a true value, or if the @scheme[#:unless]
|
condition evaluates to a true value, or if the @scheme[#:unless]
|
||||||
condition evaluates to @scheme[#f], then the pattern fails with the
|
condition evaluates to @scheme[#f], then the pattern fails with the
|
||||||
given message. Otherwise the pattern succeeds.
|
given message.
|
||||||
|
|
||||||
Fail patterns can be used together with cut patterns to recognize
|
Fail patterns can be used together with cut patterns to recognize
|
||||||
specific ill-formed terms and address them with specially-created
|
specific ill-formed terms and address them with specially-created
|
||||||
failure messages.
|
failure messages.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@specsubform[(@#,def[~and a] A-pattern ...+)]{
|
||||||
|
|
||||||
@section{H-pattern variants}
|
Performs the actions of each @scheme[A-pattern].
|
||||||
|
|
||||||
An @deftech{H-pattern} (for ``head pattern'') is a pattern that
|
|
||||||
describes some number of terms that occur at the head of some list
|
|
||||||
(possibly an improper list). An H-pattern's usefulness comes from
|
|
||||||
being able to match heads of different lengths. H-patterns are useful
|
|
||||||
for specifying optional forms such as keyword arguments.
|
|
||||||
|
|
||||||
Here are the variants of @tech{H-pattern}:
|
|
||||||
|
|
||||||
@specsubform[pvar-id:splicing-syntax-class-id]{
|
|
||||||
|
|
||||||
Equivalent to @scheme[(~var pvar-id
|
|
||||||
splicing-syntax-class-id)].
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@specsubform/subs[(@#,def[~var h] pvar-id splicing-syntax-class)
|
|
||||||
([splicing-syntax-class splicing-syntax-class-id
|
|
||||||
(splicing-syntax-class-id arg-expr ...)])]{
|
|
||||||
|
|
||||||
Pattern variable annotated with a @tech{splicing syntax
|
|
||||||
class}. Similar to a normal @tech{annotated pattern variable}, except
|
|
||||||
matches a head pattern.
|
|
||||||
}
|
|
||||||
|
|
||||||
@specsubform[(@#,defhere[~seq] . L-pattern)]{
|
|
||||||
|
|
||||||
Matches a head whose elements, if put in a list, would match the given
|
|
||||||
@tech{L-pattern}.
|
|
||||||
|
|
||||||
@myexamples[
|
|
||||||
(syntax-parse #'(1 2 3 4)
|
|
||||||
[((~seq 1 2 3) 4) 'ok])
|
|
||||||
]
|
|
||||||
|
|
||||||
See also the section on @tech{EH-patterns} for more interesting
|
|
||||||
examples of @scheme[~seq].
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@specsubform[(@#,def[~and h] H-pattern ...)]{
|
|
||||||
|
|
||||||
Like the S-pattern version of @scheme[~and], but matches a term head
|
|
||||||
instead.
|
|
||||||
|
|
||||||
@myexamples[
|
|
||||||
(syntax-parse #'(#:a 1 #:b 2 3 4 5)
|
|
||||||
[((~and (~seq (~seq k:keyword e:expr) ...)
|
|
||||||
(~seq keyword-stuff ...))
|
|
||||||
positional-stuff ...)
|
|
||||||
(syntax->datum #'((k ...) (e ...) (keyword-stuff ...)))])
|
|
||||||
]
|
|
||||||
|
|
||||||
The H-pattern variant of @scheme[~and] requires that all of the
|
|
||||||
subpatterns be strictly @tech{H-patterns} and not
|
|
||||||
@tech{S-patterns}. This is to prevent typos like the following, a
|
|
||||||
variant of the previous example with the second @scheme[~seq] omitted:
|
|
||||||
|
|
||||||
@myexamples[
|
|
||||||
(syntax-parse #'(#:a 1 #:b 2 3 4 5)
|
|
||||||
[((~and (~seq (~seq k:keyword e:expr) ...)
|
|
||||||
(keyword-stuff ...))
|
|
||||||
positional-stuff ...)
|
|
||||||
(syntax->datum #'((k ...) (e ...) (keyword-stuff ...)))])
|
|
||||||
(code:comment "If the example above were allowed, it would be equivalent to this:")
|
|
||||||
(syntax-parse #'(#:a 1 #:b 2 3 4 5)
|
|
||||||
[((~and (~seq (~seq k:keyword e:expr) ...)
|
|
||||||
(~seq (keyword-stuff ...)))
|
|
||||||
positional-stuff ...)
|
|
||||||
(syntax->datum #'((k ...) (e ...) (keyword-stuff ...)))])
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
@specsubform[(@#,def[~or h] H-pattern ...)]{
|
|
||||||
|
|
||||||
Like the S-pattern version of @scheme[~or], but matches a term head
|
|
||||||
instead.
|
|
||||||
|
|
||||||
@myexamples[
|
|
||||||
(syntax-parse #'(m #:foo 2 a b c)
|
|
||||||
[(_ (~or (~seq #:foo x) (~seq)) y:id ...)
|
|
||||||
(attribute x)])
|
|
||||||
(syntax-parse #'(m a b c)
|
|
||||||
[(_ (~or (~seq #:foo x) (~seq)) y:id ...)
|
|
||||||
(attribute x)])
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
@specsubform/subs[(@#,def[~optional h] H-pattern maybe-optional-option)
|
|
||||||
([maybe-optional-option
|
|
||||||
(code:line)
|
|
||||||
(code:line #:defaults ([attr-id expr] ...))])]{
|
|
||||||
|
|
||||||
Matches either the given head subpattern or an empty head. If the
|
|
||||||
@scheme[#: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[
|
|
||||||
(syntax-parse #'(m #:foo 2 a b c)
|
|
||||||
[(_ (~optional (~seq #:foo x) #:defaults ([x #'#f])) y:id ...)
|
|
||||||
(attribute x)])
|
|
||||||
(syntax-parse #'(m a b c)
|
|
||||||
[(_ (~optional (~seq #:foo x) #:defaults ([x #'#f])) y:id ...)
|
|
||||||
(attribute x)])
|
|
||||||
(syntax-parse #'(m a b c)
|
|
||||||
[(_ (~optional (~seq #:foo x)) y:id ...)
|
|
||||||
(attribute x)])
|
|
||||||
]
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@specsubform[(@#,def[~describe h] expr H-pattern)]{
|
|
||||||
|
|
||||||
Like the S-pattern version of @scheme[~describe], but matches a head
|
|
||||||
pattern instead.
|
|
||||||
}
|
|
||||||
|
|
||||||
@specsubform[S-pattern]{
|
|
||||||
|
|
||||||
Matches a head of one element, which must be a term matching the given
|
|
||||||
@tech{S-pattern}.
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@;{--------}
|
|
||||||
|
|
||||||
@section{EH-pattern forms}
|
|
||||||
|
|
||||||
An @deftech{EH-pattern} (for ``ellipsis-head pattern'') is pattern
|
|
||||||
that describes some number of terms, like an @tech{H-pattern}, but may
|
|
||||||
also place contraints on the number of times it occurs in a
|
|
||||||
repetition. EH-patterns (and ellipses) are useful for matching keyword
|
|
||||||
arguments where the keywords may come in any order.
|
|
||||||
|
|
||||||
@myexamples[
|
|
||||||
(define parser1
|
|
||||||
(syntax-parser
|
|
||||||
[((~or (~once (~seq #:a x) #:name "#:a keyword")
|
|
||||||
(~optional (~seq #:b y) #:name "#:b keyword")
|
|
||||||
(~seq #:c z)) ...)
|
|
||||||
'ok]))
|
|
||||||
(parser1 #'(#:a 1))
|
|
||||||
(parser1 #'(#:b 2 #:c 3 #:c 25 #:a 'hi))
|
|
||||||
(parser1 #'(#:a 1 #:a 2))
|
|
||||||
]
|
|
||||||
|
|
||||||
The pattern requires exactly one occurrence of the @scheme[#:a]
|
|
||||||
keyword and argument, at most one occurrence of the @scheme[#:b]
|
|
||||||
keyword and argument, and any number of @scheme[#:c] keywords and
|
|
||||||
arguments. The ``pieces'' can occur in any order.
|
|
||||||
|
|
||||||
Here are the variants of @tech{EH-pattern}:
|
|
||||||
|
|
||||||
@specsubform/subs[(@#,defhere[~once] H-pattern once-option ...)
|
|
||||||
([once-option (code:line #:name name-expr)
|
|
||||||
(code:line #:too-few too-few-message-expr)
|
|
||||||
(code:line #:too-many too-many-message-expr)])]{
|
|
||||||
|
|
||||||
Matches if the inner H-pattern matches. This pattern must be selected
|
|
||||||
exactly once in the match of the entire repetition sequence.
|
|
||||||
|
|
||||||
If the pattern is not chosen in the repetition sequence, then an error
|
|
||||||
is raised with a message, either @scheme[too-few-message-expr] or
|
|
||||||
@schemevalfont{"missing required occurrence of @scheme[name-expr]"}.
|
|
||||||
|
|
||||||
If the pattern is chosen more than once in the repetition sequence,
|
|
||||||
then an error is raised with a message, either
|
|
||||||
@scheme[too-many-message-expr] or @schemevalfont{"too many occurrences
|
|
||||||
of @scheme[name-expr]"}.
|
|
||||||
}
|
|
||||||
|
|
||||||
@specsubform/subs[(@#,def[~optional eh] H-pattern optional-option ...)
|
|
||||||
([optional-option (code:line #:name name-expr)
|
|
||||||
(code:line #:too-many too-many-message-expr)
|
|
||||||
(code:line #:defaults ([attr-id expr] ...))])]{
|
|
||||||
|
|
||||||
Matches if the inner H-pattern matches. This pattern may be used at
|
|
||||||
most once in the match of the entire repetition.
|
|
||||||
|
|
||||||
If the pattern is chosen more than once in the repetition sequence,
|
|
||||||
then an error is raised with a message, either
|
|
||||||
@scheme[too-many-message-expr] or @schemevalfont{"too many occurrences
|
|
||||||
of @scheme[name-expr]"}.
|
|
||||||
|
|
||||||
If the @scheme[#:defaults] option is given, the following attribute
|
|
||||||
bindings are used if the subpattern does not match at all in the
|
|
||||||
sequence. The default attributes must be a subset of the subpattern's
|
|
||||||
attributes.
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -191,10 +191,9 @@ The second pattern matches unparenthesized identifiers. The @scheme[e]
|
||||||
attribute is bound using a @scheme[#:with] clause, which matches the
|
attribute is bound using a @scheme[#:with] clause, which matches the
|
||||||
pattern @scheme[e] against the syntax from evaluating @scheme[#'#f].
|
pattern @scheme[e] against the syntax from evaluating @scheme[#'#f].
|
||||||
|
|
||||||
Optional keyword arguments are supported via ``head patterns'' (called
|
Optional keyword arguments are supported via @tech{head
|
||||||
@tech{H-patterns} in the reference documentation). Unlike normal
|
patterns}. Unlike normal patterns, which match one term, head patterns
|
||||||
patterns, which match one term, head patterns can match a variable
|
can match a variable number of subterms in a list.
|
||||||
number of subterms in a list.
|
|
||||||
|
|
||||||
Suppose @schemekeywordfont{mylet} accepted an optional
|
Suppose @schemekeywordfont{mylet} accepted an optional
|
||||||
@scheme[#:check] keyword with one argument, a procedure that would be
|
@scheme[#:check] keyword with one argument, a procedure that would be
|
||||||
|
@ -394,7 +393,7 @@ structures can share syntax class definitions.
|
||||||
(pattern syntax-pattern pattern-directive ...)])]{
|
(pattern syntax-pattern pattern-directive ...)])]{
|
||||||
|
|
||||||
Defines @scheme[name-id] as a @deftech{syntax class}, which
|
Defines @scheme[name-id] as a @deftech{syntax class}, which
|
||||||
encapsulates one or more @tech{S-patterns}.
|
encapsulates one or more @tech{single-term patterns}.
|
||||||
|
|
||||||
When the @scheme[arg-id]s are present, they are bound as variables in
|
When the @scheme[arg-id]s are present, they are bound as variables in
|
||||||
the body. The body of the syntax-class definition contains a non-empty
|
the body. The body of the syntax-class definition contains a non-empty
|
||||||
|
@ -449,7 +448,8 @@ These options have the same meaning as in @scheme[syntax-parse].
|
||||||
}
|
}
|
||||||
|
|
||||||
Each variant of a syntax class is specified as a separate
|
Each variant of a syntax class is specified as a separate
|
||||||
@scheme[pattern]-form whose syntax pattern is an @tech{S-pattern}.
|
@scheme[pattern]-form whose syntax pattern is a @tech{single-term
|
||||||
|
pattern}.
|
||||||
}
|
}
|
||||||
|
|
||||||
@defform*[#:literals (pattern)
|
@defform*[#:literals (pattern)
|
||||||
|
@ -459,13 +459,13 @@ Each variant of a syntax class is specified as a separate
|
||||||
stxclass-variant ...+)]]{
|
stxclass-variant ...+)]]{
|
||||||
|
|
||||||
Defines @scheme[name-id] as a @deftech{splicing syntax class},
|
Defines @scheme[name-id] as a @deftech{splicing syntax class},
|
||||||
analogous to a @tech{syntax class} but encapsulating @tech{H-patterns}
|
analogous to a @tech{syntax class} but encapsulating @tech{head
|
||||||
rather than @tech{S-patterns}.
|
patterns} rather than @tech{single-term patterns}.
|
||||||
|
|
||||||
The options are the same as for @scheme[define-syntax-class].
|
The options are the same as for @scheme[define-syntax-class].
|
||||||
|
|
||||||
Each variant of a splicing syntax class is specified as a separate
|
Each variant of a splicing syntax class is specified as a separate
|
||||||
@scheme[pattern]-form whose syntax pattern is an @tech{H-pattern}.
|
@scheme[pattern]-form whose syntax pattern is a @tech{head pattern}.
|
||||||
}
|
}
|
||||||
|
|
||||||
@defform[#:literals (pattern)
|
@defform[#:literals (pattern)
|
||||||
|
@ -476,9 +476,9 @@ class. The variant accepts syntax matching the given syntax pattern
|
||||||
with the accompanying @tech{pattern directives}.
|
with the accompanying @tech{pattern directives}.
|
||||||
|
|
||||||
When used within @scheme[define-syntax-class], @scheme[syntax-pattern]
|
When used within @scheme[define-syntax-class], @scheme[syntax-pattern]
|
||||||
should be an @tech{S-pattern}; within
|
should be a @tech{single-term pattern}; within
|
||||||
@scheme[define-splicing-syntax-class], it should be an
|
@scheme[define-splicing-syntax-class], it should be a @tech{head
|
||||||
@tech{H-pattern}.
|
pattern}.
|
||||||
|
|
||||||
The attributes of the variant are the attributes of the pattern
|
The attributes of the variant are the attributes of the pattern
|
||||||
together with all attributes bound by @scheme[#:with] clauses,
|
together with all attributes bound by @scheme[#:with] clauses,
|
||||||
|
|
Loading…
Reference in New Issue
Block a user