Re: [racket-users] syntax-parse: using expr/c with ~optional

2017-03-22 Thread Dupéron Georges
> (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

2017-03-21 Thread Philip McGrath
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 Knauth  wrote:

>
> 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

2017-03-20 Thread Alex Knauth

> 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.