aboutsummaryrefslogtreecommitdiff
path: root/src/openvic-dataloader/v2script/Parser.cpp
diff options
context:
space:
mode:
author Spartan322 <Megacake1234@gmail.com>2023-11-28 11:09:26 +0100
committer Spartan322 <Megacake1234@gmail.com>2024-05-09 22:11:26 +0200
commit757114a3c5b748567b42f273c7b78ca039ae983c (patch)
treee07390b682052129c91f4b157068bcdd84ceecb4 /src/openvic-dataloader/v2script/Parser.cpp
parent7211a228e68c8a6b1ad1c1c5ec68c8d720b6d2ba (diff)
Add `deps/dryad` -> https://github.com/Spartan322/dryadadd/dryad
Add `deps/fmt` -> https://github.com/fmtlib/fmt Add `deps/range-v3` -> https://github.com/ericniebler/range-v3 Improve parser error and warning support Update .clang-format Update `deps/SCsub`
Diffstat (limited to 'src/openvic-dataloader/v2script/Parser.cpp')
-rw-r--r--src/openvic-dataloader/v2script/Parser.cpp280
1 files changed, 154 insertions, 126 deletions
diff --git a/src/openvic-dataloader/v2script/Parser.cpp b/src/openvic-dataloader/v2script/Parser.cpp
index 3141550..29e9e80 100644
--- a/src/openvic-dataloader/v2script/Parser.cpp
+++ b/src/openvic-dataloader/v2script/Parser.cpp
@@ -1,29 +1,38 @@
#include "openvic-dataloader/v2script/Parser.hpp"
-#include <functional>
-#include <memory>
+#include <iostream>
#include <optional>
#include <string>
#include <utility>
-#include <vector>
+#include <openvic-dataloader/DiagnosticLogger.hpp>
+#include <openvic-dataloader/NodeLocation.hpp>
#include <openvic-dataloader/ParseError.hpp>
#include <openvic-dataloader/ParseWarning.hpp>
-#include <openvic-dataloader/detail/Concepts.hpp>
+#include <openvic-dataloader/detail/LexyReportError.hpp>
+#include <openvic-dataloader/detail/OStreamOutputIterator.hpp>
+#include <openvic-dataloader/detail/utility/Concepts.hpp>
+#include <openvic-dataloader/detail/utility/Utility.hpp>
#include <openvic-dataloader/v2script/AbstractSyntaxTree.hpp>
-#include <openvic-dataloader/v2script/NodeLocationMap.hpp>
#include <lexy/action/parse.hpp>
#include <lexy/encoding.hpp>
#include <lexy/input/buffer.hpp>
#include <lexy/input/file.hpp>
+#include <lexy/input_location.hpp>
#include <lexy/lexeme.hpp>
#include <lexy/visualize.hpp>
-#include "detail/BasicBufferHandler.hpp"
+#include <dryad/node.hpp>
+#include <dryad/tree.hpp>
+
+#include <fmt/core.h>
+
+#include "openvic-dataloader/Error.hpp"
+
#include "detail/DetectUtf8.hpp"
-#include "detail/LexyReportError.hpp"
-#include "detail/OStreamOutputIterator.hpp"
+#include "detail/NullBuff.hpp"
+#include "detail/ParseHandler.hpp"
#include "detail/Warnings.hpp"
#include "v2script/DecisionGrammar.hpp"
#include "v2script/EventGrammar.hpp"
@@ -35,42 +44,36 @@ using namespace ovdl::v2script;
/// BufferHandler ///
-class Parser::BufferHandler final : public detail::BasicBufferHandler<> {
-public:
+struct Parser::ParseHandler final : detail::BasicStateParseHandler<v2script::ast::ParseState> {
constexpr bool is_exclusive_utf8() const {
- return detail::is_utf8_no_ascii(_buffer);
+ return detail::is_utf8_no_ascii(buffer());
}
- template<typename Node, typename ErrorCallback>
- std::optional<std::vector<ParseError>> parse(const ErrorCallback& callback) {
- auto result = lexy::parse<Node>(_buffer, callback);
+ template<typename Node>
+ std::optional<DiagnosticLogger::error_range> parse() {
+ auto result = lexy::parse<Node>(buffer(), *_parse_state, _parse_state->logger().error_callback());
if (!result) {
- return result.errors();
+ return _parse_state->logger().get_errors();
}
- // This is mighty frustrating
- _root = std::unique_ptr<ast::Node>(result.value());
+ _parse_state->ast().set_root(result.value());
return std::nullopt;
}
- std::unique_ptr<ast::Node>& get_root() {
- return _root;
+ ast::FileTree* root() {
+ return _parse_state->ast().root();
}
-
- ast::NodeLocationMap<decltype(_buffer)>& get_location_map() {
- return _location_map;
- }
-
-private:
- friend class ::ovdl::v2script::ast::Node;
- std::unique_ptr<ast::Node> _root;
- ast::NodeLocationMap<decltype(_buffer)> _location_map;
};
/// BufferHandler ///
Parser::Parser()
- : _buffer_handler(std::make_unique<BufferHandler>()) {
- set_error_log_to_stderr();
+ : _parse_handler(std::make_unique<ParseHandler>()) {
+ set_error_log_to_null();
+}
+
+Parser::Parser(std::basic_ostream<char>& error_stream)
+ : _parse_handler(std::make_unique<ParseHandler>()) {
+ set_error_log_to(error_stream);
}
Parser::Parser(Parser&&) = default;
@@ -116,26 +119,29 @@ Parser Parser::from_file(const std::filesystem::path& path) {
/// @param args
///
template<typename... Args>
-constexpr void Parser::_run_load_func(detail::LoadCallback<BufferHandler, Args...> auto func, Args... args) {
- _warnings.clear();
- _errors.clear();
+constexpr void Parser::_run_load_func(detail::LoadCallback<Parser::ParseHandler*, Args...> auto func, Args... args) {
_has_fatal_error = false;
- if (auto error = func(_buffer_handler.get(), std::forward<Args>(args)...); error) {
- _has_fatal_error = error.value().type == ParseError::Type::Fatal;
- _errors.push_back(error.value());
- _error_stream.get() << "Error: " << _errors.back().message << '\n';
+ auto error = func(_parse_handler.get(), std::forward<Args>(args)...);
+ auto error_message = _parse_handler->make_error_from(error);
+ if (!error_message.empty()) {
+ _has_error = true;
+ _has_fatal_error = true;
+ _parse_handler->parse_state().logger().create_log<error::BufferError>(DiagnosticLogger::DiagnosticKind::error, fmt::runtime(error_message));
+ }
+ if (has_error() && &_error_stream.get() != &detail::cnull) {
+ print_errors_to(_error_stream.get());
}
}
constexpr Parser& Parser::load_from_buffer(const char* data, std::size_t size) {
// Type can't be deduced?
- _run_load_func(std::mem_fn(&BufferHandler::load_buffer_size), data, size);
+ _run_load_func(std::mem_fn(&ParseHandler::load_buffer_size), data, size);
return *this;
}
constexpr Parser& Parser::load_from_buffer(const char* start, const char* end) {
// Type can't be deduced?
- _run_load_func(std::mem_fn(&BufferHandler::load_buffer), start, end);
+ _run_load_func(std::mem_fn(&ParseHandler::load_buffer), start, end);
return *this;
}
@@ -146,7 +152,7 @@ constexpr Parser& Parser::load_from_string(const std::string_view string) {
constexpr Parser& Parser::load_from_file(const char* path) {
_file_path = path;
// Type can be deduced??
- _run_load_func(std::mem_fn(&BufferHandler::load_file), path);
+ _run_load_func(std::mem_fn(&ParseHandler::load_file), path);
return *this;
}
@@ -154,10 +160,6 @@ Parser& Parser::load_from_file(const std::filesystem::path& path) {
return load_from_file(path.string().c_str());
}
-constexpr Parser& Parser::load_from_file(const detail::Has_c_str auto& path) {
- return load_from_file(path.c_str());
-}
-
/* REQUIREMENTS:
* DAT-23
* DAT-26
@@ -165,149 +167,175 @@ constexpr Parser& Parser::load_from_file(const detail::Has_c_str auto& path) {
* DAT-29
*/
bool Parser::simple_parse() {
- if (!_buffer_handler->is_valid()) {
+ if (!_parse_handler->is_valid()) {
return false;
}
- if (_buffer_handler->is_exclusive_utf8()) {
- _warnings.push_back(warnings::make_utf8_warning(_file_path));
+ if (_parse_handler->is_exclusive_utf8()) {
+ _parse_handler->parse_state().logger().warning(warnings::make_utf8_warning(_file_path));
}
- auto errors = _buffer_handler->parse<grammar::File<grammar::NoStringEscapeOption>>(ovdl::detail::ReporError.path(_file_path).to(detail::OStreamOutputIterator { _error_stream }));
- if (errors) {
- _errors.reserve(errors->size());
- for (auto& err : errors.value()) {
- _has_fatal_error |= err.type == ParseError::Type::Fatal;
- _errors.push_back(err);
+ auto errors = _parse_handler->parse<grammar::File<grammar::NoStringEscapeOption>>();
+ _has_error = _parse_handler->parse_state().logger().errored();
+ _has_warning = _parse_handler->parse_state().logger().warned();
+ if (!_parse_handler->root()) {
+ _has_fatal_error = true;
+ if (&_error_stream.get() != &detail::cnull) {
+ print_errors_to(_error_stream);
}
return false;
}
- _file_node.reset(static_cast<ast::FileNode*>(_buffer_handler->get_root().release()));
return true;
}
bool Parser::event_parse() {
- if (!_buffer_handler->is_valid()) {
+ if (!_parse_handler->is_valid()) {
return false;
}
- if (_buffer_handler->is_exclusive_utf8()) {
- _warnings.push_back(warnings::make_utf8_warning(_file_path));
+ if (_parse_handler->is_exclusive_utf8()) {
+ _parse_handler->parse_state().logger().warning(warnings::make_utf8_warning(_file_path));
}
- auto errors = _buffer_handler->parse<grammar::EventFile>(ovdl::detail::ReporError.path(_file_path).to(detail::OStreamOutputIterator { _error_stream }));
- if (errors) {
- _errors.reserve(errors->size());
- for (auto& err : errors.value()) {
- _has_fatal_error |= err.type == ParseError::Type::Fatal;
- _errors.push_back(err);
+ auto errors = _parse_handler->parse<grammar::EventFile>();
+ _has_error = _parse_handler->parse_state().logger().errored();
+ _has_warning = _parse_handler->parse_state().logger().warned();
+ if (!_parse_handler->root()) {
+ _has_fatal_error = true;
+ if (&_error_stream.get() != &detail::cnull) {
+ print_errors_to(_error_stream);
}
return false;
}
- _file_node.reset(static_cast<ast::FileNode*>(_buffer_handler->get_root().release()));
return true;
}
bool Parser::decision_parse() {
- if (!_buffer_handler->is_valid()) {
+ if (!_parse_handler->is_valid()) {
return false;
}
- if (_buffer_handler->is_exclusive_utf8()) {
- _warnings.push_back(warnings::make_utf8_warning(_file_path));
+ if (_parse_handler->is_exclusive_utf8()) {
+ _parse_handler->parse_state().logger().warning(warnings::make_utf8_warning(_file_path));
}
- auto errors = _buffer_handler->parse<grammar::DecisionFile>(ovdl::detail::ReporError.path(_file_path).to(detail::OStreamOutputIterator { _error_stream }));
- if (errors) {
- _errors.reserve(errors->size());
- for (auto& err : errors.value()) {
- _has_fatal_error |= err.type == ParseError::Type::Fatal;
- _errors.push_back(err);
+ auto errors = _parse_handler->parse<grammar::DecisionFile>();
+ _has_error = _parse_handler->parse_state().logger().errored();
+ _has_warning = _parse_handler->parse_state().logger().warned();
+ if (!_parse_handler->root()) {
+ _has_fatal_error = true;
+ if (&_error_stream.get() != &detail::cnull) {
+ print_errors_to(_error_stream);
}
return false;
}
- _file_node.reset(static_cast<ast::FileNode*>(_buffer_handler->get_root().release()));
return true;
}
bool Parser::lua_defines_parse() {
- if (!_buffer_handler->is_valid()) {
+ if (!_parse_handler->is_valid()) {
return false;
}
- if (_buffer_handler->is_exclusive_utf8()) {
- _warnings.push_back(warnings::make_utf8_warning(_file_path));
+ if (_parse_handler->is_exclusive_utf8()) {
+ _parse_handler->parse_state().logger().warning(warnings::make_utf8_warning(_file_path));
}
- auto errors = _buffer_handler->parse<lua::grammar::File<>>(ovdl::detail::ReporError.path(_file_path).to(detail::OStreamOutputIterator { _error_stream }));
- if (errors) {
- _errors.reserve(errors->size());
- for (auto& err : errors.value()) {
- _has_fatal_error |= err.type == ParseError::Type::Fatal;
- _errors.push_back(err);
+ auto errors = _parse_handler->parse<lua::grammar::File<>>();
+ _has_error = _parse_handler->parse_state().logger().errored();
+ _has_warning = _parse_handler->parse_state().logger().warned();
+ if (!_parse_handler->root()) {
+ _has_fatal_error = true;
+ if (&_error_stream.get() != &detail::cnull) {
+ print_errors_to(_error_stream);
}
return false;
}
- _file_node.reset(static_cast<ast::FileNode*>(_buffer_handler->get_root().release()));
return true;
}
-const FileNode* Parser::get_file_node() const {
- return _file_node.get();
+const FileTree* Parser::get_file_node() const {
+ return _parse_handler->root();
}
-void Parser::generate_node_location_map() {
- _buffer_handler->get_location_map().clear();
- _buffer_handler->get_location_map().generate_location_map(_buffer_handler->get_buffer(), get_file_node());
+std::string_view Parser::value(const ovdl::v2script::ast::FlatValue& node) const {
+ return node.value(_parse_handler->parse_state().ast().symbol_interner());
}
-const ast::Node::line_col Parser::get_node_begin(const ast::NodeCPtr node) const {
- if (!node) return { 0, 0 };
- return node->get_begin_line_col(*this);
+std::string Parser::make_native_string() const {
+ return _parse_handler->parse_state().ast().make_native_visualizer();
}
-const ast::Node::line_col Parser::get_node_end(const ast::NodeCPtr node) const {
- if (!node) return { 0, 0 };
- return node->get_end_line_col(*this);
+std::string Parser::make_list_string() const {
+ return _parse_handler->parse_state().ast().make_list_visualizer();
}
-const ast::Node::line_col ast::Node::get_begin_line_col(const Parser& parser) const {
- if (!parser._buffer_handler->is_valid() || parser._buffer_handler->_location_map.empty()) return {};
- line_col result {};
- auto [itr, range_end] = parser._buffer_handler->_location_map.equal_range(this);
- if (itr != range_end) {
- result.line = itr->second.line_nr();
- result.column = itr->second.column_nr();
+const FilePosition Parser::get_position(const ast::Node* node) const {
+ if (!node || !node->is_linked_in_tree()) {
+ return {};
}
- // Standard doesn't really guarantee the direction of the range's sequence, but only GCC goes backwards
- // TODO: DON'T USE STANDARD UNORDERED_MULTIMAP
-#if defined(__GNUC__) && !defined(__clang__)
- itr++;
- if (itr != range_end) {
- result.line = itr->second.line_nr();
- result.column = itr->second.column_nr();
+ auto node_location = _parse_handler->parse_state().ast().location_of(node);
+ if (node_location.is_synthesized()) {
+ return {};
+ }
+
+ auto loc_begin = lexy::get_input_location(_parse_handler->buffer(), node_location.begin());
+ FilePosition result { loc_begin.line_nr(), loc_begin.line_nr(), loc_begin.column_nr(), loc_begin.column_nr() };
+ if (node_location.begin() < node_location.end()) {
+ auto loc_end = lexy::get_input_location(_parse_handler->buffer(), node_location.end(), loc_begin.anchor());
+ result.end_line = loc_end.line_nr();
+ result.end_column = loc_end.column_nr();
}
-#endif
return result;
}
-const ast::Node::line_col ast::Node::get_end_line_col(const Parser& parser) const {
- if (!parser._buffer_handler->is_valid() || parser._buffer_handler->_location_map.empty()) return {};
- line_col result {};
- auto [itr, range_end] = parser._buffer_handler->_location_map.equal_range(this);
- if (itr != range_end) {
- result.line = itr->second.line_nr();
- result.column = itr->second.column_nr();
+Parser::error_range Parser::get_errors() const {
+ return _parse_handler->parse_state().logger().get_errors();
+}
+
+const FilePosition Parser::get_error_position(const error::Error* error) const {
+ if (!error || !error->is_linked_in_tree()) {
+ return {};
}
- // Standard doesn't really guarantee the direction of the range's sequence, but only GCC goes backwards
- // TODO: DON'T USE STANDARD UNORDERED_MULTIMAP
-#if defined(__GNUC__) && !defined(__clang__)
- return result;
-#endif
- itr++;
- if (itr != range_end) {
- result.line = itr->second.line_nr();
- result.column = itr->second.column_nr();
+ auto err_location = _parse_handler->parse_state().logger().location_of(error);
+ if (err_location.is_synthesized()) {
+ return {};
+ }
+
+ auto loc_begin = lexy::get_input_location(_parse_handler->buffer(), err_location.begin());
+ FilePosition result { loc_begin.line_nr(), loc_begin.line_nr(), loc_begin.column_nr(), loc_begin.column_nr() };
+ if (err_location.begin() < err_location.end()) {
+ auto loc_end = lexy::get_input_location(_parse_handler->buffer(), err_location.end(), loc_begin.anchor());
+ result.end_line = loc_end.line_nr();
+ result.end_column = loc_end.column_nr();
}
return result;
+}
+
+void Parser::print_errors_to(std::basic_ostream<char>& stream) const {
+ auto errors = get_errors();
+ if (errors.empty()) return;
+ for (const auto error : errors) {
+ dryad::visit_tree(
+ error,
+ [&](const error::BufferError* buffer_error) {
+ stream << buffer_error->message() << '\n';
+ },
+ [&](const error::ParseError* parse_error) {
+ stream << parse_error->message() << '\n';
+ },
+ [&](dryad::child_visitor<error::ErrorKind> visitor, const error::Semantic* semantic) {
+ stream << semantic->message() << '\n';
+ auto annotations = semantic->annotations();
+ for (auto annotation : annotations) {
+ visitor(annotation);
+ }
+ },
+ [&](const error::PrimaryAnnotation* primary) {
+ stream << primary->message() << '\n';
+ },
+ [&](const error::SecondaryAnnotation* secondary) {
+ stream << secondary->message() << '\n';
+ });
+ }
} \ No newline at end of file