anchor.diff:  	    (destructure-optionals (cdr optionals) temp1)
   	  (values (append `((,temp1 (if (consp ,var)
   					(cdr ,var)
  -					'()))
  +					(if (null ,var)
  +					    '()
  +					    (error "optional expected"))))
  +			    ;; If the object is not a CONS, then it is
  +			    ;; either NIL in which case we destructure
  +			    ;; the init-arg instead, or else it is an
  +			    ;; atom other than NIL and we have already
  +			    ;; signaled an error before, so we don't
  +			    ;; need to handle that case again.
   			    (,temp2 (if (consp ,var)
   					(car ,var)
   					,(cadr optional)))
  +			    ;; If a supplied-p-parameter exists, then
  +			    ;; we give it the value TRUE whenever the
  +			    ;; object is a CONS, even though later
  +			    ;; an error might be signaled because there
  +			    ;; is no match. 
   			    ,@(if (consp (cddr optional))
   				  `((,(caddr optional) (consp ,var)))))
   			  (destructure-pattern (car optional) temp2)
   			  bindings)
   		  rest-var)))))
  -		
  +
  +;;; Recall that the keys part of a compiled lambda list is either
  +;;; :none, which means that no &key was given at all, or a list if
  +;;; &key entries.  If the list is empty, it means that &key was given,
  +;;; but no &key parameters followed.
  +;;;
  +;;; A &key entry is either:
  +;;;
  +;;;  * ((keyword pattern) init-form)
  +;;; 
  +;;;  * ((keyword pattern) init-form supplied-p-parameter)
  +;;;
  +;;; The HyperSpec is pretty skimpy about what happens with keyword
  +;;; arguments ("the rest of the list ... is taken apart
  +;;; appropriately").  What we do is the following:
  +;;;
  +;;;  * If there is a keyword argument with the right keyword, then
  +;;;    its value is matched against the pattern.
  +;;;
  +;;;  * Otherwise, the value of the init-form is matched agains the
  +;;;    pattern.
   (defun destructure-keys (keys var)
     (if (or (eq keys :none) (null keys))
         '()
  -      (let ((key (car keys)))
  -	(append `((,(cadar key)
  +      (let ((key (car keys))
  +	    (temp (gensym)))
  +	(append `(;; What we do in step 1 depends on whether there is
  +		  ;; a supplied-p-parameter or not.  If there is, then
  +		  ;; in step 1, we return a list of two things:
  +		  ;; 
  +		  ;;  * a boolean indicating whether we found the
  +		  ;;    keyword.
  +		  ;;
  +		  ;;  * either the argument found, or the value of the
  +		  ;;    init-form if no argument was found.
  +		  ;;
  +		  ;; If there is no supplied-p-parameter, then we just
  +		  ;; return the argument found or the value of the
  +		  ;; init-form if no argument was found.
  +		  (,temp
   		   ,(if (consp (cddr key))
   			`(loop for rem = ,var then (cddr rem)
   			       while (consp rem)
  
positive.code: 			  bindings)
  		  rest-var)))))
  
  (defun destructure-optionals (optionals var)
    (if (or (eq optionals :none) (null optionals))
        (values '() var)
  
negative.code: 	 (final-env-var (if (eq env-var :none) (gensym) env-var))
  	 (form-var (gensym))
  	 (args-var (gensym)))
      (multiple-value-bind (bindings ignored-variables)
  	(destructure-lambda-list parsed-lambda-list args-var)
        `(lambda (,form-var ,final-env-var)
  	 ;; If the lambda list does not contain &environment, then
  	 ;; we IGNORE the GENSYMed parameter to avoid warnings.
  	 ;; If the lambda list does contain &envionrment, we do
  	 ;; not want to make it IGNORABLE because we would want a
  	 ;; warning if it is not used then. 
  	 ,@(if (eq env-var :none)
  	       `((declare (ignore ,final-env-var)))
  	       `())
  	 (let ((,args-var (cdr ,form-var)))
  	   (let* ,bindings
  	     (declare (ignore ,@ignored-variables))
  	     ,@body))))))
  
  	 
  