[toolchain] Implement #623: require braces.

For error recovery, allow the braces around the controlled statement of
an `if`, `while`, or similar to be omitted. Remove support for nested
code blocks as this conflicts with struct literal syntax.
This commit is contained in:
Richard Smith
2021-07-30 18:27:52 -07:00
parent 91512e90e7
commit f1028fcc27
3 changed files with 178 additions and 64 deletions
+152 -54
View File
@@ -354,28 +354,6 @@ TEST_F(ParseTreeTest, BasicFunctionDefinition) {
MatchFileEnd()}));
}
TEST_F(ParseTreeTest, FunctionDefinitionWithNestedBlocks) {
TokenizedBuffer tokens = GetTokenizedBuffer(
"fn F() {\n"
" {\n"
" {{}}\n"
" }\n"
"}");
ParseTree tree = ParseTree::Parse(tokens, consumer);
EXPECT_FALSE(tree.HasErrors());
EXPECT_THAT(
tree, MatchParseTreeNodes(
{MatchFunctionDeclaration(
MatchDeclaredName("F"), MatchParameters(),
MatchCodeBlock(
MatchCodeBlock(
MatchCodeBlock(MatchCodeBlock(MatchCodeBlockEnd()),
MatchCodeBlockEnd()),
MatchCodeBlockEnd()),
MatchCodeBlockEnd())),
MatchFileEnd()}));
}
TEST_F(ParseTreeTest, FunctionDefinitionWithIdenifierInStatements) {
TokenizedBuffer tokens = GetTokenizedBuffer(
"fn F() {\n"
@@ -393,26 +371,6 @@ TEST_F(ParseTreeTest, FunctionDefinitionWithIdenifierInStatements) {
MatchFileEnd()}));
}
TEST_F(ParseTreeTest, FunctionDefinitionWithIdenifierInNestedBlock) {
TokenizedBuffer tokens = GetTokenizedBuffer(
"fn F() {\n"
" {bar}\n"
"}");
ParseTree tree = ParseTree::Parse(tokens, consumer);
// Note: this might become valid depending on the expression syntax. This test
// shouldn't be taken as a sign it should remain invalid.
EXPECT_TRUE(tree.HasErrors());
EXPECT_THAT(tree,
MatchParseTreeNodes(
{MatchFunctionDeclaration(
MatchDeclaredName("F"), MatchParameters(),
MatchCodeBlock(
MatchCodeBlock(HasError, MatchNameReference("bar"),
MatchCodeBlockEnd()),
MatchCodeBlockEnd())),
MatchFileEnd()}));
}
TEST_F(ParseTreeTest, FunctionDefinitionWithFunctionCall) {
TokenizedBuffer tokens = GetTokenizedBuffer(
"fn F() {\n"
@@ -673,6 +631,43 @@ TEST_F(ParseTreeTest, VariableDeclarations) {
}
TEST_F(ParseTreeTest, IfNoElse) {
TokenizedBuffer tokens = GetTokenizedBuffer(
"fn F() {\n"
" if (a) {\n"
" if (b) {\n"
" if (c) {\n"
" d;\n"
" }\n"
" }\n"
" }\n"
"}");
ErrorTrackingDiagnosticConsumer error_tracker(consumer);
ParseTree tree = ParseTree::Parse(tokens, error_tracker);
EXPECT_FALSE(tree.HasErrors());
EXPECT_FALSE(error_tracker.SeenError());
EXPECT_THAT(
tree,
MatchParseTreeNodes(
{MatchFunctionWithBody(MatchIfStatement(
MatchCondition(MatchNameReference("a"), MatchConditionEnd()),
MatchCodeBlock(
MatchIfStatement(
MatchCondition(MatchNameReference("b"),
MatchConditionEnd()),
MatchCodeBlock(
MatchIfStatement(
MatchCondition(MatchNameReference("c"),
MatchConditionEnd()),
MatchCodeBlock(MatchExpressionStatement(
MatchNameReference("d")),
MatchCodeBlockEnd())),
MatchCodeBlockEnd())),
MatchCodeBlockEnd()))),
MatchFileEnd()}));
}
TEST_F(ParseTreeTest, IfNoElseUnbraced) {
TokenizedBuffer tokens = GetTokenizedBuffer(
"fn F() {\n"
" if (a)\n"
@@ -680,8 +675,11 @@ TEST_F(ParseTreeTest, IfNoElse) {
" if (c)\n"
" d;\n"
"}");
ParseTree tree = ParseTree::Parse(tokens, consumer);
ErrorTrackingDiagnosticConsumer error_tracker(consumer);
ParseTree tree = ParseTree::Parse(tokens, error_tracker);
// The missing braces are invalid, but we should be able to recover.
EXPECT_FALSE(tree.HasErrors());
EXPECT_TRUE(error_tracker.SeenError());
EXPECT_THAT(
tree,
@@ -698,6 +696,74 @@ TEST_F(ParseTreeTest, IfNoElse) {
}
TEST_F(ParseTreeTest, IfElse) {
TokenizedBuffer tokens = GetTokenizedBuffer(
"fn F() {\n"
" if (a) {\n"
" if (b) {\n"
" c;\n"
" } else {\n"
" d;\n"
" }\n"
" } else {\n"
" e;\n"
" }\n"
" if (x) { G(1); }\n"
" else if (x) { G(2); }\n"
" else { G(3); }\n"
"}");
ErrorTrackingDiagnosticConsumer error_tracker(consumer);
ParseTree tree = ParseTree::Parse(tokens, error_tracker);
EXPECT_FALSE(tree.HasErrors());
EXPECT_FALSE(error_tracker.SeenError());
EXPECT_THAT(
tree,
MatchParseTreeNodes(
{MatchFunctionWithBody(
MatchIfStatement(
MatchCondition(MatchNameReference("a"), MatchConditionEnd()),
MatchCodeBlock(
MatchIfStatement(
MatchCondition(MatchNameReference("b"),
MatchConditionEnd()),
MatchCodeBlock(MatchExpressionStatement(
MatchNameReference("c")),
MatchCodeBlockEnd()),
MatchIfStatementElse(),
MatchCodeBlock(MatchExpressionStatement(
MatchNameReference("d")),
MatchCodeBlockEnd())),
MatchCodeBlockEnd()),
MatchIfStatementElse(),
MatchCodeBlock(
MatchExpressionStatement(MatchNameReference("e")),
MatchCodeBlockEnd())),
MatchIfStatement(
MatchCondition(MatchNameReference("x"), MatchConditionEnd()),
MatchCodeBlock(
MatchExpressionStatement(MatchCallExpression(
MatchNameReference("G"), MatchLiteral("1"),
MatchCallExpressionEnd())),
MatchCodeBlockEnd()),
MatchIfStatementElse(),
MatchIfStatement(
MatchCondition(MatchNameReference("x"),
MatchConditionEnd()),
MatchCodeBlock(
MatchExpressionStatement(MatchCallExpression(
MatchNameReference("G"), MatchLiteral("2"),
MatchCallExpressionEnd())),
MatchCodeBlockEnd()),
MatchIfStatementElse(),
MatchCodeBlock(
MatchExpressionStatement(MatchCallExpression(
MatchNameReference("G"), MatchLiteral("3"),
MatchCallExpressionEnd())),
MatchCodeBlockEnd())))),
MatchFileEnd()}));
}
TEST_F(ParseTreeTest, IfElseUnbraced) {
TokenizedBuffer tokens = GetTokenizedBuffer(
"fn F() {\n"
" if (a)\n"
@@ -711,8 +777,11 @@ TEST_F(ParseTreeTest, IfElse) {
" else if (x) { G(2); }\n"
" else { G(3); }\n"
"}");
ParseTree tree = ParseTree::Parse(tokens, consumer);
ErrorTrackingDiagnosticConsumer error_tracker(consumer);
ParseTree tree = ParseTree::Parse(tokens, error_tracker);
// The missing braces are invalid, but we should be able to recover.
EXPECT_FALSE(tree.HasErrors());
EXPECT_TRUE(error_tracker.SeenError());
EXPECT_THAT(
tree,
@@ -786,13 +855,17 @@ TEST_F(ParseTreeTest, WhileBreakContinue) {
TokenizedBuffer tokens = GetTokenizedBuffer(
"fn F() {\n"
" while (a) {\n"
" if (b)\n"
" if (b) {\n"
" break;\n"
" if (c)\n"
" }\n"
" if (c) {\n"
" continue;\n"
" }\n"
"}");
ParseTree tree = ParseTree::Parse(tokens, consumer);
ErrorTrackingDiagnosticConsumer error_tracker(consumer);
ParseTree tree = ParseTree::Parse(tokens, error_tracker);
EXPECT_FALSE(tree.HasErrors());
EXPECT_FALSE(error_tracker.SeenError());
EXPECT_THAT(
tree,
@@ -800,22 +873,46 @@ TEST_F(ParseTreeTest, WhileBreakContinue) {
{MatchFunctionWithBody(MatchWhileStatement(
MatchCondition(MatchNameReference("a"), MatchConditionEnd()),
MatchCodeBlock(
MatchIfStatement(MatchCondition(MatchNameReference("b"),
MatchConditionEnd()),
MatchBreakStatement(MatchStatementEnd())),
MatchIfStatement(
MatchCondition(MatchNameReference("c"),
MatchCondition(MatchNameReference("b"),
MatchConditionEnd()),
MatchContinueStatement(MatchStatementEnd())),
MatchCodeBlock(MatchBreakStatement(MatchStatementEnd()),
MatchCodeBlockEnd())),
MatchIfStatement(MatchCondition(MatchNameReference("c"),
MatchConditionEnd()),
MatchCodeBlock(MatchContinueStatement(
MatchStatementEnd()),
MatchCodeBlockEnd())),
MatchCodeBlockEnd()))),
MatchFileEnd()}));
}
TEST_F(ParseTreeTest, WhileUnbraced) {
TokenizedBuffer tokens = GetTokenizedBuffer(
"fn F() {\n"
" while (a) \n"
" break;\n"
"}");
ErrorTrackingDiagnosticConsumer error_tracker(consumer);
ParseTree tree = ParseTree::Parse(tokens, error_tracker);
EXPECT_FALSE(tree.HasErrors());
EXPECT_TRUE(error_tracker.SeenError());
EXPECT_THAT(
tree,
MatchParseTreeNodes(
{MatchFunctionWithBody(MatchWhileStatement(
MatchCondition(MatchNameReference("a"), MatchConditionEnd()),
MatchBreakStatement(MatchStatementEnd()))),
MatchFileEnd()}));
}
TEST_F(ParseTreeTest, Return) {
TokenizedBuffer tokens = GetTokenizedBuffer(
"fn F() {\n"
" if (c)\n"
" if (c) {\n"
" return;\n"
" }\n"
"}\n"
"fn G(x: Int) -> Int {\n"
" return x;\n"
@@ -828,7 +925,8 @@ TEST_F(ParseTreeTest, Return) {
MatchParseTreeNodes(
{MatchFunctionWithBody(MatchIfStatement(
MatchCondition(MatchNameReference("c"), MatchConditionEnd()),
MatchReturnStatement(MatchStatementEnd()))),
MatchCodeBlock(MatchReturnStatement(MatchStatementEnd()),
MatchCodeBlockEnd()))),
MatchFunctionDeclaration(
MatchDeclaredName(),
MatchParameters(MatchPatternBinding(MatchDeclaredName("x"), ":",