[racket] syntax-parse questions

From: Ryan Culpepper (ryanc at ccs.neu.edu)
Date: Tue Apr 12 17:38:10 EDT 2011

On 04/12/2011 03:48 PM, Eric Tanter wrote:
> Hi,
> I'm starting to play with syntax-parse. Looks really great, but also quite complex.
> Here are some newbie questions.
> (the example is based on the defmac of Eli)
> I use two optional declaration:
> (define-syntax (defmac2 stx)
>    (syntax-parse stx
>      [(defmac2 (name:identifier . xs)
>         (~optional (~seq #:keywords key:identifier ...))
>         (~optional (~seq #:captures cap:identifier ...))
>         body:expr)
>   #'(define-syntax (name stx)
>       (syntax-case stx (key ...)
>         [(name . xs)
>          (with-syntax ([cap (datum->syntax stx 'cap stx)] ...)
>            (syntax body))]))])))
> 1. according to the docs, I can pass #:name in an ~optional.
> if I do so:
> (~optional (~seq #:keywords key:identifier ...) #:name "foo")
> I get:
> ~optional: unexpected keyword, expected one of (#:defaults) in: #:name
> (according to the docs there are 3 keywords for optional, name, too-many, and defaults)

There are two kinds of ~optional: one is for head patterns and the other 
is for ellipsis-head patterns. The #:name keyword is only allowed in the 
latter case.

> 2. my macro above works ok only if both #:keywords and #:captures are given, because if they are not, the key and cap variables get bound to #f.
> And I get messages like:
> key: attribute is bound to non-syntax value: #f in: key
> I therefore want to specify a default that is more reasonable than #f in my case. I looked into the #:defaults parameter of ~optional, but unsuccessfully.
> I don't know how to have it behave as I'd expect, that is, if none is given, then key ... is "zero occurrences".

Ah, sorry, the docs are incomplete for #:defaults; I'll fix that. If the 
ellipsis depth is not 0 (for example, 'key' has a depth of 1), you must 
specify the depth too. I think this is what you want:

(define-syntax (defmac2 stx)
   (syntax-parse stx
     [(defmac2 (name:identifier . xs)
        (~optional (~seq #:keywords key:identifier ...)
                   #:defaults ([(key 1) '()]))
        (~optional (~seq #:captures cap:identifier ...)
                   #:defaults ([(cap 1) '()]))
      #'(define-syntax (name stx)
          (syntax-case stx (key ...)
            [(name . xs)
             (with-syntax ([cap (datum->syntax stx 'cap stx)] ...)
               (syntax body))]))]))

I wish I'd made #:defaults take patterns on the left-hand sides instead. 
I'll see if I can add something like that before the upcoming release.

Hope that helps,

Posted on the users mailing list.