From 04fffbe9aa14d27e0a060b994664a06cbe62fdf1 Mon Sep 17 00:00:00 2001 From: Sam Vervaeck Date: Wed, 24 May 2023 19:38:04 +0200 Subject: [PATCH] Refactor a bit and split header Diagnostics.hpp --- CMakeLists.txt | 2 +- include/bolt/CST.hpp | 55 ++++++++++++- include/bolt/DiagnosticEngine.hpp | 130 ++++++++++++++++++++++++++++++ include/bolt/Diagnostics.hpp | 111 +------------------------ include/bolt/String.hpp | 6 +- include/bolt/Text.hpp | 52 ------------ src/CST.cc | 50 +++++++++++- src/Checker.cc | 1 + src/Diagnostics.cc | 39 ++++++--- src/main.cc | 3 +- 10 files changed, 266 insertions(+), 183 deletions(-) create mode 100644 include/bolt/DiagnosticEngine.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 7a6daca6e..8b2230e48 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,7 +15,7 @@ set(ICU_LIBRARIES icuuc) add_library( BoltCore - src/Text.cc + #src/Text.cc src/CST.cc src/Diagnostics.cc src/Scanner.cc diff --git a/include/bolt/CST.hpp b/include/bolt/CST.hpp index 55c694edd..6256df06a 100644 --- a/include/bolt/CST.hpp +++ b/include/bolt/CST.hpp @@ -10,8 +10,8 @@ #include "zen/config.hpp" -#include "bolt/Text.hpp" #include "bolt/Integer.hpp" +#include "bolt/String.hpp" #include "bolt/ByteString.hpp" namespace bolt { @@ -25,6 +25,59 @@ namespace bolt { class Expression; class Statement; + class TextLoc { + public: + + size_t Line = 1; + size_t Column = 1; + + inline void advance(const ByteString& Text) { + for (auto Chr: Text) { + if (Chr == '\n') { + Line++; + Column = 1; + } else { + Column++; + } + } + } + + inline TextLoc operator+(const ByteString& Text) const { + TextLoc Out { Line, Column }; + Out.advance(Text); + return Out; + } + + }; + + struct TextRange { + TextLoc Start; + TextLoc End; + }; + + class TextFile { + + ByteString Path; + ByteString Text; + + std::vector LineOffsets; + + public: + + TextFile(ByteString Path, ByteString Text); + + size_t getLine(size_t Offset) const; + size_t getColumn(size_t Offset) const; + size_t getStartOffset(size_t Line) const; + + size_t getLineCount() const; + + ByteString getPath() const; + + ByteString getText() const; + + }; + enum class NodeKind { Equals, Colon, diff --git a/include/bolt/DiagnosticEngine.hpp b/include/bolt/DiagnosticEngine.hpp new file mode 100644 index 000000000..0038315d9 --- /dev/null +++ b/include/bolt/DiagnosticEngine.hpp @@ -0,0 +1,130 @@ + +#pragma once + +#include +#include +#include + +#include "bolt/ByteString.hpp" + +namespace bolt { + + class Diagnostic; + class TypeclassSignature; + class Type; + class Node; + + class DiagnosticEngine { + public: + + virtual void addDiagnostic(Diagnostic* Diagnostic) = 0; + + template + void add(Ts&&... Args) { + addDiagnostic(new D { std::forward(Args)... }); + } + + virtual ~DiagnosticEngine() {} + + }; + + /** + * Keeps diagnostics alive in-memory until a seperate procedure processes them. + */ + class DiagnosticStore : public DiagnosticEngine { + public: + + std::vector Diagnostics; + + void addDiagnostic(Diagnostic* Diagnostic) { + Diagnostics.push_back(Diagnostic); + } + + void clear() { + Diagnostics.clear(); + } + + ~DiagnosticStore(); + + }; + + enum class Color { + None, + Black, + White, + Red, + Yellow, + Green, + Blue, + Cyan, + Magenta, + }; + + /** + * Prints any diagnostic message that was added to it to the console. + */ + class ConsoleDiagnostics : public DiagnosticEngine { + + std::ostream& Out; + + void setForegroundColor(Color C); + void setBackgroundColor(Color C); + void setBold(bool Enable); + void setItalic(bool Enable); + void setUnderline(bool Enable); + void resetStyles(); + + void writeGutter( + std::size_t GutterWidth, + std::size_t Line + ); + + void writeHighlight( + std::size_t GutterWidth, + TextRange Range, + Color HighlightColor, + std::size_t Line, + std::size_t LineLength + ); + + void writeExcerpt( + const TextFile& File, + TextRange ToPrint, + TextRange ToHighlight, + Color HighlightColor + ); + + void writeNode(const Node* N); + + void writePrefix(const Diagnostic& D); + void writeBinding(const ByteString& Name); + void writeType(std::size_t I); + void writeType(const Type* Ty); + void writeLoc(const TextFile& File, const TextLoc& Loc); + void writeTypeclassName(const ByteString& Name); + void writeTypeclassSignature(const TypeclassSignature& Sig); + + void write(const std::string_view& S); + void write(std::size_t N); + + public: + + unsigned ExcerptLinesPre = 2; + unsigned ExcerptLinesPost = 2; + std::size_t MaxTypeSubsitutionCount = 0; + bool PrintFilePosition = true; + bool PrintExcerpts = true; + bool EnableColors = true; + + ConsoleDiagnostics(std::ostream& Out = std::cerr); + + /** + * Assumes the diagnostic is to be owned by this ConsoleDiagnostics. + */ + void addDiagnostic(Diagnostic* Diagnostic); + + void printDiagnostic(const Diagnostic& D); + + }; + +} diff --git a/include/bolt/Diagnostics.hpp b/include/bolt/Diagnostics.hpp index e6ef1dec9..d67e50d0b 100644 --- a/include/bolt/Diagnostics.hpp +++ b/include/bolt/Diagnostics.hpp @@ -32,7 +32,7 @@ namespace bolt { protected: Diagnostic(DiagnosticKind Kind); - + public: inline DiagnosticKind getKind() const noexcept { @@ -171,113 +171,4 @@ namespace bolt { }; - class DiagnosticEngine { - public: - - virtual void addDiagnostic(Diagnostic* Diagnostic) = 0; - - template - void add(Ts&&... Args) { - addDiagnostic(new D { std::forward(Args)... }); - } - - virtual ~DiagnosticEngine() {} - - }; - - /** - * Keeps diagnostics alive in-memory until a seperate procedure processes them. - */ - class DiagnosticStore : public DiagnosticEngine { - public: - - std::vector Diagnostics; - - void addDiagnostic(Diagnostic* Diagnostic) { - Diagnostics.push_back(Diagnostic); - } - - void clear() { - Diagnostics.clear(); - } - - ~DiagnosticStore() { - for (auto D: Diagnostics) { - delete D; - } - } - - }; - - enum class Color { - None, - Black, - White, - Red, - Yellow, - Green, - Blue, - Cyan, - Magenta, - }; - - class ConsoleDiagnostics : public DiagnosticEngine { - - std::ostream& Out; - - void setForegroundColor(Color C); - void setBackgroundColor(Color C); - void setBold(bool Enable); - void setItalic(bool Enable); - void setUnderline(bool Enable); - void resetStyles(); - - void writeGutter( - std::size_t GutterWidth, - std::size_t Line - ); - - void writeHighlight( - std::size_t GutterWidth, - TextRange Range, - Color HighlightColor, - std::size_t Line, - std::size_t LineLength - ); - - void writeExcerpt( - const TextFile& File, - TextRange ToPrint, - TextRange ToHighlight, - Color HighlightColor - ); - - void writeNode(const Node* N); - - void writePrefix(const Diagnostic& D); - void writeBinding(const ByteString& Name); - void writeType(std::size_t I); - void writeType(const Type* Ty); - void writeLoc(const TextFile& File, const TextLoc& Loc); - void writeTypeclassName(const ByteString& Name); - void writeTypeclassSignature(const TypeclassSignature& Sig); - - void write(const std::string_view& S); - void write(std::size_t N); - - public: - - unsigned ExcerptLinesPre = 2; - unsigned ExcerptLinesPost = 2; - std::size_t MaxTypeSubsitutionCount = 0; - bool PrintFilePosition = true; - bool PrintExcerpts = true; - bool EnableColors = true; - - ConsoleDiagnostics(std::ostream& Out = std::cerr); - - void addDiagnostic(Diagnostic* Diagnostic) override; - - }; - } diff --git a/include/bolt/String.hpp b/include/bolt/String.hpp index 1a0ed767d..e62376bc9 100644 --- a/include/bolt/String.hpp +++ b/include/bolt/String.hpp @@ -3,11 +3,13 @@ #include +// TODO make the types here UTF-8 compatible + namespace bolt { - using Char = int; + using Char = char; - using String = std::string; + using String = std::basic_string; } diff --git a/include/bolt/Text.hpp b/include/bolt/Text.hpp index 2bfebc447..ead690f3d 100644 --- a/include/bolt/Text.hpp +++ b/include/bolt/Text.hpp @@ -11,58 +11,6 @@ namespace bolt { - class TextLoc { - public: - - size_t Line = 1; - size_t Column = 1; - - inline void advance(const String& Text) { - for (auto Chr: Text) { - if (Chr == '\n') { - Line++; - Column = 1; - } else { - Column++; - } - } - } - - inline TextLoc operator+(const String& Text) const { - TextLoc Out { Line, Column }; - Out.advance(Text); - return Out; - } - - }; - - struct TextRange { - TextLoc Start; - TextLoc End; - }; - - class TextFile { - - ByteString Path; - ByteString Text; - - std::vector LineOffsets; - - public: - - TextFile(ByteString Path, ByteString Text); - - size_t getLine(size_t Offset) const; - size_t getColumn(size_t Offset) const; - size_t getStartOffset(size_t Line) const; - - size_t getLineCount() const; - - ByteString getPath() const; - - ByteString getText() const; - - }; } diff --git a/src/CST.cc b/src/CST.cc index 3e345d352..d094d404c 100644 --- a/src/CST.cc +++ b/src/CST.cc @@ -6,6 +6,50 @@ namespace bolt { + TextFile::TextFile(ByteString Path, ByteString Text): + Path(Path), Text(Text) { + LineOffsets.push_back(0); + for (size_t I = 0; I < Text.size(); I++) { + auto Chr = Text[I]; + if (Chr == '\n') { + LineOffsets.push_back(I+1); + } + } + LineOffsets.push_back(Text.size()); + } + + size_t TextFile::getLineCount() const { + return LineOffsets.size(); + } + + size_t TextFile::getStartOffset(size_t Line) const { + return LineOffsets[Line-1]; + } + + size_t TextFile::getLine(size_t Offset) const { + ZEN_ASSERT(Offset < Text.size()); + for (size_t I = 0; I < LineOffsets.size(); ++I) { + if (LineOffsets[I] > Offset) { + return I; + } + } + ZEN_UNREACHABLE + } + + size_t TextFile::getColumn(size_t Offset) const { + auto Line = getLine(Offset); + auto StartOffset = getStartOffset(Line); + return Offset - StartOffset + 1 ; + } + + ByteString TextFile::getPath() const { + return Path; + } + + ByteString TextFile::getText() const { + return Text; + } + Scope::Scope(Node* Source): Source(Source) { scan(Source); @@ -145,9 +189,9 @@ namespace bolt { /* } */ TextLoc Token::getEndLoc() { - auto EndLoc = StartLoc; - EndLoc.advance(getText()); - return EndLoc; + auto Loc = StartLoc; + Loc.advance(getText()); + return Loc; } void Node::setParents() { diff --git a/src/Checker.cc b/src/Checker.cc index 7a96f7e81..a6e00019a 100644 --- a/src/Checker.cc +++ b/src/Checker.cc @@ -19,6 +19,7 @@ #include "zen/range.hpp" #include "bolt/CSTVisitor.hpp" +#include "bolt/DiagnosticEngine.hpp" #include "bolt/Diagnostics.hpp" #include "bolt/CST.hpp" #include "bolt/Checker.hpp" diff --git a/src/Diagnostics.cc b/src/Diagnostics.cc index 0d911bdb4..d5498495f 100644 --- a/src/Diagnostics.cc +++ b/src/Diagnostics.cc @@ -8,6 +8,7 @@ #include "bolt/CST.hpp" #include "bolt/Type.hpp" +#include "bolt/DiagnosticEngine.hpp" #include "bolt/Diagnostics.hpp" #define ANSI_RESET "\u001b[0m" @@ -172,6 +173,12 @@ namespace bolt { } } + DiagnosticStore::~DiagnosticStore() { + for (auto D: Diagnostics) { + delete D; + } + } + ConsoleDiagnostics::ConsoleDiagnostics(std::ostream& Out): Out(Out) {} @@ -420,11 +427,20 @@ namespace bolt { void ConsoleDiagnostics::addDiagnostic(Diagnostic* D) { - switch (D->getKind()) { + printDiagnostic(*D); + + // Since this DiagnosticEngine is expected to own the diagnostic, we simply + // destroy the processed diagnostic so that there are no memory leaks. + delete D; + } + + void ConsoleDiagnostics::printDiagnostic(const Diagnostic& D) { + + switch (D.getKind()) { case DiagnosticKind::BindingNotFound: { - auto E = static_cast(*D); + auto E = static_cast(D); writePrefix(E); write("binding '"); writeBinding(E.Name); @@ -440,7 +456,7 @@ namespace bolt { case DiagnosticKind::UnexpectedToken: { - auto E = static_cast(*D); + auto E = static_cast(D); writePrefix(E); writeLoc(E.File, E.Actual->getStartLoc()); write(" expected "); @@ -474,7 +490,7 @@ namespace bolt { case DiagnosticKind::UnexpectedString: { - auto E = static_cast(*D); + auto E = static_cast(D); writePrefix(E); writeLoc(E.File, E.Location); write(" unexpected '"); @@ -500,7 +516,7 @@ namespace bolt { case DiagnosticKind::UnificationError: { - auto E = static_cast(*D); + auto E = static_cast(D); writePrefix(E); auto Left = E.Left->resolve(E.LeftPath); auto Right = E.Right->resolve(E.RightPath); @@ -540,7 +556,7 @@ namespace bolt { case DiagnosticKind::TypeclassMissing: { - auto E = static_cast(*D); + auto E = static_cast(D); writePrefix(E); write("the type class "); writeTypeclassSignature(E.Sig); @@ -552,7 +568,7 @@ namespace bolt { case DiagnosticKind::InstanceNotFound: { - auto E = static_cast(*D); + auto E = static_cast(D); writePrefix(E); write("a type class instance "); writeTypeclassName(E.TypeclassName); @@ -566,7 +582,7 @@ namespace bolt { case DiagnosticKind::ClassNotFound: { - auto E = static_cast(*D); + auto E = static_cast(D); writePrefix(E); write("the type class "); writeTypeclassName(E.Name); @@ -576,7 +592,7 @@ namespace bolt { case DiagnosticKind::TupleIndexOutOfRange: { - auto E = static_cast(*D); + auto E = static_cast(D); writePrefix(E); write("the index "); writeType(E.I); @@ -587,7 +603,7 @@ namespace bolt { case DiagnosticKind::InvalidTypeToTypeclass: { - auto E = static_cast(*D); + auto E = static_cast(D); writePrefix(E); write("the type "); writeType(E.Actual); @@ -604,9 +620,6 @@ namespace bolt { } - // Since this DiagnosticEngine is expected to own the diagnostic, we simply - // destroy the processed diagnostic so that there are no memory leaks. - delete D; } } diff --git a/src/main.cc b/src/main.cc index 4a754f9d5..d0368e7b8 100644 --- a/src/main.cc +++ b/src/main.cc @@ -8,6 +8,7 @@ #include "zen/config.hpp" #include "bolt/CST.hpp" +#include "bolt/DiagnosticEngine.hpp" #include "bolt/Diagnostics.hpp" #include "bolt/Scanner.hpp" #include "bolt/Parser.hpp" @@ -75,7 +76,7 @@ int main(int argc, const char* argv[]) { std::sort(DS.Diagnostics.begin(), DS.Diagnostics.end(), LT); for (auto D: DS.Diagnostics) { - DE.addDiagnostic(D); + DE.printDiagnostic(*D); } return 0;