Convert parser diagnostics to use the diagnostic emitter. (#389)

This commit is contained in:
Richard Smith
2021-03-18 22:09:06 -07:00
committed by GitHub
parent 1e6c7e3963
commit 426c789d6e
2 changed files with 64 additions and 33 deletions
+61 -32
View File
@@ -15,8 +15,61 @@
namespace Carbon {
struct UnexpectedTokenInFunctionParams
: SimpleDiagnostic<UnexpectedTokenInFunctionParams> {
static constexpr llvm::StringLiteral ShortName = "syntax-error";
static constexpr llvm::StringLiteral Message =
"Unexpected token in function parameter list.";
};
struct UnexpectedTokenInCodeBlock
: SimpleDiagnostic<UnexpectedTokenInCodeBlock> {
static constexpr llvm::StringLiteral ShortName = "syntax-error";
static constexpr llvm::StringLiteral Message =
"Unexpected token in code block.";
};
struct ExpectedFunctionName : SimpleDiagnostic<ExpectedFunctionName> {
static constexpr llvm::StringLiteral ShortName = "syntax-error";
static constexpr llvm::StringLiteral Message =
"Expected function name after `fn` keyword.";
};
struct ExpectedFunctionParams : SimpleDiagnostic<ExpectedFunctionParams> {
static constexpr llvm::StringLiteral ShortName = "syntax-error";
static constexpr llvm::StringLiteral Message =
"Expected `(` after function name.";
};
struct ExpectedFunctionBodyOrSemi
: SimpleDiagnostic<ExpectedFunctionBodyOrSemi> {
static constexpr llvm::StringLiteral ShortName = "syntax-error";
static constexpr llvm::StringLiteral Message =
"Expected function definition or `;` after function declaration.";
};
struct UnrecognizedDeclaration : SimpleDiagnostic<UnrecognizedDeclaration> {
static constexpr llvm::StringLiteral ShortName = "syntax-error";
static constexpr llvm::StringLiteral Message =
"Unrecognized declaration introducer.";
};
ParseTree::Parser::Parser(ParseTree& tree_arg, TokenizedBuffer& tokens_arg,
TokenDiagnosticEmitter& emitter)
: tree(tree_arg),
tokens(tokens_arg),
emitter(emitter),
position(tokens.Tokens().begin()),
end(tokens.Tokens().end()) {
assert(std::find_if(position, end,
[&](TokenizedBuffer::Token t) {
return tokens.GetKind(t) == TokenKind::EndOfFile();
}) != end &&
"No EndOfFileToken in token buffer.");
}
auto ParseTree::Parser::Parse(TokenizedBuffer& tokens,
TokenDiagnosticEmitter& /*unused*/) -> ParseTree {
TokenDiagnosticEmitter& emitter) -> ParseTree {
ParseTree tree(tokens);
// We expect to have a 1:1 correspondence between tokens and tree nodes, so
@@ -24,7 +77,7 @@ auto ParseTree::Parser::Parse(TokenizedBuffer& tokens,
// overhead.
tree.node_impls.reserve(tokens.Size());
Parser parser(tree, tokens);
Parser parser(tree, tokens, emitter);
while (!parser.AtEndOfFile()) {
parser.ParseDeclaration();
}
@@ -35,18 +88,6 @@ auto ParseTree::Parser::Parse(TokenizedBuffer& tokens,
return tree;
}
ParseTree::Parser::Parser(ParseTree& tree_arg, TokenizedBuffer& tokens_arg)
: tree(tree_arg),
tokens(tokens_arg),
position(tokens.Tokens().begin()),
end(tokens.Tokens().end()) {
assert(std::find_if(position, end,
[&](TokenizedBuffer::Token t) {
return tokens.GetKind(t) == TokenKind::EndOfFile();
}) != end &&
"No EndOfFileToken in token buffer.");
}
auto ParseTree::Parser::Consume(TokenKind kind) -> TokenizedBuffer::Token {
TokenizedBuffer::Token t = *position;
assert(kind != TokenKind::EndOfFile() && "Cannot consume the EOF token!");
@@ -201,9 +242,7 @@ auto ParseTree::Parser::ParseFunctionSignature() -> Node {
bool has_errors = false;
if (tokens.GetKind(*position) != TokenKind::CloseParen()) {
llvm::errs() << "ERROR: unexpected token before the close of the "
"parameters on line "
<< tokens.GetLineNumber(*position) << "!\n";
emitter.EmitError<UnexpectedTokenInFunctionParams>(*position);
has_errors = true;
// We can trivially skip to the actual close parenthesis from here.
@@ -228,9 +267,7 @@ auto ParseTree::Parser::ParseCodeBlock() -> Node {
switch (tokens.GetKind(*position)) {
default:
// FIXME: Add support for parsing more expressions & statements.
llvm::errs() << "ERROR: unexpected token before the close of the "
"function definition on line "
<< tokens.GetLineNumber(*position) << "!\n";
emitter.EmitError<UnexpectedTokenInCodeBlock>(*position);
has_errors = true;
// We can trivially skip to the actual close curly brace from here.
@@ -272,8 +309,7 @@ auto ParseTree::Parser::ParseFunctionDeclaration() -> Node {
auto name_n = ConsumeAndAddLeafNodeIf(TokenKind::Identifier(),
ParseNodeKind::Identifier());
if (!name_n) {
llvm::errs() << "ERROR: Function declaration with no name on line "
<< tokens.GetLineNumber(function_intro_token) << "!\n";
emitter.EmitError<ExpectedFunctionName>(*position);
// FIXME: We could change the lexer to allow us to synthesize certain
// kinds of tokens and try to "recover" here, but unclear that this is
// really useful.
@@ -283,10 +319,7 @@ auto ParseTree::Parser::ParseFunctionDeclaration() -> Node {
TokenizedBuffer::Token open_paren = *position;
if (tokens.GetKind(open_paren) != TokenKind::OpenParen()) {
llvm::errs()
<< "ERROR: Missing open parentheses in declaration of function '"
<< tokens.GetTokenText(tree.GetNodeToken(*name_n)) << "' on line "
<< tokens.GetLineNumber(function_intro_token) << "!\n";
emitter.EmitError<ExpectedFunctionParams>(open_paren);
SkipPastLikelyDeclarationEnd(function_intro_token);
return add_error_function_node();
}
@@ -309,9 +342,7 @@ auto ParseTree::Parser::ParseFunctionDeclaration() -> Node {
ParseCodeBlock();
} else if (!ConsumeAndAddLeafNodeIf(TokenKind::Semi(),
ParseNodeKind::DeclarationEnd())) {
llvm::errs() << "ERROR: Function declaration not terminated by a "
"semicolon on line "
<< tokens.GetLineNumber(close_paren) << "!\n";
emitter.EmitError<ExpectedFunctionBodyOrSemi>(*position);
if (tokens.GetLine(*position) == tokens.GetLine(close_paren)) {
// Only need to skip if we've not already found a new line.
SkipPastLikelyDeclarationEnd(function_intro_token);
@@ -344,9 +375,7 @@ auto ParseTree::Parser::ParseDeclaration() -> llvm::Optional<Node> {
}
// We didn't recognize an introducer for a valid declaration.
llvm::errs() << "ERROR: Unrecognized declaration introducer '"
<< tokens.GetTokenText(t) << "' on line "
<< tokens.GetLineNumber(t) << "!\n";
emitter.EmitError<UnrecognizedDeclaration>(t);
// Skip forward past any end of a declaration we simply didn't understand so
// that we can find the start of the next declaration or the end of a scope.