Parsing support for return statements.

This commit is contained in:
Richard Smith
2021-04-21 17:53:54 -07:00
parent 7a74ac18a7
commit e3b732e564
4 changed files with 69 additions and 15 deletions
+1
View File
@@ -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
View File
@@ -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
View File
@@ -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();
+9 -1
View File
@@ -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>;