1 ;;;; miscellaneous side-effectful tests of the MOP
3 ;;;; This software is part of the SBCL system. See the README file for
6 ;;;; While most of SBCL is derived from the CMU CL system, the test
7 ;;;; files (like this one) were written from scratch after the fork
10 ;;;; This software is in the public domain and is provided with
11 ;;;; absolutely no warranty. See the COPYING and CREDITS files for
12 ;;;; more information.
14 ;;; a test of a non-standard specializer class and non-standard
15 ;;; generic function class, which nevertheless admit the cacheing
16 ;;; strategy implicit in the second return value of
17 ;;; compute-applicable-methods-using-classes.
19 (load "assertoid.lisp")
21 (defpackage "OR-SPECIALIZER-TEST"
22 (:use
"CL" "SB-MOP" "ASSERTOID"))
24 (in-package "OR-SPECIALIZER-TEST")
26 (defclass or-specializer
(specializer)
27 ((classes :initform nil
:reader or-specializer-classes
:initarg
:classes
)
28 (direct-methods :initform nil
:reader specializer-direct-methods
)))
30 (defvar *or-specializer-table
* (make-hash-table :test
'equal
))
32 (defun ensure-or-specializer (&rest classes
)
33 ;; FIXME: duplicate hash values
34 (let* ((cs (mapcar (lambda (x) (if (symbolp x
) (find-class x
) x
)) classes
))
35 (sorted-classes (sort cs
#'< :key
#'sxhash
)))
36 (or (gethash sorted-classes
*or-specializer-table
*)
37 (setf (gethash sorted-classes
*or-specializer-table
*)
38 (make-instance 'or-specializer
:classes sorted-classes
)))))
40 (defclass gf-with-or
(standard-generic-function) ()
41 (:metaclass funcallable-standard-class
))
43 (defmethod compute-applicable-methods-using-classes
44 ((generic-function gf-with-or
) classes
)
45 ;; FIXME: assume one-argument for now
46 (let (applicable-methods)
47 (let ((methods (generic-function-methods generic-function
)))
49 (let ((specializer (car (method-specializers m
)))
50 (class (car classes
)))
52 (class (when (subtypep class specializer
)
53 (push m applicable-methods
)))
55 (when (eql (class-of (eql-specializer-object specializer
))
57 (return-from compute-applicable-methods-using-classes
60 (dolist (c (or-specializer-classes specializer
))
61 (when (subtypep class c
)
62 (push m applicable-methods
))))))))
63 ;; FIXME: sort the methods
64 (values applicable-methods t
)))
66 (defmethod compute-applicable-methods
67 ((generic-function gf-with-or
) arguments
)
68 ;; FIXME: assume one-argument for now
69 (let (applicable-methods)
70 (let ((methods (generic-function-methods generic-function
)))
72 (let ((specializer (car (method-specializers m
)))
73 (argument (car arguments
)))
75 (class (when (typep argument specializer
)
76 (push m applicable-methods
)))
78 (when (eql (eql-specializer-object specializer
) argument
)
79 (push m applicable-methods
)))
81 (dolist (c (or-specializer-classes specializer
))
82 (when (typep argument c
)
83 (push m applicable-methods
))))))))
84 ;; FIXME: sort the methods
87 (defmethod add-direct-method ((specializer or-specializer
) method
)
88 (pushnew method
(slot-value specializer
'direct-methods
)))
90 (defmethod remove-direct-method ((specializer or-specializer
) method
)
91 (setf (slot-value specializer
'direct-methods
)
92 (remove method
(slot-value specializer
'direct-methods
))))
94 ;;; FIXME: write SPECIALIZER-DIRECT-GENERIC-FUNCTIONS method
96 (defclass class1
() ())
97 (defclass class2
() ())
98 (defclass class3
() ())
99 (defclass class4
(class1) ())
102 (:generic-function-class gf-with-or
))
104 (let ((specializer (ensure-or-specializer 'class1
'class2
)))
105 (eval `(defmethod foo ((x ,specializer
)) t
)))
107 (assert (foo (make-instance 'class1
)))
108 (assert (foo (make-instance 'class2
)))
109 (assert (raises-error?
(foo (make-instance 'class3
))))
110 (assert (foo (make-instance 'class4
)))
112 ;;; check that we are actually cacheing effective methods. If the
113 ;;; representation in PCL changes, this test needs to change too.
114 (assert (typep (cddr (sb-pcl::gf-dfun-state
#'foo
)) 'sb-pcl
::caching
))