[plt-dev] macro error messages

From: Jon Rafkind (rafkind at cs.utah.edu)
Date: Tue Mar 30 17:44:58 EDT 2010

On 03/29/2010 09:45 PM, Jon Rafkind wrote:
> On 03/29/2010 03:19 PM, Matthew Flatt wrote:
>> At Mon, 29 Mar 2010 15:06:00 -0600, Jon Rafkind wrote:
>>> Can these error messages be reviewed as well?
>>> On 03/26/2010 03:55 PM, Jon Rafkind wrote:
>>>> Can this error message
>>>>    illegal use of syntax
>>>> be changed to
>>>>    illegal application of a transformer. transformers must be 
>>>> functions
>>>> that accept one argument.
>>>> To reproduce this error use this code:
>>>> (define-syntax (foo a b c) #'1)
>>>> (foo)
>>>> There is only one change to be made in eval.c line ~6284
>> Like the suggested `syntax-case' change, I think this one assumes the
>> perspective of a macro implementor with a particular goal.
>> In general, an identifier bound with `define-syntax' doesn't have to be
>> bound to a transformer procedure. A non-transformer binding may be
>> intentional and useful, such as when a pattern variable is bound by
>> `syntax-case'.
>> In such cases, it's a good idea to make the binding also include a
>> transformer procedure (perhaps through `prop:procedure') and refine the
>> "illegal use of syntax" error message --- just like it's a good idea to
>> cover more cases in `syntax-case' or `syntax-parse' and give good error
>> messages. But if a programmer doesn't do that, then "bad syntax" or
>> "illegal use of syntax" is about all that can be said automatically.
> I don't follow you. The C code has a check to see if the thing being 
> applied is a procedure with an arity of 1. If it is anything else, the 
> error "illegal use of syntax" will be raised. So my suggestion is for 
> the error message to mirror the check being done.

Here is some simple code that throws a nicer error for macros when they 
are used incorrectly. Probably not useful enough for planet, so I'll 
just post it here in case anyone is interested. This works correctly 
with `syntax-local-value'.

#lang scheme

(provide (all-defined-out))

(define-struct macro (name function) #:property prop:procedure
                (lambda (self . args)
                  (let ([function (macro-function self)])
                    (if (not (procedure-arity-includes? function (length 
                      (raise-syntax-error (macro-name self) "wrong 
number of arguments supplied" args)
                      (apply function args)))))

#lang scheme

(require (for-syntax scheme/base

(require (prefix-in original: (only-in scheme/base define-syntax)))

(define-syntax (define-syntax stx)
   (syntax-case stx ()
     [(_ (id args ...) expr0 expr ...)
      #'(original:define-syntax id (make-macro 'id (lambda (args ...) 
expr0 expr ...)))]
     [(_ (id args ... . rest-args) expr0 expr ...)
      #'(original:define-syntax id (make-macro 'id (lambda (args ... . 
rest) expr0 expr ...)))]
     [(_ rest ...)
      #'(original:define-syntax rest ...)]))

Then just (require "define-syntax.ss") and away you go.

Posted on the dev mailing list.