[plt-scheme] debugging ellipses
This is just an FYI email in case other people try to debug the same
problem. I didn't realize that I had to export the ellipses binding
`...' with (for-syntax) for ellipses to be used properly in macros. At
first I thought that just exporting `...' in phase 0 would have worked
but syntax-case expects `...' to be bound in the phase that it is
matching (usually phase 1).
So for anyone that tries to write their own language with the module
system (#lang my-lang) and you export a facility for writing macros, you
will also have to export `...' with (for-syntax ...). This is true for
non-language-modules, but if you stick with #lang scheme/base or #lang
scheme you probably won't have this issue.
Here is a small example. This is a simple language that exports some
primitive stuff, +, and a way to define syntaxes.
;; start
#lang scheme
(provide my-macro
#%module-begin
+
#%app #%datum #%top)
;; uncomment for things to work!!
;; (provide (for-syntax ...))
;; comment the next line because it is wrong
(provide ...)
(define-syntax (my-macro stx)
(syntax-case stx ()
[(_ (literals ...) (name pattern ...)
(template ...))
#'(define-syntax (name stx)
(syntax-case stx (literals ...)
[(_ pattern ...) #'(template ...)]))]))
;; end
If that file was f.ss and is used in another file as #lang f then
without (provide (for-syntax ...)) you will get "bad syntax" after
trying to use `my-macro' because syntax-case thought ... was just
another identifier and not the real ellipses. That is
(my-macro (qq) (foo x ... qq)
(+ x ...))
(foo 1 2 3 qq)
Will fail to match because the macro that was generated expects to match
3 things: one expression for 'x', one expression for '...' and the
literal `qq'.
One defense against accidentally using syntax literals in other contexts
is to raise an error when the identifier is not used as part of a macro.
`...' is defined this way in collects/scheme/private/ellipses.ss:
(define-syntaxes (...)
(lambda (stx)
(raise-syntax-error #f "ellipses not allowed as an expression" stx)))
But this defense mechanism did not activate because I wasn't using `...'
as an expression, I expected `...' to have an affect in a syntax pattern.
Of course I used the macro stepper to debug this but when I clicked on
the `...' in the usage of my macro it said the identifier came from f.ss
module. After I realized my mistake and changed the provide to
(for-syntax ...), I went back to the macro stepper and saw that the
syntax property for `...' now showed it coming from ellipses.ss instead
of just f.ss.