Re: [racket-users] syntax-parse attributes in macro-generated macros

2017-09-18 Thread Philip McGrath
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

2017-09-18 Thread Ryan Culpepper

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

2017-09-16 Thread Philip McGrath
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.