src/utilities.lisp (once-only): Ensure that the BINDS argument is a list.
[sod] / src / classes.lisp
1 ;;; -*-lisp-*-
2 ;;;
3 ;;; Class definitions for main classes
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 ;;; Note! You'll notice that none of the classes defined here store property
29 ;;; sets persistently, even though there's a `:pset' keyword argument
30 ;;; accepted by many of the classes' initialization methods. That's because
31 ;;; part of the pset protocol involves checking that there are no unused
32 ;;; properties, and this typically happens shortly after the appropriate
33 ;;; objects are constructed. It would be tempting to stash the pset at
34 ;;; initialization time, and then pick some property from it out later -- but
35 ;;; that won't work in general because an error might have been signalled
36 ;;; about that property. It wouldn't surprise me greatly to discover that
37 ;;; `most' code paths resulted in the property being looked up in time to
38 ;;; avoid the unused-property error, but a subtle change in circumstances
39 ;;; then causes a thing done on demand to be done later, leading to
40 ;;; irritating and misleading errors being reported to the user. So please
41 ;;; don't do that.
42
43 ;;;--------------------------------------------------------------------------
44 ;;; Classes.
45
46 (export '(sod-class sod-class-name sod-class-nickname
47 sod-class-type sod-class-metaclass
48 sod-class-direct-superclasses sod-class-precedence-list
49 sod-class-chain-link sod-class-chain-head
50 sod-class-chain sod-class-chains
51 sod-class-slots sod-class-initfrags sod-class-tearfrags
52 sod-class-instance-initializers sod-class-class-initializers
53 sod-class-messages sod-class-methods
54 sod-class-state
55 sod-class-ilayout sod-class-vtables))
56 (defclass sod-class ()
57 ((name :initarg :name :type string :reader sod-class-name)
58 (location :initarg :location :initform (file-location nil)
59 :type file-location :reader file-location)
60 (nickname :initarg :nick :type string :reader sod-class-nickname)
61 (direct-superclasses :initarg :superclasses :type list
62 :reader sod-class-direct-superclasses)
63 (chain-link :initarg :link :type (or sod-class null)
64 :reader sod-class-chain-link)
65 (metaclass :initarg :metaclass :type sod-class
66 :reader sod-class-metaclass)
67 (slots :initarg :slots :initform nil
68 :type list :accessor sod-class-slots)
69 (instance-initializers :initarg :instance-initializers :initform nil
70 :type list
71 :accessor sod-class-instance-initializers)
72 (class-initializers :initarg :class-initializers :initform nil
73 :type list :accessor sod-class-class-initializers)
74 (initargs :initarg :initargs :initform nil
75 :type list :accessor sod-class-initargs)
76 (initfrags :initarg :initfrags :initform nil
77 :type list :accessor sod-class-initfrags)
78 (tearfrags :initarg :tearfrags :initform nil
79 :type list :accessor sod-class-tearfrags)
80 (messages :initarg :messages :initform nil
81 :type list :accessor sod-class-messages)
82 (methods :initarg :methods :initform nil
83 :type list :accessor sod-class-methods)
84
85 (class-precedence-list :type list :reader sod-class-precedence-list)
86
87 (%type :type c-class-type :reader sod-class-type)
88
89 (chain-head :type sod-class :reader sod-class-chain-head)
90 (chain :type list :reader sod-class-chain)
91 (chains :type list :reader sod-class-chains)
92
93 (%ilayout :type ilayout :reader sod-class-ilayout)
94 (effective-methods :type list :reader sod-class-effective-methods)
95 (vtables :type list :reader sod-class-vtables)
96
97 (state :initform nil :type (member nil :finalized :broken)
98 :reader sod-class-state))
99 (:documentation
100 "Classes describe the layout and behaviour of objects.
101
102 The NAME, LOCATION, NICKNAME, DIRECT-SUPERCLASSES, CHAIN-LINK and
103 METACLASS slots are intended to be initialized when the class object is
104 constructed:
105
106 * The NAME is the identifier associated with the class in the user's
107 source file. It is used verbatim in the generated C code as a type
108 name, and must be distinct from other file-scope names in any source
109 file which includes the class definition. Furthermore, other names
110 are derived from the class name (most notably the class object
111 NAME__class), which have external linkage and must therefore be
112 distinct from all other identifiers in the program. It is forbidden
113 for a class NAME to begin with an underscore or to contain two
114 consecutive underscores.
115
116 * The LOCATION identifies where in the source the class was defined. It
117 gets used in error messages.
118
119 * The NICKNAME is a shorter identifier used to name the class in some
120 circumstances. The uniqueness requirements on NICKNAME are less
121 strict, which allows them to be shorter: no class may have two classes
122 with the same nickname on its class precedence list. Nicknames are
123 used (user-visibly) to distinguish slots and messages defined by
124 different classes, and (invisibly) in the derived names of direct
125 methods. It is forbidden for a nickname to begin with an underscore,
126 or to contain two consecutive underscores.
127
128 * The DIRECT-SUPERCLASSES are a list of the class's direct superclasses,
129 in the order that they were declared in the source. The class
130 precedence list is computed from the DIRECT-SUPERCLASSES lists of all
131 of the superclasses involved.
132
133 * The CHAIN-LINK is either NIL or one of the DIRECT-SUPERCLASSES. Class
134 chains are a means for recovering most of the benefits of simple
135 hierarchy lost by the introduction of multiple inheritance. A class's
136 superclasses (including itself) are partitioned into chains,
137 consisting of a class, its CHAIN-LINK superclass, that class's
138 CHAIN-LINK, and so on. It is an error if two direct subclasses of any
139 class appear in the same chain (a global property which requires
140 global knowledge of an entire program's class hierarchy in order to
141 determine sensibly). Slots of superclasses in the same chain can be
142 accessed efficiently; there is an indirection needed to access slots
143 of superclasses in other chains. Furthermore, an indirection is
144 required to perform a cross-chain conversion (i.e., converting a
145 pointer to an instance of some class into a pointer to an instance of
146 one of its superclasses in a different chain), an operation which
147 occurs implicitly in effective methods in order to call direct methods
148 defined on cross-chain superclasses.
149
150 * The METACLASS is the class of the class object. Classes are objects
151 in their own right, and therefore must be instances of some class;
152 this class is the metaclass. Metaclasses can define additional slots
153 and methods to be provided by their instances; a class definition can
154 provide (C constant expression) initial values for the metaclass
155 instance.
156
157 The next few slots can't usually be set at object-construction time, since
158 the objects need to contain references to the class object itself.
159
160 * The SLOTS are a list of the slots defined by the class (instances of
161 `sod-slot'). (The class will also define all of the slots defined by
162 its superclasses.)
163
164 * The INSTANCE-INITIALIZERS and CLASS-INITIALIZERS are lists of
165 initializers for slots (see `sod-initializer' and subclasses),
166 providing initial values for instances of the class, and for the
167 class's class object itself, respectively.
168
169 * The MESSAGES are a list of the messages recognized by the class
170 (instances of `sod-message' and subclasses). (Note that the message
171 need not have any methods defined on it. The class will also
172 recognize all of the messages defined by its superclasses.)
173
174 * The METHODS are a list of (direct) methods defined on the class
175 (instances of `sod-method' and subclasses). Each method provides
176 behaviour to be invoked by a particular message recognized by the
177 class.
178
179 Other slots are computed from these in order to describe the class's
180 layout and effective methods; this is done by `finalize-sod-class'.
181
182 * The CLASS-PRECEDENCE-LIST is a list of superclasses in a linear order.
183 It is computed by `compute-class-precedence-list', whose default
184 implementation ensures that the order of superclasses is such that (a)
185 subclasses appear before their superclasses; (b) the direct
186 superclasses of a given class appear in the order in which they were
187 declared by the programmer; and (c) classes always appear in the same
188 relative order in all class precedence lists in the same superclass
189 graph.
190
191 * The CHAIN-HEAD is the least-specific class in the class's chain. If
192 there is no link class then the CHAIN-HEAD is the class itself. This
193 slot, like the next two, is computed by the generic function
194 `compute-chains'.
195
196 * The CHAIN is the list of classes on the complete primary chain,
197 starting from this class and ending with the CHAIN-HEAD.
198
199 * The CHAINS are the complete collection of chains (most-to-least
200 specific) for the class and all of its superclasses.
201
202 Finally, slots concerning the instance and vtable layout of the class are
203 computed on demand (see `define-on-demand-slot').
204
205 * The ILAYOUT describes the layout for an instance of the class. It's
206 quite complicated; see the documentation of the `ilayout' class for
207 detais.
208
209 * The EFFECTIVE-METHODS are a list of effective methods, specialized for
210 the class.
211
212 * The VTABLES are a list of descriptions of vtables for the class. The
213 individual elements are `vtable' objects, which are even more
214 complicated than `ilayout' structures. See the class documentation
215 for details."))
216
217 (defmethod print-object ((class sod-class) stream)
218 (maybe-print-unreadable-object (class stream :type t)
219 (princ (sod-class-name class) stream)))
220
221 ;;;--------------------------------------------------------------------------
222 ;;; Slots and initializers.
223
224 (export '(sod-slot sod-slot-name sod-slot-class sod-slot-type))
225 (defclass sod-slot ()
226 ((name :initarg :name :type string :reader sod-slot-name)
227 (location :initarg :location :initform (file-location nil)
228 :type file-location :reader file-location)
229 (%class :initarg :class :type sod-class :reader sod-slot-class)
230 (%type :initarg :type :type c-type :reader sod-slot-type))
231 (:documentation
232 "Slots are units of information storage in instances.
233
234 Each class defines a number of slots, which function similarly to (data)
235 members in structures. An instance contains all of the slots defined in
236 its class and all of its superclasses.
237
238 A slot carries the following information.
239
240 * A NAME, which distinguishes it from other slots defined by the same
241 class. Unlike most (all?) other object systems, slots defined in
242 different classes are in distinct namespaces. There are no special
243 restrictions on slot names.
244
245 * A LOCATION, which states where in the user's source the slot was
246 defined. This gets used in error messages.
247
248 * A CLASS, which states which class defined the slot. The slot is
249 available in instances of this class and all of its descendents.
250
251 * A TYPE, which is the C type of the slot. This must be an object type
252 (certainly not a function type, and it must be a complete type by the
253 time that the user header code has been scanned)."))
254
255 (defmethod print-object ((slot sod-slot) stream)
256 (maybe-print-unreadable-object (slot stream :type t)
257 (pprint-c-type (sod-slot-type slot) stream
258 (format nil "~A.~A"
259 (sod-class-nickname (sod-slot-class slot))
260 (sod-slot-name slot)))))
261
262 (export '(sod-initializer sod-initializer-slot sod-initializer-class
263 sod-initializer-value))
264 (defclass sod-initializer ()
265 ((slot :initarg :slot :type sod-slot :reader sod-initializer-slot)
266 (location :initarg :location :initform (file-location nil)
267 :type file-location :reader file-location)
268 (%class :initarg :class :type sod-class :reader sod-initializer-class)
269 (value :initarg :value :type c-fragment :reader sod-initializer-value))
270 (:documentation
271 "Provides an initial value for a slot.
272
273 The slots of an initializer are as follows.
274
275 * The SLOT specifies which slot this initializer is meant to initialize.
276
277 * The LOCATION states the position in the user's source file where the
278 initializer was found. This gets used in error messages. (Depending
279 on the source layout style, this might differ from the location in the
280 VALUE C fragment.)
281
282 * The CLASS states which class defined this initializer. For instance
283 slot initializers (`sod-instance-initializer'), this will be the same
284 as the SLOT's class, or be one of its descendants. For class slot
285 initializers (`sod-class-initializer'), this will be an instance of
286 the SLOT's class, or an instance of one of its descendants.
287
288 * The VALUE gives the text of the initializer, as a C fragment.
289
290 Typically you'll see instances of subclasses of this class in the wild
291 rather than instances of this class directly. See `sod-class-initializer'
292 and `sod-instance-initializer'."))
293
294 (defmethod print-object ((initializer sod-initializer) stream)
295 (with-slots (slot value) initializer
296 (if *print-escape*
297 (print-unreadable-object (initializer stream :type t)
298 (format stream "~A = ~A" slot value))
299 (format stream "~A" value))))
300
301 (export 'sod-class-initializer)
302 (defclass sod-class-initializer (sod-initializer)
303 ()
304 (:documentation
305 "Provides an initial value for a class slot.
306
307 A class slot initializer provides an initial value for a slot in the class
308 object (i.e., one of the slots defined by the class's metaclass). Its
309 VALUE must have the syntax of an initializer, and its consituent
310 expressions must be constant expressions.
311
312 See `sod-initializer' for more details."))
313
314 (export 'sod-instance-initializer)
315 (defclass sod-instance-initializer (sod-initializer)
316 ()
317 (:documentation
318 "Provides an initial value for a slot in all instances.
319
320 An instance slot initializer provides an initial value for a slot in
321 instances of the class. Its VALUE must have the syntax of an initializer.
322 Furthermore, if the slot has aggregate type, then you'd better be sure
323 that your compiler supports compound literals (6.5.2.5) because that's
324 what the initializer gets turned into.
325
326 See `sod-initializer' for more details."))
327
328 (export 'sod-initarg)
329 (defclass sod-initarg ()
330 ((%class :initarg :class :type sod-class :reader sod-initarg-class)
331 (location :initarg :location :initform (file-location nil)
332 :type file-location :reader file-location)
333 (name :initarg :name :type string :reader sod-initarg-name)
334 (%type :initarg :type :type c-type :reader sod-initarg-type))
335 (:documentation
336 "Describes a keyword argument accepted by the initialization function."))
337
338 (export 'sod-user-initarg)
339 (defclass sod-user-initarg (sod-initarg)
340 ((default :initarg :default :type t :reader sod-initarg-default))
341 (:documentation
342 "Describes an initialization argument defined by the user."))
343
344 (export 'sod-slot-initarg)
345 (defclass sod-slot-initarg (sod-initarg)
346 ((slot :initarg :slot :type sod-slot :reader sod-initarg-slot))
347 (:documentation
348 "Describes an initialization argument used to initialize a slot."))
349
350 ;;;--------------------------------------------------------------------------
351 ;;; Messages and methods.
352
353 (export '(sod-message sod-message-name sod-message-class sod-message-type))
354 (defclass sod-message ()
355 ((name :initarg :name :type string :reader sod-message-name)
356 (location :initarg :location :initform (file-location nil)
357 :type file-location :reader file-location)
358 (%class :initarg :class :type sod-class :reader sod-message-class)
359 (%type :initarg :type :type c-function-type :reader sod-message-type))
360 (:documentation
361 "Messages are the means for stimulating an object to behave.
362
363 SOD is a single-dispatch object system, like Smalltalk, C++, Python and so
364 on, but unlike CLOS and Dylan. Behaviour is invoked by `sending messages'
365 to objects. A message carries a name (distinguishing it from other
366 messages recognized by the same class), and a number of arguments; the
367 object may return a value in response. Sending a message therefore looks
368 very much like calling a function; indeed, each message bears the static
369 TYPE signature of a function.
370
371 An object reacts to being sent a message by executing an `effective
372 method', constructed from the direct methods defined on the recpient's
373 (run-time, not necessarily statically-declared) class and its superclasses
374 according to the message's `method combination'.
375
376 Much interesting work is done by subclasses of `sod-message', which (for
377 example) specify method combinations.
378
379 The slots are as follows.
380
381 * The NAME distinguishes the message from others defined by the same
382 class. Unlike most (all?) other object systems, messages defined in
383 different classes are in distinct namespaces. It is forbidden for a
384 message name to begin with an underscore, or to contain two
385 consecutive underscores. (Final underscores are fine.)
386
387 * The LOCATION states where in the user's source the slot was defined.
388 It gets used in error messages.
389
390 * The CLASS states which class defined the message.
391
392 * The TYPE is a function type describing the message's arguments and
393 return type.
394
395 Subclasses can (and probably will) define additional slots."))
396
397 (defmethod print-object ((message sod-message) stream)
398 (maybe-print-unreadable-object (message stream :type t)
399 (pprint-c-type (sod-message-type message) stream
400 (format nil "~A.~A"
401 (sod-class-nickname (sod-message-class message))
402 (sod-message-name message)))))
403
404 (export '(sod-method sod-method-message sod-method-class sod-method-type
405 sod-method-body))
406 (defclass sod-method ()
407 ((message :initarg :message :type sod-message :reader sod-method-message)
408 (location :initarg :location :initform (file-location nil)
409 :type file-location :reader file-location)
410 (%class :initarg :class :type sod-class :reader sod-method-class)
411 (%type :initarg :type :type c-function-type :reader sod-method-type)
412 (body :initarg :body :type (or c-fragment null) :reader sod-method-body))
413 (:documentation
414 "(Direct) methods are units of behaviour.
415
416 Methods are the unit of behaviour in SOD. Classes define direct methods
417 for particular messages.
418
419 When a message is received by an instance, all of the methods defined for
420 that message on that instance's (run-time, not static) class and its
421 superclasses are `applicable'. The applicable methods are gathered
422 together and invoked in some way; the details of this are left to the
423 `method combination', determined by the subclass of `sod-message'.
424
425 The slots are as follows.
426
427 * The MESSAGE describes which meessage invokes the method's behaviour.
428 The method is combined with other methods on the same message
429 according to the message's method combination, to form an `effective
430 method'.
431
432 * The LOCATION states where, in the user's source, the method was
433 defined. This gets used in error messages. (Depending on the user's
434 coding style, this location might be subtly different from the BODY's
435 location.)
436
437 * The CLASS specifies which class defined the method. This will be
438 either the class of the message, or one of its descendents.
439
440 * The TYPE gives the type of the method, including its arguments. This
441 will, in general, differ from the type of the message for several
442 reasons.
443
444 -- The method type must include names for all of the method's
445 parameters. The message definition can omit the parameter
446 names (in the same way as a function declaration can). Formally,
447 the message definition can contain abstract declarators, whereas
448 method definitions must not.
449
450 -- Method combinations may require different parameter or return
451 types. For example, `before' and `after' methods don't
452 contribute to the message's return value, so they must be defined
453 as returning `void'.
454
455 -- Method combinations may permit methods whose parameter and/or
456 return types don't exactly match the corresponding types of the
457 message. For example, one might have methods with covariant
458 return types and contravariant parameter types. (This sounds
459 nice, but it doesn't actually seem like such a clever idea when
460 you consider that the co-/contravariance must hold among all the
461 applicable methods ordered according to the class precedence
462 list. As a result, a user might have to work hard to build
463 subclasses whose CPLs match the restrictions implied by the
464 method types.)
465
466 Method objects are fairly passive in the SOD translator. However,
467 subclasses of `sod-message' may (and probably will) construct instances of
468 subclasses of `sod-method' in order to carry the additional metadata they
469 need to keep track of."))
470
471 (defmethod print-object ((method sod-method) stream)
472 (maybe-print-unreadable-object (method stream :type t)
473 (format stream "~A ~@_~A"
474 (sod-method-message method)
475 (sod-method-class method))))
476
477 ;;;----- That's all, folks --------------------------------------------------