Support adding filename to diagnostic.
This commit is contained in:
		| @@ -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); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user