// Copyright (c) Corporation for National Research Initiatives package org.python.core; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.Enumeration; import java.util.Hashtable; public class PyReflectedFunction extends PyObject { public String __name__; public PyObject __doc__ = Py.None; public ReflectedArgs[] argslist; public int nargs; public PyReflectedFunction(String name) { __name__ = name; argslist = new ReflectedArgs[1]; nargs = 0; } public PyReflectedFunction(Method method) { this(method.getName()); addMethod(method); } public PyObject _doget(PyObject container) { return _doget(container, null); } public PyObject _doget(PyObject container, PyObject wherefound) { if (container == null) return this; return new PyMethod(container, this, wherefound); } public boolean _doset(PyObject container) { throw Py.TypeError("java function not settable: " + __name__); } private ReflectedArgs makeArgs(Method m) { return new ReflectedArgs(m, m.getParameterTypes(), m.getDeclaringClass(), Modifier.isStatic(m.getModifiers())); } public PyReflectedFunction copy() { PyReflectedFunction func = new PyReflectedFunction(__name__); func.__doc__ = __doc__; func.nargs = nargs; func.argslist = new ReflectedArgs[nargs]; System.arraycopy(argslist, 0, func.argslist, 0, nargs); return func; } public boolean handles(Method method) { return handles(makeArgs(method)); } protected boolean handles(ReflectedArgs args) { ReflectedArgs[] argsl = argslist; int n = nargs; for (int i = 0; i < n; i++) { int cmp = args.compareTo(argsl[i]); if (cmp == 0) return true; if (cmp == +1) return false; } return false; } public void addMethod(Method m) { int mods = m.getModifiers(); // Only add public methods unless we're overriding if (!Modifier.isPublic(mods) && !JavaAccessibility.accessIsMutable()) return; addArgs(makeArgs(m)); } protected void addArgs(ReflectedArgs args) { ReflectedArgs[] argsl = argslist; int n = nargs; int i; for (i = 0; i < n; i++) { int cmp = args.compareTo(argsl[i]); if (cmp == 0) return; if (cmp == ReflectedArgs.REPLACE) { argsl[i] = args; return; } if (cmp == -1) break; } int nn = n + 1; if (nn > argsl.length) { argsl = new ReflectedArgs[nn + 2]; System.arraycopy(argslist, 0, argsl, 0, n); argslist = argsl; } for (int j = n; j > i; j--) { argsl[j] = argsl[j - 1]; } argsl[i] = args; nargs = nn; } public PyObject __call__(PyObject self, PyObject[] args, String[] keywords) { ReflectedCallData callData = new ReflectedCallData(); Object method = null; ReflectedArgs[] argsl = argslist; int n = nargs; for (int i = 0; i < n; i++) { ReflectedArgs rargs = argsl[i]; //System.err.println(rargs.toString()); if (rargs.matches(self, args, keywords, callData)) { method = rargs.data; break; } } if (method == null) { throwError(callData.errArg, args.length, self != null, keywords.length != 0); } Object cself = callData.self; Method m = (Method) method; // Check to see if we should be using a super__ method instead // This is probably a bit inefficient... if (self == null && cself != null && cself instanceof PyProxy && !__name__.startsWith("super__")) { PyInstance iself = ((PyProxy) cself)._getPyInstance(); if (argslist[0].declaringClass != iself.instclass.proxyClass) { String mname = ("super__" + __name__); // xxx experimental Method[] super__methods = (Method[]) iself.instclass.super__methods.get(mname); if (super__methods != null) { Class[] msig = m.getParameterTypes(); for (int i = 0; i < super__methods.length; i++) { if (java.util.Arrays.equals(msig, super__methods[i].getParameterTypes())) { m = super__methods[i]; break; } } } /* xxx this way it is slow! Method super_method = null; try { super_method = cself.getClass().getMethod(mname,m.getParameterTypes()); } catch(NoSuchMethodException e) { // ??? more stuff to ignore? } if (super_method != null) { m = super_method; }*/ /* xxx original PyJavaClass jc = PyJavaClass.lookup(iself.__class__.proxyClass); PyObject super__ = jc.__findattr__(mname.intern()); if (super__ != null) { return super__.__call__(self, args, keywords); }*/ } } try { Object o = m.invoke(cself, callData.getArgsArray()); return Py.java2py(o); } catch (Throwable t) { throw Py.JavaError(t); } } public PyObject __call__(PyObject[] args, String[] keywords) { return __call__(null, args, keywords); } // A bunch of code to make error handling prettier protected void throwError(String message) { throw Py.TypeError(__name__ + "(): " + message); } private static void addRange(StringBuffer buf, int min, int max, String sep) { if (buf.length() > 0) { buf.append(sep); } if (min < max) { buf.append(Integer.toString(min) + "-" + max); } else { buf.append(min); } } protected void throwArgCountError(int nArgs, boolean self) { // Assume no argument lengths greater than 40... boolean[] legalArgs = new boolean[40]; int maxArgs = -1; int minArgs = 40; ReflectedArgs[] argsl = argslist; int n = nargs; for (int i = 0; i < n; i++) { ReflectedArgs rargs = argsl[i]; int l = rargs.args.length; if (!self && !rargs.isStatic) { l += 1; } legalArgs[l] = true; if (l > maxArgs) maxArgs = l; if (l < minArgs) minArgs = l; } StringBuffer buf = new StringBuffer(); int startRange = minArgs; int a = minArgs + 1; while (a < maxArgs) { if (legalArgs[a]) { a++; continue; } else { addRange(buf, startRange, a - 1, ", "); a++; while (a <= maxArgs) { if (legalArgs[a]) { startRange = a; break; } a++; } } } addRange(buf, startRange, maxArgs, " or "); throwError("expected " + buf + " args; got " + nArgs); } private static String ordinal(int n) { switch (n + 1) { case 0: return "self"; case 1: return "1st"; case 2: return "2nd"; case 3: return "3rd"; default: return Integer.toString(n + 1) + "th"; } } private static String niceName(Class arg) { if (arg == String.class || arg == PyString.class) { return "String"; } if (arg.isArray()) { return niceName(arg.getComponentType()) + "[]"; } return arg.getName(); } protected void throwBadArgError(int errArg, int nArgs, boolean self) { Hashtable table = new Hashtable(); ReflectedArgs[] argsl = argslist; int n = nargs; for (int i = 0; i < n; i++) { ReflectedArgs rargs = argsl[i]; Class[] args = rargs.args; int len = args.length; /*if (!args.isStatic && !self) { len = len-1; }*/ // This check works almost all the time. // I'm still a little worried about non-static methods // called with an explict self... if (len == nArgs) { if (errArg == -1) { table.put(rargs.declaringClass, rargs.declaringClass); } else { table.put(args[errArg], args[errArg]); } } } StringBuffer buf = new StringBuffer(); Enumeration keys = table.keys(); while (keys.hasMoreElements()) { Class arg = (Class) keys.nextElement(); String name = niceName(arg); if (keys.hasMoreElements()) { buf.append(name); buf.append(", "); } else { if (buf.length() > 2) { buf.setLength(buf.length() - 2); buf.append(" or "); } buf.append(name); } } throwError(ordinal(errArg) + " arg can't be coerced to " + buf); } protected void throwError(int errArg, int nArgs, boolean self, boolean keywords) { if (keywords) throwError("takes no keyword arguments"); if (errArg == -2) { throwArgCountError(nArgs, self); } /*if (errArg == -1) { throwBadArgError(-1); throwError("bad self argument"); // Bad declared class }*/ throwBadArgError(errArg, nArgs, self); } // Included only for debugging purposes... public void printArgs() { System.err.println("nargs: " + nargs); for (int i = 0; i < nargs; i++) { ReflectedArgs args = argslist[i]; System.err.println(args.toString()); } } public String toString() { //printArgs(); return "<java function " + __name__ + " " + Py.idstr(this) + ">"; } }