1# This patch is against chicken 1.92, but it should work just fine
2# with older versions of chicken.  It adds support for mulit-argument
3# generics, that is, generics now correctly handle adding methods
4# with different lengths of specializer lists
5
6# This patch has been committed into the CHICKEN darcs repository,
7# so chicken versions above 1.92 work fine.
8
9# Comments, bugs, suggestions send to chicken-users@nongnu.org
10
11# Patch written by John Lenz <lenz@cs.wisc.edu>
12
13--- tinyclos.scm.old	2005-04-05 01:13:56.000000000 -0500
14+++ tinyclos.scm	2005-04-11 16:37:23.746181489 -0500
15@@ -37,8 +37,10 @@
16 
17 (include "parameters")
18 
19+(cond-expand [(not chicken-compile-shared) (declare (unit tinyclos))]
20+	     [else] )
21+
22 (declare
23-  (unit tinyclos)
24   (uses extras)
25   (usual-integrations)
26   (fixnum) 
27@@ -234,7 +236,10 @@
28             y = C_block_item(y, 1);
29           }
30         }
31-        return(C_block_item(v, i + 1));
32+        if (x == C_SCHEME_END_OF_LIST && y == C_SCHEME_END_OF_LIST)
33+          return(C_block_item(v, i + 1));
34+        else
35+          goto mismatch;
36       }
37       else if(free_index == -1) free_index = i;
38     mismatch:
39@@ -438,7 +443,7 @@
40 (define hash-arg-list
41   (foreign-lambda* unsigned-int ((scheme-object args) (scheme-object svector)) "
42     C_word tag, h, x;
43-    int n, i, j;
44+    int n, i, j, len = 0;
45     for(i = 0; args != C_SCHEME_END_OF_LIST; args = C_block_item(args, 1)) {
46       x = C_block_item(args, 0);
47       if(C_immediatep(x)) {
48@@ -481,8 +486,9 @@
49         default: i += 255;
50         }
51       }
52+      ++len;
53     }
54-    return(i & (C_METHOD_CACHE_SIZE - 1));") )
55+    return((i + len) & (C_METHOD_CACHE_SIZE - 1));") )
56 
57 
58 ;
59@@ -868,13 +874,27 @@
60     (##tinyclos#slot-set!
61      generic
62      'methods
63-     (cons method
64-	   (filter-in
65-	    (lambda (m) 
66-	      (let ([ms1 (method-specializers m)]
67-		    [ms2 (method-specializers method)] )
68-		(not (every2 (lambda (x y) (eq? x y)) ms1 ms2) ) ) )
69-	    (##tinyclos#slot-ref generic 'methods))))
70+     (let* ([ms1 (method-specializers method)]
71+	    [l1 (length ms1)] )
72+       (let filter-in-method ([methods (##tinyclos#slot-ref generic 'methods)])
73+	 (if (null? methods)
74+	     (list method)
75+	     (let* ([mm (##sys#slot methods 0)]
76+		    [ms2 (method-specializers mm)]
77+		    [l2 (length ms2)])
78+	       (cond ((> l1 l2)
79+		      (cons mm (filter-in-method (##sys#slot methods 1))))
80+		     ((< l1 l2)
81+		      (cons method methods))
82+		     (else
83+		      (let check-method ([ms1 ms1]
84+					 [ms2 ms2])
85+			(cond ((and (null? ms1) (null? ms2))
86+			       (cons method (##sys#slot methods 1))) ;; skip the method already in the generic
87+			      ((eq? (##sys#slot ms1 0) (##sys#slot ms2 0))
88+			       (check-method (##sys#slot ms1 1) (##sys#slot ms2 1)))
89+			      (else
90+			       (cons mm (filter-in-method (##sys#slot methods 1)))))))))))))
91     (if (memq generic generic-invocation-generics)
92 	(set! method-cache-tag (vector))
93 	(%entity-cache-set! generic #f) )
94@@ -925,11 +945,13 @@
95 				(memq (car args) generic-invocation-generics))
96 			   (let ([proc 
97 				  (method-procedure
98+				    ; select the first method of one argument
99 				   (let lp ([lis (generic-methods generic)])
100-				     (let ([tail (##sys#slot lis 1)])
101-				       (if (null? tail)
102-					   (##sys#slot lis 0)
103-					   (lp tail)) ) ) ) ] )
104+				     (if (null? lis)
105+				       (##sys#error "Unable to find original compute-apply-generic")
106+				       (if (= (length (method-specializers (##sys#slot lis 0))) 1)
107+					 (##sys#slot lis 0)
108+					 (lp (##sys#slot lis 1)))))) ] )
109 			     (lambda (args) (apply proc #f args)) )
110 			   (let ([x (compute-apply-methods generic)]
111 				 [y ((compute-methods generic) args)] )
112@@ -946,9 +968,13 @@
113       (lambda (args)
114 	(let ([applicable
115 	       (filter-in (lambda (method)
116-			    (every2 applicable?
117-				   (method-specializers method)
118-				   args))
119+                            (let check-applicable ([list1 (method-specializers method)]
120+                                                   [list2 args])
121+                              (cond ((null? list1) #t)
122+                                    ((null? list2) #f)
123+                                    (else
124+                                      (and (applicable? (##sys#slot list1 0) (##sys#slot list2 0))
125+                                           (check-applicable (##sys#slot list1 1) (##sys#slot list2 1)))))))
126 			  (generic-methods generic) ) ] )
127 	  (if (or (null? applicable) (null? (##sys#slot applicable 1))) 
128 	      applicable
129@@ -975,8 +1001,10 @@
130 	   [else
131 	    (cond ((and (null? specls1) (null? specls2))
132 		   (##sys#error "two methods are equally specific" generic))
133-		  ((or (null? specls1) (null? specls2))
134-		   (##sys#error "two methods have different number of specializers" generic))
135+		  ;((or (null? specls1) (null? specls2))
136+		  ; (##sys#error "two methods have different number of specializers" generic))
137+                  ((null? specls1) #f)
138+                  ((null? specls2) #t)
139 		  ((null? args)
140 		   (##sys#error "fewer arguments than specializers" generic))
141 		  (else
142@@ -1210,7 +1238,7 @@
143 (define <structure>      (make-primitive-class "structure"))
144 (define <procedure> (make-primitive-class "procedure" <procedure-class>))
145 (define <end-of-file> (make-primitive-class "end-of-file"))
146-(define <environment> (make-primitive-class "environment" <structure>))	; (Benedikt insisted on this)
147+(define <environment> (make-primitive-class "environment" <structure>))
148 (define <hash-table> (make-primitive-class "hash-table" <structure>))
149 (define <promise> (make-primitive-class "promise" <structure>))
150 (define <queue> (make-primitive-class "queue" <structure>))
151