001: /* ====================================================================
002: * Tea - Copyright (c) 1997-2000 Walt Disney Internet Group
003: * ====================================================================
004: * The Tea Software License, Version 1.1
005: *
006: * Copyright (c) 2000 Walt Disney Internet Group. All rights reserved.
007: *
008: * Redistribution and use in source and binary forms, with or without
009: * modification, are permitted provided that the following conditions
010: * are met:
011: *
012: * 1. Redistributions of source code must retain the above copyright
013: * notice, this list of conditions and the following disclaimer.
014: *
015: * 2. Redistributions in binary form must reproduce the above copyright
016: * notice, this list of conditions and the following disclaimer in
017: * the documentation and/or other materials provided with the
018: * distribution.
019: *
020: * 3. The end-user documentation included with the redistribution,
021: * if any, must include the following acknowledgment:
022: * "This product includes software developed by the
023: * Walt Disney Internet Group (http://opensource.go.com/)."
024: * Alternately, this acknowledgment may appear in the software itself,
025: * if and wherever such third-party acknowledgments normally appear.
026: *
027: * 4. The names "Tea", "TeaServlet", "Kettle", "Trove" and "BeanDoc" must
028: * not be used to endorse or promote products derived from this
029: * software without prior written permission. For written
030: * permission, please contact opensource@dig.com.
031: *
032: * 5. Products derived from this software may not be called "Tea",
033: * "TeaServlet", "Kettle" or "Trove", nor may "Tea", "TeaServlet",
034: * "Kettle", "Trove" or "BeanDoc" appear in their name, without prior
035: * written permission of the Walt Disney Internet Group.
036: *
037: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
038: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
039: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
040: * DISCLAIMED. IN NO EVENT SHALL THE WALT DISNEY INTERNET GROUP OR ITS
041: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
042: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
043: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
044: * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
045: * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
046: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
047: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
048: * ====================================================================
049: *
050: * For more information about Tea, please see http://opensource.go.com/.
051: */
052:
053: package com.go.tea.compiler;
054:
055: import java.lang.reflect.Method;
056:
057: /******************************************************************************
058: * This class finds methods that best fit a given description. The compiler
059: * will then bind to one of those methods.
060: *
061: * @author Brian S O'Neill
062: * @version
063: * <!--$$Revision:--> 14 <!-- $-->, <!--$$JustDate:--> 9/07/00 <!-- $-->
064: */
065: public class MethodMatcher {
066: /**
067: * The best result candidates are stored in the Method array passed in.
068: * The int returned indicates the number of candidates in the array. Zero
069: * is returned if there is no possible match.
070: */
071: public static int match(Method[] methods, String name, Type[] params) {
072: int paramCount = params.length;
073: int matchCount = methods.length;
074: Method m;
075:
076: int[] costs = new int[matchCount];
077:
078: // Filter the available methods down to a smaller set, tossing
079: // out candidates that could not possibly match because the name
080: // differs, and the number of parameters differ. Also eliminate
081: // ones in which the parameter types are not compatible at all
082: // because no known conversion could be applied.
083:
084: int lowestTotalCost = Integer.MAX_VALUE;
085: int length = matchCount;
086: matchCount = 0;
087: for (int i = 0; i < length; i++) {
088: m = methods[i];
089: if (name == null || m.getName().equals(name)) {
090: Class[] methodParams = m.getParameterTypes();
091: if (methodParams.length == paramCount) {
092:
093: int total = 0;
094: int j;
095: for (j = 0; j < paramCount; j++) {
096: int cost = new Type(methodParams[j])
097: .convertableFrom(params[j]);
098: if (cost < 0) {
099: break;
100: } else {
101: total += cost;
102: }
103: }
104:
105: if (j == paramCount) {
106: costs[matchCount] = total;
107: methods[matchCount++] = m;
108: if (total < lowestTotalCost) {
109: lowestTotalCost = total;
110: }
111: }
112: }
113: }
114: }
115:
116: if (matchCount <= 1) {
117: return matchCount;
118: }
119:
120: // Filter out those that have a cost higher than lowestTotalCost.
121: length = matchCount;
122: matchCount = 0;
123: for (int i = 0; i < length; i++) {
124: if (costs[i] <= lowestTotalCost) {
125: costs[matchCount] = costs[i];
126: methods[matchCount++] = methods[i];
127: }
128: }
129:
130: if (matchCount <= 1) {
131: return matchCount;
132: }
133:
134: // Filter further by matching parameters with the shortest distance
135: // in the hierarchy.
136:
137: for (int j = 0; j < paramCount; j++) {
138: Class lastMatch = null;
139: Method bestFit = null;
140:
141: length = matchCount;
142: matchCount = 0;
143: for (int i = 0; i < length; i++) {
144: m = methods[i];
145: if (bestFit == null) {
146: bestFit = m;
147: }
148: Class methodParam = m.getParameterTypes()[j];
149: Class param = params[j].getNaturalClass();
150: if (methodParam.isAssignableFrom(param)) {
151: if (lastMatch == null
152: || lastMatch.isAssignableFrom(methodParam)) {
153:
154: bestFit = m;
155: lastMatch = methodParam;
156: }
157: }
158: }
159:
160: methods[matchCount++] = bestFit;
161: }
162:
163: return matchCount;
164: }
165:
166: /**
167: * Test program.
168: */
169: /*
170: public static void main(String[] arg) throws Exception {
171: new Tester().test();
172: }
173:
174: private static class Tester {
175: public Tester() {
176: }
177:
178: public void test() {
179: Type t1 = new Type(boolean.class);
180: Type t2 = new Type(int.class);
181: Type t3 = new Type(float.class);
182: Type t4 = new Type(double.class);
183:
184: Type t5 = new Type(Boolean.class);
185: Type t6 = new Type(Integer.class);
186: Type t7 = new Type(Float.class);
187: Type t8 = new Type(Double.class);
188:
189: test("test", new Type[] {});
190:
191: test("test", new Type[] {t1});
192: test("test", new Type[] {t2});
193: test("test", new Type[] {t3});
194: test("test", new Type[] {t4});
195: test("test", new Type[] {t5});
196: test("test", new Type[] {t6});
197: test("test", new Type[] {t7});
198: test("test", new Type[] {t8});
199:
200: test("test2", new Type[] {t1});
201: test("test2", new Type[] {t2});
202: test("test2", new Type[] {t3});
203: test("test2", new Type[] {t4});
204: test("test2", new Type[] {t5});
205: test("test2", new Type[] {t6});
206: test("test2", new Type[] {t7});
207: test("test2", new Type[] {t8});
208:
209: test("test3", new Type[] {t1});
210: test("test3", new Type[] {t2});
211: test("test3", new Type[] {t3});
212: test("test3", new Type[] {t4});
213: test("test3", new Type[] {t5});
214: test("test3", new Type[] {t6});
215: test("test3", new Type[] {t7});
216: test("test3", new Type[] {t8});
217:
218: test("test4", new Type[] {t1});
219: test("test4", new Type[] {t2});
220: test("test4", new Type[] {t3});
221: test("test4", new Type[] {t4});
222: test("test4", new Type[] {t5});
223: test("test4", new Type[] {t6});
224: test("test4", new Type[] {t7});
225: test("test4", new Type[] {t8});
226:
227: test("test5", new Type[] {t1});
228: test("test5", new Type[] {t2});
229: test("test5", new Type[] {t3});
230: test("test5", new Type[] {t4});
231: test("test5", new Type[] {t5});
232: test("test5", new Type[] {t6});
233: test("test5", new Type[] {t7});
234: test("test5", new Type[] {t8});
235:
236: test("test6", new Type[] {t1});
237: test("test6", new Type[] {t2});
238: test("test6", new Type[] {t3});
239: test("test6", new Type[] {t4});
240: test("test6", new Type[] {t5});
241: test("test6", new Type[] {t6});
242: test("test6", new Type[] {t7});
243: test("test6", new Type[] {t8});
244:
245: test("test7", new Type[] {t2, t6});
246: test("test7", new Type[] {t6, t2});
247: test("test7", new Type[] {t2, t2});
248: test("test7", new Type[] {t6, t6});
249:
250: // Should only produce the method that accepts B
251: test("test8", new Type[] {new Type(C.class)});
252: }
253:
254: private void test(String name, Type[] params) {
255: Method[] methods = this.getClass().getMethods();
256: int count = MethodMatcher.match(methods, name, params);
257: dump(methods, count);
258: }
259:
260: private void dump(Method[] methods, int count) {
261: for (int i=0; i<count; i++) {
262: System.out.println(methods[i]);
263: }
264: System.out.println();
265: }
266:
267: public void test(boolean i) {}
268: public void test(char i) {}
269: public void test(byte i) {}
270: public void test(short i) {}
271: public void test(int i) {}
272: public void test(float i) {}
273: public void test(long i) {}
274: public void test(double i) {}
275: public void test(Boolean i) {}
276: public void test(Character i) {}
277: public void test(Byte i) {}
278: public void test(Short i) {}
279: public void test(Integer i) {}
280: public void test(Float i) {}
281: public void test(Long i) {}
282: public void test(Double i) {}
283: public void test(Number i) {}
284: public void test(Object i) {}
285: public void test(String i) {}
286:
287: public void test2(boolean i) {}
288: public void test2(char i) {}
289: public void test2(byte i) {}
290: public void test2(short i) {}
291: public void test2(int i) {}
292: public void test2(float i) {}
293: public void test2(long i) {}
294: public void test2(double i) {}
295:
296: public void test3(Boolean i) {}
297: public void test3(Character i) {}
298: public void test3(Byte i) {}
299: public void test3(Short i) {}
300: public void test3(Integer i) {}
301: public void test3(Float i) {}
302: public void test3(Long i) {}
303: public void test3(Double i) {}
304: public void test3(Number i) {}
305:
306: public void test4(Object i) {}
307: public void test4(String i) {}
308:
309: public void test5(int i) {}
310: public void test5(String i) {}
311:
312: public void test6(Number i) {}
313: public void test6(Integer i) {}
314: public void test6(String i) {}
315:
316: public void test7(int i, Integer I) {}
317: public void test7(Integer I, int i) {}
318:
319: private class A {}
320: private class B extends A {}
321: private class C extends B {}
322:
323: public void test8(A a) {}
324: public void test8(B b) {}
325: }
326: */
327: }
|