Another thing about this, if the definition produced by the macro is instead generated by the `make-transformer' macro then it will have the wrong number of marks on it when everything is finally expanded. `syntax-local-introduce' fixes this by essentially removing that extra mark.
#lang racket (require (for-meta 0 racket/splicing) (for-meta 1 syntax/parse) (for-meta 2 syntax/parse racket/base)) (begin-for-syntax (define-syntax (make-transformer stx) (syntax-parse stx [(_ name (pattern ...) action) #'(quote-syntax (define-syntax name (lambda (stx) ;; HERE change to #'(quote-syntax (syntax-parse stx [(_ pattern ...) action]))))]))) (define-syntax (macro-generator stx) (syntax-parse stx [(_ name pattern action) #'(splicing-let-syntax ([make (lambda (stx) (syntax-parse stx [(_) (syntax-local-introduce (make-transformer name pattern action))]))]) (make))])) (macro-generator foo (x ...) #'(list x ...)) (foo 1 2 3) The `name' passed as an argument to `make-transformer' will not have the mark applied to it by the transformer in the splicing-let-syntax, so the resulting define-syntax form will use a different 'foo' from the one passed to `macro-generator'. Using `syntax-local-introduce' applies the mark that was used when `(make)' was expanded thus removing all marks from the final expansion. On 06/01/2012 12:16 PM, Jon Rafkind wrote: > Today's macro PSA is about macro-generating-macro forms. If you use a macro > to generate a transformer then you must be careful about nesting `syntax' > forms otherwise you will interpolate templates too many times. Specifically > #'#'x will interpolate x twice. Given the following bindings: > > chicken = (syntax (egg ...)) > pattern = (syntax chicken) > > The problem is if an additional `syntax' is wrapped around `pattern'. After > one interpolation of `syntax' we will have > > (syntax (egg ...)) > > At which point `egg' had better be bound as a pattern variable otherwise > interpolation will fail. > > To work around this problem the `quote-syntax' form should be used: > > #'(quote-syntax pattern) > > which prevents the (syntax (egg ...)) layer from being interpolated because > `quote-syntax' does not do interpolation. > > The following example demonstrates the issue. On the line 'HERE' the inner > syntax should be `quote-syntax' otherwise the following error is produced > > x.rkt:27:24: syntax: no pattern variables before ellipses in template at: > ... in: (_ x ...) > > To be fair this issue only comes up because I used `make-transformer' in the > body of a phase 2 function so the output of `make-transformer' had to have > two levels of syntax, because its a macro that should ultimately evaluate to > a syntax form. A simpler solution would have been to do > > #'(define-syntax name (make-transformer pattern action)) > > So that `make-transformer' only had to return one level of syntax. But anyway > I got into this situation for other reasons. > > #lang racket > > (require (for-meta 0 racket/splicing) > (for-meta 1 syntax/parse) > (for-meta 2 syntax/parse > racket/base)) > > (begin-for-syntax > (define-syntax (make-transformer stx) > (syntax-parse stx > [(_ (pattern ...) action) > #'#'(lambda (stx) ;; HERE change to #'(quote-syntax > (syntax-parse stx > [(_ pattern ...) action]))]))) > > (define-syntax (macro-generator stx) > (syntax-parse stx > [(_ name pattern action) > #'(splicing-let-syntax > ([make (lambda (stx) > (syntax-parse stx > [(_ name) > (with-syntax ([transformer (make-transformer pattern > action)]) > #'(define-syntax name transformer))]))]) > (make name))])) > > (macro-generator foo (x ...) #'(list x ...)) > (foo 1 2 3) > > > ____________________ > Racket Users list: > http://lists.racket-lang.org/users
____________________ Racket Users list: http://lists.racket-lang.org/users