mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 13:31:06 +01:00
Parsing for while, break, and continue statements, following #340.
This commit is contained in:
@@ -30,8 +30,12 @@ CARBON_PARSE_NODE_KIND(CodeBlock)
|
||||
CARBON_PARSE_NODE_KIND(ExpressionStatement)
|
||||
CARBON_PARSE_NODE_KIND(IfStatement)
|
||||
CARBON_PARSE_NODE_KIND(IfStatementElse)
|
||||
CARBON_PARSE_NODE_KIND(WhileStatement)
|
||||
CARBON_PARSE_NODE_KIND(Condition)
|
||||
CARBON_PARSE_NODE_KIND(ConditionEnd)
|
||||
CARBON_PARSE_NODE_KIND(ContinueStatement)
|
||||
CARBON_PARSE_NODE_KIND(BreakStatement)
|
||||
CARBON_PARSE_NODE_KIND(StatementEnd)
|
||||
|
||||
// Expressions.
|
||||
CARBON_PARSE_NODE_KIND(Literal)
|
||||
|
||||
@@ -643,6 +643,42 @@ TEST_F(ParseTreeTest, IfError) {
|
||||
MatchFileEnd()}));
|
||||
}
|
||||
|
||||
TEST_F(ParseTreeTest, WhileBreakContinue) {
|
||||
TokenizedBuffer tokens = GetTokenizedBuffer(
|
||||
"fn F() {\n"
|
||||
" while (a) {\n"
|
||||
" if (b)\n"
|
||||
" break;\n"
|
||||
" if (c)\n"
|
||||
" continue;\n"
|
||||
"}");
|
||||
ParseTree tree = ParseTree::Parse(tokens, consumer);
|
||||
EXPECT_FALSE(tree.HasErrors());
|
||||
|
||||
EXPECT_THAT(
|
||||
tree,
|
||||
MatchParseTreeNodes(
|
||||
{MatchFunctionDeclaration(
|
||||
MatchDeclaredName("F"),
|
||||
MatchParameterList(MatchParameterListEnd()),
|
||||
MatchCodeBlock(
|
||||
MatchWhileStatement(
|
||||
MatchCondition(MatchNameReference("a"),
|
||||
MatchConditionEnd()),
|
||||
MatchCodeBlock(
|
||||
MatchIfStatement(
|
||||
MatchCondition(MatchNameReference("b"),
|
||||
MatchConditionEnd()),
|
||||
MatchBreakStatement(MatchStatementEnd())),
|
||||
MatchIfStatement(
|
||||
MatchCondition(MatchNameReference("c"),
|
||||
MatchConditionEnd()),
|
||||
MatchContinueStatement(MatchStatementEnd())),
|
||||
MatchCodeBlockEnd())),
|
||||
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);
|
||||
|
||||
@@ -86,6 +86,17 @@ struct ExpectedSemiAfterExpression
|
||||
"Expected `;` after expression.";
|
||||
};
|
||||
|
||||
struct ExpectedSemiAfter : SimpleDiagnostic<ExpectedSemiAfter> {
|
||||
static constexpr llvm::StringLiteral ShortName = "syntax-error";
|
||||
static constexpr const char* Message = "Expected `;` after `{0}`.";
|
||||
|
||||
TokenKind preceding;
|
||||
|
||||
auto Format() -> std::string {
|
||||
return llvm::formatv(Message, preceding.GetFixedSpelling()).str();
|
||||
}
|
||||
};
|
||||
|
||||
struct ExpectedIdentifierAfterDot
|
||||
: SimpleDiagnostic<ExpectedIdentifierAfterDot> {
|
||||
static constexpr llvm::StringLiteral ShortName = "syntax-error";
|
||||
@@ -758,6 +769,31 @@ auto ParseTree::Parser::ParseIfStatement() -> llvm::Optional<Node> {
|
||||
/*has_errors=*/!cond || !then_case || else_has_errors);
|
||||
}
|
||||
|
||||
auto ParseTree::Parser::ParseWhileStatement() -> llvm::Optional<Node> {
|
||||
auto start = StartSubtree();
|
||||
auto while_token = Consume(TokenKind::WhileKeyword());
|
||||
auto cond = ParseParenCondition(TokenKind::WhileKeyword());
|
||||
auto body = ParseStatement();
|
||||
return AddNode(ParseNodeKind::WhileStatement(), while_token, start,
|
||||
/*has_errors=*/!cond || !body);
|
||||
}
|
||||
|
||||
auto ParseTree::Parser::ParseKeywordStatement(ParseNodeKind kind)
|
||||
-> llvm::Optional<Node> {
|
||||
auto keyword_kind = tokens.GetKind(*position);
|
||||
assert(keyword_kind.IsKeyword());
|
||||
|
||||
auto start = StartSubtree();
|
||||
auto keyword = Consume(keyword_kind);
|
||||
auto semi =
|
||||
ConsumeAndAddLeafNodeIf(TokenKind::Semi(), ParseNodeKind::StatementEnd());
|
||||
if (!semi) {
|
||||
emitter.EmitError<ExpectedSemiAfter>(*position,
|
||||
{.preceding = keyword_kind});
|
||||
}
|
||||
return AddNode(kind, keyword, start, /*has_errors=*/!semi);
|
||||
}
|
||||
|
||||
auto ParseTree::Parser::ParseStatement() -> llvm::Optional<Node> {
|
||||
switch (tokens.GetKind(*position)) {
|
||||
case TokenKind::VarKeyword():
|
||||
@@ -766,6 +802,15 @@ auto ParseTree::Parser::ParseStatement() -> llvm::Optional<Node> {
|
||||
case TokenKind::IfKeyword():
|
||||
return ParseIfStatement();
|
||||
|
||||
case TokenKind::WhileKeyword():
|
||||
return ParseWhileStatement();
|
||||
|
||||
case TokenKind::ContinueKeyword():
|
||||
return ParseKeywordStatement(ParseNodeKind::ContinueStatement());
|
||||
|
||||
case TokenKind::BreakKeyword():
|
||||
return ParseKeywordStatement(ParseNodeKind::BreakStatement());
|
||||
|
||||
case TokenKind::OpenCurlyBrace():
|
||||
return ParseCodeBlock();
|
||||
|
||||
|
||||
@@ -183,6 +183,12 @@ class ParseTree::Parser {
|
||||
// Parses an if-statement.
|
||||
auto ParseIfStatement() -> llvm::Optional<Node>;
|
||||
|
||||
// Parses a while-statement.
|
||||
auto ParseWhileStatement() -> llvm::Optional<Node>;
|
||||
|
||||
// Parses a statement of the form `keyword;` such as `break;` or `continue;`.
|
||||
auto ParseKeywordStatement(ParseNodeKind kind) -> llvm::Optional<Node>;
|
||||
|
||||
// Parses a statement.
|
||||
auto ParseStatement() -> llvm::Optional<Node>;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user