X-Git-Url: https://git.distorted.org.uk/~mdw/sod/blobdiff_plain/eeb8cc3f91402d0b7d78e17e09f69ff2a2b64882..e895be217c3be6769708da17c9ae87cb22db040e:/src/class-make-impl.lisp diff --git a/src/class-make-impl.lisp b/src/class-make-impl.lisp index 78f8fed..1da8bac 100644 --- a/src/class-make-impl.lisp +++ b/src/class-make-impl.lisp @@ -28,32 +28,52 @@ ;;;-------------------------------------------------------------------------- ;;; 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) @@ -64,7 +84,7 @@ ;;; 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")) @@ -79,8 +99,8 @@ (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) @@ -95,7 +115,7 @@ ;;; 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) (with-default-error-location (location) (let* ((slot (find-instance-slot-by-name class nick name)) (initarg-name (get-property pset :initarg :id)) @@ -106,16 +126,16 @@ (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 (and initarg-name (not inhibit-initargs)) + (make-sod-slot-initarg-using-slot class initarg-name slot pset + :location location)) (when initializer (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) (with-default-error-location (location) (let* ((slot (find-class-slot-by-name class nick name)) (initializer (make-sod-initializer-using-slot @@ -145,27 +165,33 @@ nil) (defmethod make-sod-user-initarg - ((class sod-class) name type pset &optional default location) - (declare (ignore pset)) + ((class sod-class) name type pset &key default location) (with-slots (initargs) class - (push (make-instance 'sod-user-initarg :location (file-location location) + (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) + ((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) - (declare (ignore pset)) + ((class sod-class) name (slot sod-slot) pset &key location) (with-slots (initargs) class (with-slots ((type %type)) slot - (push (make-instance '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) @@ -178,13 +204,13 @@ ;;; 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))))) @@ -193,7 +219,7 @@ ;;; 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) @@ -211,9 +237,11 @@ (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) @@ -225,7 +253,7 @@ ;;; 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 @@ -296,9 +324,9 @@ "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