Let's start Scheme

2015-03-26

Comparison of er-macro-transformer

In future, I don't know if it would be near or far yet, R7RS will have explicit renaming macro as its low level hygienic macro. So I thought it's nice to have some comparison. (though, I've just made one for now.)

There are some R7RS implementations which support er-macro-transformer. For now, I've used Sagittarius, Chibi, Gauche and Chicken (with R7RS egg). The main part that I was wondering for now is comparison of renamed symbols. So I made the following script to compare:
(import (scheme base) (scheme write) (scheme cxr))

(cond-expand
 (chibi (import (chibi)))
 (gauche (import (gauche base)))
 (sagittarius (import (sagittarius)))
 (chicken #t)
 (else (error "not supported")))

(define-syntax comp
  (er-macro-transformer
   (lambda (form rename compare)
     (define (print . args) (for-each display args) (newline))
     (let ((a1 (cadr form))
           (a2 (caddr form)))
       (print "eq?:               " (eq? a1 a2))
       (print "simple compare(0): " (compare a1 a2))
       (print "simple compare(1): " (compare a1 'a))
       (print "rename (eq?):      " (eq? (rename a1) a1))
       (print "rename (compare):  " (compare (rename a1) (rename a1)))
       ;; is a bound?
       a1))))

(define-syntax rename-it
  (er-macro-transformer
   (lambda (f r c) 
     (let ((cont (cadr f))
           (target (caddr f)))
       `(,@cont ,(r target))))))
(define-syntax rename-it2
  (er-macro-transformer
   (lambda (f r c) 
     (let ((cont (cadr f))
           (target (caddr f))
           (rest (cdddr f)))
       `(,cont ,(r target) ,@rest)))))

(guard (e (else (display "a is not bound") (newline)))
  (let ((a 1))
    (rename-it (rename-it2 comp a) a)
    (display "a is bound") (newline)))
It basically renames a symbol a and compare it in the macro.If you expose the renamed symbol, then implementations may raise an unbound error.
The result of above code is the following:
Chicken:
eq?:               #f
simple compare(0): #t
simple compare(1): #f
rename (eq?):      #f
rename (compare):  #t
a is not bound

Chibi:
eq?:               #f
simple compare(0): #t
simple compare(1): #f
rename (eq?):      #f
rename (compare):  #t
a is bound

Gauche:
eq?:               #f
simple compare(0): #t
simple compare(1): #f
rename (eq?):      #f
rename (compare):  #t
a is not bound

Sagittarius:
eq?:               #f
simple compare(0): #t
simple compare(1): #f
rename (eq?):      #t
rename (compare):  #t
a is not bound
In this case, Gauche and Chicken have the same behaviour. On Chibi, a is bound (which I think wrong behaviour since the macro rename-it is bound on global environment and referring the local environment. But there is no proper definition for explicit renaming yet, so who knows). Sagittarius doesn't rename if the given argument is not either a symbol or global defined identifier. I'm not sure if this is actually correct (feels not), but again there is no definition and R7RS mode is working properly with this behaviour. So I don't care much for now.
Updated on 29 March 2015: I've changed Sagittarius behaviour to rename (most of) identifiers as well so for this case it's similar to Chicken or Gauche.

During testing, I've got couple of bugs on Gauche and Chibi. Gauche's one was C level assertion error and Chibi's one was SEGV.

So far, there are not many difference among the implementations. Maybe I need to investigate more to find out (if I have time and motivation).

2 comments:

Peter Bex said...

Hi there! This is pretty interesting.

Please also note that, at least with CHICKEN, the results will typically differ if you use the macro within a let-syntax or inside a module, because that will involve multiple levels of renaming. Especially if that let-syntax involves an ir-macro or a syntax-rules macro.

Cheers,
Peter

kei said...

That's interesting, I should also check how it behaves, also others. Thanks :)

Post a Comment