2015-08-14

Renaming identifier (solution of pandoric macro)

I've found a solution for the bug described on the article: pandoricマクロ. It was a rather simple solution.

There were 2 issues and one was a bug.
  • Making a global variable strips syntax information of the given identifier (bug)
  • Explicit renaming doesn't rename when identifiers are bound
The first one was a very simple bug, on the compiler if define has an identifier for its binding's name, then it shouldn't strip. That's it. Though, this isn't a good solution because if the identifier is bound in other library then the binding would be created not the one creating a binding but the one created the identifier. I think it's not a big deal but rather weird.

To resolve the weirdness, the identifier needs to be renamed. On Sagittarius, identifiers internally contain its identity which is a sort of history when the identifier is renamed. If the identity is #f, then it's a global identifier (means almost the same as raw symbol). Now, as far as I remember, each identifier, which reached to define and contains identity, are renamed means created in macros and it should be safe to change its name to unique symbol which is done by compiler via rename-pending-identifier. So I've added extra check to change the identifier name.

The benefit of this change is not only making R7RS syntax-rules work the same as R6RS one but also make R6RS datum->syntax works more R6RS compliant. More precisely, it resolved this issue. So now this won't work:
(import (rnrs))

(define-syntax define/datum->syntax
  (lambda (x)
    (define (concat n1 n2)
      (string->symbol
       (string-append (symbol->string (syntax->datum n1))
              "-"
              (symbol->string (syntax->datum n2)))))
    (syntax-case x ()
      ((_ name1 name2 var) ;; oops
       (with-syntax ((name (datum->syntax #'k (concat #'name1 #'name2))))
     #'(define name var))))))

(define/datum->syntax n1 n2 'bar)

n1-n2
;; -> error
(though, I've also found a piece of code depending on this bug...)

In my understanding, this type of renaming isn't required on R7RS. So this is a valid R7RS script:
(define-syntax defbar
  (syntax-rules ()
    ((_ name)
     (defbar name t1))
    ((_ name t1)
     (begin
       (define t1 'bar)
       (define (name) t1)))))

(defbar foo)

t1
;; may or may not an error
For example, Chicken Scheme returns bar. (For my preferecne, if identifiers are bound in macros, then it should be renamed as R6RS requires, but I can't do much about it.)

No comments:

Post a Comment