aboutsummaryrefslogtreecommitdiff
path: root/backend/lib/Support/TextDiagnostic.cpp
diff options
context:
space:
mode:
authorRichard-Qin-X <richard.qin.001@gmail.com>2026-08-01 16:47:16 +0800
committerRichard-Qin-X <richard.qin.001@gmail.com>2026-08-01 16:47:16 +0800
commit85eed8fb2d6563fea750f7b55730c9feaecc5898 (patch)
tree81663a7028c73e245ce573cd6b52e2a751146cd6 /backend/lib/Support/TextDiagnostic.cpp
parent924dcd36ebed84f04729de05ec08b311a36a04c1 (diff)
downloadrcc-project-85eed8fb2d6563fea750f7b55730c9feaecc5898.tar.gz
rcc-project-85eed8fb2d6563fea750f7b55730c9feaecc5898.tar.xz
[Support] Add MIR YAML parsing infrastructure
Introduce source ranges, deterministic text diagnostics, and an independently authored YAML stream parser for the fixed LLVM MIR container shapes. Record the compatibility matrix and Stage 6 validation state.
Diffstat (limited to 'backend/lib/Support/TextDiagnostic.cpp')
-rw-r--r--backend/lib/Support/TextDiagnostic.cpp91
1 files changed, 91 insertions, 0 deletions
diff --git a/backend/lib/Support/TextDiagnostic.cpp b/backend/lib/Support/TextDiagnostic.cpp
new file mode 100644
index 0000000..1c027c3
--- /dev/null
+++ b/backend/lib/Support/TextDiagnostic.cpp
@@ -0,0 +1,91 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "rcc/Support/TextDiagnostic.h"
+
+#include <algorithm>
+#include <iterator>
+#include <sstream>
+#include <utility>
+
+namespace rcc {
+
+std::string_view getDiagnosticSeverityName(DiagnosticSeverity Severity) noexcept {
+ switch (Severity) {
+ case DiagnosticSeverity::Note:
+ return "note";
+ case DiagnosticSeverity::Warning:
+ return "warning";
+ case DiagnosticSeverity::Error:
+ return "error";
+ }
+
+ return "unknown";
+}
+
+TextSource::TextSource(std::string Name, std::string Text)
+ : Name(std::move(Name)), Text(std::move(Text)), LineOffsets{0} {
+ for (std::size_t Index = 0; Index < this->Text.size(); ++Index) {
+ if (this->Text[Index] == '\n')
+ LineOffsets.push_back(Index + 1);
+ }
+}
+
+TextPosition TextSource::positionAt(std::size_t Offset) const noexcept {
+ Offset = std::min(Offset, Text.size());
+ const auto LineIterator = std::upper_bound(LineOffsets.begin(), LineOffsets.end(), Offset);
+ const std::size_t LineIndex =
+ static_cast<std::size_t>(std::distance(LineOffsets.begin(), LineIterator) - 1);
+ return TextPosition{
+ .Offset = Offset,
+ .Line = LineIndex + 1,
+ .Column = Offset - LineOffsets[LineIndex] + 1,
+ };
+}
+
+TextRange TextSource::range(std::size_t Begin, std::size_t End) const noexcept {
+ Begin = std::min(Begin, Text.size());
+ End = std::clamp(End, Begin, Text.size());
+ return TextRange{.Begin = positionAt(Begin), .End = positionAt(End)};
+}
+
+std::string_view TextSource::line(std::size_t OneBasedLine) const noexcept {
+ if (OneBasedLine == 0 || OneBasedLine > LineOffsets.size())
+ return {};
+
+ const std::size_t Begin = LineOffsets[OneBasedLine - 1];
+ std::size_t End = OneBasedLine < LineOffsets.size() ? LineOffsets[OneBasedLine] - 1 : Text.size();
+ if (End > Begin && Text[End - 1] == '\r')
+ --End;
+ return std::string_view(Text).substr(Begin, End - Begin);
+}
+
+std::string formatTextDiagnostic(const TextDiagnostic &Diagnostic, const TextSource &Source) {
+ std::ostringstream Output;
+ const TextPosition Position = Diagnostic.Range.Begin;
+ const std::string_view SourceName =
+ Diagnostic.SourceName.empty() ? Source.name() : std::string_view(Diagnostic.SourceName);
+
+ Output << SourceName << ':' << Position.Line << ':' << Position.Column << ": "
+ << getDiagnosticSeverityName(Diagnostic.Severity);
+ if (!Diagnostic.Category.empty())
+ Output << '[' << Diagnostic.Category << ']';
+ Output << ": " << Diagnostic.Message;
+
+ const std::string_view SourceLine = Source.line(Position.Line);
+ if (SourceLine.empty())
+ return Output.str();
+
+ Output << '\n' << SourceLine << '\n';
+ const std::size_t PrefixWidth = Position.Column > 0 ? Position.Column - 1 : 0;
+ for (std::size_t Index = 0; Index < PrefixWidth && Index < SourceLine.size(); ++Index)
+ Output << (SourceLine[Index] == '\t' ? '\t' : ' ');
+
+ Output << '^';
+ if (Diagnostic.Range.End.Line == Position.Line &&
+ Diagnostic.Range.End.Column > Position.Column + 1) {
+ Output << std::string(Diagnostic.Range.End.Column - Position.Column - 1, '~');
+ }
+ return Output.str();
+}
+
+} // namespace rcc