X-Git-Url: http://christophe.rhodes.io/gitweb/?p=specializable.git;a=blobdiff_plain;f=prototype-specializer.lisp;fp=prototype-specializer.lisp;h=0000000000000000000000000000000000000000;hp=4a2c841f9b08c3598d469da611939cd63c1f689c;hb=9dd8f1378407cae8ec7b6b05a8b3c152bc4a5f9b;hpb=d55ebbbcbd77023c799d8d95dce5d3772aec5841 diff --git a/prototype-specializer.lisp b/prototype-specializer.lisp deleted file mode 100644 index 4a2c841..0000000 --- a/prototype-specializer.lisp +++ /dev/null @@ -1,197 +0,0 @@ -(in-package "SPECIALIZABLE") - -(defclass prototype-object () - (;; FIXME: we should add slots at some point - (delegations :initarg :delegations :accessor delegations) - (roles :initform (make-array 0 :adjustable t :fill-pointer t) - :accessor roles) - ;; debugging aid - (name))) -(defmethod print-object ((o prototype-object) s) - (if (slot-boundp o 'name) - (format s "~S" (slot-value o 'name)) - (print-unreadable-object (o s :type t :identity t) - (format s "[~{~S~^, ~}]" (delegations o))))) -(defun add-delegation (obj del) - (push del (delegations obj))) -(defun remove-delegation (obj) - (pop (delegations obj))) -(defun map-delegations (fun obj) - (funcall fun obj) - ;; FIXME: should we maintain a table of visited nodes? Should it be - ;; topologically sorted? Section 5.3 in PwMD [Salzman & Aldrich] - ;; suggests not, at least for now - (mapc (lambda (o) (map-delegations fun o)) (delegations obj)) - nil) -(defstruct (role (:type list) (:constructor make-role (method argpos))) - method argpos) -(defun add-role (obj role) - (let ((pos (role-argpos role)) - (roles (roles obj))) - (unless (< pos (length roles)) - (dotimes (i (- (1+ pos) (length roles))) - (vector-push-extend nil roles))) - (pushnew (role-method role) (aref roles pos)))) -(defun remove-role (obj role) - (let ((pos (role-argpos role))) - (setf (aref (roles obj) pos) - (remove (role-method role) (aref (roles obj) pos))) - (tagbody - start - (when (or (= (length (roles obj)) 0) - (aref (roles obj) (1- (length (roles obj))))) - (go done)) - (vector-pop (roles obj)) - (go start) - done))) -(defun map-roles (fun obj) - (dotimes (i (length (roles obj))) - (dolist (m (aref (roles obj) i)) - (funcall fun (make-role m i))))) -(defun find-role (role obj) - (when (< (role-argpos role) (length (roles obj))) - (find (role-method role) (aref (roles obj) (role-argpos role))))) -(defmacro do-roles ((rvar form &optional result) &body body) - `(progn (map-roles (lambda (,rvar) ,@body) ,form) ,result)) -(defun clone (p) - (let ((result (make-instance 'prototype-object - :delegations (copy-list (delegations p))))) - (do-roles (r p result) - (add-role result r)))) - -;;; redefinition semantics are interesting. We need the INFO here so -;;; that we can implement specializer-accepts-p, which must be able to -;;; lookup the particular method/argpos that the specializer -;;; represents. But we must also be able to redefine methods in a way -;;; that isn't insane, which I think implies that same-specializer-p -;;; should ignore the INFO and just use the OBJECT. -(defclass prototype-specializer (extended-specializer) - ((role :accessor prototype-specializer-role) - (object :initarg :object :accessor prototype-specializer-object))) -(defmethod print-object ((o prototype-specializer) s) - (print-unreadable-object (o s :type t :identity t) - (format s "~S" (prototype-specializer-object o)))) -(defmethod sb-pcl::same-specializer-p - ((s1 prototype-specializer) (s2 prototype-specializer)) - (eql (prototype-specializer-object s1) - (prototype-specializer-object s2))) -(defclass prototype-generic-function (specializable-generic-function) - () - (:metaclass sb-mop:funcallable-standard-class)) -(defmethod sb-pcl:make-method-specializers-form - ((gf prototype-generic-function) method snames env) - (flet ((frob (x) - (typecase x - (sb-mop:specializer x) - (symbol `(make-instance 'prototype-specializer :object ,x)) - ((cons (eql 'class)) `(find-class ',(cadr x))) - ((cons (eql 'eql)) `(sb-mop:intern-eql-specializer ,(cadr x))) - (t (error "unexpected specializer name: ~S" x))))) - `(list ,@(mapcar #'frob snames)))) -(defmethod sb-pcl:parse-specializer-using-class - ((gf prototype-generic-function) name) - (make-instance 'prototype-specializer :object name)) -(defmethod sb-pcl:unparse-specializer-using-class - ((gf prototype-generic-function) (s prototype-specializer)) - (let ((object (prototype-specializer-object s))) - (if (slot-boundp object 'name) - (slot-value object 'name) - s))) - -(defmethod add-method :after ((gf prototype-generic-function) m) - (let ((ss (sb-mop:method-specializers m))) - (do* ((i 0 (1+ i)) - (ss ss (cdr ss)) - (s (car ss) (car ss))) - ((null ss)) - (when (typep s 'prototype-specializer) - (let ((object (prototype-specializer-object s)) - (role (make-role m i))) - (setf (prototype-specializer-role s) role) - (add-role object role)))))) -(defmethod remove-method :after ((gf prototype-generic-function) m) - (let ((ss (sb-mop:method-specializers m))) - (do* ((i 0 (1+ i)) - (ss ss (cdr ss)) - (s (car ss) (car ss))) - ((null ss)) - (when (typep s 'prototype-specializer) - (let ((object (prototype-specializer-object s)) - (role (make-role m i))) - (setf (prototype-specializer-role s) nil) - ;; this is one of the places where the semantics - ;; are... dodgy. Removing the method from the generic - ;; function, and the role from the object, doesn't affect - ;; the roles in any clones. We could potentially use the - ;; fact that once removed the method is no longer associated - ;; with a generic function? Hm, C-A-M will not consider the - ;; removed method for applicability... - (remove-role object role)))))) - -(defmethod generalizer-of-using-class - ((gf prototype-generic-function) (object prototype-object)) - object) - -(defmethod specializer-accepts-generalizer-p - ((gf prototype-generic-function) (s prototype-specializer) object) - (values (specializer-accepts-p s object) t)) - -(defmethod specializer-accepts-p ((specializer prototype-specializer) object) - (cond - ((not (typep object 'prototype-object)) nil) - ((eql (prototype-specializer-object specializer) /root/) t) - (t - (let ((role (prototype-specializer-role specializer))) - (map-delegations - (lambda (o) - (when (find-role role o) - (return-from specializer-accepts-p t))) - object))))) - -(defmethod specializer< ((gf prototype-generic-function) (s1 prototype-specializer) (s2 prototype-specializer) g) - (let ((o1 (prototype-specializer-object s1)) - (o2 (prototype-specializer-object s2))) - (map-delegations - (lambda (o) - (cond - ((eql o o1) (return-from specializer< '<)) - ((eql o o2) (return-from specializer< '>)))) - g) - '=)) - -(defmethod compute-applicable-methods-using-generalizers ((gf prototype-generic-function) generalizers) - (values nil nil)) -(defmethod generalizer-equal-hash-key ((gf prototype-generic-function) (g prototype-object)) - g) - -(defmacro defpvar (name value) - `(let ((val ,value)) - (setf (slot-value val 'name) ',name) - (defparameter ,name val))) - -(defpvar /root/ (make-instance 'prototype-object :delegations nil)) -(defpvar /animal/ (clone /root/)) -(defpvar /fish/ (clone /root/)) -(defpvar /shark/ (clone /root/)) -(defpvar /healthy-shark/ (clone /root/)) -(defpvar /dying-shark/ (clone /root/)) -(add-delegation /fish/ /animal/) -(add-delegation /shark/ /animal/) -(add-delegation /shark/ /healthy-shark/) -(defgeneric encounter (x y) - (:generic-function-class prototype-generic-function)) -(defmethod encounter ((x /fish/) (y /healthy-shark/)) - (format t "~&~A swims away~%" x)) -(defmethod encounter ((x /fish/) (y /animal/)) - x) -(defgeneric fight (x y) - (:generic-function-class prototype-generic-function)) -(defmethod fight ((x /healthy-shark/) (y /shark/)) - (remove-delegation x) - (add-delegation x /dying-shark/) - x) -(defmethod encounter ((x /healthy-shark/) (y /fish/)) - (format t "~&~A swallows ~A~%" x y)) -(defmethod encounter ((x /healthy-shark/) (y /shark/)) - (format t "~&~A fights ~A~%" x y) - (fight x y))