X-Git-Url: https://git.distorted.org.uk/~mdw/sod/blobdiff_plain/3dca7758421664a838c54b273bd9221f02072045..e046c3f65a8f7241889fb9b6005aac21e2aad1a8:/src/class-make-impl.lisp diff --git a/src/class-make-impl.lisp b/src/class-make-impl.lisp index 878f813..7263e44 100644 --- a/src/class-make-impl.lisp +++ b/src/class-make-impl.lisp @@ -7,7 +7,7 @@ ;;;----- Licensing notice --------------------------------------------------- ;;; -;;; This file is part of the Sensble Object Design, an object system for C. +;;; This file is part of the Sensible 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 @@ -28,20 +28,6 @@ ;;;-------------------------------------------------------------------------- ;;; 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." - (do ((supers (sod-class-direct-superclasses class) (cdr supers)) - (meta nil (let ((candidate (sod-class-metaclass (car supers)))) - (cond ((null meta) candidate) - ((sod-subclass-p meta candidate) meta) - ((sod-subclass-p candidate meta) candidate) - (t (error "Unable to choose metaclass for `~A'" - class)))))) - ((endp supers) meta))) - (defmethod shared-initialize :after ((class sod-class) slot-names &key pset) "Specific behaviour for SOD class initialization. @@ -63,10 +49,11 @@ (pset :nick :id) (string-downcase (slot-value class 'name))) - ;; If no metaclass, guess one in a (Lisp) class-specific way. + ;; 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)) - (guess-metaclass class)) + (pset :metaclass :id meta (find-sod-class meta))) ;; If no chain-link, then start a new chain here. (default-slot-from-property (class 'chain-link slot-names) @@ -85,9 +72,13 @@ :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) @@ -102,42 +93,44 @@ ;;; Slot initializers. (defmethod make-sod-instance-initializer - ((class sod-class) nick name value-kind value-form pset - &optional location) + ((class sod-class) nick name value pset &optional location) (with-default-error-location (location) (let* ((slot (find-instance-slot-by-name class nick name)) - (initializer (make-sod-initializer-using-slot - class slot 'sod-instance-initializer - value-kind value-form pset - (file-location location)))) + (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 - ((class sod-class) nick name value-kind value-form pset - &optional location) + ((class sod-class) nick name value pset &optional location) (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-kind value-form pset - (file-location location)))) + value pset (file-location location)))) (with-slots (class-initializers) class (setf class-initializers (append class-initializers (list initializer)))) initializer))) (defmethod make-sod-initializer-using-slot - ((class sod-class) (slot sod-slot) - init-class value-kind value-form pset location) + ((class sod-class) (slot sod-slot) init-class value pset location) (make-instance (get-property pset :initializer-class :symbol init-class) :class class :slot slot - :value-kind value-kind - :value-form value-form - :location location + :value value + :location (file-location location) :pset pset)) (defmethod shared-initialize :after @@ -149,6 +142,51 @@ (declare (ignore slot-names pset)) nil) +(defmethod make-sod-user-initarg + ((class sod-class) name type pset &optional default location) + (declare (ignore pset)) + (with-slots (initargs) class + (push (make-instance '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) + (declare (ignore pset)) + (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)))) + +(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. + +(defmethod make-sod-class-initfrag + ((class sod-class) frag pset &optional 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) + (declare (ignore pset location)) + (with-slots (tearfrags) class + (setf tearfrags (append tearfrags (list frag))))) + ;;;-------------------------------------------------------------------------- ;;; Messages. @@ -203,7 +241,7 @@ :class class :type type :body body - :location location + :location (file-location location) :pset pset)) (defmethod sod-message-method-class @@ -221,7 +259,8 @@ (every (lambda (arg) (or (eq arg :ellipsis) (argument-name arg) - (eq (argument-type arg) (c-type void)))) + (c-type-equal-p (argument-type arg) + c-type-void))) (c-function-arguments type))) (error "Abstract declarators not permitted in method definitions"))) @@ -233,15 +272,47 @@ ((method sod-method) (message sod-message) (type c-type)) (error "Methods must have function type, not ~A" type)) +(export 'check-method-return-type) +(defun check-method-return-type (method-type wanted-type) + "Signal an error unless METHOD-TYPE does not return the WANTED-TYPE." + (let ((method-returns (c-type-subtype method-type))) + (unless (c-type-equal-p method-returns wanted-type) + (error "Method return type ~A should be ~A" + method-returns wanted-type)))) + +(export 'check-method-return-type-against-message) +(defun check-method-return-type-against-message (method-type message-type) + "Signal an error unless METHOD-TYPE and MESSAGE-TYPE return the same type." + (let ((message-returns (c-type-subtype message-type)) + (method-returns (c-type-subtype method-type))) + (unless (c-type-equal-p message-returns method-returns) + (error "Method return type ~A doesn't match message ~A" + method-returns message-returns)))) + +(export 'check-method-argument-lists) +(defun check-method-argument-lists (method-type message-type) + "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." + (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 + (unless method-keywords-p + (error "Method must declare a keyword argument list"))) + (method-keywords-p + (error "Method must not declare a keyword argument list")))) + (unless (argument-lists-compatible-p (c-function-arguments message-type) + (c-function-arguments method-type)) + (error "Method arguments ~A don't match message ~A" + method-type message-type))) + (defmethod check-method-type ((method sod-method) (message sod-message) (type c-function-type)) (with-slots ((msgtype %type)) message - (unless (c-type-equal-p (c-type-subtype msgtype) - (c-type-subtype type)) - (error "Method return type ~A doesn't match message ~A" - (c-type-subtype msgtype) (c-type-subtype type))) - (unless (argument-lists-compatible-p (c-function-arguments msgtype) - (c-function-arguments type)) - (error "Method arguments ~A don't match message ~A" type msgtype)))) + (check-method-return-type-against-message type msgtype) + (check-method-argument-lists type msgtype))) ;;;----- That's all, folks --------------------------------------------------