]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.scl.reflection/src/org/simantics/scl/reflection/ReflectionUtils.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.scl.reflection / src / org / simantics / scl / reflection / ReflectionUtils.java
diff --git a/bundles/org.simantics.scl.reflection/src/org/simantics/scl/reflection/ReflectionUtils.java b/bundles/org.simantics.scl.reflection/src/org/simantics/scl/reflection/ReflectionUtils.java
new file mode 100755 (executable)
index 0000000..1cdb548
--- /dev/null
@@ -0,0 +1,159 @@
+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