package scotch.compiler.syntax.value; import static java.util.stream.Collectors.toList; import static scotch.compiler.syntax.builder.BuilderUtil.require; import static scotch.compiler.syntax.value.Values.unshuffled; import static scotch.util.Either.right; 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.util.Either; import scotch.compiler.syntax.type.Type; @EqualsAndHashCode(callSuper = false) @ToString(exclude = "sourceLocation") public class UnshuffledValue extends Value { public static Builder builder() { return new Builder(); } private final SourceLocation sourceLocation; private final List<Value> values; UnshuffledValue(SourceLocation sourceLocation, List<Value> values) { this.sourceLocation = sourceLocation; this.values = ImmutableList.copyOf(values); } @Override public Value accumulateDependencies(DependencyAccumulator state) { return withValues(values.stream() .map(value -> value.accumulateDependencies(state)) .collect(toList())); } @Override public Value accumulateNames(NameAccumulator state) { return withValues(values.stream() .map(value -> value.accumulateNames(state)) .collect(toList())); } @Override public IntermediateValue generateIntermediateCode(IntermediateGenerator state) { throw new UnsupportedOperationException(); // TODO } @Override public Value bindMethods(TypeChecker typeChecker) { return withValues(values.stream() .map(value -> value.bindMethods(typeChecker)) .collect(toList())); } @Override public Value bindTypes(TypeChecker typeChecker) { return withValues(values.stream() .map(value -> value.bindTypes(typeChecker)) .collect(toList())); } @Override public Value checkTypes(TypeChecker typeChecker) { return withValues(values.stream() .map(value -> value.checkTypes(typeChecker)) .collect(toList())); } @Override public Value collapse() { if (values.size() == 1) { return values.get(0); } else { return this; } } @Override public Value defineOperators(OperatorAccumulator state) { return withValues(state.defineValueOperators(values)); } @Override public Either<Value, List<Value>> destructure() { return right(getValues()); } @Override public SourceLocation getSourceLocation() { return sourceLocation; } @Override public Type getType() { return Type.NULL; } public List<Value> getValues() { return values; } @Override public Value parsePrecedence(PrecedenceParser state) { if (values.size() == 1) { return values.get(0).parsePrecedence(state); } else { return state.shuffle(this); } } @Override public Value qualifyNames(NameQualifier state) { return withValues(state.qualifyValueNames(values)); } @Override public Value reducePatterns(PatternReducer reducer) { throw new UnsupportedOperationException(); // TODO } @Override public Value unwrap() { Value result = collapse(); if (result != this) { return result.unwrap(); } else { return result; } } public UnshuffledValue withSourceLocation(SourceLocation sourceLocation) { return new UnshuffledValue(sourceLocation, values); } @Override public Value withType(Type type) { throw new UnsupportedOperationException(); } public UnshuffledValue withValues(List<Value> members) { return new UnshuffledValue(sourceLocation, members); } public static class Builder implements SyntaxBuilder<UnshuffledValue> { private final List<Value> members; private Optional<SourceLocation> sourceLocation; private Builder() { members = new ArrayList<>(); sourceLocation = Optional.empty(); } @Override public UnshuffledValue build() { return unshuffled( require(sourceLocation, "Source location"), members ); } public Builder withMember(Value member) { members.add(member); return this; } @Override public Builder withSourceLocation(SourceLocation sourceLocation) { this.sourceLocation = Optional.of(sourceLocation); return this; } } }