package me.tomassetti.turin.parser.ast.expressions; import com.google.common.collect.ImmutableList; import me.tomassetti.jvm.JvmMethodDefinition; import me.tomassetti.jvm.JvmType; import me.tomassetti.turin.definitions.InternalInvokableDefinition; import me.tomassetti.turin.resolvers.SymbolResolver; import me.tomassetti.turin.parser.ast.Node; import me.tomassetti.turin.symbols.FormalParameter; import me.tomassetti.turin.typesystem.Invokable; import me.tomassetti.turin.typesystem.TypeUsage; import java.util.List; import java.util.Optional; import java.util.stream.Collectors; public class InstanceMethodInvokation extends InvokableExpr { private Expression subject; private String methodName; public InstanceMethodInvokation(Expression subject, String methodName, List<ActualParam> params) { super(params); this.subject = subject; this.subject.setParent(this); this.methodName = methodName; } @Override public String toString() { return "InstanceMethodInvokation{" + "subject=" + subject + ", methodName='" + methodName + '\'' + '}'; } public Expression getSubject() { return subject; } public String getMethodName() { return methodName; } @Override public Iterable<Node> getChildren() { return ImmutableList.<Node>builder().add(subject).addAll(actualParams).build(); } @Override public TypeUsage calcType() { List<JvmType> paramTypes = getActualParamValuesInOrder().stream().map((ap)->ap.calcType().jvmType()).collect(Collectors.toList()); TypeUsage subjectType = subject.calcType(); Invokable invokableType = subjectType.getMethod(methodName, false).get(); InternalInvokableDefinition internalInvokableDefinition = invokableType.internalInvokableDefinitionFor(actualParams).get(); return internalInvokableDefinition.asMethod().getReturnType(); } public JvmMethodDefinition findJvmDefinition(SymbolResolver resolver) { List<ActualParam> paramTypes = getActualParamValuesInOrder().stream().map((e) -> { ActualParam ap = new ActualParam (e); ap.setParent(InstanceMethodInvokation.this); return ap; }).collect(Collectors.toList()); TypeUsage subjectType = subject.calcType(); Optional<Invokable> method = subjectType.getMethod(methodName, false); Optional<? extends InternalInvokableDefinition> invokableDefinition = method.get().internalInvokableDefinitionFor(paramTypes); if (!invokableDefinition.isPresent()) { throw new IllegalStateException("Unable to retrieve the JVM definition: " + method.get().getClass().getCanonicalName()); } return invokableDefinition.get().asMethod().getJvmMethodDefinition(); } @Override public boolean isOnOverloaded(SymbolResolver resolver) { return subject.calcType().getMethod(methodName, false).get().isOverloaded(); } @Override protected List<? extends FormalParameter> formalParameters(SymbolResolver resolver) { TypeUsage typeUsage = subject.calcType(); if (!typeUsage.isReference()) { throw new UnsupportedOperationException(); } return typeUsage.asReferenceTypeUsage().getTypeDefinition().getMethodParams(methodName, actualParams, false); } }