package scotch.compiler.syntax.pattern; import static lombok.AccessLevel.PACKAGE; import static scotch.compiler.syntax.builder.BuilderUtil.require; import static scotch.compiler.syntax.value.Values.access; import static scotch.symbol.Symbol.symbol; import java.util.Optional; import lombok.AllArgsConstructor; import lombok.EqualsAndHashCode; import lombok.ToString; import scotch.compiler.analyzer.NameAccumulator; import scotch.compiler.analyzer.NameQualifier; import scotch.compiler.analyzer.TypeChecker; import scotch.compiler.syntax.builder.SyntaxBuilder; import scotch.compiler.syntax.scope.Scope; import scotch.compiler.syntax.value.Value; import scotch.compiler.text.SourceLocation; import scotch.compiler.syntax.type.Type; @AllArgsConstructor(access = PACKAGE) @EqualsAndHashCode(callSuper = false) @ToString(exclude = "sourceLocation") public class StructField { public static Builder builder() { return new Builder(); } private final SourceLocation sourceLocation; private final String field; private final Type type; private final PatternMatch patternMatch; public StructField accumulateNames(NameAccumulator state) { return withPatternMatch(patternMatch.accumulateNames(state)); } public StructField bind(Value argument, Scope scope) { return new StructField( sourceLocation, field, type, patternMatch.bind(access(sourceLocation, argument, field, scope.reserveType(), Optional.empty()), scope) ); } public StructField bindMethods(TypeChecker state) { return new StructField(sourceLocation, field, type, patternMatch.bindMethods(state)); } public StructField bindTypes(TypeChecker state) { return new StructField(sourceLocation, field, state.generate(type), patternMatch.bindTypes(state)); } public StructField checkTypes(TypeChecker state) { PatternMatch checkedMatch = patternMatch.checkTypes(state); return new StructField(sourceLocation, field, checkedMatch.getType(), checkedMatch); } public Type getType() { return type; } public StructField qualifyNames(NameQualifier state) { return withPatternMatch(patternMatch.qualifyNames(state)); } public void reducePatterns(PatternReducer reducer) { patternMatch.reducePatterns(reducer); } private StructField withPatternMatch(PatternMatch patternMatch) { return new StructField(sourceLocation, field, type, patternMatch); } public static class Builder implements SyntaxBuilder<StructField> { private Optional<SourceLocation> sourceLocation = Optional.empty(); private Optional<String> fieldName = Optional.empty(); private Optional<Type> type = Optional.empty(); private Optional<PatternMatch> patternMatch = Optional.empty(); private boolean implicit = false; private Builder() { // intentionally empty } @Override public StructField build() { PatternMatch match; if (implicit) { match = CaptureMatch.builder() .withSourceLocation(require(sourceLocation, "Source location")) .withSymbol(symbol(require(fieldName, "Field name"))) .withType(require(type, "Field type")) .build(); } else { match = require(patternMatch, "Field pattern"); } return new StructField( require(sourceLocation, "Source location"), require(fieldName, "Field name"), require(type, "Field type"), match ); } public Builder withFieldName(String fieldName) { this.fieldName = Optional.of(fieldName); return this; } public Builder withImplicitCapture() { implicit = true; return this; } public Builder withPatternMatch(PatternMatch patternMatch) { this.patternMatch = Optional.of(patternMatch); return this; } @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; } } }