[plt-scheme] debugging ellipses

From: Jon Rafkind (rafkind at cs.utah.edu)
Date: Mon Nov 2 22:48:19 EST 2009

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
         #%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.

Posted on the users mailing list.