1 package gnu.kawa.reflect; 2 import gnu.bytecode.*; 3 import gnu.bytecode.ClassType; 4 import gnu.mapping.*; 5 import gnu.expr.*; 6 import gnu.lists.FString; 7 import java.util.Vector ; 8 9 public class ClassMethods extends Procedure2 10 { 11 public static final ClassMethods classMethods = new ClassMethods(); 12 static { classMethods.setName("class-methods"); } 13 14 21 public Object apply2 (Object arg0, Object arg1) 22 { 23 return apply(this, arg0, arg1); 24 } 25 26 public static MethodProc apply(Procedure thisProc, Object arg0, Object arg1) 27 { 28 ClassType dtype; 29 String mname; 30 if (arg0 instanceof Class ) 31 arg0 = Type.make((Class ) arg0); 32 if (arg0 instanceof ClassType) 33 dtype = (ClassType) arg0; 34 else if (arg0 instanceof String || arg0 instanceof FString 35 || arg0 instanceof Symbol) 36 dtype = ClassType.make(arg0.toString()); 37 else 38 throw new WrongType(thisProc, 0, null); 39 if (arg1 instanceof String || arg1 instanceof FString 40 || arg1 instanceof Symbol) 41 mname = arg1.toString(); 42 else 43 throw new WrongType(thisProc, 1, null); 44 if (! ("<init>".equals(mname))) 45 mname = Compilation.mangleName(mname); 46 MethodProc result = apply(dtype, mname, '\0', Language.getDefaultLanguage()); 47 if (result == null) 48 throw new RuntimeException ("no applicable method named `"+mname+"' in " 49 +dtype.getName()); 50 return result; 51 } 52 53 private static int removeRedundantMethods(Vector methods) 54 { 55 int mlength = methods.size(); 57 loopi: 58 for (int i = 1; i < mlength; ) 59 { 60 Method method1 = (Method) methods.elementAt(i); 61 ClassType class1 = method1.getDeclaringClass(); 62 Type[] types1 = method1.getParameterTypes(); 63 int tlen = types1.length; 64 for (int j = 0; j < i; j++) 65 { 66 Method method2 = (Method) methods.elementAt(j); 67 Type[] types2 = method2.getParameterTypes(); 68 if (tlen != types2.length) 69 continue; 70 int k; 71 for (k = tlen; --k >= 0; ) 72 { 73 if (types1[k] != types2[k]) 74 break; 75 } 76 if (k >= 0) 77 continue; 78 if (class1.isSubtype(method2.getDeclaringClass())) 79 methods.setElementAt(method1, j); 80 methods.setElementAt(methods.elementAt(mlength - 1), i); 81 mlength--; 82 continue loopi; 84 } 85 i++; 86 } 87 return mlength; 88 } 89 90 94 public static PrimProcedure[] getMethods(ClassType dtype, String mname, 95 char mode, 96 ClassType caller, 97 Language language) 98 { 99 MethodFilter filter = new MethodFilter(mname, 0, 0, caller); 100 if (dtype == Type.tostring_type) 102 dtype = Type.string_type; 103 boolean named_class_only = mode == 'P' || "<init>".equals(mname); 104 Vector methods = new Vector (); 105 dtype.getMethods(filter, named_class_only ? 0 : 2, 106 methods, 107 caller == null ? "-" : caller.getPackageName()); 108 109 int mlength = (named_class_only ? methods.size() 110 : removeRedundantMethods(methods)); 111 112 PrimProcedure[] result = new PrimProcedure[mlength]; 113 int count = 0; 114 for (int i = mlength; --i >= 0; ) 115 { 116 Method method = (Method) methods.elementAt(i); 117 PrimProcedure pproc = new PrimProcedure(method, mode, language); 118 result[count++] = pproc; 119 } 120 return result; 121 } 122 123 131 public static long selectApplicable(PrimProcedure[] methods, 132 Type[] atypes) 133 { 134 int limit = methods.length; 135 int numDefApplicable = 0; 136 int numPosApplicable = 0; 137 for (int i = 0; i < limit; ) 138 { 139 int code = methods[i].isApplicable(atypes); 140 if (code < 0) 141 { PrimProcedure tmp = methods[limit-1]; 144 methods[limit-1] = methods[i]; 145 methods[i] = tmp; 146 limit--; 147 } 148 else if (code > 0) 149 { PrimProcedure tmp = methods[numDefApplicable]; 152 methods[numDefApplicable] = methods[i]; 153 methods[i] = tmp; 154 numDefApplicable++; 155 i++; 156 } 157 else 158 { numPosApplicable++; 160 i++; 161 } 162 } 163 return (((long) numDefApplicable) << 32) + (long) numPosApplicable; 164 } 165 166 172 public static MethodProc apply(ClassType dtype, String mname, 173 char mode, Language language) 174 { 175 PrimProcedure[] methods = getMethods(dtype, mname, mode, null, language); 176 GenericProc gproc = null; 177 PrimProcedure pproc = null; 178 for (int i = 0; i < methods.length; i++) 179 { 180 PrimProcedure cur = methods[i]; 181 if (pproc != null && gproc == null) 182 { 183 gproc = new GenericProc(); 184 gproc.add(pproc); 185 } 186 pproc = cur; 187 if (gproc != null) 188 gproc.add(pproc); 189 } 190 if (gproc != null) 191 { 192 gproc.setName(dtype.getName()+"."+mname); 193 return gproc; 194 } 195 return pproc; 196 } 197 198 202 static String checkName(Expression exp, boolean reversible) 203 { 204 if (exp instanceof QuoteExp) 205 { 206 Object name = ((QuoteExp) exp).getValue(); 207 String nam; 208 if (name instanceof FString || name instanceof String ) 209 nam = name.toString(); 210 else if (name instanceof Symbol) 211 nam = ((Symbol) name).getName(); 212 else 213 return null; 214 if (Compilation.isValidJavaName(nam)) 215 return nam; 216 return Compilation.mangleName(nam, reversible); 217 } 218 return null; 219 } 220 221 225 static String checkName(Expression exp) 226 { 227 if (exp instanceof QuoteExp) 228 { 229 Object name = ((QuoteExp) exp).getValue(); 230 if (name instanceof FString || name instanceof String ) 231 return name.toString(); 232 else if (name instanceof Symbol) 233 return ((Symbol) name).getName(); 234 else 235 return null; 236 } 237 return null; 238 } 239 } 240 241 class MethodFilter implements gnu.bytecode.Filter 242 { 243 String name; 244 int nlen; 245 int modifiers; 246 int modmask; 247 ClassType caller; 248 249 public MethodFilter(String name, int modifiers, int modmask, 250 ClassType caller) 251 { 252 this.name = name; 253 this.nlen = name.length(); 254 this.modifiers = modifiers; 255 this.modmask = modmask; 256 this.caller = caller; 257 } 258 259 public boolean select(Object value) 260 { 261 gnu.bytecode.Method method = (gnu.bytecode.Method) value; 262 String mname = method.getName(); 263 int mmods = method.getModifiers(); 264 if ((mmods & modmask) != modifiers 265 || ! mname.startsWith(name)) 266 return false; 267 int mlen = mname.length(); 268 char c; 269 if (mlen != nlen 270 && (mlen != nlen + 2 271 || mname.charAt(nlen) != '$' 272 || ((c = mname.charAt(nlen+1)) != 'V' && c != 'X')) 273 && (mlen != nlen + 4 274 || ! mname.endsWith("$V$X"))) 275 return false; 276 return caller == null 277 || caller.isAccessible(method.getDeclaringClass(), mmods); 278 } 279 } 280 | Popular Tags |