package scotch.symbol; import static java.util.Arrays.stream; import static me.qmx.jitescript.util.CodegenUtils.p; import static me.qmx.jitescript.util.CodegenUtils.sig; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.Objects; import me.qmx.jitescript.CodeBlock; public class MethodSignature { public static MethodSignature constructor(String descriptor) { return fromString(MethodTypeDescriptor.SPECIAL, descriptor); } public static MethodSignature fromMethod(Method method) { return new MethodSignature( MethodTypeDescriptor.fromAccess(method), p(method.getDeclaringClass()), method.getName(), sig(method.getReturnType(), method.getParameterTypes()) ); } public static MethodSignature fromMethod(Class<?> clazz, String methodName) { try { return stream(clazz.getMethods()) .filter(method -> methodName.equals(method.getName())) .findFirst() .map(MethodSignature::fromMethod) .orElseThrow(() -> new NoSuchMethodException("Could not find method " + methodName)); } catch (ReflectiveOperationException exception) { throw new RuntimeException(exception); } } public static MethodSignature methodSignature(String descriptor) { return fromString(MethodTypeDescriptor.STATIC, descriptor); } public static MethodSignature staticMethod(String className, String methodName, String signature) { return new MethodSignature(MethodTypeDescriptor.STATIC, className, methodName, signature); } public static MethodSignature fromString(MethodTypeDescriptor methodTypeDescriptor, String descriptor) { String[] parts = descriptor.split(":"); return new MethodSignature(methodTypeDescriptor, parts[0], parts[1], parts[2]); } private final MethodTypeDescriptor methodTypeDescriptor; private final String className; private final String methodName; private final String signature; private MethodSignature(MethodTypeDescriptor methodTypeDescriptor, String className, String methodName, String signature) { this.methodTypeDescriptor = methodTypeDescriptor; this.className = className; this.methodName = methodName; this.signature = signature; } @Override public boolean equals(Object o) { if (o == this) { return true; } else if (o instanceof MethodSignature) { MethodSignature other = (MethodSignature) o; return Objects.equals(methodTypeDescriptor, other.methodTypeDescriptor) && Objects.equals(className, other.className) && Objects.equals(methodName, other.methodName) && Objects.equals(signature, other.signature); } else { return false; } } public String getClassName() { return className; } @Override public int hashCode() { return Objects.hash(methodTypeDescriptor, className, methodName, signature); } public CodeBlock reference() { return methodTypeDescriptor.generate(this); } @Override public String toString() { return className + ":" + methodName + ":" + signature; } public enum MethodTypeDescriptor { STATIC { @Override public CodeBlock generate(MethodSignature signature) { return new CodeBlock() {{ invokestatic(signature.className, signature.methodName, signature.signature); }}; } }, VIRTUAL { @Override public CodeBlock generate(MethodSignature signature) { return new CodeBlock() {{ invokevirtual(signature.className, signature.methodName, signature.signature); }}; } }, INTERFACE { @Override public CodeBlock generate(MethodSignature signature) { return new CodeBlock() {{ invokeinterface(signature.className, signature.methodName, signature.signature); }}; } }, SPECIAL { @Override public CodeBlock generate(MethodSignature signature) { return new CodeBlock() {{ invokespecial(signature.className, signature.methodName, signature.signature); }}; } }; public static MethodTypeDescriptor fromAccess(Method method) { if (Modifier.isStatic(method.getModifiers())) { return STATIC; } else if (Modifier.isInterface(method.getModifiers())) { return INTERFACE; } else { return VIRTUAL; } } public abstract CodeBlock generate(MethodSignature signature); } }