package org.simantics.scl.compiler.internal.codegen.utils; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import org.simantics.scl.runtime.function.FunctionImpl1; import org.simantics.scl.runtime.function.FunctionImpl2; import org.simantics.scl.runtime.function.FunctionImpl3; import org.simantics.scl.runtime.function.FunctionImpl4; import org.simantics.scl.runtime.function.FunctionImplN; import org.simantics.scl.runtime.tuple.Tuple0; public class ValueFromMethod { private static final class Arity1Func extends FunctionImpl1 { private final Method method; private final boolean returnsVoid; private Arity1Func(Method method, boolean returnsVoid) { this.method = method; this.returnsVoid = returnsVoid; } @Override public Object apply(Object p0) { try { Object ret = method.invoke(null, p0); return returnsVoid ? Tuple0.INSTANCE : ret; } catch (ReflectiveOperationException e) { if (e instanceof InvocationTargetException) throw new RuntimeException(e.getCause()); throw new RuntimeException(e); } } @Override public int hashCode() { return method == null ? 0 : method.hashCode(); } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Arity1Func other = (Arity1Func) obj; return method.equals(other.method); } } private static final class Arity2Func extends FunctionImpl2 { private final Method method; private final boolean returnsVoid; private Arity2Func(Method method, boolean returnsVoid) { this.method = method; this.returnsVoid = returnsVoid; } @Override public Object apply(Object p0, Object p1) { try { Object ret = method.invoke(null, p0, p1); return returnsVoid ? Tuple0.INSTANCE : ret; } catch (ReflectiveOperationException e) { throw new RuntimeException(e); } } @Override public int hashCode() { return method == null ? 0 : method.hashCode(); } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Arity2Func other = (Arity2Func) obj; return method.equals(other.method); } } private static final class Arity3Func extends FunctionImpl3 { private final Method method; private final boolean returnsVoid; private Arity3Func(Method method, boolean returnsVoid) { this.method = method; this.returnsVoid = returnsVoid; } @Override public Object apply(Object p0, Object p1, Object p2) { try { Object ret = method.invoke(null, p0, p1, p2); return returnsVoid ? Tuple0.INSTANCE : ret; } catch (ReflectiveOperationException e) { throw new RuntimeException(e); } } @Override public int hashCode() { return method == null ? 0 : method.hashCode(); } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Arity3Func other = (Arity3Func) obj; return method.equals(other.method); } } private static final class Arity4Func extends FunctionImpl4 { private final Method method; private final boolean returnsVoid; private Arity4Func(Method method, boolean returnsVoid) { this.method = method; this.returnsVoid = returnsVoid; } @Override public Object apply(Object p0, Object p1, Object p2, Object p3) { try { Object ret = method.invoke(null, p0, p1, p2, p3); return returnsVoid ? Tuple0.INSTANCE : ret; } catch (ReflectiveOperationException e) { throw new RuntimeException(e); } } @Override public int hashCode() { return method == null ? 0 : method.hashCode(); } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Arity4Func other = (Arity4Func) obj; return method.equals(other.method); } } private static final class ArityNFunc extends FunctionImplN { private final Method method; private final boolean returnsVoid; private ArityNFunc(int arity, Method method, boolean returnsVoid) { super(arity); this.method = method; this.returnsVoid = returnsVoid; } @Override public Object doApply(Object... ps) { try { Object ret = method.invoke(null, ps); return returnsVoid ? Tuple0.INSTANCE : ret; } catch (ReflectiveOperationException e) { throw new RuntimeException(e); } } @Override public int hashCode() { return method == null ? 0 : method.hashCode(); } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; ArityNFunc other = (ArityNFunc) obj; return method.equals(other.method); } } public static Object getValueFromStaticMethod(final Method method) throws ReflectiveOperationException { int arity = method.getParameterTypes().length; final boolean returnsVoid = method.getReturnType().equals(void.class); switch(arity) { case 0: { Object ret = method.invoke(null); return returnsVoid ? Tuple0.INSTANCE : ret; } case 1: return new Arity1Func(method, returnsVoid); case 2: return new Arity2Func(method, returnsVoid); case 3: return new Arity3Func(method, returnsVoid); case 4: return new Arity4Func(method, returnsVoid); default: return new ArityNFunc(arity, method, returnsVoid); } } }