anchor.diff:  ;; (defgeneric compile-expression (form values successors))
   
   ;; ;;; factor the duplicated code
  -;; (defmethod compile-expression ((form constant-form) values successors)
  +;; (defmethod compile-expression ((form constant-ast) values successors)
   ;;   (if (null values)
   ;;       (warn "constant form compiled in a context where its value is not needed")
   ;;       (let ((succ successors))
  
positive.code: (defun fixup (form ast)
    (or (search-ast form ast)
        (cond ((symbolp form)
  	     (make-instance 'symbol-form
  			    :original-form form))
  	    ((atom form)
  	     (make-instance 'constant-form
  			    :original-form form))
  	    (t
  	     (assert (proper-list-p form))
  	     (make-instance 'compound-form
  			    :original-form form
  			    :subforms (mapcar (lambda (subform)
  						(fixup subform ast))
  					      form))))))
  
  (defclass variable-form (form)
    ((%name :initarg :name :reader name)))
  
  (defclass function-call-form (form)
    ((%function-form :initarg :function-form :reader function-form)
     (%arguments :initarg :arguments :reader arguments)))
  
  (defclass progn-form (form)
    ((%body-forms :initarg :body-forms :reader body-forms)))
  
  (defclass binding-form (form)
    ((%variable :initarg :variable :reader variable)
     (%value :initarg :value :reader value)))
  
  (defclass let-form (form)
    ((%bindings :initarg :bindings :reader bindings)
     (%body-form :initarg :body-form :reader body-form)))
  
  (defclass setq-form (form)
    ((%variable :initarg :variable :reader variable)
     (%value :initarg :value :reader value)))
  
  (defclass if-form (form)
    ((%test-form :initarg :test-form :reader test-form)
     (%then-form :initarg :then-form :reader then-form)
     (%else-form :initarg :else-form :reader else-form)))
  
  (defgeneric convert-special (operator ast environment))
  
  (defmethod convert ((ast compound-form) environment)
    ;; possibly expand macros
    (let ((macro-function
  	 (lookup (car (original-form ast)) environment 'macro)))
      (if (not (null macro-function))
  	(convert (fixup (funcall macro-function (original-form ast) nil) ast) environment)
  	(let ((special-operator
  	       (lookup (car (original-form ast)) environment 'special-operator)))
  	  (if (not (null special-operator))
  	      (convert-special (car (original-form ast))
  			       ast
  			       environment)
  	      (if (symbolp (car (original-form ast)))
  		  (make-instance 'function-call-form
  				 :original-form (original-form ast)
  				 ;; this is wrong of course
  				 :function-form (car (original-form ast))
  				 :arguments
  				 (mapcar (lambda (argument)
  					   (convert argument environment))
  					 (cdr (subforms ast))))
  		  ;; this is wrong too
  		  nil))))))
  	      
  (defmethod convert-special ((op (eql 'setq)) ast environment)
    (assert (= (length (subforms ast)) 3))
    (assert (typep (car (subforms ast)) 'symbol-form))
    ;; FIXME: issue a warning if the variable doesn't exist 
    (make-instance 'setq-form
  		 :original-form (original-form ast)
  		 :variable (lookup (original-form (cadr (subforms ast)))
  				   environment
  				   'variable)
  		 :value (convert (caddr (subforms ast)) environment)))
  
  (defmethod convert-special ((op (eql 'progn)) ast environment)
    (cond ((null (cdr (subforms ast)))
  	 (make-instance 'constant-form
  			:original-form nil
  			:value nil))
  	((null (cddr (subforms ast)))
  	 (convert (cadr (subforms ast)) environment))
  	(t (make-instance 'progn-form
  	     :original-form (original-form ast)
  	     :body-forms (loop for form in (cdr (subforms ast))
  			       collect (convert form environment))))))
  
  (defun convert-implicit-progn (asts environment)
    (let ((ast (make-instance 'compound-form
  			    :original-form nil
  			    :subforms
  			    (cons (make-instance 'symbol-form
  						 :original-form nil)
  				  asts))))
      (convert-special 'progn ast environment)))
  
  (defmethod convert-special ((op (eql 'let)) ast environment)
    (assert (>= (length (subforms ast)) 2))
    (destructuring-bind (binding-forms &rest body-forms) (cdr (subforms ast))
      (assert (typep binding-forms 'compound-form))
      (let* ((new-environment (make-instance 'lexical-environment
  					   :parent environment))
  	   (bindings
  	    (loop for binding-form in (subforms binding-forms)
  		  do (assert (or (typep binding-form 'symbol-form)
  				 (and (typep binding-form 'compound-form)
  				      (= (length (subforms binding-form)) 2)
  				      (typep (car (subforms binding-form))
  					     'symbol-form))))
  		  collect (make-instance 'binding-form
  			    :original-form (original-form binding-form)
  			    :variable 
  			    (make-instance 'variable-form
  			      :original-form 
  			      (original-form (if (typep binding-form 'symbol-form)
  						 binding-form
  						 (car (subforms binding-form))))
  			      :name
  			      (original-form (if (typep binding-form 'symbol-form)
  						 binding-form
  						 (car (subforms binding-form)))))
  			    :value 
  			    (convert (if (typep binding-form 'symbol-form)
  					 nil
  					 (cadr (subforms binding-form)))
  				     environment)))))
        (loop for binding in bindings
  	    do (add-binding (name (variable binding))
  			    (variable binding)
  			    (variables new-environment)))
        (make-instance 'let-form
  		     :original-form (original-form ast)
  		     :bindings bindings
  		     :body-form
  		     (convert-implicit-progn body-forms new-environment)))))
  
  (defmethod convert-special ((op (eql 'quote)) ast environment)
    (assert (= (length (subforms ast)) 2))
    (make-instance 'constant-form
  		 :original-form (original-form ast)
  		 :value (cadr (subforms ast))))
  
  (defmethod convert-special ((op (eql 'if)) ast environment)
    (assert (<= 3 (length (subforms ast)) 4))
    (make-instance 'if-form
  		 :original-form (original-form ast)
  		 :test-form (convert (cadr (subforms ast)) environment)
  		 :then-form (convert (caddr (subforms ast)) environment)
  		 :else-form (if (null (cdddr (subforms ast)))
  				(make-instance 'constant-form
  					       :original-form nil
  					       :value nil)
  				(convert (cadddr (subforms ast)) environment))))
  
  ;; (defgeneric normalize (form))
  
  
negative.code: 
  ;;; Search an ast to see whether its original form is eq to the ast
  (defun search-ast (form ast)
    (cond ((eq form (form ast))
  	 ast)
  	((typep ast 'compound-ast)
  	 (some (lambda (child)
  		 (search-ast form child))
  	       (children ast)))
  	(t nil)))
  
  ;;; Create a new ast from the form by either finding
  