package scotch.compiler.syntax.value; import static scotch.compiler.syntax.value.NoBindingError.noBinding; import static scotch.compiler.syntax.value.Values.apply; import java.util.ArrayList; import java.util.List; import java.util.Optional; import com.google.common.collect.ImmutableList; import lombok.EqualsAndHashCode; import lombok.ToString; import scotch.compiler.analyzer.DependencyAccumulator; import scotch.compiler.analyzer.NameAccumulator; import scotch.compiler.analyzer.NameQualifier; import scotch.compiler.analyzer.OperatorAccumulator; import scotch.compiler.analyzer.PrecedenceParser; import scotch.compiler.analyzer.TypeChecker; import scotch.compiler.intermediate.IntermediateGenerator; import scotch.compiler.intermediate.IntermediateValue; import scotch.compiler.intermediate.Intermediates; import scotch.compiler.syntax.pattern.PatternReducer; import scotch.compiler.syntax.reference.ValueReference; import scotch.compiler.text.SourceLocation; import scotch.symbol.Symbol; import scotch.compiler.syntax.type.FunctionType; import scotch.compiler.syntax.type.InstanceType; import scotch.compiler.syntax.type.Type; @EqualsAndHashCode(callSuper = false) @ToString(exclude = "sourceLocation") public class Method extends Value { private final SourceLocation sourceLocation; private final ValueReference reference; private final List<Type> instances; private final Type type; Method(SourceLocation sourceLocation, ValueReference reference, List<? extends Type> instances, Type type) { this.sourceLocation = sourceLocation; this.reference = reference; this.instances = ImmutableList.copyOf(instances); this.type = type; } @Override public Value accumulateDependencies(DependencyAccumulator state) { throw new UnsupportedOperationException(); } @Override public Value accumulateNames(NameAccumulator state) { throw new UnsupportedOperationException(); } @Override public IntermediateValue generateIntermediateCode(IntermediateGenerator state) { return Intermediates.valueRef(reference, state.valueSignature(reference)); } @Override public Value bindMethods(TypeChecker typeChecker) { List<InstanceType> instanceTypes = new ArrayList<>(); Type type = this.type; for (int i = 0; i < this.instances.size(); i++) { instanceTypes.add((InstanceType) ((FunctionType) type).getArgument()); type = ((FunctionType) type).getResult(); } Value result = this; for (InstanceType instanceType : instanceTypes) { Value typeArgument; if (instanceType.isBound()) { typeArgument = typeChecker.findInstance(this, instanceType); } else { Optional<Value> optionalTypeArgument = typeChecker.findArgument(instanceType); if (optionalTypeArgument.isPresent()) { typeArgument = optionalTypeArgument.get(); } else { typeChecker.error(noBinding(reference.getSymbol(), sourceLocation)); return this; } } result = apply(result, typeArgument, ((FunctionType) result.getType()).getResult()); } return result; } @Override public Value bindTypes(TypeChecker typeChecker) { return withType(typeChecker.generate(type)); } @Override public Value checkTypes(TypeChecker typeChecker) { return this; } @Override public Value defineOperators(OperatorAccumulator state) { throw new UnsupportedOperationException(); } public ValueReference getReference() { return reference; } @Override public SourceLocation getSourceLocation() { return sourceLocation; } public Symbol getSymbol() { return reference.getSymbol(); } @Override public Type getType() { return type; } @Override public Value parsePrecedence(PrecedenceParser state) { throw new UnsupportedOperationException(); } @Override public Value qualifyNames(NameQualifier state) { throw new UnsupportedOperationException(); } @Override public Value reducePatterns(PatternReducer reducer) { throw new UnsupportedOperationException(); // TODO } @Override public Method withType(Type type) { return new Method(sourceLocation, reference, instances, type); } }