Changeset 12302


Ignore:
Timestamp:
12/22/09 18:48:55 (11 years ago)
Author:
astalla
Message:

Applied Yoshinori Tahara's patch that allows jcall to invoke the correct method (based on argument types) if the method name is passed instead of the method metaobject.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/abcl/src/org/armedbear/lisp/Java.java

    r12299 r12302  
    641641                String methodName = methodArg.getStringValue();
    642642                Class c = instance.getClass();
    643                 // FIXME Use the actual args, not just the count!
    644                 method = findMethod(c, methodName, args.length - 2);
     643                method = findMethod(c, methodName, args);
    645644            } else
    646645                method = (Method) JavaObject.getObject(methodArg);
     
    678677    }
    679678
    680     // FIXME This just returns the first matching method that it finds. Allegro
    681     // signals a continuable error if there are multiple matching methods.
    682     private static Method findMethod(Class c, String methodName, int argCount)
    683     {
     679    private static Method findMethod(Class<?> c, String methodName, LispObject[] args) throws NoSuchMethodException {
     680        int argCount = args.length - 2;
     681        Object[] javaArgs = new Object[argCount];
     682        for (int i = 0; i < argCount; ++i) {
     683            Object x = args[i + 2];
     684            if (x == NIL) {
     685                javaArgs[i] = null;
     686            } else {
     687                javaArgs[i] = ((LispObject) x).javaInstance();
     688            }
     689        }
    684690        Method[] methods = c.getMethods();
     691        Method result = null;
    685692        for (int i = methods.length; i-- > 0;) {
    686693            Method method = methods[i];
    687             if (method.getName().equals(methodName))
    688                 if (method.getParameterTypes().length == argCount)
    689                     return method;
    690         }
    691         return null;
     694            if (!method.getName().equals(methodName)) {
     695                continue;
     696            }
     697            if (method.getParameterTypes().length != argCount) {
     698                continue;
     699            }
     700            Class<?>[] methodTypes = (Class<?>[]) method.getParameterTypes();
     701            if (!isApplicableMethod(methodTypes, javaArgs)) {
     702                continue;
     703            }
     704            if (result == null || isMoreSpecialized(method, result)) {
     705                result = method;
     706            }
     707        }
     708        if (result == null) {
     709            throw new NoSuchMethodException(methodName);
     710        }
     711        return result;
     712    }
     713
     714    private static boolean isApplicableMethod(Class<?>[] methodTypes,
     715            Object[] args) {
     716        for (int i = 0; i < methodTypes.length; ++i) {
     717            Class<?> methodType = methodTypes[i];
     718            Object arg = args[i];
     719            if (methodType.isPrimitive()) {
     720                Class<?> x = getBoxedClass(methodType);
     721                if (!x.isInstance(arg)) {
     722                    return false;
     723                }
     724            } else if (arg != null && !methodType.isInstance(arg)) {
     725                return false;
     726            }
     727        }
     728        return true;
     729    }
     730
     731    private static boolean isMoreSpecialized(Method x, Method y) {
     732        Class<?>[] xtypes = x.getParameterTypes();
     733        Class<?>[] ytypes = y.getParameterTypes();
     734        for (int i = 0; i < xtypes.length; ++i) {
     735            Class<?> xtype = xtypes[i];
     736            if (xtype.isPrimitive()) {
     737                xtype = getBoxedClass(xtype);
     738            }
     739            Class<?> ytype = ytypes[i];
     740            if (ytype.isPrimitive()) {
     741                ytype = getBoxedClass(ytype);
     742            }
     743            if (xtype.equals(ytype)) {
     744                continue;
     745            }
     746            if (ytype.isAssignableFrom(xtype)) {
     747                return true;
     748            }
     749        }
     750        return false;
     751    }
     752
     753    private static Class<?> getBoxedClass(Class<?> clazz) {
     754        if (clazz.equals(int.class)) {
     755            return Integer.class;
     756        } else if (clazz.equals(boolean.class)) {
     757            return Boolean.class;
     758        } else if (clazz.equals(byte.class)) {
     759            return Byte.class;
     760        } else if (clazz.equals(char.class)) {
     761            return Character.class;
     762        } else if (clazz.equals(long.class)) {
     763            return Long.class;
     764        } else if (clazz.equals(float.class)) {
     765            return Float.class;
     766        } else if (clazz.equals(double.class)) {
     767            return Double.class;
     768        } else if (clazz.equals(short.class)) {
     769            return Short.class;
     770        } else { // if (methodType.equals(void.class))
     771            return Void.class;
     772        }
    692773    }
    693774
Note: See TracChangeset for help on using the changeset viewer.