package scotch.compiler.syntax.definition; import static scotch.compiler.syntax.builder.BuilderUtil.require; import static scotch.compiler.syntax.reference.DefinitionReference.operatorRef; import static scotch.symbol.Operator.operator; import java.util.Objects; import java.util.Optional; import java.util.OptionalInt; 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.PatternAnalyzer; import scotch.compiler.analyzer.PrecedenceParser; import scotch.compiler.analyzer.TypeChecker; import scotch.compiler.intermediate.IntermediateGenerator; import scotch.compiler.syntax.builder.SyntaxBuilder; import scotch.compiler.syntax.reference.DefinitionReference; import scotch.compiler.text.SourceLocation; import scotch.symbol.Operator; import scotch.symbol.Symbol; import scotch.symbol.Value.Fixity; @ToString(exclude = "sourceLocation") public class OperatorDefinition extends Definition { public static Builder builder() { return new Builder(); } private final SourceLocation sourceLocation; private final Symbol symbol; private final Fixity fixity; private final int precedence; OperatorDefinition(SourceLocation sourceLocation, Symbol symbol, Fixity fixity, int precedence) { this.sourceLocation = sourceLocation; this.symbol = symbol; this.fixity = fixity; this.precedence = precedence; } @Override public Definition accumulateDependencies(DependencyAccumulator state) { return state.keep(this); } @Override public Definition accumulateNames(NameAccumulator state) { return state.keep(this); } @Override public Definition checkTypes(TypeChecker state) { return state.keep(this); } @Override public Definition defineOperators(OperatorAccumulator state) { return state.scoped(this, () -> { state.defineOperator(symbol, getOperator()); return this; }); } @Override public boolean equals(Object o) { if (o == this) { return true; } else if (o instanceof OperatorDefinition) { OperatorDefinition other = (OperatorDefinition) o; return Objects.equals(symbol, other.symbol) && Objects.equals(fixity, other.fixity) && Objects.equals(precedence, other.precedence); } else { return false; } } @Override public Optional<DefinitionReference> generateIntermediateCode(IntermediateGenerator generator) { return Optional.empty(); } public Operator getOperator() { return operator(fixity, precedence); } @Override public DefinitionReference getReference() { return operatorRef(symbol); } @Override public SourceLocation getSourceLocation() { return sourceLocation; } public Symbol getSymbol() { return symbol; } @Override public int hashCode() { return Objects.hash(symbol, fixity, precedence); } @Override public Optional<Definition> parsePrecedence(PrecedenceParser state) { return Optional.of(state.keep(this)); } @Override public Definition qualifyNames(NameQualifier state) { return state.keep(this); } @Override public Definition reducePatterns(PatternAnalyzer state) { return state.keep(this); } public static class Builder implements SyntaxBuilder<OperatorDefinition> { private Optional<Symbol> symbol; private Optional<Fixity> fixity; private OptionalInt precedence; private Optional<SourceLocation> sourceLocation; private Builder() { symbol = Optional.empty(); fixity = Optional.empty(); precedence = OptionalInt.empty(); sourceLocation = Optional.empty(); } @Override public OperatorDefinition build() { return Definitions.operatorDef( require(sourceLocation, "Source location"), require(symbol, "Operator symbol"), require(fixity, "Operator fixity"), require(precedence, "Operator precedence") ); } public Builder withFixity(Fixity fixity) { this.fixity = Optional.of(fixity); return this; } public Builder withPrecedence(int precedence) { this.precedence = OptionalInt.of(precedence); return this; } @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; } } }