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