aboutsummaryrefslogtreecommitdiff
path: root/src/test/java
diff options
context:
space:
mode:
authorMichael Williamson <mike@zwobble.org>2023-10-22 22:23:01 +0100
committerMichael Williamson <mike@zwobble.org>2023-10-22 22:23:01 +0100
commitd1d0984bc8a157a2f001d3c991dae5c9498cd790 (patch)
tree89056dc50059c60c4ce1bf9aa18a8045fb282036 /src/test/java
parentbc94a020433c8b7dc0adaa2a6adf235da9c9b4e9 (diff)
Parse function types
Diffstat (limited to 'src/test/java')
-rw-r--r--src/test/java/org/shedlang/compiler/ast/untyped/UntypedFunctionTypeNodeMatcher.java48
-rw-r--r--src/test/java/org/shedlang/compiler/ast/untyped/UntypedNodeMatchers.java14
-rw-r--r--src/test/java/org/shedlang/compiler/parser/ParserFunctionTypeTests.java168
3 files changed, 230 insertions, 0 deletions
diff --git a/src/test/java/org/shedlang/compiler/ast/untyped/UntypedFunctionTypeNodeMatcher.java b/src/test/java/org/shedlang/compiler/ast/untyped/UntypedFunctionTypeNodeMatcher.java
new file mode 100644
index 00000000..166dd1b0
--- /dev/null
+++ b/src/test/java/org/shedlang/compiler/ast/untyped/UntypedFunctionTypeNodeMatcher.java
@@ -0,0 +1,48 @@
+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;
+
+import java.util.Optional;
+
+import static org.zwobble.precisely.Matchers.has;
+
+public class UntypedFunctionTypeNodeMatcher extends MatcherBuilder<
+ UntypedTypeLevelExpressionNode,
+ UntypedFunctionTypeNode,
+ UntypedFunctionTypeNodeMatcher
+> {
+ public static UntypedFunctionTypeNodeMatcher empty() {
+ return new UntypedFunctionTypeNodeMatcher(Empty.vector());
+ }
+
+ public UntypedFunctionTypeNodeMatcher(PVector<Matcher<? super UntypedFunctionTypeNode>> submatchers) {
+ super(submatchers);
+ }
+
+ @Override
+ protected Class<UntypedFunctionTypeNode> expectedType() {
+ return UntypedFunctionTypeNode.class;
+ }
+
+ @Override
+ protected UntypedFunctionTypeNodeMatcher create(
+ PVector<Matcher<? super UntypedFunctionTypeNode>> submatchers
+ ) {
+ return new UntypedFunctionTypeNodeMatcher(submatchers);
+ }
+
+ public UntypedFunctionTypeNodeMatcher withEffect(Matcher<Optional<? extends UntypedTypeLevelExpressionNode>> effect) {
+ return with(has("effect", x -> x.effect(), effect));
+ }
+
+ public UntypedFunctionTypeNodeMatcher withParams(Matcher<UntypedParamTypesNode> params) {
+ return with(has("params", x -> x.params(), params));
+ }
+
+ public UntypedFunctionTypeNodeMatcher withReturnType(Matcher<UntypedTypeLevelExpressionNode> returnType) {
+ return with(has("returnType", x -> x.returnType(), returnType));
+ }
+}
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 35e8247a..f45adba9 100644
--- a/src/test/java/org/shedlang/compiler/ast/untyped/UntypedNodeMatchers.java
+++ b/src/test/java/org/shedlang/compiler/ast/untyped/UntypedNodeMatchers.java
@@ -123,6 +123,10 @@ public class UntypedNodeMatchers {
);
}
+ public static UntypedFunctionTypeNodeMatcher isUntypedFunctionTypeNode() {
+ return UntypedFunctionTypeNodeMatcher.empty();
+ }
+
public static Matcher<UntypedExpressionNode> isUntypedIfNode(
Matcher<Iterable<? extends UntypedConditionalBranchNode>> conditionalBranches,
Matcher<UntypedBlockNode> elseBody
@@ -188,6 +192,16 @@ public class UntypedNodeMatchers {
);
}
+ public static Matcher<UntypedParamTypesNode> isUntypedParamTypesNode(
+ Matcher<Iterable<? extends UntypedTypeLevelExpressionNode>> positional,
+ Matcher<Iterable<? extends UntypedParamNode>> named
+ ) {
+ return allOf(
+ has("positional", x -> x.positional(), positional),
+ has("named", x -> x.named(), named)
+ );
+ }
+
public static Matcher<UntypedExpressionNode> isUntypedReferenceNode(String name) {
return instanceOf(
UntypedReferenceNode.class,
diff --git a/src/test/java/org/shedlang/compiler/parser/ParserFunctionTypeTests.java b/src/test/java/org/shedlang/compiler/parser/ParserFunctionTypeTests.java
new file mode 100644
index 00000000..467930a3
--- /dev/null
+++ b/src/test/java/org/shedlang/compiler/parser/ParserFunctionTypeTests.java
@@ -0,0 +1,168 @@
+package org.shedlang.compiler.parser;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.shedlang.compiler.ast.untyped.UntypedNodeMatchers.*;
+import static org.shedlang.compiler.parser.ParserTesting.parseString;
+import static org.zwobble.precisely.AssertThat.assertThat;
+import static org.zwobble.precisely.Matchers.*;
+
+public class ParserFunctionTypeTests {
+ @Test
+ public void canParseFunctionTypeWithNoParamsAndNoEffect() {
+ var source = "fn () -> Unit";
+
+ var node = parseString(source, Parser::parseTopLevelTypeLevelExpression);
+
+ assertThat(
+ node,
+ isUntypedFunctionTypeNode()
+ .withParams(isUntypedParamTypesNode(
+ isSequence(),
+ isSequence()
+ ))
+ .withEffect(isOptionalEmpty())
+ .withReturnType(isUntypedTypeLevelReferenceNode("Unit"))
+ );
+ }
+
+ @Test
+ public void canParseFunctionWithSinglePositionalParam() {
+ var source = "fn (Int) -> Unit";
+
+ var node = parseString(source, Parser::parseTopLevelTypeLevelExpression);
+
+ assertThat(
+ node,
+ isUntypedFunctionTypeNode()
+ .withParams(isUntypedParamTypesNode(
+ isSequence(
+ isUntypedTypeLevelReferenceNode("Int")
+ ),
+ isSequence()
+ ))
+ );
+ }
+
+ @Test
+ public void canParseFunctionWithManyPositionalParams() {
+ var source = "fn (Int, String, Bool) -> Unit";
+
+ var node = parseString(source, Parser::parseTopLevelTypeLevelExpression);
+
+ assertThat(
+ node,
+ isUntypedFunctionTypeNode()
+ .withParams(isUntypedParamTypesNode(
+ isSequence(
+ isUntypedTypeLevelReferenceNode("Int"),
+ isUntypedTypeLevelReferenceNode("String"),
+ isUntypedTypeLevelReferenceNode("Bool")
+ ),
+ isSequence()
+ ))
+ );
+ }
+
+ @Test
+ public void canParseFunctionWithSingleNamedParam() {
+ var source = "fn (.a: Int) -> Unit";
+
+ var node = parseString(source, Parser::parseTopLevelTypeLevelExpression);
+
+ assertThat(
+ node,
+ isUntypedFunctionTypeNode()
+ .withParams(isUntypedParamTypesNode(
+ isSequence(),
+ isSequence(
+ isUntypedParamNode("a", isUntypedTypeLevelReferenceNode("Int"))
+ )
+ ))
+ );
+ }
+
+ @Test
+ public void canParseFunctionWithManyNamedParams() {
+ var source = "fn (.a: Int, .b: String, .c: Bool) -> Unit";
+
+ var node = parseString(source, Parser::parseTopLevelTypeLevelExpression);
+
+ assertThat(
+ node,
+ isUntypedFunctionTypeNode()
+ .withParams(isUntypedParamTypesNode(
+ isSequence(),
+ isSequence(
+ isUntypedParamNode("a", isUntypedTypeLevelReferenceNode("Int")),
+ isUntypedParamNode("b", isUntypedTypeLevelReferenceNode("String")),
+ isUntypedParamNode("c", isUntypedTypeLevelReferenceNode("Bool"))
+ )
+ ))
+ );
+ }
+
+ @Test
+ public void canParseNamedParamAfterPositionalParam() {
+ var source = "fn (Int, .b: String) -> Unit";
+
+ var node = parseString(source, Parser::parseTopLevelTypeLevelExpression);
+
+ assertThat(
+ node,
+ isUntypedFunctionTypeNode()
+ .withParams(isUntypedParamTypesNode(
+ isSequence(
+ isUntypedTypeLevelReferenceNode("Int")
+ ),
+ isSequence(
+ isUntypedParamNode("b", isUntypedTypeLevelReferenceNode("String"))
+ )
+ ))
+ );
+ }
+
+ @Test
+ public void cannotParsePositionalParamAfterNamedParam() {
+ var source = "fn (.a: Int, String) -> Unit";
+
+ assertThrows(
+ PositionalParamAfterNamedParamError.class,
+ () -> parseString(source, Parser::parseTopLevelTypeLevelExpression)
+ );
+ }
+
+ @Test
+ public void paramsCanHaveTrailingComma() {
+ var source = """
+ fun f(a: Int, ) -> Unit {
+ }""";
+
+ var node = parseString(source, Parser::parseNamespaceStatement);
+
+ assertThat(
+ node,
+ isUntypedFunctionDefinitionNode()
+ .withParams(isUntypedParamsNode(
+ isSequence(
+ isUntypedParamNode("a", isUntypedTypeLevelReferenceNode("Int"))
+ ),
+ isSequence()
+ ))
+ );
+ }
+
+ @Test
+ public void canParseFunctionTypeWithEffect() {
+ var source = "fn () ! Io -> Unit";
+
+ var node = parseString(source, Parser::parseTopLevelTypeLevelExpression);
+
+ assertThat(
+ node,
+ isUntypedFunctionTypeNode()
+ .withEffect(isOptionalOf(isUntypedTypeLevelReferenceNode("Io")))
+ );
+ }
+}