rest.scrbl (4370B)
1 #lang scribble/manual 2 @require[scribble/example 3 "utils.rkt" 4 @for-label[phc-toolkit/untyped 5 extensible-parser-specifications 6 generic-syntax-expanders 7 racket/base 8 syntax/parse 9 (only-in racket/base [... …])]] 10 11 @title{Parsing the tail of improper lists} 12 13 @defform[#:kind "eh-mixin expander" 14 {~lift-rest pat}]{ 15 Lifts @racket[pat] out of the current mixin, so that it is used as a pattern to 16 match the tail of the improper list being matched. It is subject to the 17 following restrictions: 18 @itemlist[ 19 @item{@racket[~lift-rest] is allowed only within @racket[~no-order], but not 20 within @racket[~seq-no-order]. @racket[~seq-no-order] always matches against 21 a proper sequence of elements, while @racket[~no-order] may match a proper or 22 improper list.} 23 @item{The tail of the improper list must not be a pair, otherwise the 24 @racket[car] would have been included in the main part of the list.} 25 @item{The @racket[pat] is used to match the tail only if its surrounding 26 pattern successfully matched some elements of the main section of the list. 27 28 If the @racket[{~lift-rest pat}] is the only pattern present within an 29 alternative, then it is always used. 30 31 @examples[#:eval (make-evaluator) 32 (syntax-parse #'(x y z . 1) 33 [(~no-order {~lift-rest r:nat} i:id) 34 (syntax->datum #'(r i ...))])]} 35 @item{ 36 Among the lifted rest patterns which are considered (see the point 37 above), only one may successfully match. An error is raised if two or more 38 lifted rest patterns successfully match against the tail of the list. 39 40 @examples[#:eval (make-evaluator) 41 (eval:no-prompt 42 (define p 43 (syntax-parser 44 [(~no-order {~and {~literal x} 45 {~lift-rest rn:nat} 46 {~lift-rest ri:id}} 47 {~and {~literal y} 48 {~lift-rest rs:str} 49 {~lift-rest rj:id}}) 50 'match] 51 #;[_ 52 'fail]))) 53 (code:line (p #'(x . 1)) (code:comment "rn and ri considered, rn matched")) 54 (code:line (p #'(x . z)) (code:comment "rn and ri considered, ri matched")) 55 (code:line (p #'(y . "a")) (code:comment "rs and rj considered, rs matched")) 56 (code:line (p #'(y . z)) (code:comment "rs and rj considered, rj matched")) 57 (code:line (p #'(x y . 1)) (code:comment "all four considered, rn matched")) 58 (eval:alts (code:line (p #'(x y . z)) (code:comment "all four considered, both ri and rj matched")) 59 (eval:error (p #'(x y . z))))] 60 61 The rationale is that selecting the first lifted rest pattern that matches 62 would result in unclear behaviour, as the order of the alternative clauses 63 should not be significant.} 64 @item{Post and global operations can be used within the @racket[pat]. This 65 combination of features is not thoroughly tested, however. Please report any 66 issues you run into.}]} 67 68 @defform[#:kind "eh-mixin expander" 69 {~as-rest pat ...}]{ 70 71 Like @racket[~seq], but the @racket[pat]s are injected as part of the same 72 @racket[~or] as @racket[~lift-rest]. This means that syntax/parse will not 73 throw an error for the following code: 74 75 @examples[#:eval (make-evaluator) 76 (eval:no-prompt 77 (define p2 78 (syntax-parser 79 [(~no-order {~once name:id} 80 {~once message:str} 81 (~once (~or {~as-rest val:nat} 82 {~seq {~lift-rest val:nat}}))) 83 (syntax->datum 84 #'(#:name name #:messsage message #:val val))]))) 85 (code:line (p2 #'(x 123 "msg")) (code:comment "matched by ~as-rest")) 86 (code:line (p2 #'(x "msg" 123)) (code:comment "matched by ~as-rest")) 87 (code:line (p2 #'(x "msg" . 456)) (code:comment "matched by ~lift-rest")) 88 (eval:alts (code:line (p2 #'(x "msg" 123 . 456)) (code:comment "can't have both")) 89 (eval:error (p2 #'(x "msg" 123 . 456))))]}