mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 22:02:55 +01:00
Parsing support for return statements.
This commit is contained in:
@@ -38,6 +38,7 @@ CARBON_PARSE_NODE_KIND(Condition)
|
||||
CARBON_PARSE_NODE_KIND(ConditionEnd)
|
||||
CARBON_PARSE_NODE_KIND(ContinueStatement)
|
||||
CARBON_PARSE_NODE_KIND(BreakStatement)
|
||||
CARBON_PARSE_NODE_KIND(ReturnStatement)
|
||||
CARBON_PARSE_NODE_KIND(StatementEnd)
|
||||
|
||||
// Expressions.
|
||||
|
||||
+39
-10
@@ -212,19 +212,19 @@ TEST_F(ParseTreeTest, FunctionDeclarationWithReturnType) {
|
||||
TEST_F(ParseTreeTest, FunctionDefinitionWithReturnType) {
|
||||
TokenizedBuffer tokens = GetTokenizedBuffer(
|
||||
"fn foo() -> Int {\n"
|
||||
" // return 42;\n"
|
||||
" return 42;\n"
|
||||
"}");
|
||||
ParseTree tree = ParseTree::Parse(tokens, consumer);
|
||||
EXPECT_FALSE(tree.HasErrors());
|
||||
EXPECT_THAT(
|
||||
tree,
|
||||
MatchParseTreeNodes(
|
||||
{MatchFunctionDeclaration(MatchDeclaredName("foo"), MatchParameters(),
|
||||
MatchReturnType(MatchNameReference("Int")),
|
||||
MatchCodeBlock(
|
||||
// TODO: Match a return statement.
|
||||
MatchCodeBlockEnd())),
|
||||
MatchFileEnd()}));
|
||||
EXPECT_THAT(tree,
|
||||
MatchParseTreeNodes(
|
||||
{MatchFunctionDeclaration(
|
||||
MatchDeclaredName("foo"), MatchParameters(),
|
||||
MatchReturnType(MatchNameReference("Int")),
|
||||
MatchCodeBlock(MatchReturnStatement(MatchLiteral("42"),
|
||||
MatchStatementEnd()),
|
||||
MatchCodeBlockEnd())),
|
||||
MatchFileEnd()}));
|
||||
}
|
||||
|
||||
TEST_F(ParseTreeTest, FunctionDeclarationWithSingleIdentifierParameterList) {
|
||||
@@ -693,6 +693,35 @@ TEST_F(ParseTreeTest, WhileBreakContinue) {
|
||||
MatchFileEnd()}));
|
||||
}
|
||||
|
||||
TEST_F(ParseTreeTest, Return) {
|
||||
TokenizedBuffer tokens = GetTokenizedBuffer(
|
||||
"fn F() {\n"
|
||||
" if (c)\n"
|
||||
" return;\n"
|
||||
"}\n"
|
||||
"fn G(Int x) -> Int {\n"
|
||||
" return x;\n"
|
||||
"}");
|
||||
ParseTree tree = ParseTree::Parse(tokens, consumer);
|
||||
EXPECT_FALSE(tree.HasErrors());
|
||||
|
||||
EXPECT_THAT(
|
||||
tree,
|
||||
MatchParseTreeNodes(
|
||||
{MatchFunctionWithBody(MatchIfStatement(
|
||||
MatchCondition(MatchNameReference("c"), MatchConditionEnd()),
|
||||
MatchReturnStatement(MatchStatementEnd()))),
|
||||
MatchFunctionDeclaration(
|
||||
MatchDeclaredName(),
|
||||
MatchParameters(
|
||||
MatchParameterDeclaration(MatchNameReference("Int"), "x")),
|
||||
MatchReturnType(MatchNameReference("Int")),
|
||||
MatchCodeBlock(MatchReturnStatement(MatchNameReference("x"),
|
||||
MatchStatementEnd()),
|
||||
MatchCodeBlockEnd())),
|
||||
MatchFileEnd()}));
|
||||
}
|
||||
|
||||
auto GetAndDropLine(llvm::StringRef& s) -> std::string {
|
||||
auto newline_offset = s.find_first_of('\n');
|
||||
llvm::StringRef line = s.slice(0, newline_offset);
|
||||
|
||||
+20
-4
@@ -827,20 +827,30 @@ auto ParseTree::Parser::ParseWhileStatement() -> llvm::Optional<Node> {
|
||||
/*has_errors=*/!cond || !body);
|
||||
}
|
||||
|
||||
auto ParseTree::Parser::ParseKeywordStatement(ParseNodeKind kind)
|
||||
auto ParseTree::Parser::ParseKeywordStatement(ParseNodeKind kind,
|
||||
KeywordStatementArgument argument)
|
||||
-> llvm::Optional<Node> {
|
||||
auto keyword_kind = tokens.GetKind(*position);
|
||||
assert(keyword_kind.IsKeyword());
|
||||
|
||||
auto start = StartSubtree();
|
||||
auto keyword = Consume(keyword_kind);
|
||||
|
||||
bool arg_error = false;
|
||||
if ((argument == KeywordStatementArgument::Optional &&
|
||||
tokens.GetKind(*position) != TokenKind::Semi()) ||
|
||||
argument == KeywordStatementArgument::Mandatory) {
|
||||
arg_error = !ParseExpression();
|
||||
}
|
||||
|
||||
auto semi =
|
||||
ConsumeAndAddLeafNodeIf(TokenKind::Semi(), ParseNodeKind::StatementEnd());
|
||||
if (!semi) {
|
||||
emitter.EmitError<ExpectedSemiAfter>(*position,
|
||||
{.preceding = keyword_kind});
|
||||
// FIXME: Try to skip to a semicolon to recover.
|
||||
}
|
||||
return AddNode(kind, keyword, start, /*has_errors=*/!semi);
|
||||
return AddNode(kind, keyword, start, /*has_errors=*/!semi || arg_error);
|
||||
}
|
||||
|
||||
auto ParseTree::Parser::ParseStatement() -> llvm::Optional<Node> {
|
||||
@@ -855,10 +865,16 @@ auto ParseTree::Parser::ParseStatement() -> llvm::Optional<Node> {
|
||||
return ParseWhileStatement();
|
||||
|
||||
case TokenKind::ContinueKeyword():
|
||||
return ParseKeywordStatement(ParseNodeKind::ContinueStatement());
|
||||
return ParseKeywordStatement(ParseNodeKind::ContinueStatement(),
|
||||
KeywordStatementArgument::None);
|
||||
|
||||
case TokenKind::BreakKeyword():
|
||||
return ParseKeywordStatement(ParseNodeKind::BreakStatement());
|
||||
return ParseKeywordStatement(ParseNodeKind::BreakStatement(),
|
||||
KeywordStatementArgument::None);
|
||||
|
||||
case TokenKind::ReturnKeyword():
|
||||
return ParseKeywordStatement(ParseNodeKind::ReturnStatement(),
|
||||
KeywordStatementArgument::Optional);
|
||||
|
||||
case TokenKind::OpenCurlyBrace():
|
||||
return ParseCodeBlock();
|
||||
|
||||
@@ -199,8 +199,16 @@ class ParseTree::Parser {
|
||||
// Parses a while-statement.
|
||||
auto ParseWhileStatement() -> llvm::Optional<Node>;
|
||||
|
||||
enum class KeywordStatementArgument {
|
||||
None,
|
||||
Optional,
|
||||
Mandatory,
|
||||
};
|
||||
|
||||
// Parses a statement of the form `keyword;` such as `break;` or `continue;`.
|
||||
auto ParseKeywordStatement(ParseNodeKind kind) -> llvm::Optional<Node>;
|
||||
auto ParseKeywordStatement(ParseNodeKind kind,
|
||||
KeywordStatementArgument argument)
|
||||
-> llvm::Optional<Node>;
|
||||
|
||||
// Parses a statement.
|
||||
auto ParseStatement() -> llvm::Optional<Node>;
|
||||
|
||||
Reference in New Issue
Block a user