src/: Enhance `definst' to allow general BVL syntax.
[sod] / src / method-aggregate.lisp
index 155ccb7..ec0a119 100644 (file)
   (:method (message combination type)
     t))
 
+(defgeneric aggregating-message-method-return-type (message combination)
+  (:documentation
+   "Return the primary method return type for this MESSAGE and COMBINATION.")
+  (:method ((message aggregating-message) (combination t))
+    (c-type-subtype (sod-message-type message))))
+
 (export 'aggregating-effective-method)
 (defclass aggregating-effective-method (simple-effective-method) ()
   (:documentation "Effective method counterpart to `aggregating-message'."))
                       arg-names
                       plist)))))))
 
+(defmethod check-method-type
+    ((method sod-method) (message aggregating-message)
+     (type c-function-type))
+  (let ((wanted (aggregating-message-method-return-type
+                message (sod-message-combination message)))
+       (msgtype (sod-message-type message)))
+    (unless (c-type-equal-p (c-type-subtype type) wanted)
+      (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))))
+
 ;;;--------------------------------------------------------------------------
 ;;; Utilities.
 
   :methods (lambda (invoke)
             (funcall invoke val)
             (emit-inst codegen (make-if-inst (format nil "~A > ~A" acc val)
-                                             (make-set-inst acc val) nil))))
+                                             (make-set-inst acc val)))))
 
 (define-aggregating-method-combination :max ((acc val) :codegen codegen)
   :first-method (lambda (invoke)
   :methods (lambda (invoke)
             (funcall invoke val)
             (emit-inst codegen (make-if-inst (format nil "~A < ~A" acc val)
-                                             (make-set-inst acc val) nil))))
+                                             (make-set-inst acc val)))))
 
-(define-aggregating-method-combination :and ((ret val) :codegen codegen)
-  :return-type int
+(define-aggregating-method-combination :and ((ret) :codegen codegen)
   :around (lambda (body)
            (codegen-push codegen)
-           (deliver-expr codegen ret 0)
            (funcall body)
-           (deliver-expr codegen ret 1)
            (emit-inst codegen
                       (make-do-while-inst (codegen-pop-block codegen) 0)))
   :methods (lambda (invoke)
-            (funcall invoke val)
-            (emit-inst codegen (make-if-inst (format nil "!~A" val)
-                                             (make-break-inst) nil))))
+            (funcall invoke ret)
+            (emit-inst codegen (make-if-inst (format nil "!~A" ret)
+                                             (make-break-inst)))))
 
-(define-aggregating-method-combination :or ((ret val) :codegen codegen)
-  :return-type int
+(define-aggregating-method-combination :or ((ret) :codegen codegen)
   :around (lambda (body)
            (codegen-push codegen)
-           (deliver-expr codegen ret 1)
            (funcall body)
-           (deliver-expr codegen ret 0)
            (emit-inst codegen
                       (make-do-while-inst (codegen-pop-block codegen) 0)))
   :methods (lambda (invoke)
-            (funcall invoke val)
-            (emit-inst codegen (make-if-inst val (make-break-inst) nil))))
+            (funcall invoke ret)
+            (emit-inst codegen (make-if-inst ret (make-break-inst)))))
 
 ;;;--------------------------------------------------------------------------
 ;;; A customizable aggregating method combination.
     ((message aggregating-message) (combination (eql :custom)))
   '(:retvar :id
     :valvar :id
+    :methty :type
     :decls :fragment
     :before :fragment
     :first :fragment
     :after :fragment
     :count :id))
 
+(defmethod aggregating-message-method-return-type
+    ((message aggregating-message) (combination (eql :custom)))
+  (getf (sod-message-plist message) :methty
+       (c-type-subtype (sod-message-type message))))
+
 (defmethod compute-aggregating-message-kernel
     ((message aggregating-message) (combination (eql :custom))
      codegen target methods arg-names
-     &key (retvar "sod_ret") (valvar "sod_val")
+     &key (retvar "sod_ret") (valvar "sod_val") (methty nil methtyp)
          decls before each (first each) after count)
   (let* ((type (c-type-subtype (sod-message-type message)))
-        (not-void-p (not (eq type c-type-void))))
-    (when not-void-p
-      (ensure-var codegen retvar type)
-      (ensure-var codegen valvar type))
+        (methty (if methtyp methty type)))
+    (unless (eq type c-type-void)
+      (ensure-var codegen retvar type))
+    (unless (eq methty c-type-void)
+      (ensure-var codegen valvar methty))
     (when count
       (ensure-var codegen count c-type-size-t (length methods)))
     (when decls
     (labels ((maybe-emit (fragment)
               (when fragment (emit-inst codegen fragment)))
             (invoke (method fragment)
-              (invoke-method codegen (if not-void-p valvar :void)
+              (invoke-method codegen
+                             (if (eq methty c-type-void) :void valvar)
                              arg-names method)
               (maybe-emit fragment)))
       (maybe-emit before)