Take pointer, not word count, as upper limit in verify_space()
[sbcl.git] / tests / mop-27.impure.lisp
blob03051c21522232a53ecc7b43e1a9aeb9497a9483
1 ;;;; miscellaneous side-effectful tests of the MOP
3 ;;;; This software is part of the SBCL system. See the README file for
4 ;;;; more information.
5 ;;;;
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
8 ;;;; from CMU CL.
9 ;;;;
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. Some context: a
15 ;;; (mostly content-free) discussion on comp.lang.lisp around
16 ;;; 2007-05-08 about the merits of Lisp, wherein an F#/OCaml advocate
17 ;;; implies roughly "I've heard that CLOS is slower than pattern
18 ;;; matching"
20 ;;; This implements a generic function type which dispatches on
21 ;;; patterns in its methods. The implementation below is a simple
22 ;;; interpreter of patterns; compiling the patterns into a
23 ;;; discrimination net, or other optimized dispatch structure, would
24 ;;; be an interesting exercise for the reader. (As would fixing some
25 ;;; other marked issues).
27 (defpackage "MOP-27"
28 (:use "CL" "SB-MOP"))
30 (in-package "MOP-27")
32 (defclass pattern-specializer (specializer)
33 ((pattern :initarg pattern :reader pattern)
34 (direct-methods :initform nil :reader specializer-direct-methods)))
36 (defvar *pattern-specializer-table* (make-hash-table :test 'equal))
38 (defun ensure-pattern-specializer (pattern)
39 (or (gethash pattern *pattern-specializer-table*)
40 (setf (gethash pattern *pattern-specializer-table*)
41 (make-instance 'pattern-specializer 'pattern pattern))))
43 ;;; only one arg for now
44 (defclass pattern-gf/1 (standard-generic-function) ()
45 (:metaclass funcallable-standard-class))
47 (defun matchesp (arg pattern)
48 (cond
49 ((null pattern) t)
50 ((atom pattern) (eql arg pattern))
51 (t (and (matchesp (car arg) (car pattern))
52 (matchesp (cdr arg) (cdr pattern))))))
54 (defun method-interpreting-function (methods gf)
55 (lambda (arg)
56 (dolist (method methods (no-applicable-method gf (list arg)))
57 (when (matchesp arg (pattern (car (method-specializers method))))
58 (return (funcall (method-function method) (list arg) nil))))))
60 (defmethod compute-discriminating-function ((generic-function pattern-gf/1))
61 (lambda (arg)
62 (let* ((methods (generic-function-methods generic-function))
63 (function (method-interpreting-function methods generic-function)))
64 (set-funcallable-instance-function generic-function function)
65 (funcall function arg))))
67 ;;; protocol functions. SPECIALIZER-DIRECT-METHODS is implemented by
68 ;;; a reader on the specializer. FIXME: implement
69 ;;; SPECIALIZER-DIRECT-GENERIC-FUNCTIONS.
70 (defmethod add-direct-method ((specializer pattern-specializer) method)
71 (pushnew method (slot-value specializer 'direct-methods)))
72 (defmethod remove-direct-method ((specializer pattern-specializer) method)
73 (setf (slot-value specializer 'direct-methods)
74 (remove method (slot-value specializer 'direct-methods))))
76 (defgeneric simplify (x)
77 (:generic-function-class pattern-gf/1))
78 ;;; KLUDGE: order of definition matters, as we simply traverse
79 ;;; generic-function-methods until a pattern matches our argument.
80 ;;; Additionally, we're not doing anything interesting with regard to
81 ;;; destructuring the pattern for use in the method body; a real
82 ;;; implementation would make it more convenient.
83 (let ((specializer (ensure-pattern-specializer 'nil)))
84 (eval `(defmethod simplify ((x ,specializer)) x)))
85 (let ((specializer (ensure-pattern-specializer '(* nil 0))))
86 (eval `(defmethod simplify ((x ,specializer)) 0)))
87 (let ((specializer (ensure-pattern-specializer '(* 0 nil))))
88 (eval `(defmethod simplify ((x ,specializer)) 0)))
90 (assert (eql (simplify '(* 0 3)) 0))
91 (assert (eql (simplify '(* (+ x y) 0)) 0))
92 (assert (equal (simplify '(+ x y)) '(+ x y)))