X-Git-Url: https://git.distorted.org.uk/~mdw/sod/blobdiff_plain/e75eb63d81df077c02c6c74439fb14a34d4fb93e..7e94c5fe2eff01fe81fde1f54c53d3eefb254ba0:/src/method-aggregate.lisp diff --git a/src/method-aggregate.lisp b/src/method-aggregate.lisp index 6e5d278..e374924 100644 --- a/src/method-aggregate.lisp +++ b/src/method-aggregate.lisp @@ -94,7 +94,7 @@ (:method (message combination type) t)) -(export 'standard-effective-method) +(export 'aggregating-effective-method) (defclass aggregating-effective-method (simple-effective-method) () (:documentation "Effective method counterpart to `aggregating-message'.")) @@ -179,7 +179,7 @@ (vars &key (codegen (gensym "CODEGEN-")) (methods (gensym "METHODS-"))) - &key properties + &key properties return-type ((:around around-func) '#'funcall) ((:first-method first-method-func) nil firstp) ((:methods methods-func) '#'funcall)) @@ -211,6 +211,10 @@ All of these variables, and the VARS, are available in the functions described below. + If a RETURN-TYPE is given, it's a C-type S-expression: a method is defined + on `check-aggregating-message-type' to check the that the message's return + type matches RETURN-TYPE. + The AROUND, FIRST-METHOD, and METHODS are function designators (probably `lambda' forms) providing pieces of the aggregating behaviour. @@ -233,7 +237,7 @@ the appropriate direct method and deliver its return value to TARGET, which defaults to `:void'." - (with-gensyms (type msg combvar target arg-names args + (with-gensyms (type msg combvar target arg-names args want-type meth targ func call-methfunc aroundfunc fmethfunc methfunc) `(progn @@ -251,6 +255,20 @@ (cadr prop))) properties)))) + ;; If a particular return type is wanted, check that. + ,@(and return-type + `((defmethod check-aggregating-message-type + ((,msg aggregating-message) + (,combvar (eql ',comb)) + (,type c-function-type)) + (let ((,want-type (c-type ,return-type))) + (unless (c-type-equal-p (c-type-subtype ,type) + ,want-type) + (error "Messages with `~(~A~)' combination ~ + must return `~A'." + ,combvar ,want-type))) + (call-next-method)))) + ;; Define the main kernel-compuation method. (defmethod compute-aggregating-message-kernel ((,msg aggregating-message) (,combvar (eql ',comb)) @@ -313,30 +331,8 @@ ;;;-------------------------------------------------------------------------- ;;; Fixed aggregating method combinations. -(flet ((check (comb want type) - (unless (eq (c-type-subtype type) want) - (error "Messages with `~A' combination must return `~A'." - (string-downcase comb) want)))) - (defmethod check-aggregating-message-type - ((message aggregating-message) - (combination (eql :progn)) - (type c-function-type)) - (check combination c-type-void type) - (call-next-method)) - (defmethod check-aggregating-message-type - ((message aggregating-message) - (combination (eql :and)) - (type c-function-type)) - (check combination c-type-int type) - (call-next-method)) - (defmethod check-aggregating-message-type - ((message aggregating-message) - (combination (eql :or)) - (type c-function-type)) - (check combination c-type-int type) - (call-next-method))) - -(define-aggregating-method-combination :progn (nil)) +(define-aggregating-method-combination :progn (nil) + :return-type void) (define-aggregating-method-combination :sum ((acc val) :codegen codegen) :first-method (lambda (invoke) @@ -373,6 +369,7 @@ (make-set-inst acc val) nil)))) (define-aggregating-method-combination :and ((ret val) :codegen codegen) + :return-type int :around (lambda (body) (codegen-push codegen) (deliver-expr codegen ret 0) @@ -386,6 +383,7 @@ (make-break-inst) nil)))) (define-aggregating-method-combination :or ((ret val) :codegen codegen) + :return-type int :around (lambda (body) (codegen-push codegen) (deliver-expr codegen ret 1) @@ -408,18 +406,21 @@ :before :fragment :first :fragment :each :fragment - :after :fragment)) + :after :fragment + :count :id)) (defmethod compute-aggregating-message-kernel ((message aggregating-message) (combination (eql :custom)) codegen target methods arg-names &key (retvar "sod_ret") (valvar "sod_val") - decls before each (first each) after) + 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)) + (when count + (ensure-var codegen count c-type-int (length methods))) (when decls (emit-decl codegen decls)) (labels ((maybe-emit (fragment)