Switch from manually tracking whether we've emitted any errors to asking the diagnostics machinery. (#406)

This commit is contained in:
Richard Smith
2021-03-22 14:01:01 -07:00
committed by GitHub
parent cfe52b5705
commit 9400c1c8ae
11 changed files with 150 additions and 138 deletions
+37 -4
View File
@@ -23,6 +23,13 @@ namespace Carbon {
// TODO: turn this into a much more reasonable API when we add some actual
// uses of it.
struct Diagnostic {
enum Level {
// A warning diagnostic, indicating a likely problem with the program.
Warning,
// An error diagnostic, indicating that the program is not valid.
Error,
};
struct Location {
// Name of the file or buffer that this diagnostic refers to.
std::string file_name;
@@ -32,6 +39,7 @@ struct Diagnostic {
int32_t column_number;
};
Level level;
Location location;
llvm::StringRef short_name;
std::string message;
@@ -84,9 +92,10 @@ class DiagnosticEmitter {
auto EmitError(LocationT location, DiagnosticT diag) -> void {
// TODO: Encode the diagnostic kind in the Diagnostic object rather than
// hardcoding an "error: " prefix.
consumer_->HandleDiagnostic({.location = translator_->GetLocation(location),
consumer_->HandleDiagnostic({.level = Diagnostic::Error,
.location = translator_->GetLocation(location),
.short_name = DiagnosticT::ShortName,
.message = "error: " + diag.Format()});
.message = diag.Format()});
}
// Emits a stateless error unconditionally.
@@ -107,9 +116,10 @@ class DiagnosticEmitter {
// TODO: Encode the diagnostic kind in the Diagnostic object rather than
// hardcoding a "warning: " prefix.
consumer_->HandleDiagnostic(
{.location = translator_->GetLocation(location),
{.level = Diagnostic::Warning,
.location = translator_->GetLocation(location),
.short_name = DiagnosticT::ShortName,
.message = "warning: " + diag.Format()});
.message = diag.Format()});
}
}
@@ -139,6 +149,29 @@ struct SimpleDiagnostic {
static auto Format() -> std::string { return Derived::Message.str(); }
};
// Diagnostic consumer adaptor that tracks whether any errors have been
// produced.
class ErrorTrackingDiagnosticConsumer : public DiagnosticConsumer {
public:
ErrorTrackingDiagnosticConsumer(DiagnosticConsumer& next_consumer)
: next_consumer(&next_consumer) {}
auto HandleDiagnostic(const Diagnostic& diagnostic) -> void override {
seen_error |= diagnostic.level == Diagnostic::Error;
next_consumer->HandleDiagnostic(diagnostic);
}
// Returns whether we've seen an error since the last reset.
auto SeenError() const -> bool { return seen_error; }
// Reset whether we've seen an error.
auto Reset() -> void { seen_error = false; }
private:
DiagnosticConsumer* next_consumer;
bool seen_error = false;
};
} // namespace Carbon
#endif // DIAGNOSTICS_DIAGNOSTICEMITTER_H_
+17 -14
View File
@@ -14,6 +14,7 @@ namespace Carbon {
namespace {
using Testing::DiagnosticAt;
using Testing::DiagnosticLevel;
using Testing::DiagnosticMessage;
using Testing::DiagnosticShortName;
using ::testing::ElementsAre;
@@ -47,12 +48,14 @@ TEST(DiagTest, EmitErrors) {
Testing::MockDiagnosticConsumer consumer;
DiagnosticEmitter<int> emitter(translator, consumer);
EXPECT_CALL(consumer, HandleDiagnostic(AllOf(
DiagnosticAt(1, 1), DiagnosticMessage("error: M1"),
DiagnosticShortName("fake-diagnostic"))));
EXPECT_CALL(consumer, HandleDiagnostic(AllOf(
DiagnosticAt(1, 2), DiagnosticMessage("error: M2"),
DiagnosticShortName("fake-diagnostic"))));
EXPECT_CALL(consumer, HandleDiagnostic(
AllOf(DiagnosticLevel(Diagnostic::Error),
DiagnosticAt(1, 1), DiagnosticMessage("M1"),
DiagnosticShortName("fake-diagnostic"))));
EXPECT_CALL(consumer, HandleDiagnostic(
AllOf(DiagnosticLevel(Diagnostic::Error),
DiagnosticAt(1, 2), DiagnosticMessage("M2"),
DiagnosticShortName("fake-diagnostic"))));
emitter.EmitError<FakeDiagnostic>(1, {.message = "M1"});
emitter.EmitError<FakeDiagnostic>(2, {.message = "M2"});
@@ -65,14 +68,14 @@ TEST(DiagTest, EmitWarnings) {
Testing::MockDiagnosticConsumer consumer;
DiagnosticEmitter<int> emitter(translator, consumer);
EXPECT_CALL(consumer,
HandleDiagnostic(AllOf(DiagnosticAt(1, 3),
DiagnosticMessage("warning: M1"),
DiagnosticShortName("fake-diagnostic"))));
EXPECT_CALL(consumer,
HandleDiagnostic(AllOf(DiagnosticAt(1, 5),
DiagnosticMessage("warning: M3"),
DiagnosticShortName("fake-diagnostic"))));
EXPECT_CALL(consumer, HandleDiagnostic(
AllOf(DiagnosticLevel(Diagnostic::Warning),
DiagnosticAt(1, 3), DiagnosticMessage("M1"),
DiagnosticShortName("fake-diagnostic"))));
EXPECT_CALL(consumer, HandleDiagnostic(
AllOf(DiagnosticLevel(Diagnostic::Warning),
DiagnosticAt(1, 5), DiagnosticMessage("M3"),
DiagnosticShortName("fake-diagnostic"))));
emitter.EmitWarningIf<FakeDiagnostic>(3, [](FakeDiagnostic& diagnostic) {
diagnostic.message = "M1";
+4
View File
@@ -35,6 +35,10 @@ MATCHER_P2(DiagnosticAt, line, column, "") {
return true;
}
auto DiagnosticLevel(Diagnostic::Level level) -> auto {
return testing::Field(&Diagnostic::level, level);
}
template <typename Matcher>
auto DiagnosticMessage(Matcher&& inner_matcher) -> auto {
return testing::Field(&Diagnostic::message,
+3 -10
View File
@@ -166,13 +166,9 @@ LexedNumericLiteral::Parser::Parser(DiagnosticEmitter<const char*>& emitter,
// Check that the numeric literal token is syntactically valid and meaningful,
// and diagnose if not.
auto LexedNumericLiteral::Parser::Check() -> CheckResult {
if (!CheckLeadingZero() || !CheckIntPart() || !CheckFractionalPart() ||
!CheckExponentPart()) {
return UnrecoverableError;
}
return recovered_from_error ? RecoverableError : Valid;
auto LexedNumericLiteral::Parser::Check() -> bool {
return CheckLeadingZero() && CheckIntPart() && CheckFractionalPart() &&
CheckExponentPart();
}
// Parse a string that is known to be a valid base-radix integer into an
@@ -280,7 +276,6 @@ auto LexedNumericLiteral::Parser::CheckDigitSequence(
if (!allow_digit_separators || i == 0 || text[i - 1] == '_' ||
i + 1 == n) {
emitter.EmitError<InvalidDigitSeparator>(text.begin() + i);
recovered_from_error = true;
}
++num_digit_separators;
continue;
@@ -322,7 +317,6 @@ auto LexedNumericLiteral::Parser::CheckDigitSeparatorPlacement(
auto diagnose_irregular_digit_separators = [&]() {
emitter.EmitError<IrregularDigitSeparators>(text.begin(), {.radix = radix});
recovered_from_error = true;
};
// For decimal and hexadecimal digit sequences, digit separators must form
@@ -372,7 +366,6 @@ auto LexedNumericLiteral::Parser::CheckFractionalPart() -> bool {
if (radix == 2) {
emitter.EmitError<BinaryRealLiteral>(literal.text.begin() +
literal.radix_point);
recovered_from_error = true;
// Carry on and parse the binary real literal anyway.
}
+4 -15
View File
@@ -57,19 +57,11 @@ class LexedNumericLiteral::Parser {
return literal.radix_point == static_cast<int>(literal.text.size());
}
enum CheckResult {
// The token is valid.
Valid,
// The token is invalid, but we've diagnosed and recovered from the error.
RecoverableError,
// The token is invalid, and we've diagnosed, but we can't assign meaning
// to it.
UnrecoverableError,
};
// Check that the numeric literal token is syntactically valid and
// meaningful, and diagnose if not.
auto Check() -> CheckResult;
// meaningful, and diagnose if not. Returns `true` if the token was
// sufficiently valid that we could determine its meaning. If `false` is
// returned, a diagnostic has already been issued.
auto Check() -> bool;
// Get the radix of this token. One of 2, 10, or 16.
auto GetRadix() -> int { return radix; }
@@ -119,9 +111,6 @@ class LexedNumericLiteral::Parser {
// True if we found a `-` before `exponent_part`.
bool exponent_is_negative = false;
// True if we produced an error but recovered.
bool recovered_from_error = false;
};
} // namespace Carbon
+1 -1
View File
@@ -24,7 +24,7 @@ extern "C" int LLVMFuzzerTestOneInput(const unsigned char* data,
LexedNumericLiteral::Parser parser(NullDiagnosticEmitter<const char*>(),
*token);
if (parser.Check() == LexedNumericLiteral::Parser::UnrecoverableError) {
if (!parser.Check()) {
// Lexically OK, but token is meaningless.
return 0;
}
+31 -12
View File
@@ -17,6 +17,9 @@ namespace Carbon {
namespace {
struct NumericLiteralTest : ::testing::Test {
NumericLiteralTest() : error_tracker(ConsoleDiagnosticConsumer()) {}
ErrorTrackingDiagnosticConsumer error_tracker;
std::vector<std::unique_ptr<Testing::SingleTokenDiagnosticTranslator>>
translators;
std::vector<std::unique_ptr<DiagnosticEmitter<const char*>>> emitters;
@@ -32,7 +35,7 @@ struct NumericLiteralTest : ::testing::Test {
translators.push_back(
std::make_unique<Testing::SingleTokenDiagnosticTranslator>(text));
emitters.push_back(std::make_unique<DiagnosticEmitter<const char*>>(
*translators.back(), ConsoleDiagnosticConsumer()));
*translators.back(), error_tracker));
return LexedNumericLiteral::Parser(*emitters.back(), Lex(text));
}
};
@@ -50,8 +53,10 @@ TEST_F(NumericLiteralTest, HandlesIntegerLiteral) {
{.token = "1_234_567", .value = 1'234'567, .radix = 10},
};
for (Testcase testcase : testcases) {
error_tracker.Reset();
auto parser = Parse(testcase.token);
EXPECT_EQ(parser.Check(), parser.Valid) << testcase.token;
EXPECT_TRUE(parser.Check()) << testcase.token;
EXPECT_FALSE(error_tracker.SeenError()) << testcase.token;
EXPECT_EQ(parser.IsInteger(), true);
EXPECT_EQ(parser.GetMantissa().getZExtValue(), testcase.value);
EXPECT_EQ(parser.GetExponent().getSExtValue(), 0);
@@ -75,8 +80,10 @@ TEST_F(NumericLiteralTest, ValidatesBaseSpecifier) {
"0b0000000",
};
for (llvm::StringLiteral literal : valid) {
error_tracker.Reset();
auto parser = Parse(literal);
EXPECT_EQ(parser.Check(), parser.Valid) << literal;
EXPECT_TRUE(parser.Check()) << literal;
EXPECT_FALSE(error_tracker.SeenError()) << literal;
}
llvm::StringLiteral invalid[] = {
@@ -86,8 +93,10 @@ TEST_F(NumericLiteralTest, ValidatesBaseSpecifier) {
"0x_", "0b_",
};
for (llvm::StringLiteral literal : invalid) {
error_tracker.Reset();
auto parser = Parse(literal);
EXPECT_EQ(parser.Check(), parser.UnrecoverableError) << literal;
EXPECT_FALSE(parser.Check()) << literal;
EXPECT_TRUE(error_tracker.SeenError()) << literal;
}
}
@@ -108,8 +117,10 @@ TEST_F(NumericLiteralTest, ValidatesIntegerDigitSeparators) {
"0b111_0000",
};
for (llvm::StringLiteral literal : valid) {
error_tracker.Reset();
auto parser = Parse(literal);
EXPECT_EQ(parser.Check(), parser.Valid) << literal;
EXPECT_TRUE(parser.Check()) << literal;
EXPECT_FALSE(error_tracker.SeenError()) << literal;
}
llvm::StringLiteral invalid[] = {
@@ -134,8 +145,10 @@ TEST_F(NumericLiteralTest, ValidatesIntegerDigitSeparators) {
"0b1_01_01_",
};
for (llvm::StringLiteral literal : invalid) {
error_tracker.Reset();
auto parser = Parse(literal);
EXPECT_EQ(parser.Check(), parser.RecoverableError) << literal;
EXPECT_TRUE(parser.Check()) << literal;
EXPECT_TRUE(error_tracker.SeenError()) << literal;
}
}
@@ -186,10 +199,10 @@ TEST_F(NumericLiteralTest, HandlesRealLiteral) {
.radix = 2},
};
for (Testcase testcase : testcases) {
error_tracker.Reset();
auto parser = Parse(testcase.token);
EXPECT_EQ(parser.Check(),
testcase.radix == 2 ? parser.RecoverableError : parser.Valid)
<< testcase.token;
EXPECT_TRUE(parser.Check()) << testcase.token;
EXPECT_EQ(error_tracker.SeenError(), testcase.radix == 2) << testcase.token;
EXPECT_EQ(parser.IsInteger(), false);
EXPECT_EQ(parser.GetMantissa().getZExtValue(), testcase.mantissa);
EXPECT_EQ(parser.GetExponent().getSExtValue(), testcase.exponent);
@@ -199,8 +212,10 @@ TEST_F(NumericLiteralTest, HandlesRealLiteral) {
TEST_F(NumericLiteralTest, HandlesRealLiteralOverflow) {
llvm::StringLiteral input = "0x1.000001p-9223372036854775800";
error_tracker.Reset();
auto parser = Parse(input);
EXPECT_EQ(parser.Check(), parser.Valid);
EXPECT_TRUE(parser.Check());
EXPECT_FALSE(error_tracker.SeenError());
EXPECT_EQ(parser.GetMantissa(), 0x1000001);
EXPECT_EQ((parser.GetExponent() + 9223372036854775800).getSExtValue(), -24);
EXPECT_EQ(parser.GetRadix(), 16);
@@ -213,8 +228,10 @@ TEST_F(NumericLiteralTest, ValidatesRealLiterals) {
"123.4e56_78", "0x12_34.5", "0x12.3_4", "0x12.34p5_6",
};
for (llvm::StringLiteral literal : invalid_digit_separators) {
error_tracker.Reset();
auto parser = Parse(literal);
EXPECT_EQ(parser.Check(), parser.RecoverableError) << literal;
EXPECT_TRUE(parser.Check()) << literal;
EXPECT_TRUE(error_tracker.SeenError()) << literal;
}
llvm::StringLiteral invalid[] = {
@@ -263,8 +280,10 @@ TEST_F(NumericLiteralTest, ValidatesRealLiterals) {
"0x0.0p-A",
};
for (llvm::StringLiteral literal : invalid) {
error_tracker.Reset();
auto parser = Parse(literal);
EXPECT_EQ(parser.Check(), parser.UnrecoverableError) << literal;
EXPECT_FALSE(parser.Check()) << literal;
EXPECT_TRUE(error_tracker.SeenError()) << literal;
}
}
+21 -37
View File
@@ -168,32 +168,22 @@ static auto ComputeIndentOfFinalLine(llvm::StringRef text) -> llvm::StringRef {
llvm_unreachable("Given text is required to contain a newline.");
}
namespace {
// The leading whitespace in a multi-line string literal.
struct Indent {
llvm::StringRef indent;
bool has_errors;
};
} // namespace
// Check the literal is indented properly, if it's a multi-line litera.
// Find the leading whitespace that should be removed from each line of a
// multi-line string literal.
static auto CheckIndent(LexerDiagnosticEmitter& emitter, llvm::StringRef text,
llvm::StringRef content) -> Indent {
llvm::StringRef content) -> llvm::StringRef {
// Find the leading horizontal whitespace on the final line of this literal.
// Note that for an empty literal, this might not be inside the content.
llvm::StringRef indent = ComputeIndentOfFinalLine(text);
bool has_errors = false;
// The last line is not permitted to contain any content after its
// indentation.
if (indent.end() != content.end()) {
emitter.EmitError<ContentBeforeStringTerminator>(indent.end());
has_errors = true;
}
return {.indent = indent, .has_errors = has_errors};
return indent;
}
// Expand a `\u{HHHHHH}` escape sequence into a sequence of UTF-8 code units.
@@ -233,7 +223,7 @@ static auto ExpandUnicodeEscapeSequence(LexerDiagnosticEmitter& emitter,
// `\n`), and will be updated to remove the leading escape sequence.
static auto ExpandAndConsumeEscapeSequence(LexerDiagnosticEmitter& emitter,
llvm::StringRef& content,
std::string& result) -> bool {
std::string& result) -> void {
assert(!content.empty() && "should have escaped closing delimiter");
char first = content.front();
content = content.drop_front(1);
@@ -241,36 +231,36 @@ static auto ExpandAndConsumeEscapeSequence(LexerDiagnosticEmitter& emitter,
switch (first) {
case 't':
result += '\t';
return true;
return;
case 'n':
result += '\n';
return true;
return;
case 'r':
result += '\r';
return true;
return;
case '"':
result += '"';
return true;
return;
case '\'':
result += '\'';
return true;
return;
case '\\':
result += '\\';
return true;
return;
case '0':
result += '\0';
if (!content.empty() && IsDecimalDigit(content.front())) {
emitter.EmitError<DecimalEscapeSequence>(content.begin());
return false;
return;
}
return true;
return;
case 'x':
if (content.size() >= 2 && IsUpperHexDigit(content[0]) &&
IsUpperHexDigit(content[1])) {
result +=
static_cast<char>(llvm::hexFromNibbles(content[0], content[1]));
content = content.drop_front(2);
return true;
return;
}
emitter.EmitError<HexadecimalEscapeMissingDigits>(content.begin());
break;
@@ -284,7 +274,7 @@ static auto ExpandAndConsumeEscapeSequence(LexerDiagnosticEmitter& emitter,
break;
}
content = remaining;
return true;
return;
}
}
emitter.EmitError<UnicodeEscapeMissingBracedDigits>(content.begin());
@@ -300,16 +290,14 @@ static auto ExpandAndConsumeEscapeSequence(LexerDiagnosticEmitter& emitter,
// issued a diagnostic. For error recovery purposes, expand this escape
// sequence to itself, dropping the introducer (for example, `\q` -> `q`).
result += first;
return false;
}
// Expand any escape sequences in the given string literal.
static auto ExpandEscapeSequencesAndRemoveIndent(
LexerDiagnosticEmitter& emitter, llvm::StringRef contents, int hash_level,
llvm::StringRef indent) -> LexedStringLiteral::ExpandedValue {
llvm::StringRef indent) -> std::string {
std::string result;
result.reserve(contents.size());
bool has_errors = false;
llvm::SmallString<16> escape("\\");
escape.resize(1 + hash_level, '#');
@@ -324,7 +312,6 @@ static auto ExpandEscapeSequencesAndRemoveIndent(
contents = contents.drop_while(IsHorizontalWhitespace);
if (!contents.startswith("\n")) {
emitter.EmitError<MismatchedIndentInString>(line_start);
has_errors = true;
}
}
@@ -335,7 +322,7 @@ static auto ExpandEscapeSequencesAndRemoveIndent(
contents = contents.substr(end_of_regular_text);
if (contents.empty()) {
return {.result = result, .has_errors = has_errors};
return result;
}
if (contents.consume_front("\n")) {
@@ -364,20 +351,17 @@ static auto ExpandEscapeSequencesAndRemoveIndent(
}
// Handle this escape sequence.
if (!ExpandAndConsumeEscapeSequence(emitter, contents, result)) {
has_errors = true;
}
ExpandAndConsumeEscapeSequence(emitter, contents, result);
}
}
}
auto LexedStringLiteral::ComputeValue(LexerDiagnosticEmitter& emitter) const
-> ExpandedValue {
auto indent = multi_line ? CheckIndent(emitter, text, content) : Indent();
auto result = ExpandEscapeSequencesAndRemoveIndent(emitter, content,
hash_level, indent.indent);
result.has_errors |= indent.has_errors;
return result;
-> std::string {
llvm::StringRef indent =
multi_line ? CheckIndent(emitter, text, content) : llvm::StringRef();
return ExpandEscapeSequencesAndRemoveIndent(emitter, content, hash_level,
indent);
}
} // namespace Carbon
+2 -8
View File
@@ -23,16 +23,10 @@ class LexedStringLiteral {
static auto Lex(llvm::StringRef source_text)
-> llvm::Optional<LexedStringLiteral>;
// The result of expanding escape sequences in a string literal.
struct ExpandedValue {
std::string result;
bool has_errors;
};
// Expand any escape sequences in the given string literal and compute the
// resulting value.
// resulting value. This handles error recovery internally and cannot fail.
auto ComputeValue(DiagnosticEmitter<const char*>& emitter) const
-> ExpandedValue;
-> std::string;
private:
LexedStringLiteral(llvm::StringRef text, llvm::StringRef content,
+14 -8
View File
@@ -13,6 +13,10 @@ namespace Carbon {
namespace {
struct StringLiteralTest : ::testing::Test {
StringLiteralTest() : error_tracker(ConsoleDiagnosticConsumer()) {}
ErrorTrackingDiagnosticConsumer error_tracker;
auto Lex(llvm::StringRef text) -> LexedStringLiteral {
llvm::Optional<LexedStringLiteral> result = LexedStringLiteral::Lex(text);
assert(result);
@@ -20,11 +24,10 @@ struct StringLiteralTest : ::testing::Test {
return *result;
}
auto Parse(llvm::StringRef text) -> LexedStringLiteral::ExpandedValue {
auto Parse(llvm::StringRef text) -> std::string {
LexedStringLiteral token = Lex(text);
Testing::SingleTokenDiagnosticTranslator translator(text);
DiagnosticEmitter<const char*> emitter(translator,
ConsoleDiagnosticConsumer());
DiagnosticEmitter<const char*> emitter(translator, error_tracker);
return token.ComputeValue(emitter);
}
};
@@ -182,9 +185,10 @@ TEST_F(StringLiteralTest, StringLiteralContents) {
};
for (auto [test, contents] : testcases) {
error_tracker.Reset();
auto value = Parse(test.trim());
EXPECT_FALSE(value.has_errors) << "`" << test << "`";
EXPECT_EQ(value.result, contents);
EXPECT_FALSE(error_tracker.SeenError()) << "`" << test << "`";
EXPECT_EQ(value, contents);
}
}
@@ -205,9 +209,10 @@ TEST_F(StringLiteralTest, StringLiteralBadIndent) {
};
for (auto [test, contents] : testcases) {
error_tracker.Reset();
auto value = Parse(test);
EXPECT_TRUE(value.has_errors) << "`" << test << "`";
EXPECT_EQ(value.result, contents);
EXPECT_TRUE(error_tracker.SeenError()) << "`" << test << "`";
EXPECT_EQ(value, contents);
}
}
@@ -253,8 +258,9 @@ TEST_F(StringLiteralTest, StringLiteralBadEscapeSequence) {
};
for (llvm::StringLiteral test : testcases) {
error_tracker.Reset();
auto value = Parse(test);
EXPECT_TRUE(value.has_errors) << "`" << test << "`";
EXPECT_TRUE(error_tracker.SeenError()) << "`" << test << "`";
// TODO: Test value produced by error recovery.
}
}
+16 -29
View File
@@ -132,13 +132,11 @@ class TokenizedBuffer::Lexer {
// Any comment must be the only non-whitespace on the line.
if (set_indent) {
emitter.EmitError<TrailingComment>(source_text.begin());
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>(
source_text.begin() + 2);
buffer.has_errors = true;
}
while (!source_text.empty() && source_text.front() != '\n') {
++current_column;
@@ -207,24 +205,14 @@ class TokenizedBuffer::Lexer {
LexedNumericLiteral::Parser literal_parser(emitter, *literal);
switch (literal_parser.Check()) {
case LexedNumericLiteral::Parser::UnrecoverableError: {
auto token = buffer.AddToken({
.kind = TokenKind::Error(),
.token_line = current_line,
.column = int_column,
.error_length = token_size,
});
buffer.has_errors = true;
return token;
}
case LexedNumericLiteral::Parser::RecoverableError:
buffer.has_errors = true;
break;
case LexedNumericLiteral::Parser::Valid:
break;
if (!literal_parser.Check()) {
auto token = buffer.AddToken({
.kind = TokenKind::Error(),
.token_line = current_line,
.column = int_column,
.error_length = token_size,
});
return token;
}
if (literal_parser.IsInteger()) {
@@ -281,16 +269,12 @@ class TokenizedBuffer::Lexer {
}
}
// Determine string literal value.
auto expanded = literal->ComputeValue(emitter);
buffer.has_errors |= expanded.has_errors;
auto token = buffer.AddToken({.kind = TokenKind::StringLiteral(),
.token_line = string_line,
.column = string_column});
buffer.GetTokenInfo(token).literal_index =
buffer.literal_string_storage.size();
buffer.literal_string_storage.push_back(std::move(expanded.result));
buffer.literal_string_storage.push_back(literal->ComputeValue(emitter));
return token;
}
@@ -335,7 +319,6 @@ class TokenizedBuffer::Lexer {
if (open_groups.empty()) {
closing_token_info.kind = TokenKind::Error();
closing_token_info.error_length = kind.GetFixedSpelling().size();
buffer.has_errors = true;
emitter.EmitError<UnmatchedClosing>(location);
// Note that this still returns true as we do consume a symbol.
@@ -365,7 +348,6 @@ class TokenizedBuffer::Lexer {
}
open_groups.pop_back();
buffer.has_errors = true;
token_emitter.EmitError<MismatchedClosing>(opening_token);
// TODO: do a smarter backwards scan for where to put the closing
@@ -460,7 +442,6 @@ class TokenizedBuffer::Lexer {
current_column += error_text.size();
source_text = source_text.drop_front(error_text.size());
buffer.has_errors = true;
return token;
}
@@ -474,7 +455,8 @@ class TokenizedBuffer::Lexer {
auto TokenizedBuffer::Lex(SourceBuffer& source, DiagnosticConsumer& consumer)
-> TokenizedBuffer {
TokenizedBuffer buffer(source);
Lexer lexer(buffer, consumer);
ErrorTrackingDiagnosticConsumer error_tracking_consumer(consumer);
Lexer lexer(buffer, error_tracking_consumer);
llvm::StringRef source_text = source.Text();
while (lexer.SkipWhitespace(source_text)) {
@@ -498,6 +480,11 @@ auto TokenizedBuffer::Lex(SourceBuffer& source, DiagnosticConsumer& consumer)
lexer.CloseInvalidOpenGroups(TokenKind::Error());
lexer.AddEndOfFileToken();
if (error_tracking_consumer.SeenError()) {
buffer.has_errors = true;
}
return buffer;
}