mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 19:11:09 +01:00
[toolchain] Parse postfix operator * as a type operator. (#576)
This commit is contained in:
@@ -530,6 +530,113 @@ TEST_F(ParseTreeTest, Operators) {
|
||||
MatchFileEnd()}));
|
||||
}
|
||||
|
||||
TEST_F(ParseTreeTest, OperatorFixity) {
|
||||
TokenizedBuffer tokens = GetTokenizedBuffer(
|
||||
"fn F(p: Int*, n: Int) {\n"
|
||||
" var q: Int* = p;\n"
|
||||
" var t: Type = Int*;\n"
|
||||
" t = t**;\n"
|
||||
" n = n * n;\n"
|
||||
" n = n*n;\n"
|
||||
" G(Int*, n * n);\n"
|
||||
"}");
|
||||
ParseTree tree = ParseTree::Parse(tokens, consumer);
|
||||
EXPECT_FALSE(tree.HasErrors());
|
||||
|
||||
EXPECT_THAT(
|
||||
tree,
|
||||
MatchParseTreeNodes(
|
||||
{MatchFunctionDeclaration(
|
||||
MatchDeclaredName("F"),
|
||||
MatchParameters(
|
||||
MatchPatternBinding(
|
||||
MatchDeclaredName("p"),
|
||||
MatchPostfixOperator(MatchNameReference("Int"), "*")),
|
||||
MatchParameterListComma(),
|
||||
MatchPatternBinding(MatchDeclaredName("n"),
|
||||
MatchNameReference("Int"))),
|
||||
MatchCodeBlock(
|
||||
MatchVariableDeclaration(
|
||||
MatchPatternBinding(MatchDeclaredName("q"),
|
||||
MatchPostfixOperator(
|
||||
MatchNameReference("Int"), "*")),
|
||||
MatchVariableInitializer(MatchNameReference("p")),
|
||||
MatchDeclarationEnd()),
|
||||
MatchVariableDeclaration(
|
||||
MatchPatternBinding(MatchDeclaredName("t"),
|
||||
MatchNameReference("Type")),
|
||||
MatchVariableInitializer(MatchPostfixOperator(
|
||||
MatchNameReference("Int"), "*")),
|
||||
MatchDeclarationEnd()),
|
||||
MatchExpressionStatement(MatchInfixOperator(
|
||||
MatchNameReference("t"), "=",
|
||||
MatchPostfixOperator(
|
||||
MatchPostfixOperator(MatchNameReference("t"), "*"),
|
||||
"*"))),
|
||||
MatchExpressionStatement(MatchInfixOperator(
|
||||
MatchNameReference("n"), "=",
|
||||
MatchInfixOperator(MatchNameReference("n"), "*",
|
||||
MatchNameReference("n")))),
|
||||
MatchExpressionStatement(MatchInfixOperator(
|
||||
MatchNameReference("n"), "=",
|
||||
MatchInfixOperator(MatchNameReference("n"), "*",
|
||||
MatchNameReference("n")))),
|
||||
MatchExpressionStatement(MatchCallExpression(
|
||||
MatchNameReference("G"),
|
||||
MatchPostfixOperator(MatchNameReference("Int"), "*"),
|
||||
MatchCallExpressionComma(),
|
||||
MatchInfixOperator(MatchNameReference("n"), "*",
|
||||
MatchNameReference("n")),
|
||||
MatchCallExpressionEnd())),
|
||||
MatchCodeBlockEnd())),
|
||||
MatchFileEnd()}));
|
||||
}
|
||||
|
||||
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 = Int*;", Valid},
|
||||
{"var v: Type = Int *;", Recovered},
|
||||
{"var v: Type = Int* ;", Valid},
|
||||
{"var v: Type = Int * ;", Recovered},
|
||||
{"var n: Int = n * n;", Valid},
|
||||
{"var n: Int = n*n;", Valid},
|
||||
{"var n: Int = (n)*3;", Valid},
|
||||
{"var n: Int = 3*(n);", Valid},
|
||||
{"var n: Int = n *n;", Recovered},
|
||||
// FIXME: We could figure out that this first Failed example is infix
|
||||
// with one-token lookahead.
|
||||
{"var n: Int = n* n;", Failed},
|
||||
{"var n: Int = n* -n;", Failed},
|
||||
{"var n: Int = n* *p;", Failed},
|
||||
// FIXME: 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: Int = n**p;", Failed},
|
||||
{"var n: Int = -n;", Valid},
|
||||
{"var n: Int = - n;", Recovered},
|
||||
{"var n: Int =-n;", Valid},
|
||||
{"var n: Int =- n;", Recovered},
|
||||
{"var n: Int = F(Int *);", Recovered},
|
||||
{"var n: Int = F(Int *, 0);", Recovered},
|
||||
};
|
||||
|
||||
for (auto [input, kind] : testcases) {
|
||||
TokenizedBuffer tokens = GetTokenizedBuffer(input);
|
||||
ErrorTrackingDiagnosticConsumer error_tracker(consumer);
|
||||
ParseTree tree = ParseTree::Parse(tokens, error_tracker);
|
||||
EXPECT_THAT(tree.HasErrors(), Eq(kind == Failed)) << input;
|
||||
EXPECT_THAT(error_tracker.SeenError(), Eq(kind != Valid)) << input;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(ParseTreeTest, VariableDeclarations) {
|
||||
TokenizedBuffer tokens = GetTokenizedBuffer(
|
||||
"var v: Int = 0;\n"
|
||||
|
||||
Reference in New Issue
Block a user