--- /dev/null
+package org.simantics.scl.reflection;\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
+\r
+import org.simantics.scl.compiler.types.TApply;\r
+import org.simantics.scl.compiler.types.TCon;\r
+import org.simantics.scl.compiler.types.TForAll;\r
+import org.simantics.scl.compiler.types.TFun;\r
+import org.simantics.scl.compiler.types.TMetaVar;\r
+import org.simantics.scl.compiler.types.TPred;\r
+import org.simantics.scl.compiler.types.TVar;\r
+import org.simantics.scl.compiler.types.Type;\r
+import org.simantics.scl.compiler.types.Types;\r
+import org.simantics.scl.compiler.types.exceptions.MatchException;\r
+import org.simantics.scl.compiler.types.util.MultiFunction;\r
+import org.simantics.scl.reflection.internal.registry.BindingRegistry;\r
+import org.simantics.scl.runtime.function.Function;\r
+\r
+public class ReflectionUtils {\r
+ private static Class<?> toBoxedClass(Class<?> clazz) {\r
+ if(clazz == int.class) return Integer.class;\r
+ else if(clazz == boolean.class) return Boolean.class;\r
+ else if(clazz == double.class) return Double.class;\r
+ else if(clazz == byte.class) return Byte.class;\r
+ else if(clazz == long.class) return Long.class;\r
+ else if(clazz == float.class) return Float.class;\r
+ else if(clazz == short.class) return Short.class;\r
+ else if(clazz == char.class) return Character.class;\r
+ else throw new IllegalArgumentException("Expected a primitive type, got " + clazz + "."); \r
+ }\r
+ \r
+ public static Class<?> getClass(TypeBindingScheme scheme, Type type) throws TypeNotFoundException {\r
+ while(true) {\r
+ if(type instanceof TCon) {\r
+ TCon con = (TCon)type;\r
+ return scheme.getClass(con);\r
+ }\r
+ else if(type instanceof TApply) {\r
+ TApply apply = (TApply)type;\r
+ type = apply.function;\r
+ }\r
+ else if(type instanceof TVar) {\r
+ return Object.class;\r
+ }\r
+ else if(type instanceof TForAll) {\r
+ TForAll forAll = (TForAll)type;\r
+ type = forAll.type;\r
+ }\r
+ else if(type instanceof TFun) {\r
+ return Function.class;\r
+ }\r
+ else if(type instanceof TPred) {\r
+ return Object.class;\r
+ }\r
+ else if(type instanceof TMetaVar) {\r
+ type = Types.canonical(type);\r
+ if(type instanceof TMetaVar)\r
+ return Object.class;\r
+ }\r
+ else\r
+ throw new IllegalArgumentException();\r
+ }\r
+ }\r
+ \r
+ public static boolean isAssignableFrom(TypeBindingScheme scheme, Type to, Class<?> from) throws TypeNotFoundException {\r
+ if(from.isPrimitive()) {\r
+ if(from == void.class)\r
+ return Types.canonical(to) == Types.tupleConstructor(0);\r
+ from = toBoxedClass(from);\r
+ }\r
+ return getClass(scheme, to).isAssignableFrom(from); \r
+ }\r
+ \r
+ public static boolean isAssignableFrom(TypeBindingScheme scheme, Class<?> to, Type from) throws TypeNotFoundException {\r
+ if(to.isPrimitive()) {\r
+ if(to == void.class)\r
+ return Types.canonical(from) == Types.tupleConstructor(0);\r
+ to = toBoxedClass(to);\r
+ }\r
+ return to.isAssignableFrom(getClass(scheme, from)); \r
+ }\r
+ \r
+ public static boolean isCompatible(TypeBindingScheme scheme, Type type, Method method) throws TypeNotFoundException {\r
+ try {\r
+ if(Modifier.isStatic(method.getModifiers())) {\r
+ Class<?>[] parameterTypes = method.getParameterTypes();\r
+ MultiFunction mfun = \r
+ Types.matchFunction(Types.removeForAll(type), parameterTypes.length);\r
+ for(int i=0;i<parameterTypes.length;++i)\r
+ if(!isAssignableFrom(scheme, parameterTypes[i], \r
+ mfun.parameterTypes[i]))\r
+ return false;\r
+ return isAssignableFrom(scheme, mfun.returnType,\r
+ method.getReturnType());\r
+ }\r
+ else {\r
+ Class<?>[] parameterTypes = method.getParameterTypes();\r
+ MultiFunction mfun = \r
+ Types.matchFunction(Types.removeForAll(type), parameterTypes.length+1);\r
+ if(!isAssignableFrom(scheme, method.getDeclaringClass(), mfun.parameterTypes[0]))\r
+ return false;\r
+ for(int i=0;i<parameterTypes.length;++i)\r
+ if(!isAssignableFrom(scheme, parameterTypes[i], mfun.parameterTypes[i+1]))\r
+ return false;\r
+ return isAssignableFrom(scheme, mfun.returnType,\r
+ method.getReturnType());\r
+ }\r
+ } catch(MatchException e) {\r
+ return false;\r
+ }\r
+ }\r
+ \r
+ public static boolean isCompatible(TypeBindingScheme scheme, Type type, Field field) throws TypeNotFoundException {\r
+ try {\r
+ if(Modifier.isStatic(field.getModifiers())) {\r
+ return isAssignableFrom(scheme, type, field.getType());\r
+ }\r
+ else {\r
+ MultiFunction mfun = Types.matchFunction(Types.removeForAll(type), 1);\r
+ if(!isAssignableFrom(scheme, mfun.returnType, field.getType()))\r
+ return false;\r
+ return isAssignableFrom(scheme, field.getDeclaringClass(), mfun.parameterTypes[0]);\r
+ }\r
+ } catch(MatchException e) {\r
+ return false;\r
+ }\r
+ }\r
+ \r
+ public static boolean isCompatible(TypeBindingScheme scheme, Type type, Constructor<?> constructor) throws TypeNotFoundException {\r
+ try {\r
+ Class<?>[] parameterTypes = constructor.getParameterTypes();\r
+ MultiFunction mfun = \r
+ Types.matchFunction(Types.removeForAll(type), parameterTypes.length);\r
+ for(int i=0;i<parameterTypes.length;++i)\r
+ if(!isAssignableFrom(scheme, parameterTypes[i], mfun.parameterTypes[i]))\r
+ return false;\r
+ return isAssignableFrom(scheme, mfun.returnType,\r
+ constructor.getDeclaringClass()); \r
+ } catch(MatchException e) {\r
+ return false;\r
+ }\r
+ }\r
+ \r
+ public static TypedValue getValue(String uri) throws ValueNotFoundException {\r
+ int lp = uri.lastIndexOf('/');\r
+ if(lp < -1)\r
+ throw new IllegalArgumentException("Invalid uri <" + uri + ">.");\r
+ return getValue(uri.substring(0, lp), uri.substring(lp+1));\r
+ }\r
+ \r
+ public static TypedValue getValue(\r
+ String path, \r
+ String name) throws ValueNotFoundException {\r
+ return BindingRegistry.getValue(path, name);\r
+ }\r
+}\r