]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.scl.reflection/src/org/simantics/scl/reflection/ReflectionUtils.java
Revert "Prime SCL BindingRegistry to shave ~0.5s from startup"
[simantics/platform.git] / bundles / org.simantics.scl.reflection / src / org / simantics / scl / reflection / ReflectionUtils.java
1 package org.simantics.scl.reflection;
2
3 import java.lang.reflect.Constructor;
4 import java.lang.reflect.Field;
5 import java.lang.reflect.Method;
6 import java.lang.reflect.Modifier;
7
8 import org.simantics.scl.compiler.types.TApply;
9 import org.simantics.scl.compiler.types.TCon;
10 import org.simantics.scl.compiler.types.TForAll;
11 import org.simantics.scl.compiler.types.TFun;
12 import org.simantics.scl.compiler.types.TMetaVar;
13 import org.simantics.scl.compiler.types.TPred;
14 import org.simantics.scl.compiler.types.TVar;
15 import org.simantics.scl.compiler.types.Type;
16 import org.simantics.scl.compiler.types.Types;
17 import org.simantics.scl.compiler.types.exceptions.MatchException;
18 import org.simantics.scl.compiler.types.util.MultiFunction;
19 import org.simantics.scl.reflection.internal.registry.BindingRegistry;
20 import org.simantics.scl.runtime.function.Function;
21
22 public class ReflectionUtils {
23     private static Class<?> toBoxedClass(Class<?> clazz) {
24         if(clazz == int.class) return Integer.class;
25         else if(clazz == boolean.class) return Boolean.class;
26         else if(clazz == double.class) return Double.class;
27         else if(clazz == byte.class) return Byte.class;
28         else if(clazz == long.class) return Long.class;
29         else if(clazz == float.class) return Float.class;
30         else if(clazz == short.class) return Short.class;
31         else if(clazz == char.class) return Character.class;
32         else throw new IllegalArgumentException("Expected a primitive type, got " + clazz + "."); 
33     }
34     
35     public static Class<?> getClass(TypeBindingScheme scheme, Type type) throws TypeNotFoundException {
36         while(true) {
37             if(type instanceof TCon) {
38                 TCon con = (TCon)type;
39                 return scheme.getClass(con);
40             }
41             else if(type instanceof TApply) {
42                 TApply apply = (TApply)type;
43                 type = apply.function;
44             }
45             else if(type instanceof TVar) {
46                 return Object.class;
47             }
48             else if(type instanceof TForAll) {
49                 TForAll forAll = (TForAll)type;
50                 type = forAll.type;
51             }
52             else if(type instanceof TFun) {
53                 return Function.class;
54             }
55             else if(type instanceof TPred) {
56                 return Object.class;
57             }
58             else if(type instanceof TMetaVar) {
59                 type = Types.canonical(type);
60                 if(type instanceof TMetaVar)
61                     return Object.class;
62             }
63             else
64                 throw new IllegalArgumentException();
65         }
66     }
67     
68     public static boolean isAssignableFrom(TypeBindingScheme scheme, Type to, Class<?> from) throws TypeNotFoundException {
69         if(from.isPrimitive()) {
70             if(from == void.class)
71                 return Types.canonical(to) == Types.tupleConstructor(0);
72             from = toBoxedClass(from);
73         }
74         return getClass(scheme, to).isAssignableFrom(from);   
75     }
76     
77     public static boolean isAssignableFrom(TypeBindingScheme scheme, Class<?> to, Type from) throws TypeNotFoundException {
78         if(to.isPrimitive()) {
79             if(to == void.class)
80                 return Types.canonical(from) == Types.tupleConstructor(0);
81             to = toBoxedClass(to);
82         }
83         return to.isAssignableFrom(getClass(scheme, from));   
84     }
85     
86     public static boolean isCompatible(TypeBindingScheme scheme, Type type, Method method) throws TypeNotFoundException {
87         try {
88             if(Modifier.isStatic(method.getModifiers())) {
89                 Class<?>[] parameterTypes = method.getParameterTypes();
90                 MultiFunction mfun = 
91                         Types.matchFunction(Types.removeForAll(type), parameterTypes.length);
92                 for(int i=0;i<parameterTypes.length;++i)
93                     if(!isAssignableFrom(scheme, parameterTypes[i], 
94                             mfun.parameterTypes[i]))
95                         return false;
96                 return isAssignableFrom(scheme, mfun.returnType,
97                         method.getReturnType());
98             }
99             else {
100                 Class<?>[] parameterTypes = method.getParameterTypes();
101                 MultiFunction mfun = 
102                         Types.matchFunction(Types.removeForAll(type), parameterTypes.length+1);
103                 if(!isAssignableFrom(scheme, method.getDeclaringClass(), mfun.parameterTypes[0]))
104                     return false;
105                 for(int i=0;i<parameterTypes.length;++i)
106                     if(!isAssignableFrom(scheme, parameterTypes[i], mfun.parameterTypes[i+1]))
107                         return false;
108                 return isAssignableFrom(scheme, mfun.returnType,
109                         method.getReturnType());
110             }
111         } catch(MatchException e) {
112             return false;
113         }
114     }
115     
116     public static boolean isCompatible(TypeBindingScheme scheme, Type type, Field field) throws TypeNotFoundException {
117         try {
118             if(Modifier.isStatic(field.getModifiers())) {
119                 return isAssignableFrom(scheme, type, field.getType());
120             }
121             else {
122                 MultiFunction mfun = Types.matchFunction(Types.removeForAll(type), 1);
123                 if(!isAssignableFrom(scheme, mfun.returnType, field.getType()))
124                     return false;
125                 return isAssignableFrom(scheme, field.getDeclaringClass(), mfun.parameterTypes[0]);
126             }
127         } catch(MatchException e) {
128             return false;
129         }
130     }
131     
132     public static boolean isCompatible(TypeBindingScheme scheme, Type type, Constructor<?> constructor) throws TypeNotFoundException {
133         try {
134             Class<?>[] parameterTypes = constructor.getParameterTypes();
135             MultiFunction mfun = 
136                     Types.matchFunction(Types.removeForAll(type), parameterTypes.length);
137             for(int i=0;i<parameterTypes.length;++i)
138                 if(!isAssignableFrom(scheme, parameterTypes[i], mfun.parameterTypes[i]))
139                     return false;
140             return isAssignableFrom(scheme, mfun.returnType,
141                     constructor.getDeclaringClass());           
142         } catch(MatchException e) {
143             return false;
144         }
145     }
146     
147     public static TypedValue getValue(String uri) throws ValueNotFoundException {
148         int lp = uri.lastIndexOf('/');
149         if(lp < -1)
150             throw new IllegalArgumentException("Invalid uri <" + uri + ">.");
151         return getValue(uri.substring(0, lp), uri.substring(lp+1));
152     }
153             
154     public static TypedValue getValue(
155             String path, 
156             String name) throws ValueNotFoundException {
157         return BindingRegistry.getValue(path, name);
158     }
159 }