Support adding filename to diagnostic.
This commit is contained in:
parent
dffc0d7f17
commit
125bb8459c
|
@ -4,19 +4,23 @@
|
||||||
#include "../TextSpan.hpp"
|
#include "../TextSpan.hpp"
|
||||||
#include "DiagnosticLevel.hpp"
|
#include "DiagnosticLevel.hpp"
|
||||||
#include "DiagnosticType.hpp"
|
#include "DiagnosticType.hpp"
|
||||||
|
|
||||||
namespace ElohimScript::Diagnostics {
|
namespace ElohimScript::Diagnostics {
|
||||||
class Diagnostic {
|
class Diagnostic {
|
||||||
DiagnosticLevel _level;
|
DiagnosticLevel _level;
|
||||||
DiagnosticType _type;
|
DiagnosticType _type;
|
||||||
|
std::u8string_view _scriptName;
|
||||||
TextSpan _span;
|
TextSpan _span;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
inline Diagnostic(DiagnosticLevel level, DiagnosticType type, TextSpan span)
|
inline Diagnostic(DiagnosticLevel level, DiagnosticType type, const std::u8string_view& scriptName,
|
||||||
: _level(level), _type(type), _span(span) {}
|
TextSpan span)
|
||||||
|
: _level(level), _type(type), _scriptName(scriptName), _span(span) {}
|
||||||
|
|
||||||
[[nodiscard]] inline DiagnosticLevel GetLevel() const noexcept { return _level; }
|
[[nodiscard]] inline DiagnosticLevel GetLevel() const noexcept { return _level; }
|
||||||
[[nodiscard]] inline DiagnosticType GetType() const noexcept { return _type; }
|
[[nodiscard]] inline DiagnosticType GetType() const noexcept { return _type; }
|
||||||
[[nodiscard]] inline const TextSpan& GetSpan() const noexcept { return _span; }
|
[[nodiscard]] inline const TextSpan& GetSpan() const noexcept { return _span; }
|
||||||
|
[[nodiscard]] inline const std::u8string_view& GetScriptName() const noexcept { return _scriptName; }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,14 +9,24 @@ namespace ElohimScript::Diagnostics {
|
||||||
std::vector<Diagnostic> _messages;
|
std::vector<Diagnostic> _messages;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
inline void Log(DiagnosticLevel level, DiagnosticType type, TextSpan span) {
|
inline void Log(DiagnosticLevel level, DiagnosticType type, std::u8string_view scriptName, TextSpan span) {
|
||||||
_messages.emplace_back(level, type, span);
|
_messages.emplace_back(level, type, scriptName, span);
|
||||||
|
}
|
||||||
|
inline void LogTrace(DiagnosticType type, std::u8string_view scriptName, TextSpan span) {
|
||||||
|
Log(DiagnosticLevel::Trace, type, scriptName, span);
|
||||||
|
}
|
||||||
|
inline void LogInfo(DiagnosticType type, std::u8string_view scriptName, TextSpan span) {
|
||||||
|
Log(DiagnosticLevel::Information, type, scriptName, span);
|
||||||
|
}
|
||||||
|
inline void LogWarning(DiagnosticType type, std::u8string_view scriptName, TextSpan span) {
|
||||||
|
Log(DiagnosticLevel::Warning, type, scriptName, span);
|
||||||
|
}
|
||||||
|
inline void LogError(DiagnosticType type, std::u8string_view scriptName, TextSpan span) {
|
||||||
|
Log(DiagnosticLevel::Error, type, scriptName, span);
|
||||||
|
}
|
||||||
|
inline void LogCritical(DiagnosticType type, std::u8string_view scriptName, TextSpan span) {
|
||||||
|
Log(DiagnosticLevel::Critical, type, scriptName, span);
|
||||||
}
|
}
|
||||||
inline void LogTrace(DiagnosticType type, TextSpan span) { Log(DiagnosticLevel::Trace, type, span); }
|
|
||||||
inline void LogInfo(DiagnosticType type, TextSpan span) { Log(DiagnosticLevel::Information, type, span); }
|
|
||||||
inline void LogWarning(DiagnosticType type, TextSpan span) { Log(DiagnosticLevel::Warning, type, span); }
|
|
||||||
inline void LogError(DiagnosticType type, TextSpan span) { Log(DiagnosticLevel::Error, type, span); }
|
|
||||||
inline void LogCritical(DiagnosticType type, TextSpan span) { Log(DiagnosticLevel::Critical, type, span); }
|
|
||||||
|
|
||||||
[[nodiscard]] const std::vector<Diagnostic>& GetMessages() const noexcept { return _messages; }
|
[[nodiscard]] const std::vector<Diagnostic>& GetMessages() const noexcept { return _messages; }
|
||||||
};
|
};
|
||||||
|
|
|
@ -272,7 +272,7 @@ namespace ElohimScript::Parser {
|
||||||
default:
|
default:
|
||||||
if (IsAlphaNumericalOrUnderscore(c))
|
if (IsAlphaNumericalOrUnderscore(c))
|
||||||
return LexKeywordOrIdentifier();
|
return LexKeywordOrIdentifier();
|
||||||
_diagnostics->LogError(Diagnostics::DiagnosticType::UnknownToken, TextSpan(start, start + 1));
|
LogError(Diagnostics::DiagnosticType::UnknownToken, TextSpan(start, start + 1));
|
||||||
return Create<LexTokenImpl<LexTokenKind::Unknown>>(TextSpan(start, start + 1));
|
return Create<LexTokenImpl<LexTokenKind::Unknown>>(TextSpan(start, start + 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -295,8 +295,8 @@ namespace ElohimScript::Parser {
|
||||||
case 'b':
|
case 'b':
|
||||||
case 'B': numericalSystem = 2; break;
|
case 'B': numericalSystem = 2; break;
|
||||||
default:
|
default:
|
||||||
_diagnostics->LogError(Diagnostics::DiagnosticType::InvalidNumericalBase,
|
LogError(Diagnostics::DiagnosticType::InvalidNumericalBase,
|
||||||
TextSpan(_position - 1, _position + 1));
|
TextSpan(_position - 1, _position + 1));
|
||||||
// Set to the largest numerical system, so we can prevent errors down the line.
|
// Set to the largest numerical system, so we can prevent errors down the line.
|
||||||
numericalSystem = 16;
|
numericalSystem = 16;
|
||||||
break;
|
break;
|
||||||
|
@ -442,13 +442,11 @@ namespace ElohimScript::Parser {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (current == u8'\0') {
|
if (current == u8'\0') {
|
||||||
_diagnostics->LogError(Diagnostics::DiagnosticType::ExpectedEndOfString,
|
LogError(Diagnostics::DiagnosticType::ExpectedEndOfString, TextSpan(start, start + offset));
|
||||||
TextSpan(start, start + offset));
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!heredoc && (current == u8'\n' || current == u8'\r')) {
|
if (!heredoc && (current == u8'\n' || current == u8'\r')) {
|
||||||
_diagnostics->LogError(Diagnostics::DiagnosticType::ExpectedEndOfString,
|
LogError(Diagnostics::DiagnosticType::ExpectedEndOfString, TextSpan(start, start + offset));
|
||||||
TextSpan(start, start + offset));
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
offset++;
|
offset++;
|
||||||
|
|
|
@ -9,14 +9,16 @@
|
||||||
namespace ElohimScript::Parser {
|
namespace ElohimScript::Parser {
|
||||||
class Lexer {
|
class Lexer {
|
||||||
public:
|
public:
|
||||||
Lexer(const char* script, Diagnostics::Diagnostics* diag)
|
Lexer(const char* scriptName, const char* script, Diagnostics::Diagnostics* diag)
|
||||||
: Lexer(reinterpret_cast<const char8_t*>(script), diag) {}
|
: Lexer(reinterpret_cast<const char8_t*>(scriptName), reinterpret_cast<const char8_t*>(script), diag) {}
|
||||||
Lexer(const char8_t* script, Diagnostics::Diagnostics* diag) : Lexer(std::u8string_view(script), diag) {}
|
Lexer(const char8_t* scriptName, const char8_t* script, Diagnostics::Diagnostics* diag)
|
||||||
Lexer(std::u8string_view script, Diagnostics::Diagnostics* diag)
|
: Lexer(std::u8string_view(scriptName), std::u8string_view(script), diag) {}
|
||||||
: _script(script), _scriptLength(script.size()), _diagnostics(diag) {}
|
Lexer(std::u8string_view scriptName, std::u8string_view script, Diagnostics::Diagnostics* diag)
|
||||||
|
: _scriptName(scriptName), _script(script), _scriptLength(script.size()), _diagnostics(diag) {}
|
||||||
const LexToken* Lex();
|
const LexToken* Lex();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
std::u8string_view _scriptName;
|
||||||
std::u8string_view _script;
|
std::u8string_view _script;
|
||||||
size_t _position = -1;
|
size_t _position = -1;
|
||||||
size_t _scriptLength;
|
size_t _scriptLength;
|
||||||
|
@ -56,6 +58,10 @@ namespace ElohimScript::Parser {
|
||||||
template <class T, class... parameters> inline T* Create(parameters... args) {
|
template <class T, class... parameters> inline T* Create(parameters... args) {
|
||||||
return _allocator.Create<T>(args...);
|
return _allocator.Create<T>(args...);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void LogError(Diagnostics::DiagnosticType type, TextSpan span) {
|
||||||
|
_diagnostics->LogError(type, _scriptName, span);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ using namespace ElohimScript::Parser;
|
||||||
#define KEYWORD_TEST(script, symbol) \
|
#define KEYWORD_TEST(script, symbol) \
|
||||||
TEST_CASE("Lex " script) { \
|
TEST_CASE("Lex " script) { \
|
||||||
ElohimScript::Diagnostics::Diagnostics diag; \
|
ElohimScript::Diagnostics::Diagnostics diag; \
|
||||||
auto lexer = Lexer(script, &diag); \
|
auto lexer = Lexer(script, script, &diag); \
|
||||||
const auto* token = lexer.Lex(); \
|
const auto* token = lexer.Lex(); \
|
||||||
CHECK(diag.GetMessages().empty()); \
|
CHECK(diag.GetMessages().empty()); \
|
||||||
CHECK(token->GetKind() == LexTokenKind::symbol); \
|
CHECK(token->GetKind() == LexTokenKind::symbol); \
|
||||||
|
@ -93,7 +93,7 @@ namespace doctest {
|
||||||
#define IDENTIFIER_TEST(identifier) \
|
#define IDENTIFIER_TEST(identifier) \
|
||||||
TEST_CASE("Lex identifier " identifier) { \
|
TEST_CASE("Lex identifier " identifier) { \
|
||||||
ElohimScript::Diagnostics::Diagnostics diag; \
|
ElohimScript::Diagnostics::Diagnostics diag; \
|
||||||
auto lexer = Lexer(identifier, &diag); \
|
auto lexer = Lexer(identifier, identifier, &diag); \
|
||||||
const auto* token = lexer.Lex(); \
|
const auto* token = lexer.Lex(); \
|
||||||
CHECK(diag.GetMessages().empty()); \
|
CHECK(diag.GetMessages().empty()); \
|
||||||
REQUIRE(token->GetKind() == LexTokenKind::Identifier); \
|
REQUIRE(token->GetKind() == LexTokenKind::Identifier); \
|
||||||
|
|
|
@ -6,7 +6,7 @@ using namespace ElohimScript::Parser;
|
||||||
#define LEX_TEST(script, ...) \
|
#define LEX_TEST(script, ...) \
|
||||||
TEST_CASE("Lex: " script) { \
|
TEST_CASE("Lex: " script) { \
|
||||||
ElohimScript::Diagnostics::Diagnostics diag; \
|
ElohimScript::Diagnostics::Diagnostics diag; \
|
||||||
auto lexer = Lexer(script, &diag); \
|
auto lexer = Lexer(script, script, &diag); \
|
||||||
const auto* token = lexer.Lex(); \
|
const auto* token = lexer.Lex(); \
|
||||||
CHECK(diag.GetMessages().empty()); \
|
CHECK(diag.GetMessages().empty()); \
|
||||||
std::vector<LexTokenKind> vec = {__VA_ARGS__, LexTokenKind::EndOfFile}; \
|
std::vector<LexTokenKind> vec = {__VA_ARGS__, LexTokenKind::EndOfFile}; \
|
||||||
|
|
|
@ -6,7 +6,7 @@ using namespace ElohimScript::Parser;
|
||||||
#define INTEGER_TEST(script, expected) \
|
#define INTEGER_TEST(script, expected) \
|
||||||
TEST_CASE("Lex " script) { \
|
TEST_CASE("Lex " script) { \
|
||||||
ElohimScript::Diagnostics::Diagnostics diag; \
|
ElohimScript::Diagnostics::Diagnostics diag; \
|
||||||
auto lexer = Lexer(script, &diag); \
|
auto lexer = Lexer(script, script, &diag); \
|
||||||
const auto* token = lexer.Lex(); \
|
const auto* token = lexer.Lex(); \
|
||||||
CHECK(diag.GetMessages().empty()); \
|
CHECK(diag.GetMessages().empty()); \
|
||||||
REQUIRE(token->GetKind() == LexTokenKind::IntegerLiteral); \
|
REQUIRE(token->GetKind() == LexTokenKind::IntegerLiteral); \
|
||||||
|
@ -18,7 +18,7 @@ using namespace ElohimScript::Parser;
|
||||||
#define FLOAT_TEST(script, expected) \
|
#define FLOAT_TEST(script, expected) \
|
||||||
TEST_CASE("Lex " script) { \
|
TEST_CASE("Lex " script) { \
|
||||||
ElohimScript::Diagnostics::Diagnostics diag; \
|
ElohimScript::Diagnostics::Diagnostics diag; \
|
||||||
auto lexer = Lexer(script, &diag); \
|
auto lexer = Lexer(script, script, &diag); \
|
||||||
const auto* token = lexer.Lex(); \
|
const auto* token = lexer.Lex(); \
|
||||||
CHECK(diag.GetMessages().empty()); \
|
CHECK(diag.GetMessages().empty()); \
|
||||||
REQUIRE(token->GetKind() == LexTokenKind::FloatLiteral); \
|
REQUIRE(token->GetKind() == LexTokenKind::FloatLiteral); \
|
||||||
|
@ -73,11 +73,12 @@ INTEGER_TEST("0B110011", 51);
|
||||||
|
|
||||||
TEST_CASE("Lex invalid numerical base") {
|
TEST_CASE("Lex invalid numerical base") {
|
||||||
ElohimScript::Diagnostics::Diagnostics diag;
|
ElohimScript::Diagnostics::Diagnostics diag;
|
||||||
auto lexer = Lexer("0f553", &diag);
|
auto lexer = Lexer("bad base", "0f553", &diag);
|
||||||
lexer.Lex();
|
lexer.Lex();
|
||||||
const auto& messages = diag.GetMessages();
|
const auto& messages = diag.GetMessages();
|
||||||
REQUIRE(messages.size() == 1);
|
REQUIRE(messages.size() == 1);
|
||||||
CHECK(messages[0].GetType() == ElohimScript::Diagnostics::DiagnosticType::InvalidNumericalBase);
|
CHECK(messages[0].GetType() == ElohimScript::Diagnostics::DiagnosticType::InvalidNumericalBase);
|
||||||
CHECK(messages[0].GetLevel() == ElohimScript::Diagnostics::DiagnosticLevel::Error);
|
CHECK(messages[0].GetLevel() == ElohimScript::Diagnostics::DiagnosticLevel::Error);
|
||||||
CHECK(messages[0].GetSpan() == ElohimScript::TextSpan(0, 2));
|
CHECK(messages[0].GetSpan() == ElohimScript::TextSpan(0, 2));
|
||||||
|
CHECK(messages[0].GetScriptName() == u8"bad base");
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ using namespace ElohimScript::Parser;
|
||||||
#define STRING_TEST(str, constraint) \
|
#define STRING_TEST(str, constraint) \
|
||||||
TEST_CASE("Lex string " constraint str constraint) { \
|
TEST_CASE("Lex string " constraint str constraint) { \
|
||||||
ElohimScript::Diagnostics::Diagnostics diag; \
|
ElohimScript::Diagnostics::Diagnostics diag; \
|
||||||
auto lexer = Lexer(constraint str constraint, &diag); \
|
auto lexer = Lexer(str, constraint str constraint, &diag); \
|
||||||
const auto* token = lexer.Lex(); \
|
const auto* token = lexer.Lex(); \
|
||||||
CHECK(diag.GetMessages().empty()); \
|
CHECK(diag.GetMessages().empty()); \
|
||||||
REQUIRE(token->GetKind() == LexTokenKind::StringLiteral); \
|
REQUIRE(token->GetKind() == LexTokenKind::StringLiteral); \
|
||||||
|
@ -23,7 +23,7 @@ STRING_TEST("\"\"foo bar\"\"", "\"\"\"");
|
||||||
|
|
||||||
TEST_CASE("Lex multiline string") {
|
TEST_CASE("Lex multiline string") {
|
||||||
ElohimScript::Diagnostics::Diagnostics diag;
|
ElohimScript::Diagnostics::Diagnostics diag;
|
||||||
auto lexer = Lexer(R"("""foo
|
auto lexer = Lexer("multiline", R"("""foo
|
||||||
bar""")",
|
bar""")",
|
||||||
&diag);
|
&diag);
|
||||||
const auto* token = lexer.Lex();
|
const auto* token = lexer.Lex();
|
||||||
|
|
|
@ -7,7 +7,7 @@ using namespace ElohimScript::Parser;
|
||||||
#define SYMBOL_TEST(script, symbol) \
|
#define SYMBOL_TEST(script, symbol) \
|
||||||
TEST_CASE("Lex " script) { \
|
TEST_CASE("Lex " script) { \
|
||||||
ElohimScript::Diagnostics::Diagnostics diag; \
|
ElohimScript::Diagnostics::Diagnostics diag; \
|
||||||
auto lexer = Lexer(script, &diag); \
|
auto lexer = Lexer(script, script, &diag); \
|
||||||
const auto* token = lexer.Lex(); \
|
const auto* token = lexer.Lex(); \
|
||||||
CHECK(diag.GetMessages().empty()); \
|
CHECK(diag.GetMessages().empty()); \
|
||||||
CHECK(token->GetKind() == LexTokenKind::symbol); \
|
CHECK(token->GetKind() == LexTokenKind::symbol); \
|
||||||
|
@ -72,9 +72,9 @@ SYMBOL_TEST(" ", Whitespace)
|
||||||
|
|
||||||
TEST_CASE("Lex whitespace") {
|
TEST_CASE("Lex whitespace") {
|
||||||
auto whitespace = {" ", "\t", "\n", "\r", "\xef\xbb\xbf"};
|
auto whitespace = {" ", "\t", "\n", "\r", "\xef\xbb\xbf"};
|
||||||
for (const auto *v : whitespace) {
|
for (const auto* v : whitespace) {
|
||||||
ElohimScript::Diagnostics::Diagnostics diag;
|
ElohimScript::Diagnostics::Diagnostics diag;
|
||||||
auto lexer = Lexer(v, &diag);
|
auto lexer = Lexer("whitespace", v, &diag);
|
||||||
const auto* token = lexer.Lex();
|
const auto* token = lexer.Lex();
|
||||||
CHECK(diag.GetMessages().empty());
|
CHECK(diag.GetMessages().empty());
|
||||||
CHECK(token->GetKind() == LexTokenKind::Whitespace);
|
CHECK(token->GetKind() == LexTokenKind::Whitespace);
|
||||||
|
|
Loading…
Reference in New Issue