Made attribute class layered
[clinton/lisp-on-lines.git] / src / attribute.lisp
CommitLineData
e7c5f95a 1(in-package :lisp-on-lines)
2
4358148e 3(define-layered-class direct-attribute-definition-class
4 (special-layered-direct-slot-definition contextl::singleton-direct-slot-definition)
5 ((attribute-properties :accessor direct-attribute-properties
6 :documentation "This is an plist to hold the values of the attribute's properties as described by this direct attrbiute definition.")))
e7c5f95a 7
4358148e 8(defmethod initialize-instance :after ((attribute direct-attribute-definition-class) &rest initargs)
9 (setf (direct-attribute-properties attribute) initargs))
e7c5f95a 10
4358148e 11(define-layered-class effective-attribute-definition-class (special-layered-effective-slot-definition)
12 ((direct-attributes :accessor attribute-direct-attributes)
13 (attribute-object :accessor attribute-object
f2ff8a16 14 :documentation "")
15 (attribute-object-initargs :accessor attribute-object-initargs)))
e7c5f95a 16
e7c5f95a 17
4358148e 18(define-layered-function attribute-value (object attribute))
e7c5f95a 19
4358148e 20(define-layered-method attribute-value (object attribute)
21
22 (let ((fn (handler-case (attribute-function attribute)
23 (unbound-slot () nil))))
24 (if fn
25 (funcall fn object)
26 (%attribute-value attribute))))
27
28(defmethod attribute-description (attribute)
29 ;(break "description for ~A is (slot-value attribute 'description-name)")
30 (find-layer (slot-value attribute 'description-class))
31#+nil (let ((name (slot-value attribute 'description-name)))
32 (when name
33 (find-description name))))
34
35
36(define-layered-class standard-attribute ()
37
38 ((effective-attribute-definition :initarg effective-attribute
39 :accessor attribute-effective-attribute-definition)
40 (description-name)
41 (description-class :initarg description-class)
42 (initfunctions :initform nil)
f2ff8a16 43 (attribute-class :accessor attribute-class
44 :initarg :attribute-class
4271ab0b 45 :initform 'standard-attribute
46 :layered t)
4358148e 47 (name :layered-accessor attribute-name
48 :initarg :name)
49 (label :layered-accessor attribute-label
50 :initarg :label
51 :initform nil
52 :layered t
53 ;:special t
54 )
e7c5f95a 55 (function
56 :initarg :function
57 :layered-accessor attribute-function
58 :layered t)
4358148e 59 (value :layered-accessor %attribute-value
60 :initarg :value
61 :layered t)))
62
63
64
65(defmethod print-object ((object standard-attribute) stream)
66 (print-unreadable-object (object stream :type nil :identity t)
67 (format stream "ATTRIBUTE ~A" (or (ignore-errors (attribute-name object)) "+unnamed-attribute+"))))
68
4271ab0b 69(defgeneric eval-property-initarg (att initarg)
70 (:method ((attribute standard-attribute) initarg)
71 nil)
72 (:method ((attribute standard-attribute) (initarg (eql :function)))
73 t))
74
75(defun prepare-initargs (att args)
76 (loop
77 :for (key arg)
78 :on args :by #'cddr
79 :nconc (list key
80 (if (eval-property-initarg att key)
81 (eval arg)
82 arg))))
83
4358148e 84(defvar *bypass-property-layered-function* nil)
85
86(define-layered-function property-layered-function (description attribute-name property-name)
87 (:method (description attribute-name property-name)
88 ;(dprint "First Time PLFunction for ~A ~A ~A" description attribute-name property-name)
89 (ensure-layered-function
90 (defining-description (intern (format nil "~A-~A-~A"
91 (description-print-name description)
92 attribute-name
93 property-name)))
94
95 :lambda-list '(description))))
96
97(define-layered-method (setf slot-value-using-layer)
98 :in-layer (context t)
99 (new-value class (attribute standard-attribute) property writer)
100
4271ab0b 101 (when (or *bypass-property-layered-function*)
4358148e 102 (return-from slot-value-using-layer (call-next-method)))
103
104
105 ;;FIXME: this is wrong for so many reasons.
106 (let ((layer
107 (find-layer (first (remove nil (closer-mop::class-precedence-list (class-of context))
108 :key #'class-name)))))
109
110
111 (flet ((do-set-slot()
112
113 (let ((fn
114 (let ((*bypass-property-layered-function* t))
115 (if (slot-boundp-using-class class attribute property)
116 (slot-value-using-class class attribute property)
117 (setf (slot-value-using-class class attribute property)
118 (property-layered-function
119 (attribute-description attribute)
120 (attribute-name attribute)
121 (closer-mop:slot-definition-name property)))))))
122 ;(dprint "We are setting the fn ~A " fn)
123 (when (not (generic-function-methods fn))
124 ; (dprint "... there are no methods on it ever")
125 ;; * This slot has never been set before.
126 ;; create a method on property-layered-function
127 ;; so subclasses can see this new property.
128 (ensure-layered-method
129 (layered-function-definer 'property-layered-function)
130 `(lambda (description attribute property)
131 (declare (ignore description attribute property))
132 ,fn)
133 :in-layer layer
134 :specializers
135 (list (class-of
136 (attribute-description attribute))
137 (closer-mop:intern-eql-specializer
138 (attribute-name attribute))
139 (closer-mop:intern-eql-specializer
140 (closer-mop:slot-definition-name property)))))
141
142
143 ;; finally, specialize this property to this description.
144 (ensure-layered-method
145 fn
146 `(lambda (description)
4271ab0b 147 (funcall ,(lambda()
148 new-value)))
4358148e 149 :in-layer layer
150 :specializers (list (class-of (attribute-description attribute)
151 ))))))
152
153 (if (slot-boundp attribute 'description-class)
154 (do-set-slot)
4271ab0b 155 (error "serrint wif no desc WTF!")))))
e7c5f95a 156
e7c5f95a 157
158(define-layered-method slot-value-using-layer
4358148e 159 :in-layer (layer t)
160 :around (class (attribute standard-attribute) property reader)
4358148e 161
81d70610 162 ;; (dprint "Getting the slot value of ~A" property)
4358148e 163
81d70610 164 ;; We do some magic in here and i thought it
165 ;; would be called magically in call-next-method.
166 ;; This explicit call is good enough for now.
167
168 (unless (slot-boundp-using-class class attribute property)
169 (slot-unbound class attribute (slot-definition-name property)))
170
4271ab0b 171 (let ((val (call-next-method)))
172
81d70610 173 (if (and
4271ab0b 174 ;; Not special access
175 (not (symbolp val))
4358148e 176 (contextl::slot-definition-layeredp property)
177 (not *bypass-property-layered-function*))
4271ab0b 178 (let ((fn val))
4358148e 179 ;(dprint "... using fn ~A to get value" fn)
180 (funcall fn layer (attribute-description attribute)))
4271ab0b 181 val)))
4358148e 182
81d70610 183(defmacro define-bypass-function (name function-name)
184 `(defun ,name (&rest args)
185 (let ((*bypass-property-layered-function* t))
186 (apply (function ,function-name) args))))
4358148e 187
81d70610 188(define-bypass-function real-slot-boundp-using-class slot-boundp-using-class)
189(define-bypass-function real-slot-value-using-class slot-value-using-class)
190(define-bypass-function (setf real-slot-value-using-class) (setf slot-value-using-class))
191
4358148e 192(defun slot-boundp-using-property-layered-function (class attribute property)
4271ab0b 193 ;(dprint "plf boundp:")
81d70610 194 (let* ((really-bound-p
195 (real-slot-boundp-using-class class attribute property))
196 (fn (if really-bound-p
197 (real-slot-value-using-class class attribute property)
198 (setf (real-slot-value-using-class class attribute property)
199 (property-layered-function
200 (attribute-description attribute)
4358148e 201 (attribute-name attribute)
81d70610 202 (closer-mop:slot-definition-name property))))))
4271ab0b 203
204 (if (symbolp fn)
205 ;;special symbol access in process
206 T
207 (if (generic-function-methods fn)
208 T
209 NIL))))
4358148e 210
81d70610 211(define-layered-method slot-boundp-using-layer
4358148e 212 :in-layer (layer t)
213 :around (class (attribute standard-attribute) property reader)
214 (if *bypass-property-layered-function*
215 (call-next-method)
216 (slot-boundp-using-property-layered-function class attribute property)))
217
218(defun attribute-value* (attribute)
219 (attribute-value *object* attribute))
220
221(defmacro with-attributes (names description &body body)
222 `(with-slots ,names ,description ,@body))
223
224(defun display-attribute (attribute)
225 (display-using-description attribute *display* *object*))
226
e7c5f95a 227(define-layered-method display-using-description
228 ((attribute standard-attribute) display object &rest args)
4358148e 229 (declare (ignore args))
230 (when (attribute-label attribute)
231 (format display "~A " (attribute-label attribute)))
232 (format display "~A" (attribute-value object attribute)))
233
234
e7c5f95a 235
236
237
238
239
240
241
242
243