r4665: *** empty log message ***
[kmrcl.git] / attrib-class.lisp
1 ;;;; -*- Mode: Lisp; Syntax: ANSI-Common-Lisp; Base: 10 -*-
2 ;;;; *************************************************************************
3 ;;;; FILE IDENTIFICATION
4 ;;;;
5 ;;;; Name:          attrib-class.lisp
6 ;;;; Purpose:       Defines metaclass allowing use of attributes on slots
7 ;;;; Programmer:    Kevin M. Rosenberg
8 ;;;; Date Started:  Apr 2000
9 ;;;;
10 ;;;; $Id: attrib-class.lisp,v 1.5 2003/04/28 21:12:27 kevin Exp $
11 ;;;;
12 ;;;; This file, part of KMRCL, is Copyright (c) 2002 by Kevin M. Rosenberg
13 ;;;;
14 ;;;; KMRCL users are granted the rights to distribute and use this software
15 ;;;; as governed by the terms of the Lisp Lesser GNU Public License
16 ;;;; (http://opensource.franz.com/preamble.html), also known as the LLGPL.
17 ;;;; *************************************************************************
18
19 ;;;; Defines a metaclass that allows the use of attributes (or subslots)
20 ;;;; on slots. Based on example in AMOP, but modified to use ACL's MOP.
21
22 (in-package :kmrcl)
23
24 (defclass attributes-dsd (standard-direct-slot-definition)
25   ((attributes :initarg :attributes :initform nil 
26                :accessor attributes)))
27
28 (defclass attributes-esd (standard-effective-slot-definition)
29   ((attributes :initarg :attributes :initform nil 
30                :accessor slot-definition-attributes)))
31
32
33 (defclass attributes-class (standard-class)
34   ()
35   )
36
37 #+(or cmu scl sbcl)
38 (defmethod validate-superclass ((class attributes-class)
39                                 (superclass standard-class))
40   t)
41
42 (defmethod direct-slot-definition-class ((cl attributes-class) 
43                                               &rest iargs &key attributes)
44   (declare (ignorable attributes))
45 ;;  (format t "attributes:~s iargs:~s~%" attributes iargs)
46   (find-class 'attributes-dsd))
47
48 (eval-when (:compile-toplevel :load-toplevel :execute)
49   (when (>= (length (generic-function-lambda-list
50                      (ensure-generic-function
51                       'compute-effective-slot-definition)))
52             3)
53     (push :ho-named-cesd-fun cl:*features*)))
54
55 (defmethod compute-effective-slot-definition :around
56     ((cl attributes-class) #+ho-named-cesd-fun name dsds)
57   #+ho-named-cesd-fun (declare (ignore name))
58   (apply
59    #'make-instance 'attributes-esd 
60    :attributes (remove-duplicates (mapappend #'attributes dsds))
61    (compute-effective-slot-definition-initargs cl dsds))
62   )
63
64
65 #+ignore
66 (defmethod compute-effective-slot-definition :around
67     ((cl attributes-class) #+ho-named-cesd-fun name dsds)
68   #+ho-named-cesd-fun (declare (ignore name))
69   (let ((normal-slot (call-next-method)))
70     (setf (slot-definition-attributes normal-slot)
71       (remove-duplicates
72        (mapappend #'slot-definition-attributes dsds)))
73     normal-slot))
74
75
76 (defmethod compute-slots ((class attributes-class))
77   (let* ((normal-slots (call-next-method))
78          (alist
79           (mapcar
80            #'(lambda (slot)
81                (let ((attr-list (mapcar #'(lambda (attr) (cons attr nil))
82                                         (slot-definition-attributes slot))))
83                  (when attr-list
84                    (cons (mop::slot-definition-name slot) attr-list))))
85            normal-slots)))
86     (setq alist (delete nil alist))
87     (cons (mop::make-instance 'mop::standard-effective-slot-definition
88             :name 'all-attributes
89             :initform `',alist
90             :initfunction #'(lambda () alist))
91           normal-slots)))
92   
93 (defun slot-attribute (instance slot-name attribute)
94   (cdr (slot-attribute-bucket instance slot-name attribute)))
95
96 (defun (setf slot-attribute) (new-value instance slot-name attribute)
97   (setf (cdr (slot-attribute-bucket instance slot-name attribute))
98     new-value))
99
100 (defun slot-attribute-bucket (instance slot-name attribute)
101   (let* ((all-buckets (slot-value instance 'all-attributes))
102          (slot-bucket (assoc slot-name all-buckets)))
103     (unless slot-bucket
104       (error "The slot named ~S of ~S has no attributes."
105              slot-name instance))
106     (let ((attr-bucket (assoc attribute (cdr slot-bucket))))
107       (unless attr-bucket
108         (error "The slot named ~S of ~S has no attributes named ~S."
109                slot-name instance attribute))
110       attr-bucket)))
111
112