[plt-scheme] syntax/cx+loc
For a while I've been confused about why there was a difference
between having helper procedures local to a `define-syntax'
transformer and putting them into a module and using
`require-for-syntax':
(module m1 mzscheme
(provide macro1)
(define-syntax (macro1 stx)
(define (helper1 stx)
(syntax-case stx ()
((a . b)
(syntax (list . b)))))
(helper1 stx)))
(require m1)
(macro1 1 2 3) ; => (1 2 3)
(module m2 mzscheme
(provide helper2)
(define (helper2 stx)
(syntax-case stx ()
((a . b)
(syntax (list . b))))))
(module m3 mzscheme
(require-for-syntax m2)
(provide macro2)
(define-syntax (macro2 stx)
(helper2 stx)))
(require m3)
(macro2 1 2 3) ; => stdin::324: compile: bad syntax; function application is not allowed, because no #%app syntax transformer is bound in: (list 1 2 3)
I used to be able to use `namespace-syntax-introduce' in the helper
function, which would bind `#%app', but that no longer works in 299.33
(not sure why exactly). But I think I now have a handle on what's
going on: when a `syntax' form is lexically enclosed in a transformer,
it attaches the lexical context of the input expression to the new
syntax object, which contains a transformer binding for `#%app';
otherwise, the new syntax object has the lexical context of the
module, which has no transformer bindings (because it was required for
syntax). (Am I close, Matthew?)
So instead of using `syntax' (or `syntax/loc', which copies the source
location information), now I use `syntax/cx+loc', which copies both
the lexical context and source location information:
(define-syntax syntax/cx+loc
(syntax-rules ()
((_ source-stx-expr template-expr)
(let ((source-stx source-stx-expr))
(datum->syntax-object
source-stx (syntax-e #'template-expr) source-stx)))))
This seems to work fine, so I thought I'd share it. There's probably
a better name for this... maybe `syntax*'?
--dougo at place.org