Hi everyone,

I'm writing a macro-generating macro where the generated macro uses
`syntax-parse`, and I can't figure out how to work with attributes using
the dot syntax where the base identifier is generated by the outer macro.

For example, consider the following macro:

(define-syntax example-macro
  (syntax-parser
    [(_ (~alt (~optional (~seq #:a (~var a
                                         (expr/c #'symbol?)))
                         #:defaults ([a.c #''default-a]))
              (~optional (~seq #:b (~var b
                                         (expr/c #'string?)))
                         #:defaults ([b.c #'"default-b"])))
        ...)
     #`(list a.c b.c)]))

I have a macro like `example-macro`, but more complicated and with many,
many more potential keyword arguments, so I wanted to write a macro that
would let me define `example-macro` with a more declarative syntax, like
this:

(define-example-macro/working generated-example-macro
  [#:a 'default-a symbol?]
  [#:b "default-b" string?])

My initial attempt looked something like this:

(define-syntax (define-example-macro/buggy stx)
  (define-syntax-class arg-clause
    (pattern [kw:keyword default:expr contract:expr]))
  (syntax-parse stx
    [(_ name clause:arg-clause ...+)
     ;#:with (arg ...) (generate-temporaries #'(clause.kw ...))
     ;#:with (arg.c ...) (generate-temporaries #'(clause.kw ...))
     #`(define-syntax name
         (syntax-parser
           [(_ (~alt (~optional
                      (~seq clause.kw (~var arg (expr/c #'clause.contract)))
                      #:defaults ([arg.c #'clause.default]))
                     ...)
               (... ...))
            #`(list arg.c ...)]))]))

which raises a syntax error "syntax: no pattern variables before ellipsis
in template".

The problem seems to be that `arg.c` is not recognized as a pattern
variable derived from `arg`. I tried several variants on this, none of
which allowed me to refer to `arg.c`. For example, if I uncomment the two
`#:with` lines, I get the error "~optional: attribute bound in defaults but
not in pattern".

I eventually figured out a tricky way to avoid using dotted attributes
altogether (see below), but it's rather less elegant than the non-working
way. I am hoping there is a way to generate the right identifier for
`arg.c` somehow.

Thanks,
Philip

(define-syntax (define-example-macro/working stx)
  (define-syntax-class arg-clause
    (pattern [kw:keyword default:expr contract:expr]
             #:with arg (generate-temporary #'kw)
             ))
  (syntax-parse stx
    [(_ name clause:arg-clause ...+)
     #:with add-contract (generate-temporary 'add-contract)
     #:with (unsyntax-arg.c ...)
     #`(#,@(for/list ([arg-stx (in-list (syntax-e #'(clause.arg ...)))]
                      [contract-stx (in-list (syntax-e #'(clause.contract
...)))])
             (with-syntax ([arg arg-stx]
                           [contract contract-stx])
               #'#,(add-contract #'arg #'contract))))
     #`(define-syntax (name inner-stx)
         (define (add-contract arg-stx contract-stx [err-name "name goes
here"])
           (syntax-parse arg-stx
             [the-arg
              #:declare the-arg (expr/c contract-stx
                                        #:name err-name
                                        #:macro #'name)
              #'the-arg.c]))
         (syntax-parse inner-stx
           [(_ (~alt (~optional
                      (~seq clause.kw clause.arg)
                      #:defaults ([clause.arg #'clause.default]))
                     ...)
               (... ...))
            #`(list unsyntax-arg.c ...)]))]))

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

Reply via email to