File: cx-layered-access-class.lisp

package info (click to toggle)
cl-contextl 0.40-2
  • links: PTS
  • area: main
  • in suites: lenny
  • size: 248 kB
  • ctags: 298
  • sloc: lisp: 2,271; makefile: 29
file content (166 lines) | stat: -rw-r--r-- 7,274 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
(in-package :contextl)

(defclass layered-access-class (standard-class)
  ())

(defmethod validate-superclass
           ((class layered-access-class)
            (superclass standard-class))
  t)

(defgeneric slot-definition-layeredp (slot)
  (:method ((slot slot-definition)) nil))

(defclass layered-direct-slot-definition (standard-direct-slot-definition)
  ((layeredp :initarg :layered
             :initform nil
             :reader slot-definition-layeredp)
   (layered-readers :initarg :layered-readers
                    :initform ()
                    :reader slot-definition-layered-readers)
   (layered-writers :initarg :layered-writers
                    :initform ()
                    :reader slot-definition-layered-writers)
   (layered-accessor-methods :initform ()
                             :accessor layered-accessor-methods)))

(defclass layered-effective-slot-definition (standard-effective-slot-definition)
  ())

(defmethod slot-definition-layeredp ((slot layered-effective-slot-definition))
  t)

(defmethod direct-slot-definition-class
           ((class layered-access-class) &key &allow-other-keys)
  (load-time-value (find-class 'layered-direct-slot-definition)))

(defvar *layered-effective-slot-definition-class*)

(defmethod effective-slot-definition-class
           ((class layered-access-class) &key &allow-other-keys)
  *layered-effective-slot-definition-class*)

(defmethod compute-effective-slot-definition
           ((class layered-access-class) name direct-slot-definitions)
  (declare (ignore name))
  (let ((*layered-effective-slot-definition-class*
         (if (some #'slot-definition-layeredp direct-slot-definitions)
           (load-time-value (find-class 'layered-effective-slot-definition))
           (load-time-value (find-class 'standard-effective-slot-definition)))))
    (call-next-method)))

(define-layered-function slot-value-using-layer (class object slot reader)
  (:method (class object slot reader)
   (declare (ignore class object slot))
   (funcall reader)))

(defmethod slot-value-using-class :around
  ((class layered-access-class) object (slot layered-effective-slot-definition))
  (flet ((reader () (call-next-method)))
    (slot-value-using-layer class object slot #'reader)))

(define-layered-function (setf slot-value-using-layer) (new-value class object slot writer)
  (:method (new-value class object slot writer)
   (declare (ignore class object slot))
   (funcall writer new-value)))

(defmethod (setf slot-value-using-class) :around
  (new-value (class layered-access-class) object (slot layered-effective-slot-definition))
  (flet ((writer (new-value) (call-next-method new-value class object slot)))
    (setf (slot-value-using-layer class object slot #'writer)
          new-value)))

(define-layered-function slot-boundp-using-layer (class object slot reader)
  (:method (class object slot reader)
   (declare (ignore class object slot))
   (funcall reader)))

(defmethod slot-boundp-using-class :around
  ((class layered-access-class) object (slot layered-effective-slot-definition))
  (flet ((reader () (call-next-method)))
    (slot-boundp-using-layer class object slot #'reader)))

(define-layered-function slot-makunbound-using-layer (class object slot writer)
  (:method (class object slot writer)
   (declare (ignore class object slot))
   (funcall writer)))

(defmethod slot-makunbound-using-class :around
  ((class layered-access-class) object (slot layered-effective-slot-definition))
  (flet ((writer () (call-next-method)))
    (slot-makunbound-using-layer class object slot #'writer)))

(defgeneric process-layered-access-slot-specification (slot-spec)
  (:method ((slot-spec symbol)) slot-spec)
  (:method ((slot-spec cons))
   (let ((plist (cdr slot-spec)))
     (if (get-properties plist '(:layered-reader :layered-writer :layered-accessor))
       (loop for (key value) on plist by #'cddr
             if (eq key :layered-reader)
             collect value into layered-readers
             else if (eq key :layered-writer)
             collect value into layered-writers
             else if (eq key :layered-accessor)
             collect value into layered-readers
             and collect `(setf ,value) into layered-writers
             else nconc (list key value) into other-initargs
             finally (return (list* (car slot-spec)
                                    :layered-readers layered-readers
                                    :layered-writers layered-writers
                                    other-initargs)))
       slot-spec))))

(defgeneric add-layered-accessors (class)
  (:method ((class layered-access-class))
   (loop with reader-specializers = (list class)
         with writer-specializers = (list (find-class 't) class)
         for slot in (class-direct-slots class)
         for slot-name = (slot-definition-name slot)
         for layer = (find-layer-class (slot-definition-layer slot)) do
         (loop for layered-reader in (slot-definition-layered-readers slot)
               for gf = (ensure-layered-function layered-reader :lambda-list '(object))
               for method = (ensure-layered-method
                             layered-reader
                             `(lambda (object)
                                (declare (optimize (speed 3) (debug 0) (safety 0)
                                                   (compilation-speed 0)))
                                (slot-value object ',slot-name))
                             :in-layer layer
                             :specializers reader-specializers)
               do (push (cons gf method) (layered-accessor-methods slot)))
         (loop for layered-writer in (slot-definition-layered-writers slot)
               for gf = (ensure-layered-function layered-writer
                                                 :lambda-list '(new-value object)
                                                 :argument-precedence-order '(object new-value))
               for method = (ensure-layered-method
                             layered-writer
                             `(lambda (new-value object)
                                (declare (optimize (speed 3) (debug 0) (safety 0)
                                                   (compilation-speed 0)))
                                (setf (slot-value object ',slot-name)
                                      new-value))
                             :in-layer layer
                             :specializers writer-specializers)
               do (push (cons gf method) (layered-accessor-methods slot))))))

(defgeneric remove-layered-accessors (class)
  (:method ((class layered-access-class))
   (loop for slot in (class-direct-slots class)
         do (loop for method in (layered-accessor-methods slot)
                  do (remove-method (car method) (cdr method))))))

(defmethod initialize-instance :after
  ((class layered-access-class) &key)
  (add-layered-accessors class))

(defmethod reinitialize-instance :around
  ((class layered-access-class)
   &key (direct-slots () direct-slots-p))
  (declare (ignore direct-slots))
  (if direct-slots-p
    (progn
      (remove-layered-accessors class)
      (call-next-method)
      (add-layered-accessors class)
      class)
    (call-next-method)))