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 sb-pcl:specializer-type-specifier
44 ((proto-generic-function gf-with-or
)
46 (specializer or-specializer
))
47 `(or ,@(or-specializer-classes specializer
)))
49 (defmethod compute-applicable-methods-using-classes
50 ((generic-function gf-with-or
) classes
)
51 ;; FIXME: assume one-argument for now
52 (let (applicable-methods)
53 (let ((methods (generic-function-methods generic-function
)))
55 (let ((specializer (car (method-specializers m
)))
56 (class (car classes
)))
58 (class (when (subtypep class specializer
)
59 (push m applicable-methods
)))
61 (when (eql (class-of (eql-specializer-object specializer
))
63 (return-from compute-applicable-methods-using-classes
66 (dolist (c (or-specializer-classes specializer
))
67 (when (subtypep class c
)
68 (push m applicable-methods
))))))))
69 ;; FIXME: sort the methods
70 (values applicable-methods t
)))
72 (defmethod compute-applicable-methods
73 ((generic-function gf-with-or
) arguments
)
74 ;; FIXME: assume one-argument for now
75 (let (applicable-methods)
76 (let ((methods (generic-function-methods generic-function
)))
78 (let ((specializer (car (method-specializers m
)))
79 (argument (car arguments
)))
81 (class (when (typep argument specializer
)
82 (push m applicable-methods
)))
84 (when (eql (eql-specializer-object specializer
) argument
)
85 (push m applicable-methods
)))
87 (dolist (c (or-specializer-classes specializer
))
88 (when (typep argument c
)
89 (push m applicable-methods
))))))))
90 ;; FIXME: sort the methods
93 (defmethod add-direct-method ((specializer or-specializer
) method
)
94 (pushnew method
(slot-value specializer
'direct-methods
)))
96 (defmethod remove-direct-method ((specializer or-specializer
) method
)
97 (setf (slot-value specializer
'direct-methods
)
98 (remove method
(slot-value specializer
'direct-methods
))))
100 ;;; FIXME: write SPECIALIZER-DIRECT-GENERIC-FUNCTIONS method
102 (defclass class1
() ())
103 (defclass class2
() ())
104 (defclass class3
() ())
105 (defclass class4
(class1) ())
108 (:generic-function-class gf-with-or
))
110 (let ((specializer (ensure-or-specializer 'class1
'class2
)))
111 (eval `(defmethod foo ((x ,specializer
)) t
)))
113 (assert (foo (make-instance 'class1
)))
114 (assert (foo (make-instance 'class2
)))
115 (assert-error (foo (make-instance 'class3
)))
116 (assert (foo (make-instance 'class4
)))
118 ;;; check that we are actually cacheing effective methods. If the
119 ;;; representation in PCL changes, this test needs to change too.
120 (assert (typep (cddr (sb-pcl::gf-dfun-state
#'foo
)) 'sb-pcl
::caching
))