chiark / gitweb /
src/: Factor out common machinery in `check-method-type' methods.
[sod] / src / class-make-impl.lisp
index 09ce441c9e307b87ff783a79353dae5cba918f38..ed6189f982ae27e2862e054e8d9875facf02de48 100644 (file)
@@ -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 @@ (cl:in-package #:sod)
 ;;;--------------------------------------------------------------------------
 ;;; 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 @@   (default-slot-from-property (class 'nickname slot-names)
       (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)
@@ -79,7 +66,7 @@   (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)
-    (let ((slot (make-instance (get-property pset :lisp-class :symbol
+    (let ((slot (make-instance (get-property pset :slot-class :symbol
                                             'sod-slot)
                               :class class
                               :name name
@@ -87,7 +74,8 @@ (defmethod make-sod-slot
                               :location (file-location location)
                               :pset pset)))
       (with-slots (slots) class
-       (setf slots (append slots (list slot)))))))
+       (setf slots (append slots (list slot))))
+      slot)))
 
 (defmethod shared-initialize :after ((slot sod-slot) slot-names &key pset)
   "This method does nothing.
@@ -111,7 +99,8 @@ (defmethod make-sod-instance-initializer
                         (file-location location))))
       (with-slots (instance-initializers) class
        (setf instance-initializers
-             (append instance-initializers (list initializer)))))))
+             (append instance-initializers (list initializer))))
+      initializer)))
 
 (defmethod make-sod-class-initializer
     ((class sod-class) nick name value-kind value-form pset
@@ -124,17 +113,18 @@ (defmethod make-sod-class-initializer
                         (file-location location))))
       (with-slots (class-initializers) class
        (setf class-initializers
-             (append class-initializers (list initializer)))))))
+             (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)
-  (make-instance (get-property pset :lisp-class :symbol init-class)
+  (make-instance (get-property pset :initializer-class :symbol init-class)
                 :class class
                 :slot slot
                 :value-kind value-kind
                 :value-form value-form
-                :location location
+                :location (file-location location)
                 :pset pset))
 
 (defmethod shared-initialize :after
@@ -152,20 +142,24 @@ (defmethod shared-initialize :after
 (defmethod make-sod-message
     ((class sod-class) name type pset &optional location)
   (with-default-error-location (location)
-    (let ((message (make-instance (get-property pset :lisp-class :symbol
-                                               'standard-message)
-                                 :class class
-                                 :name name
-                                 :type type
-                                 :location (file-location location)
-                                 :pset pset)))
+    (let* ((msg-class (or (get-property pset :message-class :symbol)
+                         (and (get-property pset :combination :keyword)
+                              'aggregating-message)
+                         'standard-message))
+          (message (make-instance msg-class
+                                  :class class
+                                  :name name
+                                  :type type
+                                  :location (file-location location)
+                                  :pset pset)))
       (with-slots (messages) class
-       (setf messages (append messages (list message)))))))
+       (setf messages (append messages (list message))))
+      message)))
 
 (defmethod shared-initialize :after
     ((message sod-message) slot-names &key pset)
   (declare (ignore slot-names pset))
-  (with-slots (type) message
+  (with-slots ((type %type)) message
     (check-message-type message type)))
 
 (defmethod check-message-type ((message sod-message) (type c-function-type))
@@ -185,17 +179,18 @@ (defmethod make-sod-method
                                                  type body pset
                                                  (file-location location))))
       (with-slots (methods) class
-       (setf methods (append methods (list method)))))))
+       (setf methods (append methods (list method))))
+      method)))
 
 (defmethod make-sod-method-using-message
     ((message sod-message) (class sod-class) type body pset location)
-  (make-instance (or (get-property pset :lisp-class :symbol)
+  (make-instance (or (get-property pset :method-class :symbol)
                     (sod-message-method-class message class pset))
                 :message message
                 :class class
                 :type type
                 :body body
-                :location location
+                :location (file-location location)
                 :pset pset))
 
 (defmethod sod-message-method-class
@@ -208,31 +203,56 @@ (defmethod shared-initialize :after
   (declare (ignore slot-names pset))
 
   ;; Check that the arguments are named if we have a method body.
-  (with-slots (body type) method
+  (with-slots (body (type %type)) method
     (unless (or (not body)
                (every (lambda (arg)
-                        (or (argument-name arg)
-                            (eq (argument-type arg) (c-type void))))
+                        (or (eq arg :ellipsis)
+                            (argument-name arg)
+                            (c-type-equal-p (argument-type arg)
+                                            c-type-void)))
                       (c-function-arguments type)))
       (error "Abstract declarators not permitted in method definitions")))
 
   ;; Check the method type.
-  (with-slots (message type) method
+  (with-slots (message (type %type)) method
     (check-method-type method message type)))
 
 (defmethod check-method-type
     ((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 the two types have matching lists of arguments."
+  (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))))
+  (with-slots ((msgtype %type)) message
+    (check-method-return-type-against-message type msgtype)
+    (check-method-argument-lists type msgtype)))
 
 ;;;----- That's all, folks --------------------------------------------------