[plt-scheme] macro-generating macros and the bizarre properties of syntax-local-get-shadower

From: Ryan Culpepper (ryanc at ccs.neu.edu)
Date: Mon May 14 18:19:58 EDT 2007

On Mon, 2007-05-14 at 11:13 -0400, Dimitris Vyzovitis wrote:
> Can someone explain this:

I've deleted the parts that don't have any bearing on the error.

Here's the relevant macro definition:

>   (define-syntax (define-foo1 stx)
>     (syntax-case stx ()
>       ((_ val)
>        (let-values (((foo foocheck foov) (apply values (make-foos))))
>          (syntax-local-introduce
>           #`(begin (define-syntax #,foo val)
>                    (define-syntax (#,foocheck stx)
>                      (let ((#,foov (syntax-local-value (quote-syntax #,foo))))
>                        (quasisyntax #,#,foov)))
>                    (provide #,foo #,foocheck)))))))

and here's the use:

>   (define-foo1 1)

In this use of 'define-foo1', 'val' gets bound to the '1'. The syntax
object representing that '1' carries with it the syntactic environment
of the enclosing module. That syntactic environment has a binding for
'#%datum' in the "normal" phase and also in the "for-syntax" phase.

The first definition the macro produces looks like this:

  (define-syntax foo1 1)

Since the '1' occurs in a "for-syntax" expression context, the macro
expander looks for a "for-syntax" binding of '#%datum', and it finds it.
This definition binds 'foo1' to the number 1. Note that: not a
representation of the expression '1', just the plain old number 1.

Here's the next definition the macro produces:

  (define-syntax (foocheck2 stx)
    (let ((foov3 (syntax-local-value (quote-syntax foo1))))

When this macro is called, it looks up the value associated with 'foo1':
that's the number 1. Then it tries to turn it into an expression with
that quasisyntax business. But doing it that way doesn't give it a
'#%datum' binding, and that leads to the syntax error.

When you turn an ordinary value into an expression, you've got to make
sure you give it the proper lexical context. Jens suggested one way of
doing that:

  (define-syntax (foocheck2 stx)
    (let ((foov3 (syntax-local-value (quote-syntax foo1))))
      (datum->syntax-object #'here foov3)))

That puts the right '#%datum' bindings on the resulting syntax object.

Here's another way: don't try to convert the number directly into an
expression at all. If you know it's going to be a constant, then put it
inside of an explicit  'quote' or '#%datum' expression.

(define-syntax (foocheck2 stx)
  (let ((foov3 (syntax-local-value (quote-syntax foo1))))
    #`(quote #,foov3)))


Posted on the users mailing list.