summaryrefslogtreecommitdiff
path: root/module/oop
diff options
context:
space:
mode:
authorAndy Wingo <wingo@pobox.com>2014-12-18 21:57:24 +0100
committerAndy Wingo <wingo@pobox.com>2015-01-23 16:15:59 +0100
commit3a0d1412335b175a1a432e62f1e23740ef31a880 (patch)
tree02f437c53e0b883062901f0a99436b22a515a7c2 /module/oop
parente4aa440a2f6cb341ea187c63dc4fe310f4f148af (diff)
downloadguile-3a0d1412335b175a1a432e62f1e23740ef31a880.tar.gz
Rewrite %method-more-specific? to be in Scheme
* libguile/goops.h: * libguile/goops.c (more_specificp, scm_sys_method_more_specific_p): * module/oop/goops.scm (%method-more-specific?): Rewrite in Scheme. We remove the scm_sys_method_more_specific_p interface as it is a private interface and it's not extensible.
Diffstat (limited to 'module/oop')
-rw-r--r--module/oop/goops.scm43
1 files changed, 43 insertions, 0 deletions
diff --git a/module/oop/goops.scm b/module/oop/goops.scm
index a0c6119dc..ebc47eb30 100644
--- a/module/oop/goops.scm
+++ b/module/oop/goops.scm
@@ -508,6 +508,49 @@
;;; {Methods}
;;;
+;; Note: `a' and `b' can have unequal lengths (i.e. one can be one
+;; element longer than the other when we have a dotted parameter
+;; list). For instance, with the call
+;;
+;; (M 1)
+;;
+;; with
+;;
+;; (define-method M (a . l) ....)
+;; (define-method M (a) ....)
+;;
+;; we consider that the second method is more specific.
+;;
+;; Precondition: `a' and `b' are methods and are applicable to `types'.
+(define (%method-more-specific? a b types)
+ (let lp ((a-specializers (method-specializers a))
+ (b-specializers (method-specializers b))
+ (types types))
+ (cond
+ ;; (a) less specific than (a b ...) or (a . b)
+ ((null? a-specializers) #t)
+ ;; (a b ...) or (a . b) less specific than (a)
+ ((null? b-specializers) #f)
+ ;; (a . b) less specific than (a b ...)
+ ((not (pair? a-specializers)) #f)
+ ;; (a b ...) more specific than (a . b)
+ ((not (pair? b-specializers)) #t)
+ (else
+ (let ((a-specializer (car a-specializers))
+ (b-specializer (car b-specializers))
+ (a-specializers (cdr a-specializers))
+ (b-specializers (cdr b-specializers))
+ (type (car types))
+ (types (cdr types)))
+ (if (eq? a-specializer b-specializer)
+ (lp a-specializers b-specializers types)
+ (let lp ((cpl (class-precedence-list type)))
+ (let ((elt (car cpl)))
+ (cond
+ ((eq? a-specializer elt) #t)
+ ((eq? b-specializer elt) #f)
+ (else (lp (cdr cpl))))))))))))
+
(define (%sort-applicable-methods methods types)
(sort methods (lambda (a b) (%method-more-specific? a b types))))