;;;--------------------------------------------------------------------------
;;; Classes.
+(defmethod guess-metaclass ((class sod-class))
+ "Default metaclass-guessing function for classes.
+
+ Return the most specific metaclass of any of the CLASS's direct
+ superclasses."
+
+ (select-minimal-class-property (sod-class-direct-superclasses class)
+ #'sod-class-metaclass
+ #'sod-subclass-p class "metaclass"))
+
(defmethod shared-initialize :after ((class sod-class) slot-names &key pset)
"Specific behaviour for SOD class initialization.
Properties inspected are as follows:
- * `:metaclass' names the metaclass to use. If unspecified, nil is
- stored, and (unless you intervene later) `guess-metaclass' will be
- called by `finalize-sod-class' to find a suitable default.
+ * `:metaclass' names the metaclass to use. If unspecified, this will be
+ left unbound, and (unless you intervene later) `guess-metaclass' will
+ be called by `finalize-sod-class' to find a suitable default.
* `:nick' provides a nickname for the class. If unspecified, a default
(the class's name, forced to lowercase) will be chosen in
`finalize-sod-class'.
* `:link' names the chained superclass. If unspecified, this class will
- be left at the head of its chain."
+ be left at the head of its chain.
+
+ Usually, the class's metaclass is determined here, either direcly from the
+ `:metaclass' property or by calling `guess-metaclass'. Guessing is
+ inhibited if the `:%bootstrapping' property is non-nil."
;; If no nickname, copy the class name. It won't be pretty, though.
(default-slot-from-property (class 'nickname slot-names)
(pset :nick :id)
(string-downcase (slot-value class 'name)))
- ;; Set the metaclass if the appropriate property has been provided;
- ;; otherwise leave it unbound for now, and we'll sort out the mess during
- ;; finalization.
- (default-slot-from-property (class 'metaclass slot-names)
- (pset :metaclass :id meta (find-sod-class meta)))
+ ;; Set the metaclass if the appropriate property has been provided or we're
+ ;; not bootstreapping; otherwise leave it unbound for now, and trust the
+ ;; caller to sort out the mess.
+ (multiple-value-bind (meta floc) (get-property pset :metaclass :id)
+ (cond (floc
+ (setf (slot-value class 'metaclass)
+ (with-default-error-location (floc)
+ (find-sod-class meta))))
+ ((not (get-property pset :%bootstrapping :boolean))
+ (default-slot (class 'metaclass slot-names)
+ (guess-metaclass class)))))
;; If no chain-link, then start a new chain here.
(default-slot-from-property (class 'chain-link slot-names)
;;; Slots.
(defmethod make-sod-slot
- ((class sod-class) name type pset &optional location)
+ ((class sod-class) name type pset &key location)
(with-default-error-location (location)
+ (when (typep type 'c-function-type)
+ (error "Slot declarations cannot have function type"))
(let ((slot (make-instance (get-property pset :slot-class :symbol
'sod-slot)
:class class
(with-slots (slots) class
(setf slots (append slots (list slot))))
(when initarg-name
- (make-sod-slot-initarg-using-slot class initarg-name
- slot pset location))
+ (make-sod-slot-initarg-using-slot class initarg-name slot pset
+ :location location))
slot)))
(defmethod shared-initialize :after ((slot sod-slot) slot-names &key pset)
;;; Slot initializers.
(defmethod make-sod-instance-initializer
- ((class sod-class) nick name value pset &optional location)
+ ((class sod-class) nick name value pset
+ &key location inhibit-initargs (add-to-class t))
(with-default-error-location (location)
(let* ((slot (find-instance-slot-by-name class nick name))
(initarg-name (get-property pset :initarg :id))
(with-slots (instance-initializers) class
(unless (or initarg-name initializer)
(error "Slot initializer declaration with no effect"))
- (when initarg-name
- (make-sod-slot-initarg-using-slot class initarg-name slot
- pset location))
- (when initializer
+ (when (and initarg-name (not inhibit-initargs))
+ (make-sod-slot-initarg-using-slot class initarg-name slot pset
+ :location location))
+ (when (and initializer add-to-class)
(setf instance-initializers
(append instance-initializers (list initializer)))))
initializer)))
(defmethod make-sod-class-initializer
- ((class sod-class) nick name value pset &optional location)
+ ((class sod-class) nick name value pset &key location (add-to-class t))
(with-default-error-location (location)
(let* ((slot (find-class-slot-by-name class nick name))
(initializer (make-sod-initializer-using-slot
class slot 'sod-class-initializer
value pset (file-location location))))
- (with-slots (class-initializers) class
- (setf class-initializers
- (append class-initializers (list initializer))))
+ (when add-to-class
+ (with-slots (class-initializers) class
+ (setf class-initializers
+ (append class-initializers (list initializer)))))
initializer)))
(defmethod make-sod-initializer-using-slot
nil)
(defmethod make-sod-user-initarg
- ((class sod-class) name type pset &optional default location)
+ ((class sod-class) name type pset &key default location)
(with-slots (initargs) class
(push (make-instance (get-property pset :initarg-class :symbol
'sod-user-initarg)
initargs)))
(defmethod make-sod-slot-initarg
- ((class sod-class) name nick slot-name pset &optional location)
+ ((class sod-class) name nick slot-name pset &key location)
(let ((slot (find-instance-slot-by-name class nick slot-name)))
- (make-sod-slot-initarg-using-slot class name slot pset location)))
+ (make-sod-slot-initarg-using-slot class name slot pset
+ :location location)))
(defmethod make-sod-slot-initarg-using-slot
- ((class sod-class) name (slot sod-slot) pset &optional location)
+ ((class sod-class) name (slot sod-slot) pset &key location)
(with-slots (initargs) class
(with-slots ((type %type)) slot
- (push (make-instance (get-property pset :initarg-class :symbol
- 'sod-slot-initarg)
- :location (file-location location)
- :class class :name name :type type :slot slot)
- initargs))))
+ (setf initargs
+ (append initargs
+ (cons (make-instance (get-property pset :initarg-class
+ :symbol
+ 'sod-slot-initarg)
+ :location (file-location location)
+ :class class :name name
+ :type type :slot slot)
+ nil))))))
(defmethod sod-initarg-default ((initarg sod-initarg)) nil)
;;; Initialization and teardown fragments.
(defmethod make-sod-class-initfrag
- ((class sod-class) frag pset &optional location)
+ ((class sod-class) frag pset &key location)
(declare (ignore pset location))
(with-slots (initfrags) class
(setf initfrags (append initfrags (list frag)))))
(defmethod make-sod-class-tearfrag
- ((class sod-class) frag pset &optional location)
+ ((class sod-class) frag pset &key location)
(declare (ignore pset location))
(with-slots (tearfrags) class
(setf tearfrags (append tearfrags (list frag)))))
;;; Messages.
(defmethod make-sod-message
- ((class sod-class) name type pset &optional location)
+ ((class sod-class) name type pset &key location)
(with-default-error-location (location)
(let* ((msg-class (or (get-property pset :message-class :symbol)
(and (get-property pset :combination :keyword)
(defmethod shared-initialize :after
((message sod-message) slot-names &key pset)
- (declare (ignore slot-names pset))
(with-slots ((type %type)) message
- (check-message-type message type)))
+ (check-message-type message type))
+ (default-slot-from-property (message 'readonlyp slot-names)
+ (pset :readonly :boolean)
+ nil))
(defmethod check-message-type ((message sod-message) (type c-function-type))
nil)
;;; Methods.
(defmethod make-sod-method
- ((class sod-class) nick name type body pset &optional location)
+ ((class sod-class) nick name type body pset &key location)
(with-default-error-location (location)
(let* ((message (find-message-by-name class nick name))
(method (make-sod-method-using-message message class
"Signal an error unless METHOD-TYPE and MESSAGE-TYPE have matching argument
lists.
- This checks that (a) the two types have matching lists of mandatory
- arguments, and (b) that either both or neither types accept keyword
- arguments."
+ This checks (a) that the two types have matching lists of mandatory
+ arguments, and (b) that either both or neither types accept keyword
+ arguments."
(let ((message-keywords-p (typep message-type 'c-keyword-function-type))
(method-keywords-p (typep method-type 'c-keyword-function-type)))
(cond (message-keywords-p
(check-method-return-type-against-message type msgtype)
(check-method-argument-lists type msgtype)))
+;;;--------------------------------------------------------------------------
+;;; Static instances.
+
+(defmethod shared-initialize :after
+ ((instance static-instance) slot-names &key pset)
+ "Initialize a static instance."
+ (default-slot-from-property (instance 'externp slot-names)
+ (pset :extern :boolean)
+ nil)
+ (default-slot-from-property (instance 'constp slot-names)
+ (pset :const :boolean)
+ t))
+
+(defmethod make-static-instance ((class sod-class) name initializers
+ pset location &key)
+
+ ;; Check that the initializers are all for distinct slots.
+ (find-duplicates (lambda (initializer previous)
+ (let ((slot (sod-initializer-slot initializer)))
+ (cerror*-with-location initializer
+ "Duplicate initializer for ~
+ instance slot `~A' in ~
+ static instance `~A'"
+ slot name)
+ (info-with-location previous
+ "Previous definition was here")))
+ initializers
+ :key #'sod-initializer-slot)
+
+ ;; Ensure that every slot will have an initializer, either defined directly
+ ;; on the instance or as part of some class definition.
+ (let ((have (make-hash-table)))
+
+ ;; First, populate the hash table with all of the slots for which we have
+ ;; initializers.
+ (flet ((seen-slot-initializer (init)
+ (setf (gethash (sod-initializer-slot init) have) t)))
+ (mapc #'seen-slot-initializer
+ initializers)
+ (dolist (super (sod-class-precedence-list class))
+ (mapc #'seen-slot-initializer
+ (sod-class-instance-initializers super))))
+
+ ;; Now go through all of the slots and check that they have initializers.
+ (dolist (super (sod-class-precedence-list class))
+ (dolist (slot (sod-class-slots super))
+ (unless (gethash slot have)
+ (cerror*-with-location location
+ "No initializer for instance slot `~A', ~
+ required by static instance `~A'"
+ slot name)
+ (info-with-location slot "Slot `~A' defined here" slot)))))
+
+ ;; Make the instance.
+ (make-instance 'static-instance
+ :class class
+ :name name
+ :initializers initializers
+ :location (file-location location)
+ :pset pset))
+
;;;----- That's all, folks --------------------------------------------------