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