Scott Klarenbach
Scott Klarenbach

Reputation: 38721

Racket Macro How to Pass Ellipses to Helper function?

Given:

(define-syntax (test stx)
  (syntax-case stx ()
    [(_ body ...)
     (with-syntax ([body0 (process-body #'(body ...))])
       #'body0)]))

How should I receive the pattern and the ellipses in the helper? I'm not even sure if wrapping the body ... inside () is correct, but I've seen it around and it's the only thing that doesn't crash.

The process-body procedure ends up with syntax that has extra () wrapping it. I can try and break this apart, but I'm just wondering what the correct way to do this is.

process-body wraps the body pattern with some code before AND after. And, similar to define, I want to be able to provide the macro with multiple forms rather than all forms in one list. So, if given (form1) (form2), where form2 is the ellipses, process-body should (do-something) (form1) (form2) (do-something-else).

ie,

(define-for-syntax (process-body body-syntax)
  (with-syntax ([stx body-syntax])
    (syntax/loc body-syntax
      (λ (request)
         stx))))

Of course I have this working when I define the template in-line, and I suppose I could do that here, but sometimes the template becomes unwieldy and it's nice to call a helper.

Thanks a lot.

As an edit to try dyoo's first example, I'm providing the following:

#lang racket

(define-syntax (test2 stx)
  (syntax-case stx ()
    [(_ body ...)
     (with-syntax ([(body0 ...) (process-body2 #'(body ...))])
       #'(begin body0 ...))]))

(define-for-syntax (process-body2 bodies)
  (with-syntax ([(body ...) bodies])
    (syntax/loc bodies
      (λ (request)
         body ...))))

(test2 (print "hi"))

λ: bad syntax

Upvotes: 4

Views: 967

Answers (1)

dyoo
dyoo

Reputation: 12003

The left hand side of a with-syntax pattern can also have ellipses, so that the following is possible:

(define-syntax (test stx)
  (syntax-case stx ()
    [(_ body ...)
     (with-syntax ([(body0 ...) (process-body #'(body ...))])
       #'(begin body0 ...))]))

The basic idea is that if process-body returns the transformed body elements, we can then introduce them all together with a begin.


Your process-body definition can also use with-syntax with ellipses too. So you can do something like this:

(define-for-syntax (process-body bodies)
  (with-syntax ([(body ...) bodies])
    (syntax/loc bodies
      (λ (request)
         body ...))))

If that's the definition of process-body, we should amend test since the shape of the result from process-body is now a complete lambda expression, so we can just return its result directly:

(define-syntax (test stx)
  (syntax-case stx ()
    [(_ body ...)
     (process-body (syntax/loc stx (body ...)))]))

As a self-contained example:

#lang racket

(define-syntax (test stx)
  (syntax-case stx ()
    [(_ body ...)
     (process-body 
      (syntax/loc stx (body ...)))]))

(define-for-syntax (process-body bodies)
  (with-syntax ([(body ...) bodies])
    (syntax/loc bodies
      (λ (request)
        (printf "before the body\n")
        body ...
        (printf "after the body\n")))))


;; Let's try it:    
(define p 
  (test (displayln "hello") (displayln "world")))

(p 'should-be-a-request)

Upvotes: 4

Related Questions