📄 classmethods.java
字号:
package gnu.kawa.reflect;import gnu.bytecode.*;import gnu.bytecode.ClassType;import gnu.mapping.*;import gnu.expr.*;import gnu.lists.FString;import java.util.Vector;public class ClassMethods extends Procedure2{ public static final ClassMethods classMethods = new ClassMethods(); static { classMethods.setName("class-methods"); } /** Create a method or generic of the matching methods. * @param arg0 a Class, ClassType, or a String, FString or Symbol * that names a class. * @param arg1 a method name (a String, FString, or Symbol) * Loosely the same as GetNamedPart.make(arg0, arg1), * but with some extra conversions and checks. */ public Object apply2 (Object arg0, Object arg1) { return apply(this, arg0, arg1); } public static MethodProc apply(Procedure thisProc, Object arg0, Object arg1) { ClassType dtype; String mname; if (arg0 instanceof Class) arg0 = Type.make((Class) arg0); if (arg0 instanceof ClassType) dtype = (ClassType) arg0; else if (arg0 instanceof String || arg0 instanceof FString || arg0 instanceof Symbol) dtype = ClassType.make(arg0.toString()); else throw new WrongType(thisProc, 0, null); if (arg1 instanceof String || arg1 instanceof FString || arg1 instanceof Symbol) mname = arg1.toString(); else throw new WrongType(thisProc, 1, null); if (! ("<init>".equals(mname))) mname = Compilation.mangleName(mname); MethodProc result = apply(dtype, mname, '\0', Language.getDefaultLanguage()); if (result == null) throw new RuntimeException("no applicable method named `"+mname+"' in " +dtype.getName()); return result; } private static int removeRedundantMethods(Vector methods) { // Remove over-ridden methods. int mlength = methods.size(); loopi: for (int i = 1; i < mlength; ) { Method method1 = (Method) methods.elementAt(i); ClassType class1 = method1.getDeclaringClass(); Type[] types1 = method1.getParameterTypes(); int tlen = types1.length; for (int j = 0; j < i; j++) { Method method2 = (Method) methods.elementAt(j); Type[] types2 = method2.getParameterTypes(); if (tlen != types2.length) continue; int k; for (k = tlen; --k >= 0; ) { if (types1[k] != types2[k]) break; } if (k >= 0) continue; if (class1.isSubtype(method2.getDeclaringClass())) methods.setElementAt(method1, j); methods.setElementAt(methods.elementAt(mlength - 1), i); mlength--; // Re-do current i, since methods[i] replaced. continue loopi; } i++; } return mlength; } /** Return the methods of a class with the specified name and flag. * @param caller if non-null, check that methods are accessible in it. * @return an array containing the methods. */ public static PrimProcedure[] getMethods(ObjectType dtype, String mname, char mode, ClassType caller, Language language) { MethodFilter filter = new MethodFilter(mname, 0, 0, caller); // FIXME kludge until we handle "language types". if (dtype == Type.tostring_type) dtype = Type.string_type; boolean named_class_only = mode == 'P' || "<init>".equals(mname); Vector methods = new Vector(); dtype.getMethods(filter, named_class_only ? 0 : 2, methods, caller == null ? "-" : caller.getPackageName()); int mlength = (named_class_only ? methods.size() : removeRedundantMethods(methods)); PrimProcedure[] result = new PrimProcedure[mlength]; int count = 0; for (int i = mlength; --i >= 0; ) { Method method = (Method) methods.elementAt(i); PrimProcedure pproc = new PrimProcedure(method, mode, language); result[count++] = pproc; } return result; } /** Re-order the methods such that the ones that are definite * applicable (all argtypes is subset of parameter type) are first; * those possibly applicable next (argtype overlaps parameter types); * and ending with those definitely not applicable (some argtype does * overlap its parameter type). * @return ((number of definitely applicable methods) << 32 * + (number of possibly applicable methods. */ public static long selectApplicable(PrimProcedure[] methods, Type[] atypes) { int limit = methods.length; int numDefApplicable = 0; int numPosApplicable = 0; for (int i = 0; i < limit; ) { int code = methods[i].isApplicable(atypes); if (code < 0) { // Definitely not applicable. // swap(methods[limit-1], methods[i]): PrimProcedure tmp = methods[limit-1]; methods[limit-1] = methods[i]; methods[i] = tmp; limit--; } else if (code > 0) { // Definitely applicable. // swap(methods[numDefApplicable], methods[i]): PrimProcedure tmp = methods[numDefApplicable]; methods[numDefApplicable] = methods[i]; methods[i] = tmp; numDefApplicable++; i++; } else { // Possibly applicable. numPosApplicable++; i++; } } return (((long) numDefApplicable) << 32) + (long) numPosApplicable; } /** Find methods. * @param dtype class to search * @param mname method name (already mangled, if need be). * @param mode one of 'P' (use invokespecial). 'V' (require this argument * even if method is static), or '\0' (otherwise). */ public static MethodProc apply(ObjectType dtype, String mname, char mode, Language language) { PrimProcedure[] methods = getMethods(dtype, mname, mode, null, language); GenericProc gproc = null; PrimProcedure pproc = null; for (int i = 0; i < methods.length; i++) { PrimProcedure cur = methods[i]; if (pproc != null && gproc == null) { gproc = new GenericProc(); gproc.add(pproc); } pproc = cur; if (gproc != null) gproc.add(pproc); } if (gproc != null) { gproc.setName(dtype.getName()+"."+mname); return gproc; } return pproc; } /** Convert an expression to a name. * @return a String if the expression has the form of a symbol or * string literal, mangled as needed; otherwise null */ static String checkName(Expression exp, boolean reversible) { if (exp instanceof QuoteExp) { Object name = ((QuoteExp) exp).getValue(); String nam; if (name instanceof FString || name instanceof String) nam = name.toString(); else if (name instanceof Symbol) nam = ((Symbol) name).getName(); else return null; if (Compilation.isValidJavaName(nam)) return nam; return Compilation.mangleName(nam, reversible); } return null; } /** Convert an expression to a name. * @return a String if the expression has the form of a symbol or * string literal, with no mangling; otherwise null */ static String checkName(Expression exp) { if (exp instanceof QuoteExp) { Object name = ((QuoteExp) exp).getValue(); if (name instanceof FString || name instanceof String) return name.toString(); else if (name instanceof Symbol) return ((Symbol) name).getName(); else return null; } return null; }}class MethodFilter implements gnu.bytecode.Filter{ String name; int nlen; int modifiers; int modmask; ClassType caller; public MethodFilter(String name, int modifiers, int modmask, ClassType caller) { this.name = name; this.nlen = name.length(); this.modifiers = modifiers; this.modmask = modmask; this.caller = caller; } public boolean select(Object value) { gnu.bytecode.Method method = (gnu.bytecode.Method) value; String mname = method.getName(); int mmods = method.getModifiers(); if ((mmods & modmask) != modifiers || ! mname.startsWith(name)) return false; int mlen = mname.length(); char c; if (mlen != nlen && (mlen != nlen + 2 || mname.charAt(nlen) != '$' || ((c = mname.charAt(nlen+1)) != 'V' && c != 'X')) && (mlen != nlen + 4 || ! mname.endsWith("$V$X"))) return false; return caller == null || caller.isAccessible(method.getDeclaringClass(), mmods); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -