package scotch.compiler.syntax.pattern; import static scotch.compiler.syntax.builder.BuilderUtil.require; import static scotch.compiler.syntax.pattern.Patterns.field; import static scotch.compiler.text.TextUtil.repeat; import static scotch.symbol.Symbol.qualified; import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.concurrent.atomic.AtomicInteger; import scotch.compiler.syntax.builder.SyntaxBuilder; import scotch.compiler.text.SourceLocation; import scotch.symbol.Symbol; import scotch.compiler.syntax.util.SymbolGenerator; public class ComplexMatchBuilder implements SyntaxBuilder<PatternMatch> { public static ComplexMatchBuilder complexMatchBuilder(SymbolGenerator symbolGenerator) { return new ComplexMatchBuilder(symbolGenerator); } private final SymbolGenerator symbolGenerator; private final List<PatternMatch> patternMatches; private Optional<SourceLocation> sourceLocation; private State state; private ComplexMatchBuilder(SymbolGenerator symbolGenerator) { this.symbolGenerator = symbolGenerator; this.patternMatches = new ArrayList<>(); this.sourceLocation = Optional.empty(); this.state = new DefaultState(); } @Override public PatternMatch build() { return state.build(); } public ComplexMatchBuilder withPatternMatch(PatternMatch patterMatch) { patternMatches.add(patterMatch); return this; } @Override public ComplexMatchBuilder withSourceLocation(SourceLocation sourceLocation) { this.sourceLocation = Optional.of(sourceLocation); return this; } public void tuplize() { state.tuplize(); } private interface State { PatternMatch build(); void tuplize(); } private final class DefaultState implements State { @Override public PatternMatch build() { UnshuffledStructMatch.Builder structureMatch = UnshuffledStructMatch.builder() .withSourceLocation(require(sourceLocation, "Source location")) .withType(symbolGenerator.reserveType()); patternMatches.forEach(structureMatch::withPatternMatch); return structureMatch.build(); } @Override public void tuplize() { state = new TupleState(); } } private final class TupleState implements State { @Override public PatternMatch build() { Symbol constructor = qualified("scotch.data.tuple", "(" + repeat(",", patternMatches.size() - 1) + ")"); AtomicInteger counter = new AtomicInteger(); StructMatch.Builder structureMatch = StructMatch.builder() .withSourceLocation(require(sourceLocation, "Source location")) .withType(symbolGenerator.reserveType()) .withConstructor(constructor); patternMatches.stream() .map(match -> field(match.getSourceLocation(), "_" + counter.getAndIncrement(), symbolGenerator.reserveType(), match)) .forEach(structureMatch::withField); return structureMatch.build(); } @Override public void tuplize() { // noop } } }