package scotch.compiler.syntax.value; import static lombok.AccessLevel.PACKAGE; import static scotch.compiler.error.SymbolNotFoundError.symbolNotFound; import static scotch.compiler.syntax.TypeError.typeError; import static scotch.compiler.syntax.type.Types.toType; import lombok.AllArgsConstructor; 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.intermediate.Intermediates; import scotch.compiler.syntax.pattern.PatternReducer; import scotch.compiler.text.SourceLocation; import scotch.data.bool.Bool; import scotch.symbol.Symbol; import scotch.compiler.syntax.type.Type; @AllArgsConstructor(access = PACKAGE) @EqualsAndHashCode(callSuper = false) @ToString(exclude = "sourceLocation") public class IsConstructor extends Value { private final SourceLocation sourceLocation; private final Value value; private final Symbol constructor; @Override public Value accumulateDependencies(DependencyAccumulator state) { return new IsConstructor(sourceLocation, value.accumulateDependencies(state), constructor); } @Override public Value accumulateNames(NameAccumulator state) { throw new UnsupportedOperationException(); // TODO } @Override public Value bindMethods(TypeChecker typeChecker) { return new IsConstructor(sourceLocation, value.bindMethods(typeChecker), constructor); } @Override public Value bindTypes(TypeChecker typeChecker) { return new IsConstructor(sourceLocation, value.bindTypes(typeChecker), constructor); } @Override public Value checkTypes(TypeChecker typeChecker) { return typeChecker.getDataConstructorType(constructor) .map(parentType -> { Value checkedValue = value.checkTypes(typeChecker); parentType.unify(checkedValue.getType(), typeChecker) .orElseGet(unification -> { typeChecker.error(typeError(unification, checkedValue.getSourceLocation())); return checkedValue.getType(); }); return new IsConstructor(sourceLocation, checkedValue, constructor); }) .orElseGet(() -> { typeChecker.error(symbolNotFound(constructor, sourceLocation)); return this; }); } @Override public Value defineOperators(OperatorAccumulator state) { throw new UnsupportedOperationException(); // TODO } @Override public IntermediateValue generateIntermediateCode(IntermediateGenerator state) { return Intermediates.instanceOf( value.generateIntermediateCode(state), state.getDataConstructor(constructor).getClassName() ); } @Override public SourceLocation getSourceLocation() { return sourceLocation; } @Override public Type getType() { return toType(Bool.TYPE); } @Override public Value parsePrecedence(PrecedenceParser state) { throw new UnsupportedOperationException(); // TODO } @Override public Value qualifyNames(NameQualifier state) { throw new UnsupportedOperationException(); // TODO } @Override public Value reducePatterns(PatternReducer reducer) { throw new UnsupportedOperationException(); // TODO } @Override public Value withType(Type type) { return this; // no-op } }