From: ยทยทยท@healy.washington.dc.us
Subject: Regression testing macroexpansions
Date: 
Message-ID: <51hf9hzijk.fsf@zip.local>
This is to follow up a question I had a couple weeks ago about how to
compare macroexpansions to see if they're identical, e.g. in a
regression test where an old expansion is stored in a file and a new
one is being tested.  The use of gensyms and make-symbol makes this a
bit tricky. Kent Pitman posted code which I have modified.  I renamed
things, using "symbol-test" instead of "test-case", and fixed a bug in
symbol-test-equal; this bug caused all uninterned (gensymed) symbols
to match each other.  Also, I print out the symbol mapping between the
two forms and return the hash table as a second value. Erik Naggum
made me realize that setting *print-circle* to T is necessary before
doing the macroexpansion so that when it's read from a file, the right
symbols are identified as the same.

(setf *print-circle* t)

(defvar *symbol-test-equivalents*)

(defmacro with-symbol-test (&body forms)
  `(call-with-symbol-test #'(lambda () ,@forms)))

(defparameter *print-gensym-mapping* nil)

(defun call-with-symbol-test (thunk)
  (let* ((*symbol-test-equivalents* (make-hash-table))
	 (called (funcall thunk)))
    (if *print-gensym-mapping*
	(maphash (lambda (k v) (format t "~&~s -> ~s" k v))
		 *symbol-test-equivalents*))
    (values
     called
     *symbol-test-equivalents*)))

(defun gensym-p (x)
  (and (symbolp x) 
       (not (symbol-package x))))

(defun equivalent-gensym (x)
  (and (gensym-p x)
       (gethash x *symbol-test-equivalents*)))

(defun register-equivalent-gensym (x y)
  (setf (gethash x *symbol-test-equivalents*) y))

(defun symbol-test-equal (x y)
  (or (equal x y)
      (let ((eqv (equivalent-gensym x)))
        (if eqv
	    (eq eqv y)
	  (when (and (gensym-p x) (gensym-p y))
	    (register-equivalent-gensym x y)
	    t)))))

#|
;;; This should return T 
(with-symbol-test
    (tree-equal '(ZOOP #1=#:X #2=#:X #1#)
		(let ((a (make-symbol "X")) (b (make-symbol "X")))
		  `(zoop ,a ,b ,a))
		:test #'symbol-test-equal))

;;; This should return NIL
(with-symbol-test
    (tree-equal '(ZOOP #1=#:X #2=#:X #1#)
		(let ((a (make-symbol "X")) (b (make-symbol "X")))
		  `(zoop ,a ,a ,b))
		:test #'symbol-test-equal))
|#