aboutsummaryrefslogtreecommitdiff
path: root/src/test/java
diff options
context:
space:
mode:
authorMichael Williamson <mike@zwobble.org>2023-07-28 22:30:40 +0100
committerMichael Williamson <mike@zwobble.org>2023-07-28 22:31:30 +0100
commit7367e30043ab9de09fafdb72e5fab6bac4debb9a (patch)
treeda636e75b5991ccd65cb451e1b83b4667ae7e6a4 /src/test/java
parentf3da8bbffe9cdf80ba3f422ec2d8ff7ce13ea2ae (diff)
Type check assignments
Diffstat (limited to 'src/test/java')
-rw-r--r--src/test/java/org/shedlang/compiler/ast/typed/TypedNodeMatchers.java11
-rw-r--r--src/test/java/org/shedlang/compiler/ast/untyped/Untyped.java7
-rw-r--r--src/test/java/org/shedlang/compiler/typechecker/TypeCheckerAssignTests.java78
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);
+ }
+}