package scotch.compiler.parser;
import static java.util.Arrays.asList;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
import static scotch.compiler.parser.Tree.leaf;
import static scotch.compiler.parser.Tree.node;
import static scotch.compiler.parser.Tree.tree;
import org.junit.Test;
public class ScotchParserTest extends ScotchParserBaseTest {
@Test
public void shouldParseDottedName() {
assertThat(parse(ScotchParser::qualifiedName, "scotch.test.name"), is(
tree("qualifiedName", asList(
node("moduleName", asList(
node("idVar", asList(leaf("scotch"))),
leaf("."),
node("idVar", asList(leaf("test"))))),
leaf("."),
node("name", asList(
node("idVar", asList(leaf("name")))))))));
}
@Test
public void shouldParseDottedNameWithOperator() {
assertThat(parse(ScotchParser::qualifiedName, "scotch.test.(+)"), is(
tree("qualifiedName", asList(
node("moduleName", asList(
node("idVar", asList(leaf("scotch"))),
leaf("."),
node("idVar", asList(leaf("test"))))),
leaf("."),
node("name", asList(
node("operatorName", asList(
leaf("("),
leaf("+"),
leaf(")")))))))));
}
@Test
public void shouldParseDestructuringPatternArgument() {
assertThat(parse(ScotchParser::patternArgument, "Toast { burnLevel = 4, kind = _ }"), is(
tree("patternArgument", asList(
node("destructuringArgument", asList(
node("idType", asList(leaf("Toast"))),
leaf("{"),
node("destructuringFields", asList(
node("destructuringField", asList(
leaf("burnLevel"),
leaf("="),
node("unshuffledArgument", asList(
node("patternArgument", asList(
node("literalArgument", asList(
node("literal", asList(
leaf("4"))))))))))),
leaf(","),
node("destructuringField", asList(
leaf("kind"),
leaf("="),
node("unshuffledArgument", asList(
node("patternArgument", asList(
node("ignoreArgument", asList(
leaf("_"))))))))))),
leaf("}")))))));
}
@Test
public void shouldParseTuplePatternArgument() {
assertThat(parse(ScotchParser::patternArgument, "(1, 2)"), is(
tree("patternArgument", asList(
node("tupleArgument", asList(
leaf("("),
node("tupleArgumentFields", asList(
node("unshuffledArgument", asList(
node("patternArgument", asList(
node("literalArgument", asList(
node("literal", asList(
leaf("1"))))))))),
leaf(","),
node("unshuffledArgument", asList(
node("patternArgument", asList(
node("literalArgument", asList(
node("literal", asList(
leaf("2"))))))))))),
leaf(")")))))));
}
@Test
public void shouldParseUnshuffledPatternArgument() {
assertThat(parse(ScotchParser::patternArgument, "(Map a b)"), is(
tree("patternArgument", asList(
node("parenthesizedArgument", asList(
leaf("("),
node("unshuffledArgument", asList(
node("patternArgument", asList(
node("typeArgument", asList(
node("qualifiedType", asList(
node("idType", asList(leaf("Map"))))))))),
node("patternArgument", asList(
node("captureArgument", asList(
node("idVar", asList(leaf("a"))))))),
node("patternArgument", asList(
node("captureArgument", asList(
node("idVar", asList(leaf("b"))))))))),
leaf(")")))))));
}
@Test
public void shouldDestructureAndCaptureArgument() {
assertThat(parse(ScotchParser::patternArgument, "Toast { burnLevel = 4, kind = _ } as toast"), is(
tree("patternArgument", asList(
node("destructuringArgument", asList(
node("idType", asList(leaf("Toast"))),
leaf("{"),
node("destructuringFields", asList(
node("destructuringField", asList(
leaf("burnLevel"),
leaf("="),
node("unshuffledArgument", asList(
node("patternArgument", asList(
node("literalArgument", asList(
node("literal", asList(
leaf("4"))))))))))),
leaf(","),
node("destructuringField", asList(
leaf("kind"),
leaf("="),
node("unshuffledArgument", asList(
node("patternArgument", asList(
node("ignoreArgument", asList(
leaf("_"))))))))))),
leaf("}"))),
node("asCapture", asList(
leaf("as"),
node("idVar", asList(leaf("toast")))))))));
}
@Test
public void shouldParseInitializer() {
assertThat(parse(ScotchParser::expression, "Node { left = Left, right = Right }"), is(
tree("expression", asList(
node("primaryExpression", asList(
node("reference", asList(
node("qualifiedType", asList(
node("idType", asList(leaf("Node"))))),
node("structFields", asList(
leaf("{"),
node("structField", asList(
node("idVar", asList(leaf("left"))),
leaf("="),
node("expression", asList(
node("primaryExpression", asList(
node("reference", asList(
node("qualifiedType", asList(
node("idType", asList(leaf("Left"))))))))))))),
leaf(","),
node("structField", asList(
node("idVar", asList(leaf("right"))),
leaf("="),
node("expression", asList(
node("primaryExpression", asList(
node("reference", asList(
node("qualifiedType", asList(
node("idType", asList(leaf("Right"))))))))))))),
leaf("}"))))))),
leaf(";")))));
}
@Test
public void shouldParsePartialOperator() {
assertThat(parse(ScotchParser::expression, "(+2)"), is(
tree("expression", asList(
node("primaryExpression", asList(
node("partialOperator", asList(
leaf("("),
leaf("+"),
node("primaryExpression", asList(
node("literal", asList(
leaf("2"))))),
leaf(")"))))),
leaf(";")))));
}
@Test
public void shouldParseModules() {
String result = parse(ScotchParser::modules,
"module a.b.c",
"x = y",
"module x.y.z",
"a = b"
);
assertThat(result, is(
tree("modules", asList(
node("module", asList(
leaf("module"),
node("moduleName", asList(
node("idVar", asList(leaf("a"))),
leaf("."),
node("idVar", asList(leaf("b"))),
leaf("."),
node("idVar", asList(leaf("c"))))),
leaf(";"),
node("moduleMembers", asList(
node("moduleMember", asList(
node("pattern", asList(
node("patternArguments", asList(
node("patternArgument", asList(
node("captureArgument", asList(
node("idVar", asList(leaf("x"))))))))),
leaf("="),
node("patternBody", asList(
node("expression", asList(
node("primaryExpression", asList(
node("reference", asList(
node("qualifiedName", asList(
node("name", asList(
node("idVar", asList(leaf("y"))))))))))))))))))),
leaf(";"))))),
node("module", asList(
leaf("module"),
node("moduleName", asList(
node("idVar", asList(leaf("x"))),
leaf("."),
node("idVar", asList(leaf("y"))),
leaf("."),
node("idVar", asList(leaf("z"))))),
leaf(";"),
node("moduleMembers", asList(
node("moduleMember", asList(
node("pattern", asList(
node("patternArguments", asList(
node("patternArgument", asList(
node("captureArgument", asList(
node("idVar", asList(leaf("a"))))))))),
leaf("="),
node("patternBody", asList(
node("expression", asList(
node("primaryExpression", asList(
node("reference", asList(
node("qualifiedName", asList(
node("name", asList(
node("idVar", asList(leaf("b"))))))))))))))))))),
leaf(";"))))),
leaf("<EOF>")))));
}
@Test
public void shouldParseModuleImports() {
String result = parse(ScotchParser::module,
"module a.b.c",
"import x.y.z"
);
assertThat(result, is(
tree("module", asList(
leaf("module"),
node("moduleName", asList(
node("idVar", asList(leaf("a"))),
leaf("."),
node("idVar", asList(leaf("b"))),
leaf("."),
node("idVar", asList(leaf("c"))))),
leaf(";"),
node("moduleImports", asList(
node("moduleImport", asList(
leaf("import"),
node("moduleName", asList(
node("idVar", asList(leaf("x"))),
leaf("."),
node("idVar", asList(leaf("y"))),
leaf("."),
node("idVar", asList(leaf("z"))))))),
leaf(";")))))));
}
@Test
public void shouldParseFunctionSignature() {
String result = parse(ScotchParser::moduleMember, "(+) :: a -> a -> a");
assertThat(result, is(
tree("moduleMember", asList(
node("patternSignature", asList(
node("patternNames", asList(
node("name", asList(
node("operatorName", asList(
leaf("("),
leaf("+"),
leaf(")"))))))),
leaf("::"),
node("typeSignature", asList(
node("primarySignature", asList(
node("typeVariable", asList(
node("idVar", asList(leaf("a"))))))),
leaf("->"),
node("typeSignature", asList(
node("primarySignature", asList(
node("typeVariable", asList(
node("idVar", asList(leaf("a"))))))),
leaf("->"),
node("typeSignature", asList(
node("primarySignature", asList(
node("typeVariable", asList(
node("idVar", asList(leaf("a"))))),
leaf(";")))))))))))))));
}
@Test
public void shouldParseSumSignature() {
String result = parse(ScotchParser::moduleMember, "thing :: Node a b -> c");
assertThat(result, is(
tree("moduleMember", asList(
node("patternSignature", asList(
node("patternNames", asList(
node("name", asList(
node("idVar", asList(
leaf("thing"))))))),
leaf("::"),
node("typeSignature", asList(
node("primarySignature", asList(
node("qualifiedType", asList(
node("idType", asList(leaf("Node"))))),
node("typeParameter", asList(
node("typeVariable", asList(
node("idVar", asList(leaf("a"))))))),
node("typeParameter", asList(
node("typeVariable", asList(
node("idVar", asList(leaf("b"))))))))),
leaf("->"),
node("typeSignature", asList(
node("primarySignature", asList(
node("typeVariable", asList(
node("idVar", asList(leaf("c"))))),
leaf(";")))))))))))));
}
@Test
public void shouldParseParenthesizedSignature() {
String result = parse(ScotchParser::moduleMember, "thing :: (a -> b) -> c");
assertThat(result, is(
tree("moduleMember", asList(
node("patternSignature", asList(
node("patternNames", asList(
node("name", asList(
node("idVar", asList(leaf("thing"))))))),
leaf("::"),
node("typeSignature", asList(
node("primarySignature", asList(
node("parenthesizedTypeSignature", asList(
leaf("("),
node("typeSignature", asList(
node("primarySignature", asList(
node("typeVariable", asList(
node("idVar", asList(leaf("a"))))))),
leaf("->"),
node("typeSignature", asList(
node("primarySignature", asList(
node("typeVariable", asList(
node("idVar", asList(leaf("b"))))))))))),
leaf(")"))))),
leaf("->"),
node("typeSignature", asList(
node("primarySignature", asList(
node("typeVariable", asList(
node("idVar", asList(leaf("c"))))),
leaf(";")))))))))))));
}
@Test
public void shouldParseMultiNameSignature() {
String result = parse(ScotchParser::moduleMember, "one, two, (+) :: b");
assertThat(result, is(
tree("moduleMember", asList(
node("patternSignature", asList(
node("patternNames", asList(
node("name", asList(
node("idVar", asList(leaf("one"))))),
leaf(","),
node("name", asList(
node("idVar", asList(leaf("two"))))),
leaf(","),
node("name", asList(
node("operatorName", asList(
leaf("("),
leaf("+"),
leaf(")"))))))),
leaf("::"),
node("typeSignature", asList(
node("primarySignature", asList(
node("typeVariable", asList(
node("idVar", asList(leaf("b"))))),
leaf(";")))))))))));
}
@Test
public void shouldParseLeftInfixOperator() {
String result = parse(ScotchParser::moduleMember, "left infix 0 (|>)");
assertThat(result, is(
tree("moduleMember", asList(
node("operatorDefinition", asList(
node("fixity", asList(
leaf("left"),
leaf("infix"))),
leaf("0"),
node("operatorNames", asList(
node("operatorName", asList(
leaf("("),
leaf("|>"),
leaf(")"))),
leaf(";")))))))));
}
@Test
public void shouldParseRightInfixOperator() {
String result = parse(ScotchParser::moduleMember, "right infix 0 ($)");
assertThat(result, is(
tree("moduleMember", asList(
node("operatorDefinition", asList(
node("fixity", asList(
leaf("right"),
leaf("infix"))),
leaf("0"),
node("operatorNames", asList(
node("operatorName", asList(
leaf("("),
leaf("$"),
leaf(")"))),
leaf(";")))))))));
}
@Test
public void shouldParsePrefixOperator() {
String result = parse(ScotchParser::moduleMember, "prefix 9 (!)");
assertThat(result, is(
tree("moduleMember", asList(
node("operatorDefinition", asList(
node("fixity", asList(
leaf("prefix")
)),
leaf("9"),
node("operatorNames", asList(
node("operatorName", asList(
leaf("("),
leaf("!"),
leaf(")"))),
leaf(";")))))))));
}
@Test
public void shouldParseOperatorList() {
String result = parse(ScotchParser::moduleMember, "left infix 6 (+), (-)");
assertThat(result, is(
tree("moduleMember", asList(
node("operatorDefinition", asList(
node("fixity", asList(
leaf("left"),
leaf("infix"))),
leaf("6"),
node("operatorNames", asList(
node("operatorName", asList(
leaf("("),
leaf("+"),
leaf(")"))),
leaf(","),
node("operatorName", asList(
leaf("("),
leaf("-"),
leaf(")"))),
leaf(";")))))))));
}
@Test
public void shouldParseDefaultOperator() {
String result = parse(ScotchParser::moduleMember, "left infix 7 `mod`");
assertThat(result, is(
tree("moduleMember", asList(
node("operatorDefinition", asList(
node("fixity", asList(
leaf("left"),
leaf("infix"))),
leaf("7"),
node("operatorNames", asList(
node("operatorName", asList(
leaf("`"),
node("idVar", asList(leaf("mod"))),
leaf("`"))),
leaf(";")))))))));
}
@Test
public void shouldParseExpression() {
String result = parse(ScotchParser::expression, "2 + 2");
assertThat(result, is(
tree("expression", asList(
node("primaryExpression", asList(
node("literal", asList(leaf("2"))))),
node("primaryExpression", asList(
node("reference", asList(
node("operatorReference", asList(
leaf("+"))))))),
node("primaryExpression", asList(
node("literal", asList(
leaf("2"))))),
leaf(";")))));
}
@Test
public void shouldParseParenthesizedExpression() {
String result = parse(ScotchParser::expression, "(2 + 2) * 2");
assertThat(result, is(
tree("expression", asList(
node("primaryExpression", asList(
node("parenthesizedExpression", asList(
leaf("("),
node("expression", asList(
node("primaryExpression", asList(
node("literal", asList(
leaf("2"))))),
node("primaryExpression", asList(
node("reference", asList(
node("operatorReference", asList(
leaf("+"))))))),
node("primaryExpression", asList(
node("literal", asList(
leaf("2"))))))),
leaf(")"))))),
node("primaryExpression", asList(
node("reference", asList(
node("operatorReference", asList(
leaf("*"))))))),
node("primaryExpression", asList(
node("literal", asList(
leaf("2"))))),
leaf(";")))));
}
@Test
public void shouldParseTypeSignatureWithSingleContextParameter() {
String result = parse(ScotchParser::moduleMember, "(+) :: Num a => a -> a -> a");
assertThat(result, is(
tree("moduleMember", asList(
node("patternSignature", asList(
node("patternNames", asList(
node("name", asList(
node("operatorName", asList(
leaf("("),
leaf("+"),
leaf(")"))))))),
leaf("::"),
node("typeContext", asList(
node("contextParameter", asList(
node("qualifiedType", asList(
node("idType", asList(leaf("Num"))))),
node("idVar", asList(leaf("a"))))),
leaf("=>"))),
node("typeSignature", asList(
node("primarySignature", asList(
node("typeVariable", asList(
node("idVar", asList(leaf("a"))))))),
leaf("->"),
node("typeSignature", asList(
node("primarySignature", asList(
node("typeVariable", asList(
node("idVar", asList(leaf("a"))))))),
leaf("->"),
node("typeSignature", asList(
node("primarySignature", asList(
node("typeVariable", asList(
node("idVar", asList(leaf("a"))))),
leaf(";")))))))))))))));
}
@Test
public void shouldParseTypeWithMultipleContextParameters() {
String result = parse(ScotchParser::moduleMember, "convert :: (Num a, Num b) => a -> b");
assertThat(result, is(
tree("moduleMember", asList(
node("patternSignature", asList(
node("patternNames", asList(
node("name", asList(
node("idVar", asList(leaf("convert"))))))),
leaf("::"),
node("typeContext", asList(
leaf("("),
node("contextParameters", asList(
node("contextParameter", asList(
node("qualifiedType", asList(
node("idType", asList(leaf("Num"))))),
node("idVar", asList(leaf("a"))))),
leaf(","),
node("contextParameter", asList(
node("qualifiedType", asList(
node("idType", asList(leaf("Num"))))),
node("idVar", asList(leaf("b"))))))),
leaf(")"),
leaf("=>"))),
node("typeSignature", asList(
node("primarySignature", asList(
node("typeVariable", asList(
node("idVar", asList(leaf("a"))))))),
leaf("->"),
node("typeSignature", asList(
node("primarySignature", asList(
node("typeVariable", asList(
node("idVar", asList(leaf("b"))))),
leaf(";")))))))))))));
}
@Test
public void shouldParseFunctionLiteral() {
String result = parse(ScotchParser::expression, "\\x -> x");
assertThat(result, is(
tree("expression", asList(
node("primaryExpression", asList(
node("functionLiteral", asList(
leaf("\\"),
node("patternArguments", asList(
node("patternArgument", asList(
node("captureArgument", asList(
node("idVar", asList(leaf("x"))))))))),
leaf("->"),
node("expression", asList(
node("primaryExpression", asList(
node("reference", asList(
node("qualifiedName", asList(
node("name", asList(
node("idVar", asList(leaf("x"))))))))))),
leaf(";")))))))))));
}
@Test
public void shouldParseFunctionLiteralWithMultipleArguments() {
String result = parse(ScotchParser::expression, "\\x y -> x");
assertThat(result, is(
tree("expression", asList(
node("primaryExpression", asList(
node("functionLiteral", asList(
leaf("\\"),
node("patternArguments", asList(
node("patternArgument", asList(
node("captureArgument", asList(
node("idVar", asList(leaf("x"))))))),
node("patternArgument", asList(
node("captureArgument", asList(
node("idVar", asList(leaf("y"))))))))),
leaf("->"),
node("expression", asList(
node("primaryExpression", asList(
node("reference", asList(
node("qualifiedName", asList(
node("name", asList(
node("idVar", asList(leaf("x"))))))))))),
leaf(";")))))))))));
}
@Test
public void shouldParseConditional() {
String result = parse(ScotchParser::expression, "if True then \"a\" else \"b\"");
assertThat(result, is(
tree("expression", asList(
node("primaryExpression", asList(
node("conditional", asList(
leaf("if"),
node("expression", asList(
node("primaryExpression", asList(
node("literal", asList(leaf("True"))))))),
leaf("then"),
node("expression", asList(
node("primaryExpression", asList(
node("literal", asList(
leaf("\"a\""))))))),
leaf("else"),
node("expression", asList(
node("primaryExpression", asList(
node("literal", asList(
leaf("\"b\""))))),
leaf(";")))))))))));
}
@Test
public void shouldParseGuardCase() {
String result = parse(ScotchParser::pattern,
"guardCase z | a = b",
" | x = y"
);
assertThat(result, is(
tree("pattern", asList(
node("patternArguments", asList(
node("patternArgument", asList(
node("captureArgument", asList(
node("idVar", asList(leaf("guardCase"))))))),
node("patternArgument", asList(
node("captureArgument", asList(
node("idVar", asList(leaf("z"))))))))),
node("guardCases", asList(
node("guardCase", asList(
leaf("|"),
node("expression", asList(
node("primaryExpression", asList(
node("reference", asList(
node("qualifiedName", asList(
node("name", asList(
node("idVar", asList(leaf("a"))))))))))))),
leaf("="),
node("patternBody", asList(
node("expression", asList(
node("primaryExpression", asList(
node("reference", asList(
node("qualifiedName", asList(
node("name", asList(
node("idVar", asList(leaf("b"))))))))))))))))),
node("guardCase", asList(
leaf("|"),
node("expression", asList(
node("primaryExpression", asList(
node("reference", asList(
node("qualifiedName", asList(
node("name", asList(
node("idVar", asList(leaf("x"))))))))))))),
leaf("="),
node("patternBody", asList(
node("expression", asList(
node("primaryExpression", asList(
node("reference", asList(
node("qualifiedName", asList(
node("name", asList(
node("idVar", asList(leaf("y"))))))))))),
leaf(";")))))))))))));
}
@Test
public void shouldParseListInTypeSignature() {
String result = parse(ScotchParser::typeSignature, "[a] -> a");
assertThat(result, is(
tree("typeSignature", asList(
node("primarySignature", asList(
node("listSignature", asList(
leaf("["),
node("typeSignature", asList(
node("primarySignature", asList(
node("typeVariable", asList(
node("idVar", asList(leaf("a"))))))))),
leaf("]"))))),
leaf("->"),
node("typeSignature", asList(
node("primarySignature", asList(
node("typeVariable", asList(
node("idVar", asList(leaf("a"))))),
leaf(";")))))))));
}
@Test
public void shouldParseListLiteral() {
String result = parse(ScotchParser::expression, "[1, 2, 3]");
assertThat(result, is(
tree("expression", asList(
node("primaryExpression", asList(
node("listLiteral", asList(
leaf("["),
node("listElements", asList(
node("expression", asList(
node("primaryExpression", asList(
node("literal", asList(
leaf("1"))))))),
leaf(","),
node("expression", asList(
node("primaryExpression", asList(
node("literal", asList(
leaf("2"))))))),
leaf(","),
node("expression", asList(
node("primaryExpression", asList(
node("literal", asList(
leaf("3"))))))))),
leaf("]"))))),
leaf(";")))));
}
@Test
public void shouldParseTupleInTypeSignature() {
String result = parse(ScotchParser::typeSignature, "(a, b) -> a");
assertThat(result, is(
tree("typeSignature", asList(
node("primarySignature", asList(
node("tupleSignature", asList(
leaf("("),
node("tupleSignatureElements", asList(
node("tupleSignatureElement", asList(
node("typeSignature", asList(
node("primarySignature", asList(
node("typeVariable", asList(
node("idVar", asList(leaf("a"))))))))))),
leaf(","),
node("tupleSignatureElement", asList(
node("typeSignature", asList(
node("primarySignature", asList(
node("typeVariable", asList(
node("idVar", asList(leaf("b"))))))))))))),
leaf(")"))))),
leaf("->"),
node("typeSignature", asList(
node("primarySignature", asList(
node("typeVariable", asList(
node("idVar", asList(leaf("a"))))),
leaf(";")))))))));
}
@Test
public void shouldParseTupleLiteral() {
String result = parse(ScotchParser::expression, "(1, 2, 3)");
assertThat(result, is(
tree("expression", asList(
node("primaryExpression", asList(
node("tupleLiteral", asList(
leaf("("),
node("tupleElements", asList(
node("tupleElement", asList(
node("expression", asList(
node("primaryExpression", asList(
node("literal", asList(leaf("1"))))))))),
leaf(","),
node("tupleElement", asList(
node("expression", asList(
node("primaryExpression", asList(
node("literal", asList(leaf("2"))))))))),
leaf(","),
node("tupleElement", asList(
node("expression", asList(
node("primaryExpression", asList(
node("literal", asList(leaf("3"))))))))))),
leaf(")"))))),
leaf(";")))));
}
@Test
public void shouldParseListPatternArgument() {
String result = parse(ScotchParser::patternArgument, "[a, b]");
assertThat(result, is(
tree("patternArgument", asList(
node("listArgument", asList(
leaf("["),
node("listArgumentElements", asList(
node("listArgumentElement", asList(
node("patternArgument", asList(
node("captureArgument", asList(
node("idVar", asList(leaf("a"))))))))),
leaf(","),
node("listArgumentElement", asList(
node("patternArgument", asList(
node("captureArgument", asList(
node("idVar", asList(leaf("b"))))))))))),
leaf("]")))))));
}
@Test
public void shouldParseClassDefinition() {
String result = parse(ScotchParser::moduleMember,
"class Eq a where",
" a :: b",
" a = b"
);
assertThat(result, is(
tree("moduleMember", asList(
node("classDefinition", asList(
leaf("class"),
node("idType", asList(leaf("Eq"))),
node("classParameters", asList(
node("classParameter", asList(
node("idVar", asList(leaf("a"))))))),
leaf("where"),
leaf("{"),
node("classMembers", asList(
node("classMember", asList(
node("patternSignature", asList(
node("patternNames", asList(
node("name", asList(
node("idVar", asList(leaf("a"))))))),
leaf("::"),
node("typeSignature", asList(
node("primarySignature", asList(
node("typeVariable", asList(
node("idVar", asList(leaf("b"))))))))))))),
leaf(";"),
node("classMember", asList(
node("pattern", asList(
node("patternArguments", asList(
node("patternArgument", asList(
node("captureArgument", asList(
node("idVar", asList(leaf("a"))))))))),
leaf("="),
node("patternBody", asList(
node("expression", asList(
node("primaryExpression", asList(
node("reference", asList(
node("qualifiedName", asList(
node("name", asList(
node("idVar", asList(leaf("b"))))))))))))))))))),
leaf(";"),
leaf(";"))),
leaf("}")))))));
}
@Test
public void shouldParseClassDefinitionWithContext() {
String result = parse(ScotchParser::moduleMember,
"class Eq a => Ord a where",
" a :: b"
);
assertThat(result, is(
tree("moduleMember", asList(
node("classDefinition", asList(
leaf("class"),
node("typeContext", asList(
node("contextParameter", asList(
node("qualifiedType", asList(
node("idType", asList(leaf("Eq"))))),
node("idVar", asList(leaf("a"))))),
leaf("=>"))),
node("idType", asList(leaf("Ord"))),
node("classParameters", asList(
node("classParameter", asList(
node("idVar", asList(leaf("a"))))))),
leaf("where"),
leaf("{"),
node("classMembers", asList(
node("classMember", asList(
node("patternSignature", asList(
node("patternNames", asList(
node("name", asList(
node("idVar", asList(leaf("a"))))))),
leaf("::"),
node("typeSignature", asList(
node("primarySignature", asList(
node("typeVariable", asList(
node("idVar", asList(leaf("b"))))))))))))),
leaf(";"),
leaf(";"))),
leaf("}")))))));
}
@Test
public void shouldParseInstanceDefinition() {
String result = parse(ScotchParser::moduleMember,
"instance Eq Int where",
" a = b"
);
assertThat(result, is(
tree("moduleMember", asList(
node("instanceDefinition", asList(
leaf("instance"),
node("idType", asList(leaf("Eq"))),
node("instanceParameters", asList(
node("instanceParameter", asList(
node("qualifiedType", asList(
node("idType", asList(leaf("Int"))))))))),
leaf("where"),
leaf("{"),
node("instanceMembers", asList(
node("instanceMember", asList(
node("pattern", asList(
node("patternArguments", asList(
node("patternArgument", asList(
node("captureArgument", asList(
node("idVar", asList(leaf("a"))))))))),
leaf("="),
node("patternBody", asList(
node("expression", asList(
node("primaryExpression", asList(
node("reference", asList(
node("qualifiedName", asList(
node("name", asList(
node("idVar", asList(leaf("b"))))))))))))))))))),
leaf(";"),
leaf(";"))),
leaf("}")))))));
}
@Test
public void shouldParseInstanceDefinitionWithTypeContext() {
String result = parse(ScotchParser::moduleMember,
"instance Eq a => Eq [a] where",
" a = b"
);
assertThat(result, is(
tree("moduleMember", asList(
node("instanceDefinition", asList(
leaf("instance"),
node("typeContext", asList(
node("contextParameter", asList(
node("qualifiedType", asList(
node("idType", asList(leaf("Eq"))))),
node("idVar", asList(leaf("a"))))),
leaf("=>"))),
node("idType", asList(leaf("Eq"))),
node("instanceParameters", asList(
node("instanceParameter", asList(
node("listParameter", asList(
leaf("["),
node("typeSignature", asList(
node("primarySignature", asList(
node("typeVariable", asList(
node("idVar", asList(leaf("a"))))))))),
leaf("]"))))))),
leaf("where"),
leaf("{"),
node("instanceMembers", asList(
node("instanceMember", asList(
node("pattern", asList(
node("patternArguments", asList(
node("patternArgument", asList(
node("captureArgument", asList(
node("idVar", asList(leaf("a"))))))))),
leaf("="),
node("patternBody", asList(
node("expression", asList(
node("primaryExpression", asList(
node("reference", asList(
node("qualifiedName", asList(
node("name", asList(
node("idVar", asList(leaf("b"))))))))))))))))))),
leaf(";"),
leaf(";"))),
leaf("}")))))));
}
@Test
public void shouldParseParenthesizedInstanceParameterWithTypeSum() {
assertThat(parse(ScotchParser::instanceParameter, "(Map a b)"), is(
tree("instanceParameter", asList(
node("parenthesizedParameter", asList(
leaf("("),
node("typeSignature", asList(
node("primarySignature", asList(
node("qualifiedType", asList(
node("idType", asList(leaf("Map"))))),
node("typeParameter", asList(
node("typeVariable", asList(
node("idVar", asList(leaf("a"))))))),
node("typeParameter", asList(
node("typeVariable", asList(
node("idVar", asList(leaf("b"))))))))))),
leaf(")")))))));
}
@Test
public void shouldParseTupleInstanceParameter() {
assertThat(parse(ScotchParser::instanceParameter, "(a, b)"), is(
tree("instanceParameter", asList(
node("tupleParameter", asList(
leaf("("),
node("tupleParameterElements", asList(
node("tupleParameterElement", asList(
node("instanceParameter", asList(
node("typeVariable", asList(
node("idVar", asList(leaf("a"))))))))),
leaf(","),
node("tupleParameterElement", asList(
node("instanceParameter", asList(
node("typeVariable", asList(
node("idVar", asList(leaf("b"))))))))))),
leaf(")")))))));
}
@Test
public void shouldParseDoNotation() {
String result = parse(ScotchParser::patternBody,
"do x <- y",
" x"
);
assertThat(result, is(
tree("patternBody", asList(
node("doNotation", asList(
leaf("do"),
leaf("{"),
node("doStatements", asList(
node("doStatement", asList(
node("drawFrom", asList(
node("patternArgument", asList(
node("captureArgument", asList(
node("idVar", asList(leaf("x"))))))),
leaf("<-"),
node("expression", asList(
node("primaryExpression", asList(
node("reference", asList(
node("qualifiedName", asList(
node("name", asList(
node("idVar", asList(leaf("y"))))))))))))))))),
leaf(";"),
node("doStatement", asList(
node("expression", asList(
node("primaryExpression", asList(
node("reference", asList(
node("qualifiedName", asList(
node("name", asList(
node("idVar", asList(leaf("x"))))))))))))))),
leaf(";"),
leaf(";"))),
leaf("}")))))));
}
@Test
public void shouldParseWhereStatement() {
String result = parse(ScotchParser::pattern,
"a x = b y",
" where y = x"
);
assertThat(result, is(
tree("pattern", asList(
node("patternArguments", asList(
node("patternArgument", asList(
node("captureArgument", asList(
node("idVar", asList(leaf("a"))))))),
node("patternArgument", asList(
node("captureArgument", asList(
node("idVar", asList(leaf("x"))))))))),
leaf("="),
node("patternBody", asList(
node("expression", asList(
node("primaryExpression", asList(
node("reference", asList(
node("qualifiedName", asList(
node("name", asList(
node("idVar", asList(leaf("b"))))))))))),
node("primaryExpression", asList(
node("reference", asList(
node("qualifiedName", asList(
node("name", asList(
node("idVar", asList(leaf("y"))))))))))))))),
node("whereStatement", asList(
leaf("where"),
leaf("{"),
node("wherePatterns", asList(
node("wherePattern", asList(
node("pattern", asList(
node("patternArguments", asList(
node("patternArgument", asList(
node("captureArgument", asList(
node("idVar", asList(leaf("y"))))))))),
leaf("="),
node("patternBody", asList(
node("expression", asList(
node("primaryExpression", asList(
node("reference", asList(
node("qualifiedName", asList(
node("name", asList(
node("idVar", asList(leaf("x"))))))))))))))))))),
leaf(";"),
leaf(";"))),
leaf("}")))))));
}
@Test
public void shouldParseLetDeclaration() {
String result = parse(ScotchParser::expression,
"let x = y",
"x"
);
assertThat(result, is(
tree("expression", asList(
node("letDeclaration", asList(
leaf("let"),
leaf("{"),
node("letPatterns", asList(
node("letPattern", asList(
node("pattern", asList(
node("patternArguments", asList(
node("patternArgument", asList(
node("captureArgument", asList(
node("idVar", asList(leaf("x"))))))))),
leaf("="),
node("patternBody", asList(
node("expression", asList(
node("primaryExpression", asList(
node("reference", asList(
node("qualifiedName", asList(
node("name", asList(
node("idVar", asList(leaf("y"))))))))))))))))))),
leaf(";"))),
leaf("}"),
leaf("in"),
node("expression", asList(
node("primaryExpression", asList(
node("reference", asList(
node("qualifiedName", asList(
node("name", asList(
node("idVar", asList(leaf("x"))))))))))),
leaf(";")))))))));
}
@Test
public void shouldParseSignatureInLetPattern() {
assertThat(parse(ScotchParser::letPattern, "a :: b"), is(
tree("letPattern", asList(
node("patternSignature", asList(
node("patternNames", asList(
node("name", asList(
node("idVar", asList(leaf("a"))))))),
leaf("::"),
node("typeSignature", asList(
node("primarySignature", asList(
node("typeVariable", asList(
node("idVar", asList(leaf("b"))))),
leaf(";")))))))))));
}
@Test
public void shouldParseParallelPatternInLetPattern() {
assertThat(parse(ScotchParser::letPattern, "(a, _) = b"), is(
tree("letPattern", asList(
node("parallelPattern", asList(
node("parallelDeclaration", asList(
leaf("("),
node("parallelArguments", asList(
node("parallelArgument", asList(
node("captureArgument", asList(
node("idVar", asList(leaf("a"))))))),
leaf(","),
node("parallelArgument", asList(
node("ignoreArgument", asList(leaf("_"))))))),
leaf(")"))),
leaf("="),
node("expression", asList(
node("primaryExpression", asList(
node("reference", asList(
node("qualifiedName", asList(
node("name", asList(
node("idVar", asList(leaf("b"))))))))))),
leaf(";")
))))))));
}
@Test
public void shouldParseParallelPatternInWherePattern() {
assertThat(parse(ScotchParser::wherePattern, "(a, _) = b"), is(
tree("wherePattern", asList(
node("parallelPattern", asList(
node("parallelDeclaration", asList(
leaf("("),
node("parallelArguments", asList(
node("parallelArgument", asList(
node("captureArgument", asList(
node("idVar", asList(leaf("a"))))))),
leaf(","),
node("parallelArgument", asList(
node("ignoreArgument", asList(leaf("_"))))))),
leaf(")"))),
leaf("="),
node("expression", asList(
node("primaryExpression", asList(
node("reference", asList(
node("qualifiedName", asList(
node("name", asList(
node("idVar", asList(leaf("b"))))))))))),
leaf(";")
))))))));
}
@Test
public void shouldParseConsListPattern() {
assertThat(parse(ScotchParser::patternArgument, "(x:xs)"), is(
tree("patternArgument", asList(
node("parenthesizedArgument", asList(
leaf("("),
node("unshuffledArgument", asList(
node("patternArgument", asList(
node("captureArgument", asList(
node("idVar", asList(leaf("x"))))))),
node("patternArgument", asList(
node("typeArgument", asList(
node("qualifiedType", asList(
node("idType", asList(leaf(":"))))))))),
node("patternArgument", asList(
node("captureArgument", asList(
node("idVar", asList(leaf("xs"))))))))),
leaf(")")))))));
}
@Test
public void shouldParseNilListPattern() {
assertThat(parse(ScotchParser::patternArgument, "[]"), is(
tree("patternArgument", asList(
node("typeArgument", asList(
node("qualifiedType", asList(
node("idType", asList(leaf("[]")))))))))));
}
@Test
public void shouldParseSingletonDataDefinition() {
String result = parse(ScotchParser::moduleMember,
"data Box a {",
" value :: a,",
" }"
);
assertThat(result, is(
tree("moduleMember", asList(
node("singletonDataDefinition", asList(
leaf("data"),
node("idType", asList(leaf("Box"))),
node("dataParameters", asList(
node("typeVariable", asList(
node("idVar", asList(leaf("a"))))))),
leaf("{"),
node("dataFields", asList(
node("dataField", asList(
node("idVar", asList(leaf("value"))),
leaf("::"),
node("typeSignature", asList(
node("primarySignature", asList(
node("typeVariable", asList(
node("idVar", asList(leaf("a"))))))))))),
leaf(","))),
leaf("}")))))));
}
@Test
public void shouldParseDataDefinitionWithConstants() {
String result = parse(ScotchParser::moduleMember,
"data Colors = Red | Green | Blue"
);
assertThat(result, is(
tree("moduleMember", asList(
node("dataDefinition", asList(
leaf("data"),
node("idType", asList(leaf("Colors"))),
leaf("="),
node("dataConstructors", asList(
node("dataConstructor", asList(
node("dataConstant", asList(
node("idType", asList(leaf("Red"))))))),
leaf("|"),
node("dataConstructor", asList(
node("dataConstant", asList(
node("idType", asList(leaf("Green"))))))),
leaf("|"),
node("dataConstructor", asList(
node("dataConstant", asList(
node("idType", asList(leaf("Blue"))))))),
leaf(";")))))))));
}
@Test
public void shouldParseDataTuple() {
String result = parse(ScotchParser::dataConstructor, "Node a b");
assertThat(result, is(
tree("dataConstructor", asList(
node("dataTuple", asList(
node("idType", asList(leaf("Node"))),
node("dataTupleParameters", asList(
node("dataTupleParameter", asList(
node("typeVariable", asList(
node("idVar", asList(leaf("a"))))))),
node("dataTupleParameter", asList(
node("typeVariable", asList(
node("idVar", asList(leaf("b"))))))),
leaf(";")))))))));
}
@Test
public void shouldParseDataRecord() {
String result = parse(ScotchParser::dataConstructor,
"Node { left :: Tree, right :: Tree }"
);
assertThat(result, is(
tree("dataConstructor", asList(
node("dataRecord", asList(
node("idType", asList(leaf("Node"))),
leaf("{"),
node("dataFields", asList(
node("dataField", asList(
node("idVar", asList(leaf("left"))),
leaf("::"),
node("typeSignature", asList(
node("primarySignature", asList(
node("qualifiedType", asList(
node("idType", asList(leaf("Tree"))))))))))),
leaf(","),
node("dataField", asList(
node("idVar", asList(leaf("right"))),
leaf("::"),
node("typeSignature", asList(
node("primarySignature", asList(
node("qualifiedType", asList(
node("idType", asList(leaf("Tree"))))))))))))),
leaf("}")))))));
}
@Test
public void shouldParsePatternMatchWithOperator() {
String result = parse(ScotchParser::patternArguments, "x == y");
assertThat(result, is(
tree("patternArguments", asList(
node("patternArgument", asList(
node("captureArgument", asList(
node("idVar", asList(leaf("x")))
))
)),
node("patternArgument", asList(
node("operatorArgument", asList(leaf("==")))
)),
node("patternArgument", asList(
node("captureArgument", asList(
node("idVar", asList(leaf("y")))
))
)),
leaf(";")
))
));
}
@Test
public void shouldParseDoubleLiteral() {
String result = parse(ScotchParser::literal, ".23");
assertThat(result, is(
tree("literal", asList(leaf(".23")))
));
}
@Test
public void shouldParseBigIntLiteral() {
String result = parse(ScotchParser::literal, "2131215b");
assertThat(result, is(
tree("literal", asList(leaf("2131215b")))
));
}
}