Refactor a bit and split header Diagnostics.hpp

This commit is contained in:
Sam Vervaeck 2023-05-24 19:38:04 +02:00
parent 31d813e94b
commit 04fffbe9aa
Signed by: samvv
SSH key fingerprint: SHA256:dIg0ywU1OP+ZYifrYxy8c5esO72cIKB+4/9wkZj1VaY
10 changed files with 266 additions and 183 deletions

View file

@ -15,7 +15,7 @@ set(ICU_LIBRARIES icuuc)
add_library( add_library(
BoltCore BoltCore
src/Text.cc #src/Text.cc
src/CST.cc src/CST.cc
src/Diagnostics.cc src/Diagnostics.cc
src/Scanner.cc src/Scanner.cc

View file

@ -10,8 +10,8 @@
#include "zen/config.hpp" #include "zen/config.hpp"
#include "bolt/Text.hpp"
#include "bolt/Integer.hpp" #include "bolt/Integer.hpp"
#include "bolt/String.hpp"
#include "bolt/ByteString.hpp" #include "bolt/ByteString.hpp"
namespace bolt { namespace bolt {
@ -25,6 +25,59 @@ namespace bolt {
class Expression; class Expression;
class Statement; 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<size_t> 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 { enum class NodeKind {
Equals, Equals,
Colon, Colon,

View file

@ -0,0 +1,130 @@
#pragma once
#include <utility>
#include <vector>
#include <iostream>
#include "bolt/ByteString.hpp"
namespace bolt {
class Diagnostic;
class TypeclassSignature;
class Type;
class Node;
class DiagnosticEngine {
public:
virtual void addDiagnostic(Diagnostic* Diagnostic) = 0;
template<typename D, typename ...Ts>
void add(Ts&&... Args) {
addDiagnostic(new D { std::forward<Ts>(Args)... });
}
virtual ~DiagnosticEngine() {}
};
/**
* Keeps diagnostics alive in-memory until a seperate procedure processes them.
*/
class DiagnosticStore : public DiagnosticEngine {
public:
std::vector<Diagnostic*> 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);
};
}

View file

@ -32,7 +32,7 @@ namespace bolt {
protected: protected:
Diagnostic(DiagnosticKind Kind); Diagnostic(DiagnosticKind Kind);
public: public:
inline DiagnosticKind getKind() const noexcept { inline DiagnosticKind getKind() const noexcept {
@ -171,113 +171,4 @@ namespace bolt {
}; };
class DiagnosticEngine {
public:
virtual void addDiagnostic(Diagnostic* Diagnostic) = 0;
template<typename D, typename ...Ts>
void add(Ts&&... Args) {
addDiagnostic(new D { std::forward<Ts>(Args)... });
}
virtual ~DiagnosticEngine() {}
};
/**
* Keeps diagnostics alive in-memory until a seperate procedure processes them.
*/
class DiagnosticStore : public DiagnosticEngine {
public:
std::vector<Diagnostic*> 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;
};
} }

View file

@ -3,11 +3,13 @@
#include <string> #include <string>
// TODO make the types here UTF-8 compatible
namespace bolt { namespace bolt {
using Char = int; using Char = char;
using String = std::string; using String = std::basic_string<Char>;
} }

View file

@ -11,58 +11,6 @@
namespace bolt { 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<size_t> 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;
};
} }

View file

@ -6,6 +6,50 @@
namespace bolt { 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): Scope::Scope(Node* Source):
Source(Source) { Source(Source) {
scan(Source); scan(Source);
@ -145,9 +189,9 @@ namespace bolt {
/* } */ /* } */
TextLoc Token::getEndLoc() { TextLoc Token::getEndLoc() {
auto EndLoc = StartLoc; auto Loc = StartLoc;
EndLoc.advance(getText()); Loc.advance(getText());
return EndLoc; return Loc;
} }
void Node::setParents() { void Node::setParents() {

View file

@ -19,6 +19,7 @@
#include "zen/range.hpp" #include "zen/range.hpp"
#include "bolt/CSTVisitor.hpp" #include "bolt/CSTVisitor.hpp"
#include "bolt/DiagnosticEngine.hpp"
#include "bolt/Diagnostics.hpp" #include "bolt/Diagnostics.hpp"
#include "bolt/CST.hpp" #include "bolt/CST.hpp"
#include "bolt/Checker.hpp" #include "bolt/Checker.hpp"

View file

@ -8,6 +8,7 @@
#include "bolt/CST.hpp" #include "bolt/CST.hpp"
#include "bolt/Type.hpp" #include "bolt/Type.hpp"
#include "bolt/DiagnosticEngine.hpp"
#include "bolt/Diagnostics.hpp" #include "bolt/Diagnostics.hpp"
#define ANSI_RESET "\u001b[0m" #define ANSI_RESET "\u001b[0m"
@ -172,6 +173,12 @@ namespace bolt {
} }
} }
DiagnosticStore::~DiagnosticStore() {
for (auto D: Diagnostics) {
delete D;
}
}
ConsoleDiagnostics::ConsoleDiagnostics(std::ostream& Out): ConsoleDiagnostics::ConsoleDiagnostics(std::ostream& Out):
Out(Out) {} Out(Out) {}
@ -420,11 +427,20 @@ namespace bolt {
void ConsoleDiagnostics::addDiagnostic(Diagnostic* D) { 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: case DiagnosticKind::BindingNotFound:
{ {
auto E = static_cast<const BindingNotFoundDiagnostic&>(*D); auto E = static_cast<const BindingNotFoundDiagnostic&>(D);
writePrefix(E); writePrefix(E);
write("binding '"); write("binding '");
writeBinding(E.Name); writeBinding(E.Name);
@ -440,7 +456,7 @@ namespace bolt {
case DiagnosticKind::UnexpectedToken: case DiagnosticKind::UnexpectedToken:
{ {
auto E = static_cast<const UnexpectedTokenDiagnostic&>(*D); auto E = static_cast<const UnexpectedTokenDiagnostic&>(D);
writePrefix(E); writePrefix(E);
writeLoc(E.File, E.Actual->getStartLoc()); writeLoc(E.File, E.Actual->getStartLoc());
write(" expected "); write(" expected ");
@ -474,7 +490,7 @@ namespace bolt {
case DiagnosticKind::UnexpectedString: case DiagnosticKind::UnexpectedString:
{ {
auto E = static_cast<const UnexpectedStringDiagnostic&>(*D); auto E = static_cast<const UnexpectedStringDiagnostic&>(D);
writePrefix(E); writePrefix(E);
writeLoc(E.File, E.Location); writeLoc(E.File, E.Location);
write(" unexpected '"); write(" unexpected '");
@ -500,7 +516,7 @@ namespace bolt {
case DiagnosticKind::UnificationError: case DiagnosticKind::UnificationError:
{ {
auto E = static_cast<const UnificationErrorDiagnostic&>(*D); auto E = static_cast<const UnificationErrorDiagnostic&>(D);
writePrefix(E); writePrefix(E);
auto Left = E.Left->resolve(E.LeftPath); auto Left = E.Left->resolve(E.LeftPath);
auto Right = E.Right->resolve(E.RightPath); auto Right = E.Right->resolve(E.RightPath);
@ -540,7 +556,7 @@ namespace bolt {
case DiagnosticKind::TypeclassMissing: case DiagnosticKind::TypeclassMissing:
{ {
auto E = static_cast<const TypeclassMissingDiagnostic&>(*D); auto E = static_cast<const TypeclassMissingDiagnostic&>(D);
writePrefix(E); writePrefix(E);
write("the type class "); write("the type class ");
writeTypeclassSignature(E.Sig); writeTypeclassSignature(E.Sig);
@ -552,7 +568,7 @@ namespace bolt {
case DiagnosticKind::InstanceNotFound: case DiagnosticKind::InstanceNotFound:
{ {
auto E = static_cast<const InstanceNotFoundDiagnostic&>(*D); auto E = static_cast<const InstanceNotFoundDiagnostic&>(D);
writePrefix(E); writePrefix(E);
write("a type class instance "); write("a type class instance ");
writeTypeclassName(E.TypeclassName); writeTypeclassName(E.TypeclassName);
@ -566,7 +582,7 @@ namespace bolt {
case DiagnosticKind::ClassNotFound: case DiagnosticKind::ClassNotFound:
{ {
auto E = static_cast<const ClassNotFoundDiagnostic&>(*D); auto E = static_cast<const ClassNotFoundDiagnostic&>(D);
writePrefix(E); writePrefix(E);
write("the type class "); write("the type class ");
writeTypeclassName(E.Name); writeTypeclassName(E.Name);
@ -576,7 +592,7 @@ namespace bolt {
case DiagnosticKind::TupleIndexOutOfRange: case DiagnosticKind::TupleIndexOutOfRange:
{ {
auto E = static_cast<const TupleIndexOutOfRangeDiagnostic&>(*D); auto E = static_cast<const TupleIndexOutOfRangeDiagnostic&>(D);
writePrefix(E); writePrefix(E);
write("the index "); write("the index ");
writeType(E.I); writeType(E.I);
@ -587,7 +603,7 @@ namespace bolt {
case DiagnosticKind::InvalidTypeToTypeclass: case DiagnosticKind::InvalidTypeToTypeclass:
{ {
auto E = static_cast<const InvalidTypeToTypeclassDiagnostic&>(*D); auto E = static_cast<const InvalidTypeToTypeclassDiagnostic&>(D);
writePrefix(E); writePrefix(E);
write("the type "); write("the type ");
writeType(E.Actual); 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;
} }
} }

View file

@ -8,6 +8,7 @@
#include "zen/config.hpp" #include "zen/config.hpp"
#include "bolt/CST.hpp" #include "bolt/CST.hpp"
#include "bolt/DiagnosticEngine.hpp"
#include "bolt/Diagnostics.hpp" #include "bolt/Diagnostics.hpp"
#include "bolt/Scanner.hpp" #include "bolt/Scanner.hpp"
#include "bolt/Parser.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); std::sort(DS.Diagnostics.begin(), DS.Diagnostics.end(), LT);
for (auto D: DS.Diagnostics) { for (auto D: DS.Diagnostics) {
DE.addDiagnostic(D); DE.printDiagnostic(*D);
} }
return 0; return 0;