;;;--------------------------------------------------------------------------
;;; 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)
(defmethod make-sod-slot
((class sod-class) name type pset &optional 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
:name name
:type type
:location (file-location location)
- :pset pset)))
+ :pset pset))
+ (initarg-name (get-property pset :initarg :id)))
(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))
slot)))
(defmethod shared-initialize :after ((slot sod-slot) slot-names &key pset)
((class sod-class) nick name value pset &optional location)
(with-default-error-location (location)
(let* ((slot (find-instance-slot-by-name class nick name))
+ (initarg-name (get-property pset :initarg :id))
(initializer (and value
(make-sod-initializer-using-slot
class slot 'sod-instance-initializer
value pset (file-location location)))))
(with-slots (instance-initializers) class
-
- (setf instance-initializers
- (append instance-initializers (list initializer))))
+ (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
+ (setf instance-initializers
+ (append instance-initializers (list initializer)))))
initializer)))
(defmethod make-sod-class-initializer
(declare (ignore slot-names pset))
nil)
+(defmethod make-sod-user-initarg
+ ((class sod-class) name type pset &optional default location)
+ (with-slots (initargs) class
+ (push (make-instance (get-property pset :initarg-class :symbol
+ 'sod-user-initarg)
+ :location (file-location location)
+ :class class :name name :type type :default default)
+ initargs)))
+
+(defmethod make-sod-slot-initarg
+ ((class sod-class) name nick slot-name pset &optional location)
+ (let ((slot (find-instance-slot-by-name class nick slot-name)))
+ (make-sod-slot-initarg-using-slot class name slot pset location)))
+
+(defmethod make-sod-slot-initarg-using-slot
+ ((class sod-class) name (slot sod-slot) pset &optional 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))))
+
+(defmethod sod-initarg-default ((initarg sod-initarg)) nil)
+
+(defmethod sod-initarg-argument ((initarg sod-initarg))
+ (make-argument (sod-initarg-name initarg)
+ (sod-initarg-type initarg)
+ (sod-initarg-default initarg)))
+
;;;--------------------------------------------------------------------------
;;; Initialization and teardown fragments.