aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Spartan322 <Megacake1234@gmail.com>2023-08-17 13:24:36 +0200
committer Spartan322 <Megacake1234@gmail.com>2023-08-17 13:24:36 +0200
commit9808d275dc7a98fb26c4d67b610a5f1030891b07 (patch)
treec26834ea94407111152e76c20218cf069c75a694
parent90f15b582788a9aab0dfe6c81fc4cbbe1d4d3308 (diff)
Add error retrieval
-rw-r--r--include/openvic-dataloader/ParseData.hpp11
-rw-r--r--include/openvic-dataloader/ParseError.hpp20
-rw-r--r--include/openvic-dataloader/ParseWarning.hpp10
-rw-r--r--include/openvic-dataloader/v2script/Parser.hpp27
-rw-r--r--src/openvic-dataloader/detail/Errors.hpp4
-rw-r--r--src/openvic-dataloader/detail/LexyReportError.hpp99
-rw-r--r--src/openvic-dataloader/detail/Warnings.hpp4
-rw-r--r--src/openvic-dataloader/v2script/Parser.cpp29
8 files changed, 165 insertions, 39 deletions
diff --git a/include/openvic-dataloader/ParseData.hpp b/include/openvic-dataloader/ParseData.hpp
new file mode 100644
index 0000000..8bec7d2
--- /dev/null
+++ b/include/openvic-dataloader/ParseData.hpp
@@ -0,0 +1,11 @@
+#pragma once
+
+#include <string>
+
+namespace ovdl {
+ struct ParseData {
+ const std::string production_name;
+ const unsigned int context_start_line;
+ const unsigned int context_start_column;
+ };
+} \ No newline at end of file
diff --git a/include/openvic-dataloader/ParseError.hpp b/include/openvic-dataloader/ParseError.hpp
new file mode 100644
index 0000000..f3ae287
--- /dev/null
+++ b/include/openvic-dataloader/ParseError.hpp
@@ -0,0 +1,20 @@
+#pragma once
+
+#include <string>
+
+#include "openvic-dataloader/ParseData.hpp"
+
+namespace ovdl {
+ struct ParseError {
+ const enum class Type : unsigned char {
+ Recoverable,
+ Fatal
+ } type;
+ const std::string message;
+ const int error_value;
+ const ParseData parse_data;
+ const unsigned int start_line;
+ const unsigned int start_column;
+ };
+
+} \ No newline at end of file
diff --git a/include/openvic-dataloader/ParseWarning.hpp b/include/openvic-dataloader/ParseWarning.hpp
new file mode 100644
index 0000000..307599f
--- /dev/null
+++ b/include/openvic-dataloader/ParseWarning.hpp
@@ -0,0 +1,10 @@
+#pragma once
+
+#include <string>
+
+namespace ovdl {
+ struct ParseWarning {
+ const std::string message;
+ const int warning_value;
+ };
+} \ No newline at end of file
diff --git a/include/openvic-dataloader/v2script/Parser.hpp b/include/openvic-dataloader/v2script/Parser.hpp
index dbbec73..e971cdb 100644
--- a/include/openvic-dataloader/v2script/Parser.hpp
+++ b/include/openvic-dataloader/v2script/Parser.hpp
@@ -5,9 +5,10 @@
#include <memory>
#include <optional>
#include <ostream>
-#include <string>
#include <vector>
+#include <openvic-dataloader/ParseError.hpp>
+#include <openvic-dataloader/ParseWarning.hpp>
#include <openvic-dataloader/v2script/AbstractSyntaxTree.hpp>
namespace ovdl::v2script {
@@ -16,20 +17,6 @@ namespace ovdl::v2script {
class Parser {
public:
- struct Error {
- const enum class Type : unsigned char {
- Recoverable,
- Fatal
- } type;
- const std::string message;
- const int error_value;
- };
-
- struct Warning {
- const std::string message;
- const int warning_value;
- };
-
Parser();
static Parser from_buffer(const char* data, std::size_t size);
@@ -51,8 +38,8 @@ namespace ovdl::v2script {
bool has_fatal_error() const;
bool has_warning() const;
- const std::vector<Error>& get_errors() const;
- const std::vector<Warning>& get_warnings() const;
+ const std::vector<ParseError>& get_errors() const;
+ const std::vector<ParseWarning>& get_warnings() const;
const FileNode* get_file_node() const;
@@ -62,8 +49,8 @@ namespace ovdl::v2script {
~Parser();
private:
- std::vector<Error> _errors;
- std::vector<Warning> _warnings;
+ std::vector<ParseError> _errors;
+ std::vector<ParseWarning> _warnings;
class BufferHandler;
friend class BufferHandler;
@@ -74,6 +61,6 @@ namespace ovdl::v2script {
bool _has_fatal_error = false;
template<typename... Args>
- inline void _run_load_func(std::optional<Error> (BufferHandler::*func)(Args...), Args... args);
+ inline void _run_load_func(std::optional<ParseError> (BufferHandler::*func)(Args...), Args... args);
};
} \ No newline at end of file
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;
}