Refactor a bit and split header Diagnostics.hpp
This commit is contained in:
parent
31d813e94b
commit
04fffbe9aa
10 changed files with 266 additions and 183 deletions
|
@ -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
|
||||
|
|
|
@ -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<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 {
|
||||
Equals,
|
||||
Colon,
|
||||
|
|
130
include/bolt/DiagnosticEngine.hpp
Normal file
130
include/bolt/DiagnosticEngine.hpp
Normal 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);
|
||||
|
||||
};
|
||||
|
||||
}
|
|
@ -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<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;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -3,11 +3,13 @@
|
|||
|
||||
#include <string>
|
||||
|
||||
// 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<Char>;
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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<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;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
|
50
src/CST.cc
50
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() {
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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<const BindingNotFoundDiagnostic&>(*D);
|
||||
auto E = static_cast<const BindingNotFoundDiagnostic&>(D);
|
||||
writePrefix(E);
|
||||
write("binding '");
|
||||
writeBinding(E.Name);
|
||||
|
@ -440,7 +456,7 @@ namespace bolt {
|
|||
|
||||
case DiagnosticKind::UnexpectedToken:
|
||||
{
|
||||
auto E = static_cast<const UnexpectedTokenDiagnostic&>(*D);
|
||||
auto E = static_cast<const UnexpectedTokenDiagnostic&>(D);
|
||||
writePrefix(E);
|
||||
writeLoc(E.File, E.Actual->getStartLoc());
|
||||
write(" expected ");
|
||||
|
@ -474,7 +490,7 @@ namespace bolt {
|
|||
|
||||
case DiagnosticKind::UnexpectedString:
|
||||
{
|
||||
auto E = static_cast<const UnexpectedStringDiagnostic&>(*D);
|
||||
auto E = static_cast<const UnexpectedStringDiagnostic&>(D);
|
||||
writePrefix(E);
|
||||
writeLoc(E.File, E.Location);
|
||||
write(" unexpected '");
|
||||
|
@ -500,7 +516,7 @@ namespace bolt {
|
|||
|
||||
case DiagnosticKind::UnificationError:
|
||||
{
|
||||
auto E = static_cast<const UnificationErrorDiagnostic&>(*D);
|
||||
auto E = static_cast<const UnificationErrorDiagnostic&>(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<const TypeclassMissingDiagnostic&>(*D);
|
||||
auto E = static_cast<const TypeclassMissingDiagnostic&>(D);
|
||||
writePrefix(E);
|
||||
write("the type class ");
|
||||
writeTypeclassSignature(E.Sig);
|
||||
|
@ -552,7 +568,7 @@ namespace bolt {
|
|||
|
||||
case DiagnosticKind::InstanceNotFound:
|
||||
{
|
||||
auto E = static_cast<const InstanceNotFoundDiagnostic&>(*D);
|
||||
auto E = static_cast<const InstanceNotFoundDiagnostic&>(D);
|
||||
writePrefix(E);
|
||||
write("a type class instance ");
|
||||
writeTypeclassName(E.TypeclassName);
|
||||
|
@ -566,7 +582,7 @@ namespace bolt {
|
|||
|
||||
case DiagnosticKind::ClassNotFound:
|
||||
{
|
||||
auto E = static_cast<const ClassNotFoundDiagnostic&>(*D);
|
||||
auto E = static_cast<const ClassNotFoundDiagnostic&>(D);
|
||||
writePrefix(E);
|
||||
write("the type class ");
|
||||
writeTypeclassName(E.Name);
|
||||
|
@ -576,7 +592,7 @@ namespace bolt {
|
|||
|
||||
case DiagnosticKind::TupleIndexOutOfRange:
|
||||
{
|
||||
auto E = static_cast<const TupleIndexOutOfRangeDiagnostic&>(*D);
|
||||
auto E = static_cast<const TupleIndexOutOfRangeDiagnostic&>(D);
|
||||
writePrefix(E);
|
||||
write("the index ");
|
||||
writeType(E.I);
|
||||
|
@ -587,7 +603,7 @@ namespace bolt {
|
|||
|
||||
case DiagnosticKind::InvalidTypeToTypeclass:
|
||||
{
|
||||
auto E = static_cast<const InvalidTypeToTypeclassDiagnostic&>(*D);
|
||||
auto E = static_cast<const InvalidTypeToTypeclassDiagnostic&>(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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue