package scotch.compiler.syntax.value;
import static java.util.stream.Collectors.toList;
import static scotch.compiler.syntax.builder.BuilderUtil.require;
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.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.text.SourceLocation;
import scotch.compiler.syntax.type.Type;
@EqualsAndHashCode(callSuper = false)
@ToString(exclude = "sourceLocation")
public class Initializer extends Value {
public static Builder builder() {
return new Builder();
}
private final SourceLocation sourceLocation;
private final Value value;
private final List<InitializerField> fields;
private final Type type;
Initializer(SourceLocation sourceLocation, Value value, List<InitializerField> fields, Type type) {
this.sourceLocation = sourceLocation;
this.value = value;
this.fields = ImmutableList.copyOf(fields);
this.type = type;
}
@Override
public Value accumulateDependencies(DependencyAccumulator state) {
return new Initializer(
sourceLocation,
value.accumulateDependencies(state),
fields.stream()
.map(field -> field.accumulateDependencies(state))
.collect(toList()),
type
);
}
@Override
public Value accumulateNames(NameAccumulator state) {
return new Initializer(
sourceLocation,
value.accumulateNames(state),
fields.stream()
.map(field -> field.accumulateNames(state))
.collect(toList()),
type
);
}
@Override
public IntermediateValue generateIntermediateCode(IntermediateGenerator state) {
throw new UnsupportedOperationException(); // TODO
}
@Override
public Value bindMethods(TypeChecker typeChecker) {
return this;
}
@Override
public Value bindTypes(TypeChecker typeChecker) {
return this;
}
@Override
public Value checkTypes(TypeChecker typeChecker) {
return value
.asInitializer(this, typeChecker)
.orElse(this);
}
@Override
public Value defineOperators(OperatorAccumulator state) {
return new Initializer(
sourceLocation,
value.defineOperators(state),
fields.stream()
.map(field -> field.defineOperators(state))
.collect(toList()),
type
);
}
public List<InitializerField> getFields() {
return fields;
}
@Override
public SourceLocation getSourceLocation() {
return sourceLocation;
}
@Override
public Type getType() {
return type;
}
@Override
public Value parsePrecedence(PrecedenceParser state) {
return new Initializer(
sourceLocation,
value.parsePrecedence(state),
fields.stream()
.map(field -> field.parsePrecedence(state))
.collect(toList()),
type
);
}
@Override
public Value qualifyNames(NameQualifier state) {
return withValue(value.qualifyNames(state))
.withFields(fields.stream()
.map(field -> field.qualifyNames(state))
.collect(toList()));
}
@Override
public Value reducePatterns(PatternReducer reducer) {
return withValue(value.reducePatterns(reducer))
.withFields(fields.stream()
.map(field -> field.reducePatterns(reducer))
.collect(toList()));
}
@Override
public Value withType(Type type) {
return new Initializer(sourceLocation, value, fields, type);
}
private Value withFields(List<InitializerField> fields) {
return new Initializer(sourceLocation, value, fields, type);
}
private Initializer withValue(Value value) {
return new Initializer(sourceLocation, value, fields, type);
}
public static class Builder implements SyntaxBuilder<Initializer> {
private Optional<SourceLocation> sourceLocation;
private Optional<Value> value;
private Optional<List<InitializerField>> fields;
private Optional<Type> type;
private Builder() {
sourceLocation = Optional.empty();
value = Optional.empty();
fields = Optional.empty();
type = Optional.empty();
}
public Builder addField(InitializerField field) {
if (!fields.isPresent()) {
fields = Optional.of(new ArrayList<>());
}
fields.ifPresent(list -> list.add(field));
return this;
}
@Override
public Initializer build() {
return new Initializer(
require(sourceLocation, "Source location"),
require(value, "Initializer value"),
require(fields, "Initializer fields"),
require(type, "Initializer type")
);
}
@Override
public Builder withSourceLocation(SourceLocation sourceLocation) {
this.sourceLocation = Optional.of(sourceLocation);
return this;
}
public Builder withType(Type type) {
this.type = Optional.of(type);
return this;
}
public Builder withValue(Value value) {
this.value = Optional.of(value);
return this;
}
}
}