--- /dev/null
+package org.simantics.scl.compiler.internal.codegen.types;\r
+\r
+import java.lang.reflect.Constructor;\r
+import java.lang.reflect.Field;\r
+import java.lang.reflect.Method;\r
+import java.lang.reflect.Modifier;\r
+import java.util.ArrayList;\r
+\r
+import org.cojen.classfile.TypeDesc;\r
+import org.simantics.scl.compiler.constants.generic.ClassRef;\r
+import org.simantics.scl.runtime.function.Function;\r
+\r
+public abstract class AbstractRuntimeJavaReferenceValidator \r
+implements JavaReferenceValidator<Class<?>, Method, Field, Constructor<?>> {\r
+\r
+ @Override\r
+ public abstract Class<?> findClass(TypeDesc name);\r
+ \r
+ @Override\r
+ public boolean isInterface(Class<?> clazz) {\r
+ return clazz.isInterface();\r
+ }\r
+ \r
+ @Override\r
+ public boolean isPublic(Class<?> clazz) {\r
+ return Modifier.isPublic(clazz.getModifiers());\r
+ }\r
+\r
+ @Override\r
+ public Method[] findCompatibleMethods(Class<?> clazz, boolean isStatic, String name, TypeDesc[] parameterTypes, TypeDesc returnType) {\r
+ Class<?>[] parameterClasses = new Class[parameterTypes.length];\r
+ for(int i=0;i<parameterTypes.length;++i)\r
+ parameterClasses[i] = findClass(parameterTypes[i]);\r
+ Class<?> returnClass = findClass(returnType);\r
+ \r
+ ArrayList<Method> methods = new ArrayList<Method>(2);\r
+ \r
+ methodLoop: \r
+ for(Method method : clazz.getMethods()) {\r
+ if(!method.getName().equals(name))\r
+ continue;\r
+ if(Modifier.isStatic(method.getModifiers()) != isStatic)\r
+ continue;\r
+ \r
+ Class<?>[] parameters = method.getParameterTypes();\r
+ if(parameters.length != parameterClasses.length)\r
+ continue;\r
+ for(int i=0;i<parameters.length;++i)\r
+ if(!parameters[i].isAssignableFrom(parameterClasses[i]))\r
+ continue methodLoop;\r
+\r
+ if(!returnClass.isAssignableFrom(method.getReturnType()))\r
+ continue; \r
+ \r
+ methods.add(method);\r
+ } \r
+ \r
+ return methods.toArray(new Method[methods.size()]);\r
+ }\r
+\r
+ @Override\r
+ public TypeDesc getReturnType(Method method) {\r
+ return TypeDesc.forClass(method.getReturnType());\r
+ }\r
+\r
+ @Override\r
+ public TypeDesc[] getParameterTypes(Method method) {\r
+ Class<?>[] parameters = method.getParameterTypes();\r
+ TypeDesc[] result = new TypeDesc[parameters.length];\r
+ for(int i=0;i<parameters.length;++i)\r
+ result[i] = TypeDesc.forClass(parameters[i]);\r
+ return result;\r
+ }\r
+\r
+ @Override\r
+ public Constructor<?>[] findCompatibleConstructors(Class<?> clazz,\r
+ TypeDesc[] types) {\r
+ Class<?>[] classes = new Class[types.length];\r
+ for(int i=0;i<types.length;++i)\r
+ classes[i] = findClass(types[i]);\r
+ int maxArity = types.length-1;\r
+ \r
+ ArrayList<Constructor<?>> constructors = new ArrayList<Constructor<?>>(2);\r
+ \r
+ methodLoop: \r
+ for(Constructor<?> constructor : clazz.getConstructors()) { \r
+ Class<?>[] parameters = constructor.getParameterTypes();\r
+ int arity = parameters.length;\r
+ if(arity > maxArity)\r
+ continue;\r
+ for(int i=0;i<parameters.length;++i)\r
+ if(!parameters[i].isAssignableFrom(classes[i]))\r
+ continue methodLoop;\r
+ \r
+ if(arity == maxArity) {\r
+ if(!classes[maxArity].isAssignableFrom(clazz))\r
+ continue;\r
+ }\r
+ else {\r
+ if(!Function.class.isAssignableFrom(clazz))\r
+ continue;\r
+ }\r
+ \r
+ constructors.add(constructor);\r
+ } \r
+ \r
+ return constructors.toArray(new Constructor[constructors.size()]);\r
+ }\r
+\r
+ @Override\r
+ public TypeDesc[] getConstructorParameterTypes(Constructor<?> constructor) {\r
+ Class<?>[] parameters = constructor.getParameterTypes();\r
+ TypeDesc[] result = new TypeDesc[parameters.length];\r
+ for(int i=0;i<parameters.length;++i)\r
+ result[i] = TypeDesc.forClass(parameters[i]);\r
+ return result;\r
+ }\r
+\r
+ @Override\r
+ public Field findField(Class<?> clazz, String name) {\r
+ try {\r
+ return clazz.getField(name);\r
+ } catch(NoSuchFieldException e) {\r
+ return null;\r
+ }\r
+ }\r
+\r
+ @Override\r
+ public boolean isStaticField(Field field) {\r
+ return Modifier.isStatic(field.getModifiers());\r
+ }\r
+\r
+ @Override\r
+ public TypeDesc getFieldType(Field field) {\r
+ return TypeDesc.forClass(field.getType());\r
+ }\r
+\r
+ @Override\r
+ public boolean isAssignableFrom(TypeDesc to, TypeDesc from) {\r
+ if(to == from)\r
+ return true;\r
+ Class<?> toClass = findClass(to);\r
+ Class<?> fromClass = findClass(from);\r
+ if(toClass == null || fromClass == null)\r
+ // Note: I added this branch when I noticed that type can be\r
+ // one from the module under compilation.\r
+ // Note2: A problem with this seems to be that also \r
+ // some other type descs go to null, such as double[][]\r
+ return false; \r
+ else\r
+ return toClass.isAssignableFrom(fromClass);\r
+ }\r
+\r
+ @Override\r
+ public Method[] chooseBest(Method[] methods) {\r
+ ArrayList<Method> newResult = new ArrayList<Method>();\r
+ for(Method method : methods)\r
+ if(!method.isSynthetic())\r
+ newResult.add(method);\r
+ return newResult.toArray(new Method[newResult.size()]);\r
+ }\r
+ \r
+ @Override\r
+ public ClassRef getClassRef(String className) {\r
+ Class<?> clazz = findClass(TypeDesc.forClass(className));\r
+ if(clazz == null)\r
+ return null;\r
+ return new ClassRef(clazz);\r
+ }\r
+\r
+}\r