chiark / gitweb /
a2783ee81d92085e17280086927ef848c5399b99
[sod] / src / class-make-proto.lisp
1 ;;; -*-lisp-*-
2 ;;;
3 ;;; Class construction protocol
4 ;;;
5 ;;; (c) 2009 Straylight/Edgeware
6 ;;;
7
8 ;;;----- Licensing notice ---------------------------------------------------
9 ;;;
10 ;;; This file is part of the Sensible Object Design, an object system for C.
11 ;;;
12 ;;; SOD is free software; you can redistribute it and/or modify
13 ;;; it under the terms of the GNU General Public License as published by
14 ;;; the Free Software Foundation; either version 2 of the License, or
15 ;;; (at your option) any later version.
16 ;;;
17 ;;; SOD is distributed in the hope that it will be useful,
18 ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 ;;; GNU General Public License for more details.
21 ;;;
22 ;;; You should have received a copy of the GNU General Public License
23 ;;; along with SOD; if not, write to the Free Software Foundation,
24 ;;; Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25
26 (cl:in-package #:sod)
27
28 ;;;--------------------------------------------------------------------------
29 ;;; Classes.
30
31 (export 'guess-metaclass)
32 (defgeneric guess-metaclass (class)
33   (:documentation
34    "Determine a suitable metaclass for the CLASS.
35
36    The default behaviour is to choose the most specific metaclass of any of
37    the direct superclasses of CLASS, or to signal an error if that failed."))
38
39 (export 'make-sod-class)
40 (defun make-sod-class (name superclasses pset &key location)
41   "Construct and return a new SOD class with the given NAME and SUPERCLASSES.
42
43    This is the main constructor function for classes.  The protocol works as
44    follows.  The `:lisp-metaclass' property in PSET is checked: if it exists,
45    it must be a symbol naming a (CLOS) class, which is used in place of
46    `sod-class'.  All of the arguments are then passed to `make-instance';
47    further behaviour is left to the standard CLOS instance construction
48    protocol; for example, `sod-class' defines an `:after'-method on
49    `shared-initialize'.
50
51    Minimal sanity checking is done during class construction; most of it is
52    left for `finalize-sod-class' to do (via `check-sod-class')."
53
54   (with-default-error-location (location)
55     (let* ((pset (property-set pset))
56            (best-class (or (get-property pset :lisp-metaclass :symbol nil)
57                            (select-minimal-class-property
58                             superclasses #'class-of #'subtypep 'sod-class
59                             "Lisp metaclass"
60                             :present (lambda (class)
61                                        (format nil "`~S'"
62                                                (class-name class)))
63                             :allow-empty t)))
64            (class (make-instance best-class
65                                  :name name
66                                  :superclasses superclasses
67                                  :location (file-location location)
68                                  :pset pset)))
69       class)))
70
71 ;;;--------------------------------------------------------------------------
72 ;;; Slots and slot initializers.
73
74 (export 'make-sod-slot)
75 (defgeneric make-sod-slot (class name type pset &key location)
76   (:documentation
77    "Construct, add, and attach a new slot with given NAME and TYPE, to CLASS.
78
79    This is the main constructor function for slots.  This is a generic
80    function primarily so that the CLASS can intervene in the construction
81    process.  The default method uses the `:slot-class' property (defaulting
82    to `sod-slot') to choose a (CLOS) class to instantiate.  The slot is then
83    constructed by `make-instance' passing the arguments as initargs; further
84    behaviour is left to the standard CLOS instance construction protocol; for
85    example, `sod-slot' defines an `:after'-method on `shared-initialize'."))
86
87 (export 'make-sod-instance-initializer)
88 (defgeneric make-sod-instance-initializer
89     (class nick name value pset &key location)
90   (:documentation
91    "Construct and attach an instance slot initializer, to CLASS.
92
93    This is the main constructor function for instance initializers.  This is
94    a generic function primarily so that the CLASS can intervene in the
95    construction process.  The default method looks up the slot using
96    `find-instance-slot-by-name', calls `make-sod-initializer-using-slot' to
97    actually make the initializer object, and adds it to the appropriate list
98    in CLASS."))
99
100 (export 'make-sod-class-initializer)
101 (defgeneric make-sod-class-initializer
102     (class nick name value pset &key location)
103   (:documentation
104    "Construct and attach a class slot initializer, to CLASS.
105
106    This is the main constructor function for class initializers.  This is a
107    generic function primarily so that the CLASS can intervene in the
108    construction process.  The default method looks up the slot using
109    `find-class-slot-by-name', calls `make-sod-initializer-using-slot' to
110    actually make the initializer object, and adds it to the appropriate list
111    in CLASS."))
112
113 (export 'make-sod-initializer-using-slot)
114 (defgeneric make-sod-initializer-using-slot
115     (class slot init-class value pset location)
116   (:documentation
117    "Common construction protocol for slot initializers.
118
119    This generic function does the common work for constructing instance and
120    class initializers.  It can usefully be specialized according to both the
121    class and slot types.  The default method uses the `:initializer-class'
122    property (defaulting to INIT-CLASS) to choose a (CLOS) class to
123    instantiate.  The slot is then constructed by `make-instance' passing the
124    arguments as initargs; further behaviour is left to the standard CLOS
125    instance construction protocol; for example, `sod-initializer' defines an
126    `:after'-method on `shared-initialize'.
127
128    Diagnosing unused properties is left for the caller (usually
129    `make-sod-instance-initializer' or `make-sod-class-initializer') to do.
130    The caller is also expected to have set `with-default-error-location' if
131    appropriate.
132
133    You are not expected to call this generic function directly; it's more
134    useful as a place to hang methods for custom initializer classes."))
135
136 (export 'make-sod-user-initarg)
137 (defgeneric make-sod-user-initarg
138     (class name type pset &key default location)
139   (:documentation
140    "Attach a user-defined initialization keyword argument to the CLASS.
141
142    The new argument has the given NAME and TYPE, and maybe a DEFAULT value.
143    Currently, initialization arguments are just dumb objects held in a
144    list."))
145
146 (export 'make-sod-slot-initarg)
147 (defgeneric make-sod-slot-initarg
148     (class name nick slot-name pset &key location)
149   (:documentation
150    "Attach an initialization keyword argument to a slot by name.
151
152    The default method uses `find-instance-slot-by-name' to find the slot, and
153    `make-slot-initarg-using-slot' to actually make and attach the initarg."))
154
155 (export 'make-sod-slot-initarg-using-slot)
156 (defgeneric make-sod-slot-initarg-using-slot
157     (class name slot pset &key location)
158   (:documentation
159    "Attach an initialization keyword argument to a SLOT.
160
161    The argument's type is taken from the slot type.  Slot initargs can't have
162    defaults: the slot's most-specific initializer is used instead.
163
164    You are not expected to call this generic function directly; it's more
165    useful as a place to hang methods for custom classes."))
166
167 (export 'sod-initarg-argument)
168 (defgeneric sod-initarg-argument (initarg)
169   (:documentation "Returns an `argument' object for the initarg."))
170
171 (export 'make-sod-class-initfrag)
172 (defgeneric make-sod-class-initfrag (class frag pset &key location)
173   (:documentation
174    "Attach an initialization fragment FRAG to the CLASS.
175
176    Currently, initialization fragments are just dumb objects held in a
177    list."))
178
179 (export 'make-sod-class-tearfrag)
180 (defgeneric make-sod-class-tearfrag (class frag pset &key location)
181   (:documentation
182    "Attach a teardown fragment FRAG to the CLASS.
183
184    Currently, teardown fragments are just dumb objects held in a
185    list."))
186
187 ;;;--------------------------------------------------------------------------
188 ;;; Messages and methods.
189
190 (export 'make-sod-message)
191 (defgeneric make-sod-message (class name type pset &key location)
192   (:documentation
193    "Construct and attach a new message with given NAME and TYPE, to CLASS.
194
195    This is the main constructor function for messages.  This is a generic
196    function primarily so that the CLASS can intervene in the construction
197    process.  The default method uses the `:message-class' property to choose
198    a (CLOS) class to instantiate; if no such property is provided but a
199    `combination' property is present, then `aggregating-message' is chosen;
200    otherwise `standard-message' is used.  The message is then constructed by
201    `make-instance' passing the arguments as initargs; further behaviour is
202    left to the standard CLOS instance construction protocol; for example,
203    `sod-message' defines an `:after'-method on `shared-initialize'."))
204
205 (export 'make-sod-method)
206 (defgeneric make-sod-method
207     (class nick name type body pset &key location)
208   (:documentation
209    "Construct and attach a new method to CLASS.
210
211    This is the main constructor function for methods.  This is a generic
212    function primarily so that the CLASS can intervene in the message lookup
213    process, though this is actually a fairly unlikely occurrence.
214
215    The default method looks up the message using `find-message-by-name',
216    invokes `make-sod-method-using-message' to make the method object, and
217    then adds the method to the class's list of methods.  This split allows
218    the message class to intervene in the class selection process, for
219    example."))
220
221 (export 'make-sod-method-using-message)
222 (defgeneric make-sod-method-using-message
223     (message class type body pset location)
224   (:documentation
225    "Main construction subroutine for method construction.
226
227    This is a generic function so that it can be specialized according to both
228    a class and -- more particularly -- a message.  The default method uses
229    the `:method-class' property (defaulting to the result of calling
230    `sod-message-method-class') to choose a (CLOS) class to instantiate.  The
231    method is then constructed by `make-instance' passing the arguments as
232    initargs; further behaviour is left to the standard CLOS instance
233    construction protocol; for example, `sod-method' defines an
234    `:after'-method on `shared-initialize'.
235
236    Diagnosing unused properties is left for the caller (usually
237    `make-sod-method') to do.  The caller is also expected to have set
238    `with-default-error-location' if appropriate.
239
240    You are not expected to call this generic function directly; it's more
241    useful as a place to hang methods for custom method classes."))
242
243 (export 'sod-message-method-class)
244 (defgeneric sod-message-method-class (message class pset)
245   (:documentation
246    "Return the preferred class for methods on MESSAGE.
247
248    The message can inspect the PSET to decide on a particular message.  A
249    `:method-class' property will usually override this decision: it's then
250    the programmer's responsibility to ensure that the selected method class
251    is appropriate."))
252
253 (export 'check-message-type)
254 (defgeneric check-message-type (message type)
255   (:documentation
256    "Check that TYPE is a suitable type for MESSAGE.  Signal errors if not.
257
258    This is separated out of `shared-initialize', where it's called, so that
259    it can be overridden conveniently by subclasses."))
260
261 (export 'check-method-type)
262 (defgeneric check-method-type (method message type)
263   (:documentation
264    "Check that TYPE is a suitable type for METHOD.  Signal errors if not.
265
266    This is separated out of `shared-initialize', where it's called, so that
267    it can be overridden conveniently by subclasses."))
268
269 ;;;----- That's all, folks --------------------------------------------------