[racket] free-id-table. Is it a bug?

From: Ryan Culpepper (ryanc at ccs.neu.edu)
Date: Thu Apr 3 09:46:29 EDT 2014

On 04/03/2014 05:51 AM, Jens Axel Søgaard wrote:
> It seems the table needs to be created with #:phase -1.
>
> Since syntax-case uses a fender expression I added
> a begin in save-and-define, but it works either way
> (because free-id-table-set! returns a non-false value).
>
> #lang racket
> (require (for-syntax syntax/id-table))
>
> (define-for-syntax table (make-free-id-table #:phase -1))
>
> (define-syntax (save-and-define stx)
>    (syntax-case stx ()
>       [(_ ID)
>        (begin
>          (free-id-table-set! table #'ID 1)
>          #'(define ID 1))]))
>
> (define-syntax (load stx)
>    (syntax-case stx ()
>       [(_ ID2)
>        (if (free-id-table-ref table #'ID2 #f)
>              #''ok
>              #''different)]))
>
> (module+ test
>    (save-and-define a)
>    (displayln (load a)))

The code above is not correct. Here's a counterexample:

   (require (for-template (only-in racket/base [lambda x] [lambda y])))
   ;; x and y mean the same thing at phase -1
   (save-and-define x)
   (load y) ;; => 'ok, but should be 'different

The #:phase -1 means compare the for-template bindings, which is not 
what you want. You want to compare the normal (phase-0) bindings, 
because the identifiers are defined using plain old 'define'. See my 
other message for a fix.

As an aside, you should rarely-to-never use a constant phase number like 
-1. Use (sub1 (syntax-local-phase-level)) instead. That way your code 
will still work if required at a shifted phase (eg, for-syntax).

Ryan



Posted on the users mailing list.