diff options
| author | Michael Williamson <mike@zwobble.org> | 2023-07-28 22:30:40 +0100 |
|---|---|---|
| committer | Michael Williamson <mike@zwobble.org> | 2023-07-28 22:31:30 +0100 |
| commit | 7367e30043ab9de09fafdb72e5fab6bac4debb9a (patch) | |
| tree | da636e75b5991ccd65cb451e1b83b4667ae7e6a4 /src/test/java | |
| parent | f3da8bbffe9cdf80ba3f422ec2d8ff7ce13ea2ae (diff) | |
Type check assignments
Diffstat (limited to 'src/test/java')
3 files changed, 96 insertions, 0 deletions
diff --git a/src/test/java/org/shedlang/compiler/ast/typed/TypedNodeMatchers.java b/src/test/java/org/shedlang/compiler/ast/typed/TypedNodeMatchers.java index ef2e4686..9ee8c8fa 100644 --- a/src/test/java/org/shedlang/compiler/ast/typed/TypedNodeMatchers.java +++ b/src/test/java/org/shedlang/compiler/ast/typed/TypedNodeMatchers.java @@ -16,6 +16,17 @@ public class TypedNodeMatchers { return TypedArgsNodeMatcher.empty(); } + public static Matcher<TypedNode> isTypedAssignNode( + Matcher<? super TypedTargetNode> target, + Matcher<? super TypedExpressionNode> expression + ) { + return instanceOf( + TypedAssignNode.class, + has("target", x -> x.target(), target), + has("expression", x -> x.expression(), expression) + ); + } + public static Matcher<TypedExpressionNode> isTypedBinaryOperationNode( TypedBinaryOperator operator, Matcher<TypedExpressionNode> left, diff --git a/src/test/java/org/shedlang/compiler/ast/untyped/Untyped.java b/src/test/java/org/shedlang/compiler/ast/untyped/Untyped.java index 141212cc..1fe48649 100644 --- a/src/test/java/org/shedlang/compiler/ast/untyped/Untyped.java +++ b/src/test/java/org/shedlang/compiler/ast/untyped/Untyped.java @@ -22,6 +22,13 @@ public class Untyped { ); } + public static UntypedAssignNode assign( + UntypedTargetNode target, + UntypedExpressionNode expression + ) { + return new UntypedAssignNode(target, expression, Sources.NULL); + } + public static UntypedBlockNode block(List<UntypedFunctionStatementNode> statements) { return new UntypedBlockNode(statements, Sources.NULL); } diff --git a/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerAssignTests.java b/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerAssignTests.java new file mode 100644 index 00000000..21ebfbc3 --- /dev/null +++ b/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerAssignTests.java @@ -0,0 +1,78 @@ +package org.shedlang.compiler.typechecker; + +import org.junit.jupiter.api.Test; +import org.shedlang.compiler.ast.typed.TypedFunctionStatementNode; +import org.shedlang.compiler.ast.typed.TypedNamespaceStatementNode; +import org.shedlang.compiler.ast.untyped.Untyped; +import org.shedlang.compiler.ast.untyped.UntypedFunctionStatementNode; +import org.shedlang.compiler.ast.untyped.UntypedNamespaceStatementNode; +import org.shedlang.compiler.typechecker.errors.UnexpectedTypeError; +import org.shedlang.compiler.typechecker.typesets.TypeSets; +import org.shedlang.compiler.types.Types; +import org.shedlang.compiler.util.P; + +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.shedlang.compiler.ast.typed.TypedNodeMatchers.*; +import static org.zwobble.precisely.AssertThat.assertThat; +import static org.zwobble.precisely.Matchers.equalTo; + +public class TypeCheckerAssignTests { + @Test + public void canTypeCheckAssign() { + var untyped = Untyped.assign(Untyped.targetVariable("x"), Untyped.stringLiteral("hello")); + var context = TypeCheckerContext.EMPTY + .enterNamespace(P.map( + Map.entry("x", TypeCheckerContext.defined(Types.STRING)) + )); + + var typed = typeCheckFunctionStatement(untyped, context); + + assertThat(typed.value(), isTypedAssignNode( + isTypedTargetVariable("x"), + isTypedStringLiteralNode("hello") + )); + } + + @Test + public void whenExpressionIsNotSubTypeOfTargetVariableThenErrorIsThrown() { + var untyped = Untyped.assign(Untyped.targetVariable("x"), Untyped.stringLiteral("hello")); + var context = TypeCheckerContext.EMPTY + .enterNamespace(P.map( + Map.entry("x", TypeCheckerContext.defined(Types.INT)) + )); + + var error = assertThrows( + UnexpectedTypeError.class, + () -> typeCheckFunctionStatement(untyped, context) + ); + + assertThat(error.expected(), equalTo(TypeSets.type(Types.INT))); + assertThat(error.actual(), equalTo(Types.STRING)); + } + + private static TypeCheckerResult<? extends TypedFunctionStatementNode> typeCheckFunctionStatement( + UntypedFunctionStatementNode untyped, + TypeCheckerContext context + ) { + var declaredVariables = DeclaredVariables.forFunctionStatement(untyped, P.vector()); + var environment = EnvironmentBuilder.EMPTY.addUndefined(declaredVariables); + + context = context.enterNamespace(environment.build()); + + return TypeChecker.typeCheckFunctionStatement(untyped, context); + } + + private static TypeCheckerResult<? extends TypedNamespaceStatementNode> typeCheckNamespaceStatement( + UntypedNamespaceStatementNode untyped, + TypeCheckerContext context + ) { + var declaredVariables = DeclaredVariables.forNamespaceStatement(untyped, P.vector()); + var environment = EnvironmentBuilder.EMPTY.addUndefined(declaredVariables); + + context = context.enterNamespace(environment.build()); + + return TypeChecker.typeCheckNamespaceStatement(untyped).typeCheckAllPhases(context); + } +} |
