Hello,

I have a working macro written using `syntax-parse`, but it still has
some kinks that need to be worked out. What I want the macro to do is
define a function and as it as input to another function. Example:

  (define-nvim-function (foo bar baz) #:name "foo" #:sync #f
    (display bar)
    (display baz))

This would expand to

  (define (foo bar baz)
    (display bar)
    (display baz))
  (register-nvim-function! foo "foo" #:sync #f)

The `register-nvim-function!` function is defined like this:

  (define (register-nvim-function! proc name
                                   #:range [range     #f]
                                   #:eval  [eval  (void)]
                                   #:sync  [sync?     #f])
    ...)

The point is that `proc` and `name` are mandatory, but the keyword
arguments are optional. I want the keyword arguments of the macro to be
optional as well, except for the name, and their order should not
matter. Here is what I got so far:


  (define-syntax (define-nvim-function stx)
    (syntax-parse stx
      [(define-function (head:id arg-id:id ...)
                        (~alt (~once     (~seq #:name name:expr)
                                         #:name "#:name name")
                              (~optional (~seq #:range range:expr)
                                         #:name "#:range range"
                                         #:defaults ([range #'#f]))
                              (~optional (~seq #:eval eval:expr)
                                         #:name "#:eval eval"
                                         #:defaults ([eval #'(void)]))
                              (~optional (~seq #:sync sync?:expr)
                                         #:name "#:sync sync?"
                                         #:defaults ([sync? #'#f])))
                        ...
         body:expr ...+)
       #'(define-function head #:name name #:range range #:eval eval #:sync 
sync?
           (λ (arg-id ...) body ...)) ]
      [(define-function head:id
                        (~alt (~once     (~seq #:name name:expr)
                                         #:name "#:name name")
                              (~optional (~seq #:range range:expr)
                                         #:name "#:range range"
                                         #:defaults ([range #'#f]))
                              (~optional (~seq #:eval eval:expr)
                                         #:name "#:eval eval"
                                         #:defaults ([eval #'(void)]))
                              (~optional (~seq #:sync sync?:expr)
                                         #:name "#:sync sync?"
                                         #:defaults ([sync? #'#f])))
                        ...
         body:expr)
       #'(begin
           (define head body)
           (register-function! head name #:range range #:eval eval #:sync 
sync?))]))

The macros supports two variants, similar to how `define` allows two
ways of defining a function. The problems with this implementation are:

- The giant blob of keyword arguments is repeated twice
- The template is listing all the keyword arguments the function can
  take

I was thinking of a macro more like this:

  (define-syntax (define-nvim-function stx)
    (define-splicing-syntax-class option
      (pattern (#:name    name:expr))
      (pattern (#:range range?:expr))
      (pattern (#:eval   eval?:expr))
      (pattern (#:sync   sync?:expr)))
    (syntax-parse stx
      [(define-function (head:id arg-id:id ...) option:option ...
         body:expr ...+)
       #'(define-function head option ...
           (λ (arg-id ...) body ...)) ]
      [(define-function head:id option.option ...
         body:expr)
       #'(begin
           (define head body)
           (register-function! head option))]))

This won't work though. First I lose the optional/unique specifications
from above, second the keyword-value pairs are wrapped in parentheses
for some reason. Expansion becomes

  (register-function! foo (#:name "foo") (#:sync #f))
  ;; instead of
  (register-function! foo #:name "foo" #:sync #f)

What am I doing wrong here? I have a pretty solid grasp of Racket thanks
to the great guide, but when it comes to macros I am still totally lost.

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