gablin
gablin

Reputation: 4798

Can syntax parameters be used to replace syntax?

I'm trying to use syntax parameters in order to inject new syntax where I need it to be injected. The result of this is then used in other syntax. However, it's not working as I expect it to. Here's a minimal working example:

(require racket/stxparam)
(require (for-syntax racket/stxparam))

;; declare parameter to be replaced with code
(define-syntax-parameter placeholder
  (lambda (stx)
    (raise-syntax-error
     (syntax-e stx)
     "can only be used inside declare-many-commands")))

;; this is just to print what 'arg' looks like
(define-syntax (print-syntax stx)
  (syntax-case stx ()
    [(_ arg)
     #'(displayln 'arg)]))

;; this is the top-level entity invoked to produce many commands
(define-syntax-rule (declare-many-commands cmds)
  (begin
    (let ([X 10])
      (syntax-parameterize
       ([placeholder (make-rename-transformer #'X)])
       cmds))
    (let ([X 20])
      (syntax-parameterize
       ([placeholder (make-rename-transformer #'X)])
       cmds))))

(declare-many-commands
 (print-syntax placeholder))

What I would like to get as result when running this is:

10
20

but what I get is:

placeholder
placeholder

EDIT:

Posted a new question to refine the problem: Injecting syntax at compile time using Racket's syntax parameters?

Upvotes: 0

Views: 68

Answers (1)

Alexis King
Alexis King

Reputation: 43842

The problem here is that your print-syntax macro quotes its input, and inputs to macro transformers are unexpanded syntax. This means that the expansion of (print-syntax placeholder) will always be (displayln 'placeholder), and no macroexpansion ever occurs under quote, so the placeholder binding in scope is irrelevant.

If you want to use the syntax parameter, you need to actually produce a reference to the placeholder binding. In this case, you just need to remove the use of quote. You could change print-syntax to (displayln arg), but at that point, there’s really no reason for print-syntax to be a macro, since it’s equivalent to the displayln function. Just use that instead:

(declare-many-commands
 (displayln placeholder))

This will print 10 and 20 as you expect.

It’s possible you really do want the quote, and I don’t understand your question. In that case, though, I think it’s difficult for me to understand what you’re getting at without some additional context.

Upvotes: 2

Related Questions