[armedbear-cvs] r13787 - trunk/abcl/src/org/armedbear/lisp

ehuelsmann at common-lisp.net ehuelsmann at common-lisp.net
Tue Jan 17 19:39:55 UTC 2012


Author: ehuelsmann
Date: Tue Jan 17 11:39:54 2012
New Revision: 13787

Log:
Implement keyword argument verification in the method invocation protocol.

Modified:
   trunk/abcl/src/org/armedbear/lisp/clos.lisp

Modified: trunk/abcl/src/org/armedbear/lisp/clos.lisp
==============================================================================
--- trunk/abcl/src/org/armedbear/lisp/clos.lisp	Tue Jan 17 11:38:01 2012	(r13786)
+++ trunk/abcl/src/org/armedbear/lisp/clos.lisp	Tue Jan 17 11:39:54 2012	(r13787)
@@ -2027,13 +2027,72 @@
 	  (unless (subclassp (car classes) specializer)
 	    (return (values nil t)))))))
 
+(defun check-applicable-method-keyword-args (gf args
+                                             keyword-args
+                                             applicable-keywords)
+  (when (oddp (length keyword-args))
+    (error 'program-error
+           :format-control "Odd number of keyword arguments in call to ~S ~
+with arguments list ~S"
+           :format-arguments (list gf args)))
+  (unless (getf keyword-args :allow-other-keys)
+    (loop for key in keyword-args by #'cddr
+       unless (or (member key applicable-keywords)
+                  (eq key :allow-other-keys))
+       do (error 'program-error
+                 :format-control "Invalid keyword argument ~S in call ~
+to ~S with argument list ~S."
+                 :format-arguments (list key gf args)))))
+
+(defun compute-applicable-keywords (gf applicable-methods)
+  (let ((applicable-keywords
+         (getf (analyze-lambda-list (generic-function-lambda-list gf))
+               :keywords)))
+    (loop for method in applicable-methods
+       do (multiple-value-bind
+                (keywords allow-other-keys)
+              (function-keywords method)
+            (when allow-other-keys
+              (setf applicable-keywords :any)
+              (return))
+            (setf applicable-keywords
+                  (union applicable-keywords keywords))))
+    applicable-keywords))
+
+(defun wrap-emfun-for-keyword-args-check (gf emfun non-keyword-args
+                                          applicable-keywords)
+  #'(lambda (args)
+      (check-applicable-method-keyword-args
+         gf args
+         (nthcdr non-keyword-args args) applicable-keywords)
+      (funcall emfun args)))
+
 (defun slow-method-lookup (gf args)
   (let ((applicable-methods (%compute-applicable-methods gf args)))
     (if applicable-methods
-        (let ((emfun (funcall (if (eq (class-of gf) +the-standard-generic-function-class+)
-                                  #'std-compute-effective-method-function
-                                  #'compute-effective-method-function)
-                              gf applicable-methods)))
+        (let* ((emfun (funcall (if (eq (class-of gf) +the-standard-generic-function-class+)
+                                   #'std-compute-effective-method-function
+                                   #'compute-effective-method-function)
+                               gf applicable-methods))
+               (non-keyword-args
+                (+ (length (gf-required-args gf))
+                   (length (gf-optional-args gf))))
+               (gf-lambda-list (generic-function-lambda-list gf))
+               (checks-required (and (member '&key gf-lambda-list)
+                                     (not (member '&allow-other-keys
+                                                  gf-lambda-list)))
+                 )
+              (applicable-keywords
+               (when checks-required
+                 ;; Don't do applicable keyword checks when this is
+                 ;; one of the 'exceptional four' or when the gf allows
+                 ;; other keywords.
+                 (compute-applicable-keywords gf applicable-methods))))
+          (when (and checks-required
+                     (not (eq applicable-keywords :any)))
+            (setf emfun
+                  (wrap-emfun-for-keyword-args-check gf emfun non-keyword-args
+                                                     applicable-keywords)))
           (cache-emf gf args emfun)
           (funcall emfun args))
         (apply #'no-applicable-method gf args))))
@@ -2407,6 +2466,7 @@
     (%set-method-function method function)
     (%set-method-fast-function method fast-function)
     (set-reader-method-slot-name method slot-name)
+    (%set-function-keywords method nil nil)
     method))
 
 (defun add-reader-method (class function-name slot-name)
@@ -2830,8 +2890,7 @@
               ((null tail))
               (unless (memq initarg allowable-initargs)
                 (error 'program-error
-                       :format-control "Invalid initarg ~S in call to ~S ~
-with arglist ~S."
+                       :format-control "Invalid initarg ~S in call to ~S with arglist ~S."
                        :format-arguments (list initarg call-site args))))))))
 
 (defun merge-initargs-sets (list1 list2)
@@ -2949,7 +3008,8 @@
                                         &rest initargs
                                         &key &allow-other-keys))
 
-(defmethod shared-initialize ((instance standard-object) slot-names &rest initargs)
+(defmethod shared-initialize ((instance standard-object) slot-names
+                              &rest initargs)
   (std-shared-initialize instance slot-names initargs))
 
 (defmethod shared-initialize ((slot slot-definition) slot-names
@@ -3372,7 +3432,6 @@
   (:method ((method standard-method))
     (%function-keywords method)))
 
-
 (setf *gf-initialize-instance* (symbol-function 'initialize-instance))
 (setf *gf-allocate-instance* (symbol-function 'allocate-instance))
 (setf *gf-shared-initialize* (symbol-function 'shared-initialize))




More information about the armedbear-cvs mailing list