Re: [racket-users] syntax-parse attributes in macro-generated macros
Thanks, that was more obvious than I expected. Aside from improving readability, the definition and use combined of the macro-defining version comes out to about 40% of the original in terms of lines of code, and it was trivial to have the same macro also expand into a seperate submodule to generate the documentation automatically. -Philip On Mon, Sep 18, 2017 at 4:41 PM, Ryan Culpepper wrote: > On 09/17/2017 01:00 AM, Philip McGrath wrote: > >> [...] >> >> 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". >> > > If you uncomment the two "#:with" lines and look at the first expansion > step of your example, you get the following: > > (define-example-macro generated-example-macro > [#:a 'default-a symbol?] > [#:b "default-b" string?]) > => > (define-syntax generated-example-macro > (syntax-parser > ((_ > (~alt > (~optional > (~seq #:a (~var a5 (expr/c #'symbol?))) > #:defaults > ((a7 #''default-a))) > (~optional > (~seq #:b (~var b6 (expr/c #'string?))) > #:defaults > ((b8 #'"default-b" > ...) >#`(list a7 b8 > > The problem is that a7 and b8 need to be a5.c and b6.c, respectively. So > rather than two independent calls to generate-temporaries, you should build > the arg.cs from the args: > > #:with (arg ...) (generate-temporaries #'(clause.kw ...)) > #:with (arg.c ...) (map (lambda (arg) > (format-id arg "~a.c" arg)) > (syntax->list #'(arg ...))) > > Ryan > -- 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 attributes in macro-generated macros
On 09/17/2017 01:00 AM, Philip McGrath wrote: [...] 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". If you uncomment the two "#:with" lines and look at the first expansion step of your example, you get the following: (define-example-macro generated-example-macro [#:a 'default-a symbol?] [#:b "default-b" string?]) => (define-syntax generated-example-macro (syntax-parser ((_ (~alt (~optional (~seq #:a (~var a5 (expr/c #'symbol?))) #:defaults ((a7 #''default-a))) (~optional (~seq #:b (~var b6 (expr/c #'string?))) #:defaults ((b8 #'"default-b" ...) #`(list a7 b8 The problem is that a7 and b8 need to be a5.c and b6.c, respectively. So rather than two independent calls to generate-temporaries, you should build the arg.cs from the args: #:with (arg ...) (generate-temporaries #'(clause.kw ...)) #:with (arg.c ...) (map (lambda (arg) (format-id arg "~a.c" arg)) (syntax->list #'(arg ...))) Ryan -- 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 attributes in macro-generated macros
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.