Re: [racket-users] syntax-parse: using expr/c with ~optional
> (prefix 6 5 4) raises the same error as before, and the definition of > prefix/parse complains "syntax-parse: duplicate attribute in: tail". This is because ~or behaves differently under ellipses, and nested ~or are just inlined. Your code for prefix/parse is therefore equivalent to (~or alt1 (~seq #:tail) (~and (~seq) (~parse tail #'null))) ... To make a ~or pattern behave as a normal ~or, and not as a list of possibly-repeated elements, you can wrap it with a dummy ~and, i.e. writing (~or alt1 alt2 (~and (~or foo bar)) alt4) ... instead of (~or alt1 alt2 (~or foo bar) alt4) ... I like to define a (~either . pats) pattern expander which aliases to (~and (~or . pats)), for better readability [1] . In your case, since you want to limit it to a single occurrence anyway, you can simply wrap the inner ~or with ~once, as follows: #lang racket (require (for-syntax syntax/parse)) (define-syntax (prefix/parse stx) (syntax-parse stx [(_ (~or (~seq nat:exact-nonnegative-integer) (~once (~or (~seq #:tail tail) (~and (~seq) (~parse tail #'null) ...) #:declare tail (expr/c #'(listof natural-number/c)) #'(list* nat ... tail.c)])) The issue with this solution, however, is that it allows the empty sequence (~seq) to be matched as part of a ellipsis-head pattern. This means that the (~seq) could match anywhere, and, save for the ~once, could match an infinite amount of times without consuming any element. To prevent such issues, syntax/parse guards against this, and you will get the following error: syntax-parse: an ellipsis-head pattern matched an empty sequence The simplest solution I can see is to re-bind the tail attribute to a real pattern variable, safe in the knowledge that the tail attribute is never #f, thanks to the #:defaults (note that if you nest uses of ~optional, e.g. (~optional (~seq (~seq a (~optional b #:defaults ([b c]))) ...)), then I think this is not true anymore, you'd have to provide #:defaults for the outer ~optional too. I'll use #:with here, but you could equally use a {~parse pvar-tail #'tail) in the pattern, somewhere after the (~or . pats) ...: #lang racket (require (for-syntax syntax/parse)) (define-syntax (prefix/parse stx) (syntax-parse stx [(_ (~or (~seq nat:exact-nonnegative-integer) (~optional (~seq #:tail tail) #:defaults ([tail #'null]))) ...) #:with pvar-tail #'tail #:declare pvar-tail (expr/c #'(listof natural-number/c)) #'(list* nat ... pvar-tail.c)])) (prefix/parse 1 2 3) (prefix/parse 1 2 3 #:tail 42) ;; contract violation, as expected. It would probably be possible to abstract this using my extensible-parser-specifications library [2] which defines a ~seq-no-order similar to the one by Alexander Knauth, but allows some "post" operations which are executed after matching the whole sequence. I would recommend against it, however, as my library has severe limitations, and could really use a redesign (which might need some changes in syntax/parse itself, as achieving these "post" operations required a few hacks). Alternatively, it would make sense to fix #:declare so that it handles gracefully #f values. Could you file an issue for this so that it is not forgotten? [1]: http://docs.racket-lang.org/phc-toolkit/syntax-parse_helpers.html#%28form._%28%28submod._%28lib._phc-toolkit%2Fsyntax-parse..rkt%29._typed%29._~7eeither%29%29 [2]: http://docs.racket-lang.org/extensible-parser-specifications/ -- You received this message because you are subscribed to the Google Groups "Racket Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to racket-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: [racket-users] syntax-parse: using expr/c with ~optional
Thanks! Is there an equivalent approach that works to replace ~optional as a repetition constraint? Given: (define-syntax (prefix stx) > (syntax-parse stx > [(_ (~or (~seq nat:exact-nonnegative-integer) > (~optional (~seq #:tail tail) > #:defaults ([tail #'null]))) > ...) > #:declare tail (expr/c #'(listof natural-number/c)) > #'(list* nat ... tail.c)])) > (define-syntax (prefix/parse stx) > (syntax-parse stx > [(_ (~or (~seq nat:exact-nonnegative-integer) > (~or (~seq #:tail tail) > (~and (~seq) (~parse tail #'null > ...) > #:declare tail (expr/c #'(listof natural-number/c)) > #'(list* nat ... tail.c)])) (prefix 6 5 4) raises the same error as before, and the definition of prefix/parse complains "syntax-parse: duplicate attribute in: tail". On Mon, Mar 20, 2017 at 1:18 PM Alex Knauthwrote: > > On Mar 20, 2017, at 11:04 AM, Philip McGrath > wrote: > > Using expr/c to attach a contract to a macro sub-pattern doesn't seem to > work with ~optional, even when the attribute is bound with #:defaults. > > For example, this program: > > #lang racket > > (require (for-syntax syntax/parse)) > (define-syntax (example stx) > (syntax-parse stx > [(_ (~optional (~seq #:return val) >#:defaults ([val #'42]))) > #:declare val (expr/c #'(or/c list? #f)) > #'val.c])) > (example) > > reports the following error: > > val.c: bad attribute value for syntax template > attribute value: #f > expected for attribute: syntax > sub-value: #f > expected for sub-value: syntax in: val.c > > > Is there a better way to do this? > > > This is because the `val` in the #:defaults is treated as just an > attribute name, not a variable pattern, and syntax-classes like `expr/c` > can only apply to variable patterns. One way to work around this is to use > ~or and ~parse to put it in a pattern position: > > #lang racket > (require (for-syntax syntax/parse)) > (define-syntax example > (syntax-parser > [(_ (~or (~seq #:return val) > (~and (~seq) (~parse val #'42 > #:declare val (expr/c #'(or/c list? #f)) > #'val.c])) > (example) > > This raises the contract violation you expected. > > Alex Knauth > -- You received this message because you are subscribed to the Google Groups "Racket Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to racket-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: [racket-users] syntax-parse: using expr/c with ~optional
> On Mar 20, 2017, at 11:04 AM, Philip McGrathwrote: > > Using expr/c to attach a contract to a macro sub-pattern doesn't seem to work > with ~optional, even when the attribute is bound with #:defaults. > > For example, this program: > #lang racket > (require (for-syntax syntax/parse)) > (define-syntax (example stx) > (syntax-parse stx > [(_ (~optional (~seq #:return val) >#:defaults ([val #'42]))) > #:declare val (expr/c #'(or/c list? #f)) > #'val.c])) > (example) > reports the following error: > val.c: bad attribute value for syntax template > attribute value: #f > expected for attribute: syntax > sub-value: #f > expected for sub-value: syntax in: val.c > > Is there a better way to do this? This is because the `val` in the #:defaults is treated as just an attribute name, not a variable pattern, and syntax-classes like `expr/c` can only apply to variable patterns. One way to work around this is to use ~or and ~parse to put it in a pattern position: #lang racket (require (for-syntax syntax/parse)) (define-syntax example (syntax-parser [(_ (~or (~seq #:return val) (~and (~seq) (~parse val #'42 #:declare val (expr/c #'(or/c list? #f)) #'val.c])) (example) This raises the contract violation you expected. Alex Knauth -- You received this message because you are subscribed to the Google Groups "Racket Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to racket-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
[racket-users] syntax-parse: using expr/c with ~optional
Using expr/c to attach a contract to a macro sub-pattern doesn't seem to work with ~optional, even when the attribute is bound with #:defaults. For example, this program: > #lang racket (require (for-syntax syntax/parse)) > (define-syntax (example stx) > (syntax-parse stx > [(_ (~optional (~seq #:return val) >#:defaults ([val #'42]))) > #:declare val (expr/c #'(or/c list? #f)) > #'val.c])) > (example) reports the following error: > val.c: bad attribute value for syntax template > attribute value: #f > expected for attribute: syntax > sub-value: #f > expected for sub-value: syntax in: val.c Is there a better way to do this? -- You received this message because you are subscribed to the Google Groups "Racket Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to racket-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.