diff options
| author | Michael Williamson <mike@zwobble.org> | 2023-06-10 11:00:22 +0100 |
|---|---|---|
| committer | Michael Williamson <mike@zwobble.org> | 2023-06-10 11:01:18 +0100 |
| commit | 74b2aa135e2bf1af1ef65476aa03406eaaddd2ab (patch) | |
| tree | c558aa52c7735b52bda18eded51b325111f57aa3 /src/test/java | |
| parent | 677a2627c238c511b33f7586f97197f5cf3ced5b (diff) | |
Add incomplete type checking for calls
Diffstat (limited to 'src/test/java')
10 files changed, 208 insertions, 17 deletions
diff --git a/src/test/java/org/shedlang/compiler/ast/typed/TypedArgsNodeMatcher.java b/src/test/java/org/shedlang/compiler/ast/typed/TypedArgsNodeMatcher.java new file mode 100644 index 00000000..05037526 --- /dev/null +++ b/src/test/java/org/shedlang/compiler/ast/typed/TypedArgsNodeMatcher.java @@ -0,0 +1,36 @@ +package org.shedlang.compiler.ast.typed; + +import org.pcollections.Empty; +import org.pcollections.PVector; +import org.shedlang.compiler.testing.MatcherBuilder; +import org.zwobble.precisely.Matcher; + +import static org.zwobble.precisely.Matchers.has; + +public class TypedArgsNodeMatcher extends MatcherBuilder<TypedArgsNode, TypedArgsNode, TypedArgsNodeMatcher> { + public static TypedArgsNodeMatcher empty() { + return new TypedArgsNodeMatcher(Empty.vector()); + } + + public TypedArgsNodeMatcher(PVector<Matcher<? super TypedArgsNode>> submatchers) { + super(submatchers); + } + + @Override + protected Class<TypedArgsNode> expectedType() { + return TypedArgsNode.class; + } + + @Override + protected TypedArgsNodeMatcher create(PVector<Matcher<? super TypedArgsNode>> submatchers) { + return new TypedArgsNodeMatcher(submatchers); + } + + public TypedArgsNodeMatcher withPositional(Matcher<? super Iterable<TypedExpressionNode>> positional) { + return with(has("positional", x -> x.positional(), positional)); + } + + public TypedArgsNodeMatcher withNamed(Matcher<? super Iterable<TypedNamedArgNode>> named) { + return with(has("named", x -> x.named(), named)); + } +} diff --git a/src/test/java/org/shedlang/compiler/ast/typed/TypedCallNodeMatcher.java b/src/test/java/org/shedlang/compiler/ast/typed/TypedCallNodeMatcher.java new file mode 100644 index 00000000..5512d9c8 --- /dev/null +++ b/src/test/java/org/shedlang/compiler/ast/typed/TypedCallNodeMatcher.java @@ -0,0 +1,46 @@ +package org.shedlang.compiler.ast.typed; + +import org.pcollections.Empty; +import org.pcollections.PVector; +import org.shedlang.compiler.testing.MatcherBuilder; +import org.shedlang.compiler.types.Type; +import org.zwobble.precisely.Matcher; + +import static org.zwobble.precisely.Matchers.equalTo; +import static org.zwobble.precisely.Matchers.has; + +public class TypedCallNodeMatcher extends MatcherBuilder<TypedExpressionNode, TypedCallNode, TypedCallNodeMatcher> { + public static TypedCallNodeMatcher empty() { + return new TypedCallNodeMatcher(Empty.vector()); + } + + public TypedCallNodeMatcher(PVector<Matcher<? super TypedCallNode>> submatchers) { + super(submatchers); + } + + @Override + protected Class<TypedCallNode> expectedType() { + return TypedCallNode.class; + } + + @Override + protected TypedCallNodeMatcher create(PVector<Matcher<? super TypedCallNode>> submatchers) { + return new TypedCallNodeMatcher(submatchers); + } + + public TypedCallNodeMatcher withArgs(Matcher<TypedArgsNode> args) { + return with(has("args", x -> x.args(), args)); + } + + public TypedCallNodeMatcher withHasEffects(boolean hasEffects) { + return with(has("hasEffects", x -> x.hasEffects(), equalTo(hasEffects))); + } + + public TypedCallNodeMatcher withReceiver(Matcher<TypedExpressionNode> receiver) { + return with(has("receiver", x -> x.receiver(), receiver)); + } + + public TypedCallNodeMatcher withType(Type type) { + return with(has("type", x -> x.type(), equalTo(type))); + } +} 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 7716b76a..acf61900 100644 --- a/src/test/java/org/shedlang/compiler/ast/typed/TypedNodeMatchers.java +++ b/src/test/java/org/shedlang/compiler/ast/typed/TypedNodeMatchers.java @@ -11,6 +11,10 @@ public class TypedNodeMatchers { private TypedNodeMatchers() { } + public static TypedArgsNodeMatcher isTypedArgsNode() { + return TypedArgsNodeMatcher.empty(); + } + public static Matcher<TypedExpressionNode> isTypedBoolLiteralNode(boolean value) { return instanceOf( TypedBoolLiteralNode.class, @@ -18,6 +22,10 @@ public class TypedNodeMatchers { ); } + public static TypedCallNodeMatcher isTypedCallNode() { + return TypedCallNodeMatcher.empty(); + } + public static Matcher<TypedExpressionNode> isTypedIntLiteralNode(int value) { return isTypedIntLiteralNode(BigInteger.valueOf(value)); } @@ -29,6 +37,16 @@ public class TypedNodeMatchers { ); } + public static Matcher<TypedNamedArgNode> isTypedNamedArgNode( + String name, + Matcher<TypedExpressionNode> expression + ) { + return allOf( + has("name", x -> x.name(), equalTo(name)), + has("expression", x -> x.expression(), expression) + ); + } + public static Matcher<TypedExpressionNode> isTypedReferenceNode(String name, Type type) { return instanceOf( TypedReferenceNode.class, 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 37778968..11e7b38f 100644 --- a/src/test/java/org/shedlang/compiler/ast/untyped/Untyped.java +++ b/src/test/java/org/shedlang/compiler/ast/untyped/Untyped.java @@ -3,6 +3,7 @@ package org.shedlang.compiler.ast.untyped; import org.shedlang.compiler.sources.Sources; import java.math.BigInteger; +import java.util.List; public class Untyped { private Untyped() { @@ -20,6 +21,10 @@ public class Untyped { return new UntypedIntLiteralNode(value, Sources.NULL); } + public static UntypedNamedArgNode namedArg(String name, UntypedExpressionNode expression) { + return new UntypedNamedArgNode(name, expression, Sources.NULL); + } + public static UntypedReferenceNode reference(String name) { return new UntypedReferenceNode(name, Sources.NULL); } @@ -27,4 +32,24 @@ public class Untyped { public static UntypedStringLiteralNode stringLiteral(String value) { return new UntypedStringLiteralNode(value, Sources.NULL); } + + public static UntypedCallNode call( + UntypedExpressionNode receiver, + List<UntypedExpressionNode> positionalArgs + ) { + return call(receiver, positionalArgs, List.of()); + } + + public static UntypedCallNode call( + UntypedExpressionNode receiver, + List<UntypedExpressionNode> positionalArgs, + List<UntypedNamedArgNode> namedArgs + ) { + return new UntypedCallNode( + receiver, + new UntypedArgsNode(positionalArgs, namedArgs, Sources.NULL), + false, + Sources.NULL + ); + } } diff --git a/src/test/java/org/shedlang/compiler/ast/untyped/UntypedArgsNodeMatcher.java b/src/test/java/org/shedlang/compiler/ast/untyped/UntypedArgsNodeMatcher.java index ce782c0d..da40138d 100644 --- a/src/test/java/org/shedlang/compiler/ast/untyped/UntypedArgsNodeMatcher.java +++ b/src/test/java/org/shedlang/compiler/ast/untyped/UntypedArgsNodeMatcher.java @@ -1,5 +1,6 @@ package org.shedlang.compiler.ast.untyped; +import org.pcollections.Empty; import org.pcollections.PVector; import org.shedlang.compiler.testing.MatcherBuilder; import org.zwobble.precisely.Matcher; @@ -7,8 +8,8 @@ import org.zwobble.precisely.Matcher; import static org.zwobble.precisely.Matchers.has; public class UntypedArgsNodeMatcher extends MatcherBuilder<UntypedArgsNode, UntypedArgsNode, UntypedArgsNodeMatcher> { - public UntypedArgsNodeMatcher() { - super(); + public static UntypedArgsNodeMatcher empty() { + return new UntypedArgsNodeMatcher(Empty.vector()); } public UntypedArgsNodeMatcher(PVector<Matcher<? super UntypedArgsNode>> submatchers) { @@ -22,7 +23,7 @@ public class UntypedArgsNodeMatcher extends MatcherBuilder<UntypedArgsNode, Unty @Override protected UntypedArgsNodeMatcher create(PVector<Matcher<? super UntypedArgsNode>> submatchers) { - return new UntypedArgsNodeMatcher(); + return new UntypedArgsNodeMatcher(submatchers); } public UntypedArgsNodeMatcher withPositional(Matcher<? super Iterable<UntypedExpressionNode>> positional) { diff --git a/src/test/java/org/shedlang/compiler/ast/untyped/UntypedCallNodeMatcher.java b/src/test/java/org/shedlang/compiler/ast/untyped/UntypedCallNodeMatcher.java index b9411fec..aeb020a3 100644 --- a/src/test/java/org/shedlang/compiler/ast/untyped/UntypedCallNodeMatcher.java +++ b/src/test/java/org/shedlang/compiler/ast/untyped/UntypedCallNodeMatcher.java @@ -1,5 +1,6 @@ package org.shedlang.compiler.ast.untyped; +import org.pcollections.Empty; import org.pcollections.PVector; import org.shedlang.compiler.testing.MatcherBuilder; import org.zwobble.precisely.Matcher; @@ -8,8 +9,8 @@ import static org.zwobble.precisely.Matchers.equalTo; import static org.zwobble.precisely.Matchers.has; public class UntypedCallNodeMatcher extends MatcherBuilder<UntypedExpressionNode, UntypedCallNode, UntypedCallNodeMatcher> { - public UntypedCallNodeMatcher() { - super(); + public static UntypedCallNodeMatcher empty() { + return new UntypedCallNodeMatcher(Empty.vector()); } public UntypedCallNodeMatcher(PVector<Matcher<? super UntypedCallNode>> submatchers) { @@ -23,7 +24,7 @@ public class UntypedCallNodeMatcher extends MatcherBuilder<UntypedExpressionNode @Override protected UntypedCallNodeMatcher create(PVector<Matcher<? super UntypedCallNode>> submatchers) { - return new UntypedCallNodeMatcher(); + return new UntypedCallNodeMatcher(submatchers); } public UntypedCallNodeMatcher withArgs(Matcher<UntypedArgsNode> args) { diff --git a/src/test/java/org/shedlang/compiler/ast/untyped/UntypedFunctionDefinitionNodeMatcher.java b/src/test/java/org/shedlang/compiler/ast/untyped/UntypedFunctionDefinitionNodeMatcher.java index e8a227c3..c88111df 100644 --- a/src/test/java/org/shedlang/compiler/ast/untyped/UntypedFunctionDefinitionNodeMatcher.java +++ b/src/test/java/org/shedlang/compiler/ast/untyped/UntypedFunctionDefinitionNodeMatcher.java @@ -1,5 +1,6 @@ package org.shedlang.compiler.ast.untyped; +import org.pcollections.Empty; import org.pcollections.PVector; import org.shedlang.compiler.testing.MatcherBuilder; import org.zwobble.precisely.Matcher; @@ -10,8 +11,8 @@ import static org.zwobble.precisely.Matchers.equalTo; import static org.zwobble.precisely.Matchers.has; public class UntypedFunctionDefinitionNodeMatcher extends MatcherBuilder<UntypedNamespaceStatementNode, UntypedFunctionDefinitionNode, UntypedFunctionDefinitionNodeMatcher> { - public UntypedFunctionDefinitionNodeMatcher() { - super(); + public static UntypedFunctionDefinitionNodeMatcher empty() { + return new UntypedFunctionDefinitionNodeMatcher(Empty.vector()); } public UntypedFunctionDefinitionNodeMatcher(PVector<Matcher<? super UntypedFunctionDefinitionNode>> submatchers) { @@ -25,7 +26,7 @@ public class UntypedFunctionDefinitionNodeMatcher extends MatcherBuilder<Untyped @Override protected UntypedFunctionDefinitionNodeMatcher create(PVector<Matcher<? super UntypedFunctionDefinitionNode>> submatchers) { - return new UntypedFunctionDefinitionNodeMatcher(); + return new UntypedFunctionDefinitionNodeMatcher(submatchers); } public UntypedFunctionDefinitionNodeMatcher withBody(Matcher<Iterable<UntypedFunctionStatementNode>> body) { diff --git a/src/test/java/org/shedlang/compiler/ast/untyped/UntypedNodeMatchers.java b/src/test/java/org/shedlang/compiler/ast/untyped/UntypedNodeMatchers.java index 04c56443..6c06e52a 100644 --- a/src/test/java/org/shedlang/compiler/ast/untyped/UntypedNodeMatchers.java +++ b/src/test/java/org/shedlang/compiler/ast/untyped/UntypedNodeMatchers.java @@ -9,11 +9,11 @@ public class UntypedNodeMatchers { } public static UntypedArgsNodeMatcher isUntypedArgsNode() { - return new UntypedArgsNodeMatcher(); + return UntypedArgsNodeMatcher.empty(); } public static UntypedCallNodeMatcher isUntypedCallNode() { - return new UntypedCallNodeMatcher(); + return UntypedCallNodeMatcher.empty(); } public static Matcher<UntypedFunctionStatementNode> isUntypedExpressionStatementNode( @@ -26,7 +26,7 @@ public class UntypedNodeMatchers { } public static UntypedFunctionDefinitionNodeMatcher isUntypedFunctionDefinitionNode() { - return new UntypedFunctionDefinitionNodeMatcher(); + return UntypedFunctionDefinitionNodeMatcher.empty(); } public static Matcher<UntypedNamedArgNode> isUntypedNamedArgNode( diff --git a/src/test/java/org/shedlang/compiler/testing/MatcherBuilder.java b/src/test/java/org/shedlang/compiler/testing/MatcherBuilder.java index 6736659f..984ba3da 100644 --- a/src/test/java/org/shedlang/compiler/testing/MatcherBuilder.java +++ b/src/test/java/org/shedlang/compiler/testing/MatcherBuilder.java @@ -1,6 +1,5 @@ package org.shedlang.compiler.testing; -import org.pcollections.Empty; import org.pcollections.PVector; import org.zwobble.precisely.MatchResult; import org.zwobble.precisely.Matcher; @@ -11,10 +10,6 @@ import static org.zwobble.precisely.Matchers.instanceOf; public abstract class MatcherBuilder<T, U, This> implements Matcher<T> { private final PVector<Matcher<? super U>> submatchers; - public MatcherBuilder() { - this(Empty.vector()); - } - public MatcherBuilder(PVector<Matcher<? super U>> submatchers) { this.submatchers = submatchers; } diff --git a/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerCallTests.java b/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerCallTests.java new file mode 100644 index 00000000..379368a1 --- /dev/null +++ b/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerCallTests.java @@ -0,0 +1,68 @@ +package org.shedlang.compiler.typechecker; + +import org.junit.jupiter.api.Test; +import org.shedlang.compiler.ast.untyped.Untyped; +import org.shedlang.compiler.types.FunctionType; +import org.shedlang.compiler.types.Types; +import org.shedlang.compiler.util.P; + +import java.util.List; +import java.util.Map; + +import static org.shedlang.compiler.ast.typed.TypedNodeMatchers.*; +import static org.zwobble.precisely.AssertThat.assertThat; +import static org.zwobble.precisely.Matchers.isSequence; + +public class TypeCheckerCallTests { + @Test + public void canCallFunctionWithNoArgs() { + var untyped = Untyped.call( + Untyped.reference("f"), + List.of() + ); + var functionType = FunctionType.builder() + .withReturnType(Types.STRING) + .build(); + var context = TypeCheckerContext.EMPTY + .enter(P.map(Map.entry("f", functionType))); + + var typed = TypeChecker.typeCheckExpression(untyped, context); + + assertThat( + typed, + isTypedCallNode() + .withReceiver(isTypedReferenceNode("f", functionType)) + .withArgs(isTypedArgsNode().withPositional(isSequence()).withNamed(isSequence())) + .withHasEffects(false) + .withType(Types.STRING) + ); + } + + @Test + public void positionalArgsAreTypedChecked() { + var untyped = Untyped.call( + Untyped.reference("f"), + List.of( + Untyped.stringLiteral("hello"), + Untyped.intLiteral(42) + ) + ); + var functionType = FunctionType.builder() + .addPositionalParam(Types.STRING) + .addPositionalParam(Types.INT) + .build(); + var context = TypeCheckerContext.EMPTY + .enter(P.map(Map.entry("f", functionType))); + + var typed = TypeChecker.typeCheckExpression(untyped, context); + + assertThat( + typed, + isTypedCallNode() + .withArgs(isTypedArgsNode().withPositional(isSequence( + isTypedStringLiteralNode("hello"), + isTypedIntLiteralNode(42) + ))) + ); + } +} |
