mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 19:51:09 +01:00
Simplify error reporting interface (#291)
This commit is contained in:
+33
-96
@@ -21,59 +21,35 @@
|
||||
|
||||
namespace Carbon {
|
||||
|
||||
struct TrailingComment {
|
||||
struct TrailingComment : SimpleDiagnostic<TrailingComment> {
|
||||
static constexpr llvm::StringLiteral ShortName = "syntax-comments";
|
||||
static constexpr llvm::StringLiteral Message =
|
||||
"Trailing comments are not permitted.";
|
||||
|
||||
struct Substitutions {};
|
||||
static auto Format(const Substitutions&) -> std::string {
|
||||
return Message.str();
|
||||
}
|
||||
};
|
||||
|
||||
struct NoWhitespaceAfterCommentIntroducer {
|
||||
struct NoWhitespaceAfterCommentIntroducer
|
||||
: SimpleDiagnostic<NoWhitespaceAfterCommentIntroducer> {
|
||||
static constexpr llvm::StringLiteral ShortName = "syntax-comments";
|
||||
static constexpr llvm::StringLiteral Message =
|
||||
"Whitespace is required after '//'.";
|
||||
|
||||
struct Substitutions {};
|
||||
static auto Format(const Substitutions&) -> std::string {
|
||||
return Message.str();
|
||||
}
|
||||
};
|
||||
|
||||
struct UnmatchedClosing {
|
||||
struct UnmatchedClosing : SimpleDiagnostic<UnmatchedClosing> {
|
||||
static constexpr llvm::StringLiteral ShortName = "syntax-balanced-delimiters";
|
||||
static constexpr llvm::StringLiteral Message =
|
||||
"Closing symbol without a corresponding opening symbol.";
|
||||
|
||||
struct Substitutions {};
|
||||
static auto Format(const Substitutions&) -> std::string {
|
||||
return Message.str();
|
||||
}
|
||||
};
|
||||
|
||||
struct MismatchedClosing {
|
||||
struct MismatchedClosing : SimpleDiagnostic<MismatchedClosing> {
|
||||
static constexpr llvm::StringLiteral ShortName = "syntax-balanced-delimiters";
|
||||
static constexpr llvm::StringLiteral Message =
|
||||
"Closing symbol does not match most recent opening symbol.";
|
||||
|
||||
struct Substitutions {};
|
||||
static auto Format(const Substitutions&) -> std::string {
|
||||
return Message.str();
|
||||
}
|
||||
};
|
||||
|
||||
struct EmptyDigitSequence {
|
||||
struct EmptyDigitSequence : SimpleDiagnostic<EmptyDigitSequence> {
|
||||
static constexpr llvm::StringLiteral ShortName = "syntax-invalid-number";
|
||||
static constexpr llvm::StringLiteral Message =
|
||||
"Empty digit sequence in numeric literal.";
|
||||
|
||||
struct Substitutions {};
|
||||
static auto Format(const Substitutions&) -> std::string {
|
||||
return Message.str();
|
||||
}
|
||||
};
|
||||
|
||||
struct InvalidDigit {
|
||||
@@ -84,27 +60,19 @@ struct InvalidDigit {
|
||||
int radix;
|
||||
};
|
||||
static auto Format(const Substitutions& subst) -> std::string {
|
||||
// TODO: Switch Format to using raw_ostream so we can easily use
|
||||
// llvm::format here.
|
||||
llvm::StringRef digit_str(&subst.digit, 1);
|
||||
return (llvm::Twine("Invalid digit '") + digit_str + "' in " +
|
||||
(subst.radix == 2 ? "binary"
|
||||
: subst.radix == 16 ? "hexadecimal"
|
||||
: "decimal") +
|
||||
" numeric literal.")
|
||||
return llvm::formatv("Invalid digit '{0}' in {1} numeric literal.",
|
||||
subst.digit,
|
||||
(subst.radix == 2 ? "binary"
|
||||
: subst.radix == 16 ? "hexadecimal"
|
||||
: "decimal"))
|
||||
.str();
|
||||
}
|
||||
};
|
||||
|
||||
struct InvalidDigitSeparator {
|
||||
struct InvalidDigitSeparator : SimpleDiagnostic<InvalidDigitSeparator> {
|
||||
static constexpr llvm::StringLiteral ShortName = "syntax-invalid-number";
|
||||
static constexpr llvm::StringLiteral Message =
|
||||
"Misplaced digit separator in numeric literal.";
|
||||
|
||||
struct Substitutions {};
|
||||
static auto Format(const Substitutions&) -> std::string {
|
||||
return Message.str();
|
||||
}
|
||||
};
|
||||
|
||||
struct IrregularDigitSeparators {
|
||||
@@ -116,34 +84,25 @@ struct IrregularDigitSeparators {
|
||||
};
|
||||
static auto Format(const Substitutions& subst) -> std::string {
|
||||
assert((subst.radix == 10 || subst.radix == 16) && "unexpected radix");
|
||||
return (llvm::Twine("Digit separators in ") +
|
||||
(subst.radix == 10 ? "decimal" : "hexadecimal") +
|
||||
" should appear every " + (subst.radix == 10 ? "3" : "4") +
|
||||
" characters from the right.")
|
||||
return llvm::formatv(
|
||||
"Digit separators in {0} number should appear every {1} "
|
||||
"characters from the right.",
|
||||
(subst.radix == 10 ? "decimal" : "hexadecimal"),
|
||||
(subst.radix == 10 ? "3" : "4"))
|
||||
.str();
|
||||
}
|
||||
};
|
||||
|
||||
struct UnknownBaseSpecifier {
|
||||
struct UnknownBaseSpecifier : SimpleDiagnostic<UnknownBaseSpecifier> {
|
||||
static constexpr llvm::StringLiteral ShortName = "syntax-invalid-number";
|
||||
static constexpr llvm::StringLiteral Message =
|
||||
"Unknown base specifier in numeric literal.";
|
||||
|
||||
struct Substitutions {};
|
||||
static auto Format(const Substitutions&) -> std::string {
|
||||
return Message.str();
|
||||
}
|
||||
};
|
||||
|
||||
struct BinaryRealLiteral {
|
||||
struct BinaryRealLiteral : SimpleDiagnostic<BinaryRealLiteral> {
|
||||
static constexpr llvm::StringLiteral ShortName = "syntax-invalid-number";
|
||||
static constexpr llvm::StringLiteral Message =
|
||||
"Binary real number literals are not supported.";
|
||||
|
||||
struct Substitutions {};
|
||||
static auto Format(const Substitutions&) -> std::string {
|
||||
return Message.str();
|
||||
}
|
||||
};
|
||||
|
||||
struct WrongRealLiteralExponent {
|
||||
@@ -153,23 +112,17 @@ struct WrongRealLiteralExponent {
|
||||
char expected;
|
||||
};
|
||||
static auto Format(const Substitutions& subst) -> std::string {
|
||||
char expected_str[] = {subst.expected, '\0'};
|
||||
return (llvm::Twine("Expected '") + expected_str +
|
||||
"' to introduce exponent.")
|
||||
return llvm::formatv("Expected '{0}' to introduce exponent.",
|
||||
subst.expected)
|
||||
.str();
|
||||
}
|
||||
};
|
||||
|
||||
struct UnrecognizedCharacters {
|
||||
struct UnrecognizedCharacters : SimpleDiagnostic<UnrecognizedCharacters> {
|
||||
static constexpr llvm::StringLiteral ShortName =
|
||||
"syntax-unrecognized-characters";
|
||||
static constexpr llvm::StringLiteral Message =
|
||||
"Encountered unrecognized characters while parsing.";
|
||||
|
||||
struct Substitutions {};
|
||||
static auto Format(const Substitutions&) -> std::string {
|
||||
return Message.str();
|
||||
}
|
||||
};
|
||||
|
||||
// TODO(zygoloid): Update this to match whatever we decide qualifies as
|
||||
@@ -387,24 +340,19 @@ class NumericLiteralParser {
|
||||
// next to another digit separator, or at the end.
|
||||
if (!allow_digit_separators || i == 0 || text[i - 1] == '_' ||
|
||||
i + 1 == n) {
|
||||
emitter.EmitError<InvalidDigitSeparator>(
|
||||
[&](InvalidDigitSeparator::Substitutions&) {});
|
||||
emitter.EmitError<InvalidDigitSeparator>();
|
||||
recovered_from_error = true;
|
||||
}
|
||||
++num_digit_separators;
|
||||
continue;
|
||||
}
|
||||
|
||||
emitter.EmitError<InvalidDigit>([&](InvalidDigit::Substitutions& subst) {
|
||||
subst.digit = c;
|
||||
subst.radix = radix;
|
||||
});
|
||||
emitter.EmitError<InvalidDigit>({.digit = c, .radix = radix});
|
||||
return {.ok = false};
|
||||
}
|
||||
|
||||
if (num_digit_separators == static_cast<int>(text.size())) {
|
||||
emitter.EmitError<EmptyDigitSequence>(
|
||||
[&](EmptyDigitSequence::Substitutions&) {});
|
||||
emitter.EmitError<EmptyDigitSequence>();
|
||||
return {.ok = false};
|
||||
}
|
||||
|
||||
@@ -425,10 +373,7 @@ class NumericLiteralParser {
|
||||
"given wrong number of digit separators");
|
||||
|
||||
auto diagnose_irregular_digit_separators = [&] {
|
||||
emitter.EmitError<IrregularDigitSeparators>(
|
||||
[&](IrregularDigitSeparators::Substitutions& subst) {
|
||||
subst.radix = radix;
|
||||
});
|
||||
emitter.EmitError<IrregularDigitSeparators>({.radix = radix});
|
||||
recovered_from_error = true;
|
||||
};
|
||||
|
||||
@@ -452,8 +397,7 @@ class NumericLiteralParser {
|
||||
// Check that we don't have a '0' prefix on a non-zero decimal integer.
|
||||
auto CheckLeadingZero() -> bool {
|
||||
if (radix == 10 && int_part.startswith("0") && int_part != "0") {
|
||||
emitter.EmitError<UnknownBaseSpecifier>(
|
||||
[&](UnknownBaseSpecifier::Substitutions& subst) {});
|
||||
emitter.EmitError<UnknownBaseSpecifier>();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -474,8 +418,7 @@ class NumericLiteralParser {
|
||||
}
|
||||
|
||||
if (radix == 2) {
|
||||
emitter.EmitError<BinaryRealLiteral>(
|
||||
[&](BinaryRealLiteral::Substitutions& subst) {});
|
||||
emitter.EmitError<BinaryRealLiteral>();
|
||||
recovered_from_error = true;
|
||||
// Carry on and parse the binary real literal anyway.
|
||||
}
|
||||
@@ -497,9 +440,7 @@ class NumericLiteralParser {
|
||||
char expected_exponent_kind = (radix == 10 ? 'e' : 'p');
|
||||
if (literal.text[literal.exponent] != expected_exponent_kind) {
|
||||
emitter.EmitError<WrongRealLiteralExponent>(
|
||||
[&](WrongRealLiteralExponent::Substitutions& subst) {
|
||||
subst.expected = expected_exponent_kind;
|
||||
});
|
||||
{.expected = expected_exponent_kind});
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -617,14 +558,12 @@ class TokenizedBuffer::Lexer {
|
||||
if (source_text.startswith("//")) {
|
||||
// Any comment must be the only non-whitespace on the line.
|
||||
if (set_indent) {
|
||||
emitter.EmitError<TrailingComment>(
|
||||
[](TrailingComment::Substitutions&) {});
|
||||
emitter.EmitError<TrailingComment>();
|
||||
buffer.has_errors = true;
|
||||
}
|
||||
// The introducer '//' must be followed by whitespace or EOF.
|
||||
if (source_text.size() > 2 && !isSpace(source_text[2])) {
|
||||
emitter.EmitError<NoWhitespaceAfterCommentIntroducer>(
|
||||
[](NoWhitespaceAfterCommentIntroducer::Substitutions&) {});
|
||||
emitter.EmitError<NoWhitespaceAfterCommentIntroducer>();
|
||||
buffer.has_errors = true;
|
||||
}
|
||||
while (!source_text.empty() && source_text.front() != '\n') {
|
||||
@@ -779,8 +718,7 @@ class TokenizedBuffer::Lexer {
|
||||
closing_token_info.error_length = kind.GetFixedSpelling().size();
|
||||
buffer.has_errors = true;
|
||||
|
||||
emitter.EmitError<UnmatchedClosing>(
|
||||
[](UnmatchedClosing::Substitutions&) {});
|
||||
emitter.EmitError<UnmatchedClosing>();
|
||||
// Note that this still returns true as we do consume a symbol.
|
||||
return token;
|
||||
}
|
||||
@@ -809,8 +747,7 @@ class TokenizedBuffer::Lexer {
|
||||
|
||||
open_groups.pop_back();
|
||||
buffer.has_errors = true;
|
||||
emitter.EmitError<MismatchedClosing>(
|
||||
[](MismatchedClosing::Substitutions&) {});
|
||||
emitter.EmitError<MismatchedClosing>();
|
||||
|
||||
// TODO: do a smarter backwards scan for where to put the closing
|
||||
// token.
|
||||
|
||||
Reference in New Issue
Block a user