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;
}
}
}