mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-03 21:05:50 +01:00
Move parse tree tests to files. (#2437)
I think it'd be helpful to examine what the parse tree looks like in failure cases. Note, I'm not sure that the behavior of the recovery situations is correct; the test had been asserting that the parse tree should indicate it's error free. However, this means that the only signal the the driver that the input is invalid is that the diagnostic emitter was used. I think it may be important to have it return a non-zero error to prevent compile, or we can turn these into warnings but then "requiring a space" is wrong. Either way, that's a concern I have with the pre-existing recovery behavior: I'm just trying to highlight it as I make this change, because now the test is really that nodes aren't tagged with has_error.
This commit is contained in:
@@ -52,102 +52,6 @@ TEST_F(ParseTreeTest, IsValid) {
|
||||
EXPECT_TRUE((*tree.postorder().begin()).is_valid());
|
||||
}
|
||||
|
||||
TEST_F(ParseTreeTest, OperatorWhitespaceErrors) {
|
||||
// Test dispositions: Recovered means we issued an error but recovered a
|
||||
// proper parse tree; Failed means we didn't fully recover from the error.
|
||||
enum Kind { Valid, Recovered, Failed };
|
||||
|
||||
struct Testcase {
|
||||
const char* input;
|
||||
Kind kind;
|
||||
} testcases[] = {
|
||||
{"var v: Type = i8*;", Valid},
|
||||
{"var v: Type = i8 *;", Recovered},
|
||||
{"var v: Type = i8* ;", Valid},
|
||||
{"var v: Type = i8 * ;", Recovered},
|
||||
{"var n: i8 = n * n;", Valid},
|
||||
{"var n: i8 = n*n;", Valid},
|
||||
{"var n: i8 = (n)*3;", Valid},
|
||||
{"var n: i8 = 3*(n);", Valid},
|
||||
{"var n: i8 = n *n;", Recovered},
|
||||
// TODO: We could figure out that this first Failed example is infix
|
||||
// with one-token lookahead.
|
||||
{"var n: i8 = n* n;", Failed},
|
||||
{"var n: i8 = n* -n;", Failed},
|
||||
{"var n: i8 = n* *p;", Failed},
|
||||
// TODO: We try to form (n*)*p and reject due to missing parentheses
|
||||
// before we notice the missing whitespace around the second `*`.
|
||||
// It'd be better to (somehow) form n*(*p) and reject due to the missing
|
||||
// whitespace around the first `*`.
|
||||
{"var n: i8 = n**p;", Failed},
|
||||
{"var n: i8 = -n;", Valid},
|
||||
{"var n: i8 = - n;", Recovered},
|
||||
{"var n: i8 =-n;", Valid},
|
||||
{"var n: i8 =- n;", Recovered},
|
||||
{"var n: i8 = F(i8 *);", Recovered},
|
||||
{"var n: i8 = F(i8 *, 0);", Recovered},
|
||||
};
|
||||
|
||||
for (auto [input, kind] : testcases) {
|
||||
TokenizedBuffer tokens = GetTokenizedBuffer(input);
|
||||
ErrorTrackingDiagnosticConsumer error_tracker(consumer);
|
||||
ParseTree tree =
|
||||
ParseTree::Parse(tokens, error_tracker, /*vlog_stream=*/nullptr);
|
||||
EXPECT_THAT(tree.has_errors(), Eq(kind == Failed)) << input;
|
||||
EXPECT_THAT(error_tracker.seen_error(), Eq(kind != Valid)) << input;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(ParseTreeTest, StructErrors) {
|
||||
struct Testcase {
|
||||
llvm::StringLiteral input;
|
||||
::testing::Matcher<const Diagnostic&> diag_matcher;
|
||||
};
|
||||
Testcase testcases[] = {
|
||||
{"var x: {i32} = {};",
|
||||
IsDiagnosticMessage("Expected `.field: type` or `.field = value`.")},
|
||||
{"var x: {a} = {};",
|
||||
IsDiagnosticMessage("Expected `.field: type` or `.field = value`.")},
|
||||
{"var x: {a:} = {};",
|
||||
IsDiagnosticMessage("Expected `.field: type` or `.field = value`.")},
|
||||
{"var x: {a=} = {};",
|
||||
IsDiagnosticMessage("Expected `.field: type` or `.field = value`.")},
|
||||
{"var x: {.} = {};",
|
||||
IsDiagnosticMessage("Expected identifier after `.`.")},
|
||||
{"var x: {.\"hello\" = 0, .y = 4} = {};",
|
||||
IsDiagnosticMessage("Expected identifier after `.`.")},
|
||||
{"var x: {.\"hello\": i32, .y: i32} = {};",
|
||||
IsDiagnosticMessage("Expected identifier after `.`.")},
|
||||
{"var x: {.a} = {};",
|
||||
IsDiagnosticMessage("Expected `.field: type` or `.field = value`.")},
|
||||
{"var x: {.a:} = {};", IsDiagnosticMessage("Expected expression.")},
|
||||
{"var x: {.a=} = {};", IsDiagnosticMessage("Expected expression.")},
|
||||
{"var x: {.a: i32, .b = 0} = {};",
|
||||
IsDiagnosticMessage("Expected `.field: type`.")},
|
||||
{"var x: {.a = 0, b: i32} = {};",
|
||||
IsDiagnosticMessage("Expected `.field = value`.")},
|
||||
{"var x: {,} = {};",
|
||||
IsDiagnosticMessage("Expected `.field: type` or `.field = value`.")},
|
||||
{"var x: {.a: i32,,} = {};",
|
||||
IsDiagnosticMessage("Expected `.field: type`.")},
|
||||
{"var x: {.a = 0,,} = {};",
|
||||
IsDiagnosticMessage("Expected `.field = value`.")},
|
||||
{"var x: {.a: i32 banana} = {.a = 0};",
|
||||
IsDiagnosticMessage("Expected `,` or `}`.")},
|
||||
{"var x: {.a: i32} = {.a = 0 banana};",
|
||||
IsDiagnosticMessage("Expected `,` or `}`.")},
|
||||
};
|
||||
|
||||
for (const Testcase& testcase : testcases) {
|
||||
TokenizedBuffer tokens = GetTokenizedBuffer(testcase.input);
|
||||
Testing::MockDiagnosticConsumer consumer;
|
||||
EXPECT_CALL(consumer, HandleDiagnostic(testcase.diag_matcher));
|
||||
ParseTree tree =
|
||||
ParseTree::Parse(tokens, consumer, /*vlog_stream=*/nullptr);
|
||||
EXPECT_TRUE(tree.has_errors());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(ParseTreeTest, PrintPostorderAsYAML) {
|
||||
TokenizedBuffer tokens = GetTokenizedBuffer("fn F();");
|
||||
ParseTree tree = ParseTree::Parse(tokens, consumer, /*vlog_stream=*/nullptr);
|
||||
@@ -223,38 +127,5 @@ TEST_F(ParseTreeTest, HighRecursion) {
|
||||
EXPECT_FALSE(tree.has_errors());
|
||||
}
|
||||
|
||||
TEST_F(ParseTreeTest, PackageErrors) {
|
||||
struct TestCase {
|
||||
llvm::StringLiteral input;
|
||||
::testing::Matcher<const Diagnostic&> diag_matcher;
|
||||
};
|
||||
|
||||
TestCase testcases[] = {
|
||||
{"package;", IsDiagnosticMessage("Expected identifier after `package`.")},
|
||||
{"package fn;",
|
||||
IsDiagnosticMessage("Expected identifier after `package`.")},
|
||||
{"package library \"Shapes\" api;",
|
||||
IsDiagnosticMessage("Expected identifier after `package`.")},
|
||||
{"package Geometry library Shapes api;",
|
||||
IsDiagnosticMessage(
|
||||
"Expected a string literal to specify the library name.")},
|
||||
{"package Geometry \"Shapes\" api;",
|
||||
IsDiagnosticMessage("Missing `library` keyword.")},
|
||||
{"package Geometry api",
|
||||
IsDiagnosticMessage("Expected `;` to end package directive.")},
|
||||
{"package Geometry;", IsDiagnosticMessage("Expected a `api` or `impl`.")},
|
||||
{R"(package Foo library "bar" "baz";)",
|
||||
IsDiagnosticMessage("Expected a `api` or `impl`.")}};
|
||||
|
||||
for (const TestCase& testcase : testcases) {
|
||||
TokenizedBuffer tokens = GetTokenizedBuffer(testcase.input);
|
||||
Testing::MockDiagnosticConsumer consumer;
|
||||
EXPECT_CALL(consumer, HandleDiagnostic(testcase.diag_matcher));
|
||||
ParseTree tree =
|
||||
ParseTree::Parse(tokens, consumer, /*vlog_stream=*/nullptr);
|
||||
EXPECT_TRUE(tree.has_errors());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace Carbon::Testing
|
||||
|
||||
Reference in New Issue
Block a user