package scotch.compiler.syntax.value;
import static scotch.compiler.syntax.builder.BuilderUtil.require;
import static scotch.util.Pair.pair;
import static scotch.symbol.Operator.operator;
import static scotch.symbol.Value.Fixity.LEFT_INFIX;
import java.util.Objects;
import java.util.Optional;
import scotch.compiler.analyzer.DependencyAccumulator;
import scotch.compiler.analyzer.NameAccumulator;
import scotch.compiler.analyzer.OperatorAccumulator;
import scotch.compiler.analyzer.PrecedenceParser;
import scotch.compiler.analyzer.NameQualifier;
import scotch.compiler.analyzer.TypeChecker;
import scotch.compiler.intermediate.IntermediateGenerator;
import scotch.compiler.intermediate.IntermediateValue;
import scotch.compiler.syntax.builder.SyntaxBuilder;
import scotch.compiler.syntax.pattern.PatternReducer;
import scotch.compiler.syntax.scope.Scope;
import scotch.compiler.text.SourceLocation;
import scotch.util.Pair;
import scotch.symbol.Operator;
import scotch.symbol.Symbol;
import scotch.compiler.syntax.type.Type;
public class DefaultOperator extends Value {
public static Builder builder() {
return new Builder();
}
private final SourceLocation sourceLocation;
private final Symbol symbol;
private final Type type;
DefaultOperator(SourceLocation sourceLocation, Symbol symbol, Type type) {
this.sourceLocation = sourceLocation;
this.symbol = symbol;
this.type = type;
}
@Override
public Value accumulateDependencies(DependencyAccumulator state) {
throw new UnsupportedOperationException();
}
private Identifier asIdentifier() {
return Identifier.builder()
.withSourceLocation(sourceLocation)
.withSymbol(symbol)
.withType(type)
.build();
}
@Override
public Value accumulateNames(NameAccumulator state) {
throw new UnsupportedOperationException();
}
@Override
public IntermediateValue generateIntermediateCode(IntermediateGenerator state) {
throw new UnsupportedOperationException(); // TODO
}
@Override
public Optional<Pair<Identifier, Operator>> asOperator(Scope scope) {
if (scope.isOperator(symbol)) {
return scope.qualify(symbol)
.flatMap(scope::getOperator)
.map(operator -> pair(asIdentifier(), operator));
} else {
return Optional.of(pair(asIdentifier(), operator(LEFT_INFIX, 6)));
}
}
@Override
public Value bindMethods(TypeChecker typeChecker) {
throw new UnsupportedOperationException();
}
@Override
public Value bindTypes(TypeChecker typeChecker) {
throw new UnsupportedOperationException();
}
@Override
public Value checkTypes(TypeChecker typeChecker) {
throw new UnsupportedOperationException();
}
@Override
public Value defineOperators(OperatorAccumulator state) {
return this;
}
@Override
public boolean equals(Object o) {
if (o == this) {
return true;
} else if (o instanceof DefaultOperator) {
DefaultOperator other = (DefaultOperator) o;
return Objects.equals(sourceLocation, other.sourceLocation)
&& Objects.equals(symbol, other.symbol)
&& Objects.equals(type, other.type);
} else {
return false;
}
}
@Override
public SourceLocation getSourceLocation() {
return sourceLocation;
}
@Override
public Type getType() {
return type;
}
@Override
public int hashCode() {
return Objects.hash(symbol, type);
}
@Override
public boolean isOperator(Scope scope) {
return true;
}
@Override
public Value parsePrecedence(PrecedenceParser state) {
return this;
}
@Override
public Value qualifyNames(NameQualifier state) {
throw new UnsupportedOperationException();
}
@Override
public Value reducePatterns(PatternReducer reducer) {
throw new UnsupportedOperationException(); // TODO
}
@Override
public String toString() {
return "`" + symbol + "`";
}
@Override
public Value withType(Type type) {
throw new UnsupportedOperationException();
}
public static class Builder implements SyntaxBuilder<DefaultOperator> {
private Optional<SourceLocation> sourceLocation = Optional.empty();
private Optional<Symbol> symbol = Optional.empty();
private Optional<Type> type = Optional.empty();
@Override
public DefaultOperator build() {
return new DefaultOperator(
require(sourceLocation, "Source location"),
require(symbol, "Default operator symbol"),
require(type, "Default operator type")
);
}
@Override
public Builder withSourceLocation(SourceLocation sourceLocation) {
this.sourceLocation = Optional.of(sourceLocation);
return this;
}
public Builder withSymbol(Symbol symbol) {
this.symbol = Optional.of(symbol);
return this;
}
public Builder withType(Type type) {
this.type = Optional.of(type);
return this;
}
}
}