package scotch.compiler.syntax.definition; import static scotch.compiler.syntax.builder.BuilderUtil.require; import static scotch.compiler.syntax.definition.Definitions.classDef; import static scotch.compiler.syntax.reference.DefinitionReference.classRef; 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.OperatorAccumulator; import scotch.compiler.analyzer.PatternAnalyzer; import scotch.compiler.analyzer.PrecedenceParser; import scotch.compiler.analyzer.NameQualifier; 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.Symbol; import scotch.compiler.syntax.type.Type; @EqualsAndHashCode(callSuper = false) @ToString(exclude = "sourceLocation") public class ClassDefinition extends Definition { private final SourceLocation sourceLocation; private final Symbol symbol; private final List<Type> arguments; private final List<DefinitionReference> members; ClassDefinition(SourceLocation sourceLocation, Symbol symbol, List<Type> arguments, List<DefinitionReference> members) { if (arguments.isEmpty()) { throw new IllegalArgumentException("Can't create class definition with 0 arguments"); } else if (members.isEmpty()) { throw new IllegalArgumentException("Can't create class definition with 0 members"); } this.sourceLocation = sourceLocation; this.symbol = symbol; this.arguments = ImmutableList.copyOf(arguments); this.members = ImmutableList.copyOf(members); } @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) { throw new UnsupportedOperationException(); // TODO } @Override public Definition defineOperators(OperatorAccumulator state) { return state.keep(this); } @Override public Optional<DefinitionReference> generateIntermediateCode(IntermediateGenerator generator) { throw new UnsupportedOperationException(); // TODO } @Override public DefinitionReference getReference() { return classRef(symbol); } @Override public SourceLocation getSourceLocation() { return sourceLocation; } public Symbol getSymbol() { return symbol; } @Override public Optional<Definition> parsePrecedence(PrecedenceParser state) { return Optional.of(state.keep(this)); } @Override public Definition qualifyNames(NameQualifier state) { throw new UnsupportedOperationException(); // TODO } @Override public Definition reducePatterns(PatternAnalyzer state) { throw new UnsupportedOperationException(); // TODO } public static class ClassDefinitionBuilder implements SyntaxBuilder<ClassDefinition> { private Optional<Symbol> symbol; private Optional<List<Type>> arguments; private Optional<List<DefinitionReference>> members; private Optional<SourceLocation> sourceLocation; public ClassDefinitionBuilder() { symbol = Optional.empty(); arguments = Optional.empty(); members = Optional.empty(); sourceLocation = Optional.empty(); } @Override public ClassDefinition build() { return classDef( require(sourceLocation, "Source location"), require(symbol, "Class symbol"), require(arguments, "Class arguments"), require(members, "Class member definitions") ); } public ClassDefinitionBuilder withArguments(List<Type> arguments) { this.arguments = Optional.of(arguments); return this; } public ClassDefinitionBuilder withMembers(List<DefinitionReference> members) { this.members = Optional.of(members); return this; } @Override public ClassDefinitionBuilder withSourceLocation(SourceLocation sourceLocation) { this.sourceLocation = Optional.of(sourceLocation); return this; } public ClassDefinitionBuilder withSymbol(Symbol symbol) { this.symbol = Optional.of(symbol); return this; } } }