diff options
author | Spartan322 <Megacake1234@gmail.com> | 2023-08-17 13:24:36 +0200 |
---|---|---|
committer | Spartan322 <Megacake1234@gmail.com> | 2023-08-17 13:24:36 +0200 |
commit | 9808d275dc7a98fb26c4d67b610a5f1030891b07 (patch) | |
tree | c26834ea94407111152e76c20218cf069c75a694 /src/openvic-dataloader | |
parent | 90f15b582788a9aab0dfe6c81fc4cbbe1d4d3308 (diff) |
Add error retrieval
Diffstat (limited to 'src/openvic-dataloader')
-rw-r--r-- | src/openvic-dataloader/detail/Errors.hpp | 4 | ||||
-rw-r--r-- | src/openvic-dataloader/detail/LexyReportError.hpp | 99 | ||||
-rw-r--r-- | src/openvic-dataloader/detail/Warnings.hpp | 4 | ||||
-rw-r--r-- | src/openvic-dataloader/v2script/Parser.cpp | 29 |
4 files changed, 117 insertions, 19 deletions
diff --git a/src/openvic-dataloader/detail/Errors.hpp b/src/openvic-dataloader/detail/Errors.hpp index f8ed21b..c8f2954 100644 --- a/src/openvic-dataloader/detail/Errors.hpp +++ b/src/openvic-dataloader/detail/Errors.hpp @@ -3,7 +3,7 @@ #include "openvic-dataloader/v2script/Parser.hpp" namespace ovdl::v2script::errors { - inline const v2script::Parser::Error make_no_file_error(const char* file_path) { + inline const ParseError make_no_file_error(const char* file_path) { std::string message; if (!file_path) { message = "File path not specified."; @@ -11,7 +11,7 @@ namespace ovdl::v2script::errors { message = "File '" + std::string(file_path) + "' was not found."; } - return v2script::Parser::Error { Parser::Error::Type::Fatal, message, 1 }; + return ParseError { ParseError::Type::Fatal, message, 1 }; } } diff --git a/src/openvic-dataloader/detail/LexyReportError.hpp b/src/openvic-dataloader/detail/LexyReportError.hpp new file mode 100644 index 0000000..46d7911 --- /dev/null +++ b/src/openvic-dataloader/detail/LexyReportError.hpp @@ -0,0 +1,99 @@ +#pragma once + +#include <cstddef> +#include <string> +#include <utility> +#include <vector> + +#include "openvic-dataloader/ParseData.hpp" +#include <lexy/input_location.hpp> +#include <lexy/visualize.hpp> +#include <lexy_ext/report_error.hpp> +#include <openvic-dataloader/ParseError.hpp> + +namespace ovdl::detail { + template<typename OutputIterator> + struct _ReportError { + OutputIterator _iter; + lexy::visualization_options _opts; + const char* _path; + + struct _sink { + OutputIterator _iter; + lexy::visualization_options _opts; + const char* _path; + std::size_t _count; + std::vector<ParseError> _errors; + + using return_type = std::vector<ParseError>; + + template<typename Input, typename Reader, typename Tag> + void operator()(const lexy::error_context<Input>& context, const lexy::error<Reader, Tag>& error) { + _iter = lexy_ext::_detail::write_error(_iter, context, error, _opts, _path); + ++_count; + + // Convert the context location and error location into line/column information. + auto context_location = lexy::get_input_location(context.input(), context.position()); + auto location = lexy::get_input_location(context.input(), error.position(), context_location.anchor()); + + std::string message; + + // Write the main annotation. + if constexpr (std::is_same_v<Tag, lexy::expected_literal>) { + auto string = lexy::_detail::make_literal_lexeme<typename Reader::encoding>(error.string(), error.length()); + + message = std::string("expected '") + string.data() + "'"; + } else if constexpr (std::is_same_v<Tag, lexy::expected_keyword>) { + auto string = lexy::_detail::make_literal_lexeme<typename Reader::encoding>(error.string(), error.length()); + + message = std::string("expected keyword '") + string.data() + "'"; + } else if constexpr (std::is_same_v<Tag, lexy::expected_char_class>) { + message = std::string("expected ") + error.name(); + } else { + message = error.message(); + } + + _errors.push_back( + ParseError { + ParseError::Type::Fatal, // TODO: distinguish recoverable errors from fatal errors + std::move(message), + 0, // TODO: implement proper error codes + ParseData { + context.production(), + context_location.line_nr(), + context_location.column_nr(), + }, + location.line_nr(), + location.column_nr(), + }); + } + + return_type finish() && { + if (_count != 0) + *_iter++ = '\n'; + return _errors; + } + }; + constexpr auto sink() const { + return _sink { _iter, _opts, _path, 0 }; + } + + /// Specifies a path that will be printed alongside the diagnostic. + constexpr _ReportError path(const char* path) const { + return { _iter, _opts, path }; + } + + /// Specifies an output iterator where the errors are written to. + template<typename OI> + constexpr _ReportError<OI> to(OI out) const { + return { out, _opts, _path }; + } + + /// Overrides visualization options. + constexpr _ReportError opts(lexy::visualization_options opts) const { + return { _iter, opts, _path }; + } + }; + + constexpr auto ReporError = _ReportError<lexy::stderr_output_iterator> {}; +}
\ No newline at end of file diff --git a/src/openvic-dataloader/detail/Warnings.hpp b/src/openvic-dataloader/detail/Warnings.hpp index f854fa8..fc0fbed 100644 --- a/src/openvic-dataloader/detail/Warnings.hpp +++ b/src/openvic-dataloader/detail/Warnings.hpp @@ -3,7 +3,7 @@ #include "openvic-dataloader/v2script/Parser.hpp" namespace ovdl::v2script::warnings { - inline const v2script::Parser::Warning make_utf8_warning(const char* file_path) { + inline const ParseWarning make_utf8_warning(const char* file_path) { constexpr std::string_view message_suffix = "This may cause problems. Prefer Windows-1252 encoding."; std::string message; @@ -13,7 +13,7 @@ namespace ovdl::v2script::warnings { message = "File '" + std::string(file_path) + "' is a UTF-8 encoded file. " + std::string(message_suffix); } - return v2script::Parser::Warning { message, 1 }; + return ParseWarning { message, 1 }; } } diff --git a/src/openvic-dataloader/v2script/Parser.cpp b/src/openvic-dataloader/v2script/Parser.cpp index c0b6bd8..7df9b99 100644 --- a/src/openvic-dataloader/v2script/Parser.cpp +++ b/src/openvic-dataloader/v2script/Parser.cpp @@ -4,13 +4,13 @@ #include <memory> #include <optional> #include <string> -#include <string_view> #include <utility> #include <vector> #include "SimpleGrammar.hpp" #include "detail/DetectUtf8.hpp" #include "detail/Errors.hpp" +#include "detail/LexyReportError.hpp" #include "detail/NullBuff.hpp" #include "detail/Warnings.hpp" #include <lexy/action/parse.hpp> @@ -19,7 +19,8 @@ #include <lexy/input/file.hpp> #include <lexy/lexeme.hpp> #include <lexy/visualize.hpp> -#include <lexy_ext/report_error.hpp> +#include <openvic-dataloader/ParseError.hpp> +#include <openvic-dataloader/ParseWarning.hpp> #include <openvic-dataloader/v2script/AbstractSyntaxTree.hpp> using namespace ovdl::v2script; @@ -32,17 +33,17 @@ public: return _buffer.size() != 0; } - std::optional<Error> load_buffer(const char* data, std::size_t size) { + std::optional<ParseError> load_buffer(const char* data, std::size_t size) { _buffer = lexy::buffer(data, size); return std::nullopt; } - std::optional<Error> load_buffer(const char* start, const char* end) { + std::optional<ParseError> load_buffer(const char* start, const char* end) { _buffer = lexy::buffer(start, end); return std::nullopt; } - std::optional<Error> load_file(const char* path) { + std::optional<ParseError> load_file(const char* path) { auto file = lexy::read_file(path); if (!file) { return errors::make_no_file_error(path); @@ -57,11 +58,10 @@ public: } template<typename Node, typename ErrorCallback> - std::optional<std::vector<Error>> parse(const ErrorCallback& callback) { + std::optional<std::vector<ParseError>> parse(const ErrorCallback& callback) { auto result = lexy::parse<Node>(_buffer, callback); if (!result) { - std::vector<Error> errors; - return errors; + return result.errors(); } // This is mighty frustrating _root = std::unique_ptr<ast::Node>(result.value()); @@ -117,12 +117,12 @@ Parser Parser::from_file(const char* path) { /// @param args /// template<typename... Args> -inline void Parser::_run_load_func(std::optional<Error> (BufferHandler::*func)(Args...), Args... args) { +inline void Parser::_run_load_func(std::optional<ParseError> (BufferHandler::*func)(Args...), Args... args) { _warnings.clear(); _errors.clear(); _has_fatal_error = false; if (auto error = (_buffer_handler.get()->*func)(args...); error) { - _has_fatal_error = error.value().type == Error::Type::Fatal; + _has_fatal_error = error.value().type == ParseError::Type::Fatal; _errors.push_back(error.value()); _error_stream.get() << "Error: " << _errors.back().message << '\n'; } @@ -185,13 +185,12 @@ bool Parser::simple_parse() { _warnings.push_back(warnings::make_utf8_warning(_file_path)); } - auto errors = _buffer_handler->parse<grammar::File>(lexy_ext::report_error.path(_file_path).to(ostream_output_iterator { _error_stream })); + auto errors = _buffer_handler->parse<grammar::File>(ovdl::detail::ReporError.path(_file_path).to(ostream_output_iterator { _error_stream })); if (errors) { _errors.reserve(errors->size()); for (auto& err : errors.value()) { - _has_fatal_error |= err.type == Error::Type::Fatal; + _has_fatal_error |= err.type == ParseError::Type::Fatal; _errors.push_back(err); - _error_stream.get() << "Error: " << err.message << '\n'; } return false; } @@ -211,11 +210,11 @@ bool Parser::has_warning() const { return !_warnings.empty(); } -const std::vector<Parser::Error>& Parser::get_errors() const { +const std::vector<ovdl::ParseError>& Parser::get_errors() const { return _errors; } -const std::vector<Parser::Warning>& Parser::get_warnings() const { +const std::vector<ovdl::ParseWarning>& Parser::get_warnings() const { return _warnings; } |