--- /dev/null
+;;; -*-lisp-*-
+;;;
+;;; Class definitions for main classes
+;;;
+;;; (c) 2009 Straylight/Edgeware
+;;;
+
+;;;----- Licensing notice ---------------------------------------------------
+;;;
+;;; This file is part of the Sensble Object Design, an object system for C.
+;;;
+;;; SOD is free software; you can redistribute it and/or modify
+;;; it under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 2 of the License, or
+;;; (at your option) any later version.
+;;;
+;;; SOD is distributed in the hope that it will be useful,
+;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with SOD; if not, write to the Free Software Foundation,
+;;; Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+(cl:in-package #:sod)
+
+;;;--------------------------------------------------------------------------
+;;; Classes.
+
+(export '(sod-class sod-class-name sod-class-nickname
+ sod-class-type sod-class-metaclass
+ sod-class-direct-superclasses sod-class-precedence-list
+ sod-class-chain-link sod-class-chain-head
+ sod-class-chain sod-class-chains
+ sod-class-slots
+ sod-class-instance-initializers sod-class-class-initializers
+ sod-class-messages sod-class-methods
+ sod-class-state
+ sod-class-ilayout sod-class-vtables))
+(defclass sod-class ()
+ ((name :initarg :name :type string :reader sod-class-name)
+ (location :initarg :location :initform (file-location nil)
+ :type file-location :reader file-location)
+ (nickname :initarg :nick :type string :reader sod-class-nickname)
+ (direct-superclasses :initarg :superclasses :type list
+ :reader sod-class-direct-superclasses)
+ (chain-link :initarg :link :type (or sod-class null)
+ :reader sod-class-chain-link)
+ (metaclass :initarg :metaclass :type sod-class
+ :reader sod-class-metaclass)
+ (slots :initarg :slots :initform nil
+ :type list :accessor sod-class-slots)
+ (instance-initializers :initarg :instance-initializers :initform nil
+ :type list
+ :accessor sod-class-instance-initializers)
+ (class-initializers :initarg :class-initializers :initform nil
+ :type list :accessor sod-class-class-initializers)
+ (messages :initarg :messages :initform nil
+ :type list :accessor sod-class-messages)
+ (methods :initarg :methods :initform nil
+ :type list :accessor sod-class-methods)
+
+ (class-precedence-list :type list :accessor sod-class-precedence-list)
+
+ (type :type c-class-type :accessor sod-class-type)
+
+ (chain-head :type sod-class :accessor sod-class-chain-head)
+ (chain :type list :accessor sod-class-chain)
+ (chains :type list :accessor sod-class-chains)
+
+ (ilayout :type ilayout :accessor sod-class-ilayout)
+ (effective-methods :type list :accessor sod-class-effective-methods)
+ (vtables :type list :accessor sod-class-vtables)
+
+ (state :initform nil :type (member nil :finalized broken)
+ :accessor sod-class-state))
+ (:documentation
+ "Classes describe the layout and behaviour of objects.
+
+ The NAME, LOCATION, NICKNAME, DIRECT-SUPERCLASSES, CHAIN-LINK and
+ METACLASS slots are intended to be initialized when the class object is
+ constructed:
+
+ * The NAME is the identifier associated with the class in the user's
+ source file. It is used verbatim in the generated C code as a type
+ name, and must be distinct from other file-scope names in any source
+ file which includes the class definition. Furthermore, other names
+ are derived from the class name (most notably the class object
+ NAME__class), which have external linkage and must therefore be
+ distinct from all other identifiers in the program. It is forbidden
+ for a class NAME to begin with an underscore or to contain two
+ consecutive underscores.
+
+ * The LOCATION identifies where in the source the class was defined. It
+ gets used in error messages.
+
+ * The NICKNAME is a shorter identifier used to name the class in some
+ circumstances. The uniqueness requirements on NICKNAME are less
+ strict, which allows them to be shorter: no class may have two classes
+ with the same nickname on its class precedence list. Nicknames are
+ used (user-visibly) to distinguish slots and messages defined by
+ different classes, and (invisibly) in the derived names of direct
+ methods. It is forbidden for a nickname to begin with an underscore,
+ or to contain two consecutive underscores.
+
+ * The DIRECT-SUPERCLASSES are a list of the class's direct superclasses,
+ in the order that they were declared in the source. The class
+ precedence list is computed from the DIRECT-SUPERCLASSES lists of all
+ of the superclasses involved.
+
+ * The CHAIN-LINK is either NIL or one of the DIRECT-SUPERCLASSES. Class
+ chains are a means for recovering most of the benefits of simple
+ hierarchy lost by the introduction of multiple inheritance. A class's
+ superclasses (including itself) are partitioned into chains,
+ consisting of a class, its CHAIN-LINK superclass, that class's
+ CHAIN-LINK, and so on. It is an error if two direct subclasses of any
+ class appear in the same chain (a global property which requires
+ global knowledge of an entire program's class hierarchy in order to
+ determine sensibly). Slots of superclasses in the same chain can be
+ accessed efficiently; there is an indirection needed to access slots
+ of superclasses in other chains. Furthermore, an indirection is
+ required to perform a cross-chain conversion (i.e., converting a
+ pointer to an instance of some class into a pointer to an instance of
+ one of its superclasses in a different chain), an operation which
+ occurs implicitly in effective methods in order to call direct methods
+ defined on cross-chain superclasses.
+
+ * The METACLASS is the class of the class object. Classes are objects
+ in their own right, and therefore must be instances of some class;
+ this class is the metaclass. Metaclasses can define additional slots
+ and methods to be provided by their instances; a class definition can
+ provide (C constant expression) initial values for the metaclass
+ instance.
+
+ The next few slots can't usually be set at object-construction time, since
+ the objects need to contain references to the class object itself.
+
+ * The SLOTS are a list of the slots defined by the class (instances of
+ `sod-slot'). (The class will also define all of the slots defined by
+ its superclasses.)
+
+ * The INSTANCE-INITIALIZERS and CLASS-INITIALIZERS are lists of
+ initializers for slots (see `sod-initializer' and subclasses),
+ providing initial values for instances of the class, and for the
+ class's class object itself, respectively.
+
+ * The MESSAGES are a list of the messages recognized by the class
+ (instances of `sod-message' and subclasses). (Note that the message
+ need not have any methods defined on it. The class will also
+ recognize all of the messages defined by its superclasses.)
+
+ * The METHODS are a list of (direct) methods defined on the class
+ (instances of `sod-method' and subclasses). Each method provides
+ behaviour to be invoked by a particular message recognized by the
+ class.
+
+ Other slots are computed from these in order to describe the class's
+ layout and effective methods; this is done by `finalize-sod-class'.
+
+ * The CLASS-PRECEDENCE-LIST is a list of superclasses in a linear order.
+ It is computed by `compute-class-precedence-list', whose default
+ implementation ensures that the order of superclasses is such that (a)
+ subclasses appear before their superclasses; (b) the direct
+ superclasses of a given class appear in the order in which they were
+ declared by the programmer; and (c) classes always appear in the same
+ relative order in all class precedence lists in the same superclass
+ graph.
+
+ * The CHAIN-HEAD is the least-specific class in the class's chain. If
+ there is no link class then the CHAIN-HEAD is the class itself. This
+ slot, like the next two, is computed by the generic function
+ `compute-chains'.
+
+ * The CHAIN is the list of classes on the complete primary chain,
+ starting from this class and ending with the CHAIN-HEAD.
+
+ * The CHAINS are the complete collection of chains (most-to-least
+ specific) for the class and all of its superclasses.
+
+ Finally, slots concerning the instance and vtable layout of the class are
+ computed on demand via methods on `slot-unbound'.
+
+ * The ILAYOUT describes the layout for an instance of the class. It's
+ quite complicated; see the documentation of the ILAYOUT class for
+ detais.
+
+ * The EFFECTIVE-METHODS are a list of effective methods, specialized for
+ the class.
+
+ * The VTABLES are a list of descriptions of vtables for the class. The
+ individual elements are VTABLE objects, which are even more
+ complicated than ILAYOUT structures. See the class documentation for
+ details."))
+
+(defmethod print-object ((class sod-class) stream)
+ (maybe-print-unreadable-object (class stream :type t)
+ (princ (sod-class-name class) stream)))
+
+;;;--------------------------------------------------------------------------
+;;; Slots and initializers.
+
+(export '(sod-slot sod-slot-name sod-slot-class sod-slot-type))
+(defclass sod-slot ()
+ ((name :initarg :name :type string :reader sod-slot-name)
+ (location :initarg :location :initform (file-location nil)
+ :type file-location :reader file-location)
+ (class :initarg :class :type sod-class :reader sod-slot-class)
+ (type :initarg :type :type c-type :reader sod-slot-type))
+ (:documentation
+ "Slots are units of information storage in instances.
+
+ Each class defines a number of slots, which function similarly to (data)
+ members in structures. An instance contains all of the slots defined in
+ its class and all of its superclasses.
+
+ A slot carries the following information.
+
+ * A NAME, which distinguishes it from other slots defined by the same
+ class. Unlike most (all?) other object systems, slots defined in
+ different classes are in distinct namespaces. There are no special
+ restrictions on slot names.
+
+ * A LOCATION, which states where in the user's source the slot was
+ defined. This gets used in error messages.
+
+ * A CLASS, which states which class defined the slot. The slot is
+ available in instances of this class and all of its descendents.
+
+ * A TYPE, which is the C type of the slot. This must be an object type
+ (certainly not a function type, and it must be a complete type by the
+ time that the user header code has been scanned)."))
+
+(defmethod print-object ((slot sod-slot) stream)
+ (maybe-print-unreadable-object (slot stream :type t)
+ (pprint-c-type (sod-slot-type slot) stream
+ (format nil "~A.~A"
+ (sod-class-nickname (sod-slot-class slot))
+ (sod-slot-name slot)))))
+
+(export '(sod-initializer sod-initializer-slot sod-initializer-class
+ sod-initializer-value-kind sod-initializer-value-form))
+(defclass sod-initializer ()
+ ((slot :initarg :slot :type sod-slot :reader sod-initializer-slot)
+ (location :initarg :location :initform (file-location nil)
+ :type file-location :reader file-location)
+ (class :initarg :class :type sod-class :reader sod-initializer-class)
+ (value-kind :initarg :value-kind :type keyword
+ :reader sod-initializer-value-kind)
+ (value-form :initarg :value-form :type c-fragment
+ :reader sod-initializer-value-form))
+ (:documentation
+ "Provides an initial value for a slot.
+
+ The slots of an initializer are as follows.
+
+ * The SLOT specifies which slot this initializer is meant to initialize.
+
+ * The LOCATION states the position in the user's source file where the
+ initializer was found. This gets used in error messages. (Depending
+ on the source layout style, this might differ from the location in the
+ VALUE-FORM C fragment.)
+
+ * The CLASS states which class defined this initializer. For instance
+ slot initializers (`sod-instance-initializer'), this will be the same
+ as the SLOT's class, or be one of its descendants. For class slot
+ initializers (`sod-class-initializer'), this will be an instance of
+ the SLOT's class, or an instance of one of its descendants.
+
+ * The VALUE-KIND states what manner of initializer we have. It can be
+ either `:single', indicating a standalone expression, or `:compound',
+ indicating a compound initializer which must be surrounded by braces
+ on output.
+
+ * The VALUE-FORM gives the text of the initializer, as a C fragment.
+
+ Typically you'll see instances of subclasses of this class in the wild
+ rather than instances of this class directly. See `sod-class-initializer'
+ and `sod-instance-initializer'."))
+
+(defmethod print-object ((initializer sod-initializer) stream)
+ (if *print-escape*
+ (print-unreadable-object (initializer stream :type t)
+ (format stream "~A = ~A"
+ (sod-initializer-slot initializer)
+ initializer))
+ (format stream "~:[{~A}~;~A~]"
+ (eq (sod-initializer-value-kind initializer) :single)
+ (sod-initializer-value-form initializer))))
+
+(export 'sod-class-initializer)
+(defclass sod-class-initializer (sod-initializer)
+ ()
+ (:documentation
+ "Provides an initial value for a class slot.
+
+ A class slot initializer provides an initial value for a slot in the class
+ object (i.e., one of the slots defined by the class's metaclass). Its
+ VALUE-FORM must have the syntax of an initializer, and its consituent
+ expressions must be constant expressions.
+
+ See `sod-initializer' for more details."))
+
+(export 'sod-instance-initializer)
+(defclass sod-instance-initializer (sod-initializer)
+ ()
+ (:documentation
+ "Provides an initial value for a slot in all instances.
+
+ An instance slot initializer provides an initial value for a slot in
+ instances of the class. Its VALUE-FORM must have the syntax of an
+ initializer. Furthermore, if the slot has aggregate type, then you'd
+ better be sure that your compiler supports compound literals (6.5.2.5)
+ because that's what the initializer gets turned into.
+
+ See `sod-initializer' for more details."))
+
+;;;--------------------------------------------------------------------------
+;;; Messages and methods.
+
+(export '(sod-message sod-message-name sod-message-class sod-message-type))
+(defclass sod-message ()
+ ((name :initarg :name :type string :reader sod-message-name)
+ (location :initarg :location :initform (file-location nil)
+ :type file-location :reader file-location)
+ (class :initarg :class :type sod-class :reader sod-message-class)
+ (type :initarg :type :type c-function-type :reader sod-message-type))
+ (:documentation
+ "Messages the means for stimulating an object to behave.
+
+ SOD is a single-dispatch object system, like Smalltalk, C++, Python and so
+ on, but unlike CLOS and Dylan. Behaviour is invoked by `sending messages'
+ to objects. A message carries a name (distinguishing it from other
+ messages recognized by the same class), and a number of arguments; the
+ object may return a value in response. Sending a message therefore looks
+ very much like calling a function; indeed, each message bears the static
+ TYPE signature of a function.
+
+ An object reacts to being sent a message by executing an `effective
+ method', constructed from the direct methods defined on the recpient's
+ (run-time, not necessarily statically-declared) class and its superclasses
+ according to the message's `method combination'.
+
+ Much interesting work is done by subclasses of `sod-message', which (for
+ example) specify method combinations.
+
+ The slots are as follows.
+
+ * The NAME distinguishes the message from others defined by the same
+ class. Unlike most (all?) other object systems, messages defined in
+ different classes are in distinct namespaces. It is forbidden for a
+ message name to begin with an underscore, or to contain two
+ consecutive underscores. (Final underscores are fine.)
+
+ * The LOCATION states where in the user's source the slot was defined.
+ It gets used in error messages.
+
+ * The CLASS states which class defined the message.
+
+ * The TYPE is a function type describing the message's arguments and
+ return type.
+
+ Subclasses can (and probably will) define additional slots."))
+
+(defmethod print-object ((message sod-message) stream)
+ (maybe-print-unreadable-object (message stream :type t)
+ (pprint-c-type (sod-message-type message) stream
+ (format nil "~A.~A"
+ (sod-class-nickname (sod-message-class message))
+ (sod-message-name message)))))
+
+(export '(sod-method sod-method-message sod-method-class sod-method-type
+ sod-method-body))
+(defclass sod-method ()
+ ((message :initarg :message :type sod-message :reader sod-method-message)
+ (location :initarg :location :initform (file-location nil)
+ :type file-location :reader file-location)
+ (class :initarg :class :type sod-class :reader sod-method-class)
+ (type :initarg :type :type c-function-type :reader sod-method-type)
+ (body :initarg :body :type (or c-fragment null) :reader sod-method-body))
+ (:documentation
+ "(Direct) methods are units of behaviour.
+
+ Methods are the unit of behaviour in SOD. Classes define direct methods
+ for particular messages.
+
+ When a message is received by an instance, all of the methods defined for
+ that message on that instance's (run-time, not static) class and its
+ superclasses are `applicable'. The applicable methods are gathered
+ together and invoked in some way; the details of this are left to the
+ `method combination', determined by the subclass of `sod-message'.
+
+ The slots are as follows.
+
+ * The MESSAGE describes which meessage invokes the method's behaviour.
+ The method is combined with other methods on the same message
+ according to the message's method combination, to form an `effective
+ method'.
+
+ * The LOCATION states where, in the user's source, the method was
+ defined. This gets used in error messages. (Depending on the user's
+ coding style, this location might be subtly different from the BODY's
+ location.)
+
+ * The CLASS specifies which class defined the method. This will be
+ either the class of the message, or one of its descendents.
+
+ * The TYPE gives the type of the method, including its arguments. This
+ will, in general, differ from the type of the message for several
+ reasons.
+
+ -- Firstly, the method type must include names for all of the
+ method's parameters. The message definition can omit the
+ parameter names (in the same way as a function declaration can).
+ Formally, the message definition can contain abstract
+ declarators, whereas method definitions must not.
+
+ -- Method combinations may require different parameter or return
+ types. For example, `before' and `after' methods don't
+ contribute to the message's return value, so they must be defined
+ as returning `void'.
+
+ -- Method combinations may permit methods whose parameter and/or
+ return types don't exactly match the corresponding types of the
+ message. For example, one might have methods with covariant
+ return types and contravariant parameter types. (This sounds
+ nice, but it doesn't actually seem like such a clever idea when
+ you consider that the co-/contravariance must hold among all the
+ applicable methods ordered according to the class precedence
+ list. As a result, a user might have to work hard to build
+ subclasses whose CPLs match the restrictions implied by the
+ method types.)
+
+ Method objects are fairly passive in the SOD translator. However,
+ subclasses of `sod-message' may (and probably will) construct instances of
+ subclasses of `sod-method' in order to carry the additional metadata they
+ need to keep track of."))
+
+(defmethod print-object ((method sod-method) stream)
+ (maybe-print-unreadable-object (method stream :type t)
+ (format stream "~A ~@_~A"
+ (sod-method-message method)
+ (sod-method-class method))))
+
+;;;----- That's all, folks --------------------------------------------------