From 757114a3c5b748567b42f273c7b78ca039ae983c Mon Sep 17 00:00:00 2001 From: Spartan322 Date: Tue, 28 Nov 2023 05:09:26 -0500 Subject: Add `deps/dryad` -> https://github.com/Spartan322/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` --- src/openvic-dataloader/AbstractSyntaxTree.cpp | 27 ++ src/openvic-dataloader/DiagnosticLogger.cpp | 16 + src/openvic-dataloader/File.cpp | 9 + src/openvic-dataloader/NodeLocation.cpp | 26 ++ src/openvic-dataloader/csv/CsvGrammar.hpp | 201 +++++----- src/openvic-dataloader/csv/CsvParseState.hpp | 28 ++ src/openvic-dataloader/csv/Parser.cpp | 161 +++++--- .../detail/BasicBufferHandler.hpp | 51 --- src/openvic-dataloader/detail/BasicParser.cpp | 51 --- src/openvic-dataloader/detail/BufferError.hpp | 17 + src/openvic-dataloader/detail/DetectUtf8.hpp | 12 +- src/openvic-dataloader/detail/LexyLitRange.hpp | 16 - src/openvic-dataloader/detail/LexyReportError.hpp | 106 ------ src/openvic-dataloader/detail/NullBuff.hpp | 8 +- .../detail/OStreamOutputIterator.hpp | 21 -- src/openvic-dataloader/detail/ParseHandler.hpp | 145 +++++++ src/openvic-dataloader/detail/Parser.cpp | 43 +++ src/openvic-dataloader/detail/StringLiteral.hpp | 232 ++++++++++++ src/openvic-dataloader/detail/Warnings.hpp | 4 +- src/openvic-dataloader/detail/dsl.hpp | 150 ++++++++ .../v2script/AbstractSyntaxTree.cpp | 417 +++++++-------------- .../v2script/AiBehaviorGrammar.hpp | 18 +- .../v2script/DecisionGrammar.hpp | 115 ++---- src/openvic-dataloader/v2script/EffectGrammar.hpp | 31 +- src/openvic-dataloader/v2script/EventGrammar.hpp | 214 ++++------- .../v2script/LuaDefinesGrammar.hpp | 82 ++-- .../v2script/ModifierGrammar.hpp | 49 ++- src/openvic-dataloader/v2script/Parser.cpp | 280 +++++++------- src/openvic-dataloader/v2script/SimpleGrammar.hpp | 262 +++++++------ src/openvic-dataloader/v2script/TriggerGrammar.hpp | 31 +- 30 files changed, 1537 insertions(+), 1286 deletions(-) create mode 100644 src/openvic-dataloader/AbstractSyntaxTree.cpp create mode 100644 src/openvic-dataloader/DiagnosticLogger.cpp create mode 100644 src/openvic-dataloader/File.cpp create mode 100644 src/openvic-dataloader/NodeLocation.cpp create mode 100644 src/openvic-dataloader/csv/CsvParseState.hpp delete mode 100644 src/openvic-dataloader/detail/BasicBufferHandler.hpp delete mode 100644 src/openvic-dataloader/detail/BasicParser.cpp create mode 100644 src/openvic-dataloader/detail/BufferError.hpp delete mode 100644 src/openvic-dataloader/detail/LexyLitRange.hpp delete mode 100644 src/openvic-dataloader/detail/LexyReportError.hpp delete mode 100644 src/openvic-dataloader/detail/OStreamOutputIterator.hpp create mode 100644 src/openvic-dataloader/detail/ParseHandler.hpp create mode 100644 src/openvic-dataloader/detail/Parser.cpp create mode 100644 src/openvic-dataloader/detail/StringLiteral.hpp create mode 100644 src/openvic-dataloader/detail/dsl.hpp (limited to 'src/openvic-dataloader') diff --git a/src/openvic-dataloader/AbstractSyntaxTree.cpp b/src/openvic-dataloader/AbstractSyntaxTree.cpp new file mode 100644 index 0000000..11a90dc --- /dev/null +++ b/src/openvic-dataloader/AbstractSyntaxTree.cpp @@ -0,0 +1,27 @@ +#include + +using namespace ovdl; + +AbstractSyntaxTree::symbol_type AbstractSyntaxTree::intern(const char* str, std::size_t length) { + return _symbol_interner.intern(str, length); +} + +AbstractSyntaxTree::symbol_type AbstractSyntaxTree::intern(std::string_view str) { + return intern(str.data(), str.size()); +} + +const char* AbstractSyntaxTree::intern_cstr(const char* str, std::size_t length) { + return intern(str, length).c_str(_symbol_interner); +} + +const char* AbstractSyntaxTree::intern_cstr(std::string_view str) { + return intern_cstr(str.data(), str.size()); +} + +AbstractSyntaxTree::symbol_interner_type& AbstractSyntaxTree::symbol_interner() { + return _symbol_interner; +} + +const AbstractSyntaxTree::symbol_interner_type& AbstractSyntaxTree::symbol_interner() const { + return _symbol_interner; +} \ No newline at end of file diff --git a/src/openvic-dataloader/DiagnosticLogger.cpp b/src/openvic-dataloader/DiagnosticLogger.cpp new file mode 100644 index 0000000..aae3dcb --- /dev/null +++ b/src/openvic-dataloader/DiagnosticLogger.cpp @@ -0,0 +1,16 @@ +#include + +using namespace ovdl; + +DiagnosticLogger::operator bool() const { + return !_errored; +} + +bool DiagnosticLogger::errored() const { return _errored; } +bool DiagnosticLogger::warned() const { return _warned; } + + +NodeLocation DiagnosticLogger::location_of(const error::Error* error) const { + auto result = _map.lookup(error); + return result ? *result : NodeLocation{}; +} \ No newline at end of file diff --git a/src/openvic-dataloader/File.cpp b/src/openvic-dataloader/File.cpp new file mode 100644 index 0000000..9b27bf0 --- /dev/null +++ b/src/openvic-dataloader/File.cpp @@ -0,0 +1,9 @@ +#include + +using namespace ovdl; + +File::File(const char* path) : _path(path) {} + +const char* File::path() const noexcept { + return _path; +} \ No newline at end of file diff --git a/src/openvic-dataloader/NodeLocation.cpp b/src/openvic-dataloader/NodeLocation.cpp new file mode 100644 index 0000000..9e4f669 --- /dev/null +++ b/src/openvic-dataloader/NodeLocation.cpp @@ -0,0 +1,26 @@ +#include + +using namespace ovdl; + +NodeLocation::NodeLocation() = default; +NodeLocation::NodeLocation(const char* pos) : _begin(pos), + _end(pos) {} +NodeLocation::NodeLocation(const char* begin, const char* end) : _begin(begin), + _end(end) {} + +NodeLocation::NodeLocation(const NodeLocation&) noexcept = default; +NodeLocation& NodeLocation::operator=(const NodeLocation&) = default; + +NodeLocation::NodeLocation(NodeLocation&&) = default; +NodeLocation& NodeLocation::operator=(NodeLocation&&) = default; + +const char* NodeLocation::begin() const { return _begin; } +const char* NodeLocation::end() const { return _end; } + +bool NodeLocation::is_synthesized() const { return _begin == nullptr && _end == nullptr; } + +NodeLocation NodeLocation::make_from(const char* begin, const char* end) { + end++; + if (begin >= end) return NodeLocation(begin); + return NodeLocation(begin, end); +} diff --git a/src/openvic-dataloader/csv/CsvGrammar.hpp b/src/openvic-dataloader/csv/CsvGrammar.hpp index 712bddc..5451f26 100644 --- a/src/openvic-dataloader/csv/CsvGrammar.hpp +++ b/src/openvic-dataloader/csv/CsvGrammar.hpp @@ -7,14 +7,17 @@ #include #include +#include #include #include -#include "detail/LexyLitRange.hpp" +#include "detail/dsl.hpp" // Grammar Definitions // namespace ovdl::csv::grammar { + using EncodingType = ovdl::csv::EncodingType; + template concept ParseChars = requires() { { T::character }; @@ -51,123 +54,117 @@ namespace ovdl::csv::grammar { .map<'"'>('"'); template - struct StringValue { - static constexpr auto rule = [] { - // Arbitrary code points - auto c = Options.character - Options.control; - - auto back_escape = lexy::dsl::backslash_escape // - .symbol(); + struct CsvGrammar { + struct StringValue { + static constexpr auto rule = [] { + // Arbitrary code points + auto c = Options.character - Options.control; - auto quote_escape = lexy::dsl::escape(lexy::dsl::lit_c<'"'>) // - .template symbol(); + auto back_escape = lexy::dsl::backslash_escape // + .symbol(); - return lexy::dsl::delimited(lexy::dsl::lit_c<'"'>, lexy::dsl::not_followed_by(lexy::dsl::lit_c<'"'>, lexy::dsl::lit_c<'"'>))(c, back_escape, quote_escape); - }(); - - static constexpr auto value = lexy::as_string; - }; + auto quote_escape = lexy::dsl::escape(lexy::dsl::lit_c<'"'>) // + .template symbol(); - template - struct PlainValue { - static constexpr auto rule = [] { - if constexpr (Options.SupportStrings) { - return lexy::dsl::identifier(Options.character - (lexy::dsl::lit_b / lexy::dsl::ascii::newline)); - } else { - auto escape_check_char = Options.character - (lexy::dsl::lit_b / lexy::dsl::ascii::newline); - auto id_check_char = escape_check_char - lexy::dsl::lit_b<'\\'>; - auto id_segment = lexy::dsl::identifier(id_check_char); - auto escape_segement = lexy::dsl::token(escape_check_char); - auto escape_sym = lexy::dsl::symbol(escape_segement); - auto escape_rule = lexy::dsl::lit_b<'\\'> >> escape_sym; - return lexy::dsl::list(id_segment | escape_rule); - } - }(); - static constexpr auto value = lexy::as_string; - }; + return lexy::dsl::delimited(lexy::dsl::lit_c<'"'>, lexy::dsl::not_followed_by(lexy::dsl::lit_c<'"'>, lexy::dsl::lit_c<'"'>))(c, back_escape, quote_escape); + }(); - template - struct Value { - static constexpr auto rule = [] { - if constexpr (Options.SupportStrings) { - return lexy::dsl::p> | lexy::dsl::p>; - } else { - return lexy::dsl::p>; - } - }(); - static constexpr auto value = lexy::forward; - }; - - template - struct SepConst { - static constexpr auto rule = lexy::dsl::lit_b; - static constexpr auto value = lexy::constant(1); - }; + static constexpr auto value = lexy::as_string; + }; - template - struct Seperator { - static constexpr auto rule = lexy::dsl::list(lexy::dsl::p>); - static constexpr auto value = lexy::count; - }; + struct PlainValue { + static constexpr auto rule = [] { + if constexpr (Options.SupportStrings) { + return lexy::dsl::identifier(Options.character - (lexy::dsl::lit_b / lexy::dsl::ascii::newline)); + } else { + auto escape_check_char = Options.character - (lexy::dsl::lit_b / lexy::dsl::ascii::newline); + auto id_check_char = escape_check_char - lexy::dsl::lit_b<'\\'>; + auto id_segment = lexy::dsl::identifier(id_check_char); + auto escape_segement = lexy::dsl::token(escape_check_char); + auto escape_sym = lexy::dsl::symbol(escape_segement); + auto escape_rule = lexy::dsl::lit_b<'\\'> >> escape_sym; + return lexy::dsl::list(id_segment | escape_rule); + } + }(); + static constexpr auto value = lexy::as_string; + }; - template - struct LineEnd { - static constexpr auto rule = lexy::dsl::list(lexy::dsl::p>, lexy::dsl::trailing_sep(lexy::dsl::p>)); - static constexpr auto value = lexy::fold_inplace( - std::initializer_list {}, - [](ovdl::csv::LineObject& result, auto&& arg) { - if constexpr (std::is_same_v, std::size_t>) { - // Count seperators, adds to previous value, making it a position - using position_type = ovdl::csv::LineObject::position_type; - result.emplace_back(static_cast(arg + result.back().first), ""); + struct Value { + static constexpr auto rule = [] { + if constexpr (Options.SupportStrings) { + return lexy::dsl::p | lexy::dsl::p; } else { - if (result.empty()) result.emplace_back(0u, LEXY_MOV(arg)); - else { - auto& [pos, value] = result.back(); - value = arg; - } + return lexy::dsl::p; } - }); - }; + }(); + static constexpr auto value = lexy::forward; + }; - template - struct Line { - static constexpr auto suffix_setter(ovdl::csv::LineObject& line) { - auto& [position, value] = line.back(); - if (value.empty()) { - line.set_suffix_end(position); - line.pop_back(); - } else { - line.set_suffix_end(position + 1); - } + struct SepConst { + static constexpr auto rule = lexy::dsl::lit_b; + static constexpr auto value = lexy::constant(1); }; - static constexpr auto rule = lexy::dsl::p> | lexy::dsl::p> >> lexy::dsl::opt(lexy::dsl::p>); - static constexpr auto value = - lexy::callback( - [](ovdl::csv::LineObject&& line) { - suffix_setter(line); - return LEXY_MOV(line); - }, - [](std::size_t prefix_count, ovdl::csv::LineObject&& line) { - line.set_prefix_end(prefix_count); - // position needs to be adjusted to prefix - for (auto& [position, value] : line) { - position += prefix_count; + struct Seperator { + static constexpr auto rule = lexy::dsl::list(lexy::dsl::p); + static constexpr auto value = lexy::count; + }; + + struct LineEnd { + static constexpr auto rule = lexy::dsl::list(lexy::dsl::p, lexy::dsl::trailing_sep(lexy::dsl::p)); + static constexpr auto value = lexy::fold_inplace( + std::initializer_list {}, + [](ovdl::csv::LineObject& result, auto&& arg) { + if constexpr (std::is_same_v, std::size_t>) { + // Count seperators, adds to previous value, making it a position + using position_type = ovdl::csv::LineObject::position_type; + result.emplace_back(static_cast(arg + result.back().first), ""); + } else { + if (result.empty()) result.emplace_back(0u, LEXY_MOV(arg)); + else { + auto& [pos, value] = result.back(); + value = arg; + } } - suffix_setter(line); - return LEXY_MOV(line); - }, - [](std::size_t suffix_count, lexy::nullopt = {}) { - return ovdl::csv::LineObject(0, {}, suffix_count + 1); }); + }; + + struct Line { + static constexpr auto suffix_setter(ovdl::csv::LineObject& line) { + auto& [position, value] = line.back(); + if (value.empty()) { + line.set_suffix_end(position); + line.pop_back(); + } else { + line.set_suffix_end(position + 1); + } + }; + + static constexpr auto rule = lexy::dsl::p | lexy::dsl::p >> lexy::dsl::opt(lexy::dsl::p); + static constexpr auto value = + lexy::callback( + [](ovdl::csv::LineObject&& line) { + suffix_setter(line); + return LEXY_MOV(line); + }, + [](std::size_t prefix_count, ovdl::csv::LineObject&& line) { + line.set_prefix_end(prefix_count); + // position needs to be adjusted to prefix + for (auto& [position, value] : line) { + position += prefix_count; + } + suffix_setter(line); + return LEXY_MOV(line); + }, + [](std::size_t suffix_count, lexy::nullopt = {}) { + return ovdl::csv::LineObject(0, {}, suffix_count + 1); + }); + }; }; template struct File { - static constexpr auto rule = lexy::dsl::terminator(lexy::dsl::eof).opt_list( - lexy::dsl::p> | lexy::dsl::newline - ); + static constexpr auto rule = lexy::dsl::terminator(lexy::dsl::eof).opt_list(lexy::dsl::p::Line> | lexy::dsl::newline); static constexpr auto value = lexy::as_list>; }; @@ -199,7 +196,7 @@ namespace ovdl::csv::grammar { namespace ovdl::csv::grammar::windows1252 { struct windows1252_t { - static constexpr auto character = detail::lexydsl::make_range<0x01, 0xFF>(); + static constexpr auto character = dsl::make_range<0x01, 0xFF>(); static constexpr auto control = lexy::dsl::ascii::control / lexy::dsl::lit_b<0x81> / lexy::dsl::lit_b<0x8D> / lexy::dsl::lit_b<0x8F> / diff --git a/src/openvic-dataloader/csv/CsvParseState.hpp b/src/openvic-dataloader/csv/CsvParseState.hpp new file mode 100644 index 0000000..2390453 --- /dev/null +++ b/src/openvic-dataloader/csv/CsvParseState.hpp @@ -0,0 +1,28 @@ +#pragma once + +#include +#include +#include +#include + +#include + +template +struct LexyEncodingFrom { +}; + +template<> +struct LexyEncodingFrom { + using encoding = lexy::default_encoding; +}; + +template<> +struct LexyEncodingFrom { + using encoding = lexy::utf8_char_encoding; +}; + +template +using CsvFile = ovdl::BasicFile::encoding, std::vector>; + +template +using CsvParseState = ovdl::FileParseState>; \ No newline at end of file diff --git a/src/openvic-dataloader/csv/Parser.cpp b/src/openvic-dataloader/csv/Parser.cpp index 0ca3402..849ea05 100644 --- a/src/openvic-dataloader/csv/Parser.cpp +++ b/src/openvic-dataloader/csv/Parser.cpp @@ -1,47 +1,34 @@ -#include #include +#include #include #include -#include +#include +#include +#include #include #include #include #include -#include "csv/CsvGrammar.hpp" -#include "detail/BasicBufferHandler.hpp" -#include "detail/LexyReportError.hpp" -#include "detail/OStreamOutputIterator.hpp" +#include "CsvGrammar.hpp" +#include "CsvParseState.hpp" +#include "detail/NullBuff.hpp" +#include "detail/ParseHandler.hpp" using namespace ovdl; using namespace ovdl::csv; -/// BufferHandler /// - -template -struct LexyEncodingFrom { -}; - -template<> -struct LexyEncodingFrom { - using encoding = lexy::default_encoding; -}; - -template<> -struct LexyEncodingFrom { - using encoding = lexy::utf8_char_encoding; -}; +/// ParseHandler /// template -class Parser::BufferHandler final : public detail::BasicBufferHandler::encoding> { -public: - template - std::optional> parse(const ErrorCallback& callback) { - auto result = lexy::parse(this->_buffer, callback); +struct Parser::ParseHandler final : detail::BasicFileParseHandler> { + template + std::optional parse() { + auto result = lexy::parse(this->buffer(), *this->_parse_state, this->_parse_state->logger().error_callback()); if (!result) { - return result.errors(); + return this->_parse_state->logger().get_errors(); } _lines = std::move(result.value()); return std::nullopt; @@ -59,8 +46,14 @@ private: template Parser::Parser() - : _buffer_handler(std::make_unique()) { - set_error_log_to_stderr(); + : _parse_handler(std::make_unique()) { + set_error_log_to_null(); +} + +template +Parser::Parser(std::basic_ostream& error_stream) + : _parse_handler(std::make_unique()) { + set_error_log_to(error_stream); } template @@ -115,28 +108,31 @@ Parser Parser::from_file(const std::filesystem::path& path) /// template template -constexpr void Parser::_run_load_func(detail::LoadCallback auto func, Args... args) { - _warnings.clear(); - _errors.clear(); +constexpr void Parser::_run_load_func(detail::LoadCallback auto func, Args... args) { _has_fatal_error = false; - if (auto error = func(_buffer_handler.get(), std::forward(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)...); + 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().template create_log(DiagnosticLogger::DiagnosticKind::error, fmt::runtime(error_message)); + } + if (has_error() && &_error_stream.get() != &detail::cnull) { + print_errors_to(_error_stream.get()); } } template 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; } template 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; } @@ -149,7 +145,7 @@ template 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; } @@ -158,39 +154,35 @@ Parser& Parser::load_from_file(const std::filesystem::path& return load_from_file(path.string().c_str()); } -template -constexpr Parser& Parser::load_from_file(const detail::Has_c_str auto& path) { - return load_from_file(path.c_str()); -} - template bool Parser::parse_csv(bool handle_strings) { - if (!_buffer_handler->is_valid()) { + if (!_parse_handler->is_valid()) { return false; } - std::optional> errors; - auto report_error = ovdl::detail::ReporError.path(_file_path).to(detail::OStreamOutputIterator { _error_stream }); + std::optional::error_range> errors; + // auto report_error = ovdl::detail::ReporError.path(_file_path).to(detail::OStreamOutputIterator { _error_stream }); if constexpr (Encoding == EncodingType::Windows1252) { if (handle_strings) - errors = _buffer_handler->template parse(report_error); + errors = _parse_handler->template parse(); else - errors = _buffer_handler->template parse(report_error); + errors = _parse_handler->template parse(); } else { if (handle_strings) - errors = _buffer_handler->template parse(report_error); + errors = _parse_handler->template parse(); else - errors = _buffer_handler->template parse(report_error); + errors = _parse_handler->template parse(); } - if (errors) { - _errors.reserve(errors->size()); - for (auto& err : errors.value()) { - _has_fatal_error |= err.type == ParseError::Type::Fatal; - _errors.push_back(err); + _has_error = _parse_handler->parse_state().logger().errored(); + _has_warning = _parse_handler->parse_state().logger().warned(); + if (!errors->empty()) { + _has_fatal_error = true; + if (&_error_stream.get() != &detail::cnull) { + print_errors_to(_error_stream); } return false; } - _lines = std::move(_buffer_handler->get_lines()); + _lines = std::move(_parse_handler->get_lines()); return true; } @@ -199,5 +191,60 @@ const std::vector& Parser::get_lines() const { return _lines; } +template +typename Parser::error_range Parser::get_errors() const { + return _parse_handler->parse_state().logger().get_errors(); +} + +template +const FilePosition Parser::get_error_position(const error::Error* error) const { + if (!error || !error->is_linked_in_tree()) { + return {}; + } + 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; +} + +template +void Parser::print_errors_to(std::basic_ostream& 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 visitor, const error::Semantic* semantic) { + stream << semantic->message() << '\n'; + auto annotations = semantic->annotations(); + if (annotations.empty()) return; + for (auto annotation : annotations) { + visitor(annotation); + } + }, + [&](const error::PrimaryAnnotation* primary) { + stream << primary->message() << '\n'; + }, + [&](const error::SecondaryAnnotation* secondary) { + stream << secondary->message() << '\n'; + }); + } +} + template class ovdl::csv::Parser; template class ovdl::csv::Parser; \ No newline at end of file diff --git a/src/openvic-dataloader/detail/BasicBufferHandler.hpp b/src/openvic-dataloader/detail/BasicBufferHandler.hpp deleted file mode 100644 index f26544b..0000000 --- a/src/openvic-dataloader/detail/BasicBufferHandler.hpp +++ /dev/null @@ -1,51 +0,0 @@ -#pragma once - -#include - -#include -#include - -#include -#include -#include - -#include "detail/Errors.hpp" - -namespace ovdl::detail { - template - class BasicBufferHandler { - public: - using encoding_type = Encoding; - - OVDL_OPTIONAL_CONSTEXPR bool is_valid() const { - return _buffer.data() != nullptr; - } - - OVDL_OPTIONAL_CONSTEXPR std::optional load_buffer_size(const char* data, std::size_t size) { - _buffer = lexy::buffer(data, size); - return std::nullopt; - } - - OVDL_OPTIONAL_CONSTEXPR std::optional load_buffer(const char* start, const char* end) { - _buffer = lexy::buffer(start, end); - return std::nullopt; - } - - std::optional load_file(const char* path) { - auto file = lexy::read_file(path); - if (!file) { - return ovdl::errors::make_no_file_error(path); - } - - _buffer = file.buffer(); - return std::nullopt; - } - - const auto& get_buffer() const { - return _buffer; - } - - protected: - lexy::buffer _buffer; - }; -} \ No newline at end of file diff --git a/src/openvic-dataloader/detail/BasicParser.cpp b/src/openvic-dataloader/detail/BasicParser.cpp deleted file mode 100644 index 212bf00..0000000 --- a/src/openvic-dataloader/detail/BasicParser.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include -#include - -#include - -#include "detail/NullBuff.hpp" - -using namespace ovdl; -using namespace ovdl::detail; - -BasicParser::BasicParser() : _error_stream(detail::cnull) {} - -void BasicParser::set_error_log_to_null() { - set_error_log_to(detail::cnull); -} - -void BasicParser::set_error_log_to_stderr() { - set_error_log_to(std::cerr); -} - -void BasicParser::set_error_log_to_stdout() { - set_error_log_to(std::cout); -} - -void BasicParser::set_error_log_to(std::basic_ostream& stream) { - _error_stream = stream; -} - -bool BasicParser::has_error() const { - return !_errors.empty(); -} - -bool BasicParser::has_fatal_error() const { - return _has_fatal_error; -} - -bool BasicParser::has_warning() const { - return !_warnings.empty(); -} - -const std::vector& BasicParser::get_errors() const { - return _errors; -} - -const std::vector& BasicParser::get_warnings() const { - return _warnings; -} - -std::string_view BasicParser::get_file_path() const { - return _file_path; -} \ No newline at end of file diff --git a/src/openvic-dataloader/detail/BufferError.hpp b/src/openvic-dataloader/detail/BufferError.hpp new file mode 100644 index 0000000..1fbb0f4 --- /dev/null +++ b/src/openvic-dataloader/detail/BufferError.hpp @@ -0,0 +1,17 @@ +#pragma once + +#include + +namespace ovdl::detail { + enum class buffer_error : std::uint8_t { + success, + /// An internal OS error, such as failure to read from the file. + os_error, + /// The file was not found. + file_not_found, + /// The file cannot be opened. + permission_denied, + /// The buffer failed to handle the data + buffer_is_null + }; +} \ No newline at end of file diff --git a/src/openvic-dataloader/detail/DetectUtf8.hpp b/src/openvic-dataloader/detail/DetectUtf8.hpp index 2045b3c..e9d0350 100644 --- a/src/openvic-dataloader/detail/DetectUtf8.hpp +++ b/src/openvic-dataloader/detail/DetectUtf8.hpp @@ -3,7 +3,7 @@ #include #include -#include "detail/LexyLitRange.hpp" +#include "detail/dsl.hpp" namespace ovdl::detail { namespace detect_utf8 { @@ -18,15 +18,15 @@ namespace ovdl::detail { constexpr auto is_not_ascii_flag = lexy::dsl::context_flag; // & 0b10000000 == 0b00000000 - constexpr auto ascii_values = lexydsl::make_range<0b00000000, 0b01111111>(); + constexpr auto ascii_values = dsl::make_range<0b00000000, 0b01111111>(); // & 0b11100000 == 0b11000000 - constexpr auto two_byte = lexydsl::make_range<0b11000000, 0b11011111>(); + constexpr auto two_byte = dsl::make_range<0b11000000, 0b11011111>(); // & 0b11110000 == 0b11100000 - constexpr auto three_byte = lexydsl::make_range<0b11100000, 0b11101111>(); + constexpr auto three_byte = dsl::make_range<0b11100000, 0b11101111>(); // & 0b11111000 == 0b11110000 - constexpr auto four_byte = lexydsl::make_range<0b11110000, 0b11110111>(); + constexpr auto four_byte = dsl::make_range<0b11110000, 0b11110111>(); // & 0b11000000 == 0b10000000 - constexpr auto check_bytes = lexydsl::make_range<0b10000000, 0b10111111>(); + constexpr auto check_bytes = dsl::make_range<0b10000000, 0b10111111>(); constexpr auto utf8_check = ((four_byte >> lexy::dsl::times<3>(check_bytes)) | diff --git a/src/openvic-dataloader/detail/LexyLitRange.hpp b/src/openvic-dataloader/detail/LexyLitRange.hpp deleted file mode 100644 index a6761a8..0000000 --- a/src/openvic-dataloader/detail/LexyLitRange.hpp +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -#include - -namespace ovdl::detail::lexydsl { - template - consteval auto make_range() { - if constexpr (LOW == HIGH) { - return lexy::dsl::lit_c; - } else if constexpr (LOW == (HIGH - 1)) { - return lexy::dsl::lit_c / lexy::dsl::lit_c; - } else { - return lexy::dsl::lit_c / make_range(); - } - } -} \ No newline at end of file diff --git a/src/openvic-dataloader/detail/LexyReportError.hpp b/src/openvic-dataloader/detail/LexyReportError.hpp deleted file mode 100644 index 213090b..0000000 --- a/src/openvic-dataloader/detail/LexyReportError.hpp +++ /dev/null @@ -1,106 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - -#include - -namespace ovdl::detail { - template - 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 _errors; - - using return_type = std::vector; - - template - void operator()(const lexy::error_context& context, const lexy::error& 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::basic_stringstream message; - - // Write the main annotation. - if constexpr (std::is_same_v) { - auto string = lexy::_detail::make_literal_lexeme(error.string(), error.length()); - - message << "expected '" << string.data() << '\''; - } else if constexpr (std::is_same_v) { - auto string = lexy::_detail::make_literal_lexeme(error.string(), error.length()); - - message << "expected keyword '" << string.data() << '\''; - } else if constexpr (std::is_same_v) { - message << "expected " << error.name(); - } else { - message << error.message(); - } - - _errors.push_back( - ParseError { - ParseError::Type::Fatal, // TODO: distinguish recoverable errors from fatal errors - std::move(message.str()), - 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 }; - } - - constexpr _ReportError path(const detail::Has_c_str auto& path_object) const { - return path(path_object.c_str()); - } - - /// Specifies an output iterator where the errors are written to. - template - constexpr _ReportError 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 {}; -} \ No newline at end of file diff --git a/src/openvic-dataloader/detail/NullBuff.hpp b/src/openvic-dataloader/detail/NullBuff.hpp index baf9e1b..e5c6f4a 100644 --- a/src/openvic-dataloader/detail/NullBuff.hpp +++ b/src/openvic-dataloader/detail/NullBuff.hpp @@ -22,9 +22,9 @@ namespace ovdl::detail { basic_nullbuf m_sbuf; }; - typedef basic_onullstream onullstream; - typedef basic_onullstream wonullstream; + using onullstream = basic_onullstream; + using wonullstream = basic_onullstream; - inline onullstream cnull; - inline onullstream wcnull; + static inline onullstream cnull; + static inline onullstream wcnull; } \ No newline at end of file diff --git a/src/openvic-dataloader/detail/OStreamOutputIterator.hpp b/src/openvic-dataloader/detail/OStreamOutputIterator.hpp deleted file mode 100644 index 81f6c89..0000000 --- a/src/openvic-dataloader/detail/OStreamOutputIterator.hpp +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -#include - -namespace ovdl::detail { - struct OStreamOutputIterator { - std::reference_wrapper _stream; - - auto operator*() const noexcept { - return *this; - } - auto operator++(int) const noexcept { - return *this; - } - - OStreamOutputIterator& operator=(char c) { - _stream.get().put(c); - return *this; - } - }; -} \ No newline at end of file diff --git a/src/openvic-dataloader/detail/ParseHandler.hpp b/src/openvic-dataloader/detail/ParseHandler.hpp new file mode 100644 index 0000000..fbec0d7 --- /dev/null +++ b/src/openvic-dataloader/detail/ParseHandler.hpp @@ -0,0 +1,145 @@ +#pragma once + +#include + +#include +#include + +#include +#include +#include + +#include "detail/BufferError.hpp" + +namespace ovdl::detail { + template + struct ParseHandler { + std::string make_error_from(buffer_error error) { + switch (error) { + using enum ovdl::detail::buffer_error; + case buffer_is_null: + return "Buffer could not be loaded."; + case os_error: + return "OS file error."; + case file_not_found: + return "File not found."; + case permission_denied: + return "Read Permission denied."; + default: + return ""; + } + } + + template + constexpr void _run_load_func(detail::LoadCallback auto func, Args... args); + }; + + template + struct BasicFileParseHandler : ParseHandler> { + using parse_state_type = ParseState; + using encoding_type = typename parse_state_type::file_type::encoding_type; + + constexpr bool is_valid() const { + if (!_parse_state) return false; + return buffer().data() != nullptr; + } + + constexpr buffer_error load_buffer_size(const char* data, std::size_t size) { + lexy::buffer buffer(data, size); + if (buffer.data() == nullptr) return buffer_error::buffer_is_null; + _parse_state.reset(new parse_state_type { std::move(buffer) }); + return is_valid() ? buffer_error::success : buffer_error::buffer_is_null; + } + + constexpr buffer_error load_buffer(const char* start, const char* end) { + lexy::buffer buffer(start, end); + if (buffer.data() == nullptr) return buffer_error::buffer_is_null; + _parse_state.reset(new parse_state_type { std::move(buffer) }); + return is_valid() ? buffer_error::success : buffer_error::buffer_is_null; + } + + buffer_error load_file(const char* path) { + lexy::read_file_result file = lexy::read_file(path); + if (!file) { + _parse_state.reset(new parse_state_type { path, lexy::buffer() }); + return ovdl::detail::from_underlying(ovdl::detail::to_underlying(file.error())); + } + _parse_state.reset(new parse_state_type { path, std::move(file).buffer() }); + return is_valid() ? buffer_error::success : buffer_error::buffer_is_null; + } + + const char* path() const { + if (!_parse_state) return ""; + return _parse_state->file().path(); + } + + parse_state_type& parse_state() { + return *_parse_state; + } + + const parse_state_type& parse_state() const { + return *_parse_state; + } + + constexpr const auto& buffer() const { + return _parse_state->file().buffer(); + } + + protected: + std::unique_ptr _parse_state; + }; + + template + struct BasicStateParseHandler : ParseHandler> { + using parse_state_type = ParseState; + using encoding_type = typename parse_state_type::ast_type::file_type::encoding_type; + + constexpr bool is_valid() const { + if (!_parse_state) return false; + return buffer().data() != nullptr; + } + + constexpr buffer_error load_buffer_size(const char* data, std::size_t size) { + lexy::buffer buffer(data, size); + _parse_state.reset(new parse_state_type { std::move(buffer) }); + return is_valid() ? buffer_error::success : buffer_error::buffer_is_null; + } + + constexpr buffer_error load_buffer(const char* start, const char* end) { + lexy::buffer buffer(start, end); + _parse_state.reset(new parse_state_type { std::move(buffer) }); + return is_valid() ? buffer_error::success : buffer_error::buffer_is_null; + } + + buffer_error load_file(const char* path) { + lexy::read_file_result file = lexy::read_file(path); + if (!file) { + _parse_state.reset(new parse_state_type { path, lexy::buffer() }); + return ovdl::detail::from_underlying(ovdl::detail::to_underlying(file.error())); + } + + _parse_state.reset(new parse_state_type { path, std::move(file).buffer() }); + return is_valid() ? buffer_error::success : buffer_error::buffer_is_null; + } + + const char* path() const { + if (!_parse_state) return ""; + return _parse_state->ast().file().path(); + } + + parse_state_type& parse_state() { + return *_parse_state; + } + + const parse_state_type& parse_state() const { + return *_parse_state; + } + + constexpr const auto& buffer() const { + return _parse_state->ast().file().buffer(); + } + + protected: + std::unique_ptr _parse_state; + }; +} \ No newline at end of file diff --git a/src/openvic-dataloader/detail/Parser.cpp b/src/openvic-dataloader/detail/Parser.cpp new file mode 100644 index 0000000..fd87687 --- /dev/null +++ b/src/openvic-dataloader/detail/Parser.cpp @@ -0,0 +1,43 @@ +#include +#include + +#include + +#include "detail/NullBuff.hpp" + +using namespace ovdl; +using namespace ovdl::detail; + +BasicParser::BasicParser() : _error_stream(detail::cnull) {} + +void BasicParser::set_error_log_to_null() { + set_error_log_to(detail::cnull); +} + +void BasicParser::set_error_log_to_stderr() { + set_error_log_to(std::cerr); +} + +void BasicParser::set_error_log_to_stdout() { + set_error_log_to(std::cout); +} + +void BasicParser::set_error_log_to(std::basic_ostream& stream) { + _error_stream = stream; +} + +bool BasicParser::has_error() const { + return _has_error; +} + +bool BasicParser::has_fatal_error() const { + return _has_fatal_error; +} + +bool BasicParser::has_warning() const { + return _has_warning; +} + +std::string_view BasicParser::get_file_path() const { + return _file_path; +} \ No newline at end of file diff --git a/src/openvic-dataloader/detail/StringLiteral.hpp b/src/openvic-dataloader/detail/StringLiteral.hpp new file mode 100644 index 0000000..985b087 --- /dev/null +++ b/src/openvic-dataloader/detail/StringLiteral.hpp @@ -0,0 +1,232 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace ovdl::detail { + + template + struct string_literal; + + struct _string_literal { + protected: + static constexpr auto _to_string(const auto& input) { return string_literal(input); } + static constexpr auto _concat(const auto&... input) { return string_literal(_to_string(input)...); } + }; + + template + struct string_literal : _string_literal { + using value_type = CharT; + using pointer = value_type*; + using const_pointer = const value_type*; + using reference = value_type&; + using const_reference = const value_type&; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + using traits_type = std::char_traits; + + static constexpr size_type npos = size_type(-1); + + static constexpr auto size = std::integral_constant {}; + static constexpr auto length = size; + + value_type _data[N]; + + constexpr string_literal() noexcept = default; + + constexpr string_literal(const value_type (&literal)[N]) noexcept { + for (auto i = 0u; i != N; i++) + _data[i] = literal[i]; + } + + constexpr string_literal(value_type c) noexcept : _data {} { + _data[0] = c; + } + + constexpr auto begin() noexcept { return std::begin(_data); } + constexpr auto end() noexcept { return std::end(_data); } + constexpr auto cbegin() const noexcept { return std::cbegin(_data); } + constexpr auto cend() const noexcept { return std::cend(_data); } + constexpr auto rbegin() noexcept { return std::rbegin(_data); } + constexpr auto rend() noexcept { return std::rend(_data); } + constexpr auto crbegin() const noexcept { return std::crbegin(_data); } + constexpr auto crend() const noexcept { return std::crend(_data); } + + constexpr auto front() const noexcept { return as_string_view().front(); } + constexpr auto back() const noexcept { return as_string_view().back(); } + constexpr auto at(size_type pos) const { return as_string_view().at(pos); } + + constexpr auto operator[](size_type pos) const noexcept { return as_string_view()[pos]; } + + constexpr bool empty() const { return as_string_view().empty(); } + + template + constexpr bool operator==(const string_literal& other) const { + return as_string_view() == other.as_string_view(); + } + + constexpr bool starts_with(std::basic_string_view sv) const noexcept { return as_string_view().starts_with(sv); } + constexpr bool starts_with(value_type ch) const noexcept { return as_string_view().starts_with(ch); } + constexpr bool starts_with(const value_type* s) const { return as_string_view().starts_with(s); } + + template + constexpr bool starts_with(const string_literal& other) const { + return starts_with(other.as_string_view()); + } + + constexpr bool ends_with(std::basic_string_view sv) const noexcept { return as_string_view().ends_with(sv); } + constexpr bool ends_with(value_type ch) const noexcept { return as_string_view().ends_with(ch); } + constexpr bool ends_with(const value_type* s) const { return as_string_view().ends_with(s); } + + template + constexpr bool ends_with(const string_literal& other) const { + return ends_with(other.as_string_view()); + } + + constexpr auto clear() const noexcept { + return string_literal<0, value_type> {}; + } + + constexpr auto push_back(value_type c) const noexcept { + return *this + string_literal { c }; + } + + constexpr auto pop_back() const noexcept { + string_literal result {}; + for (auto i = 0u; i != N - 2; i++) + result._data[i] = _data[i]; + return result; + } + + template + constexpr auto append(value_type ch) const noexcept { + string_literal result {}; + for (auto i = 0u; i != N; i++) + result._data[i] = _data[i]; + + for (auto i = N; i != N + count; i++) + result._data[i] = ch; + + return result; + } + + template + constexpr auto append(string_literal str) const noexcept { + return *this + str; + } + + template + constexpr auto append(const value_type (&literal)[N2]) const noexcept { + return *this + literal; + } + + template + constexpr auto substr() const noexcept { + static_assert(pos <= N, "pos must be less than or equal to N"); + constexpr size_type result_size = std::min(count - pos, N - pos); + + string_literal result {}; + for (size_type i = 0u, i2 = pos; i != result_size; i++, i2++) + result._data[i] = _data[i2]; + return result; + } + + constexpr auto substr() const noexcept { + return substr<>(); + } + + constexpr std::string_view substr(size_type pos, size_type count = npos) const noexcept { + return as_string_view().substr(pos, count); + } + + constexpr size_type find(std::string_view str, size_type pos = 0) const noexcept { + return as_string_view().find(str, pos); + } + + template + constexpr size_type find(const value_type (&literal)[N2], size_type pos = 0) const noexcept { + return as_string_view().find(literal, pos, N2 - 2); + } + + constexpr size_type rfind(std::string_view str, size_type pos = 0) const noexcept { + return as_string_view().rfind(str, pos); + } + + template + constexpr size_type rfind(const value_type (&literal)[N2], size_type pos = 0) const noexcept { + return as_string_view().find(literal, pos, N2 - 2); + } + + constexpr int compare(std::string_view str) const noexcept { + return as_string_view().compare(str); + } + + template + constexpr int compare(const value_type (&literal)[N2]) const noexcept { + return as_string_view().compare(0, N, literal, N2 - 2); + } + + constexpr operator std::basic_string_view() const& { return as_string_view(); } + constexpr operator std::basic_string_view() const&& = delete; + + constexpr std::basic_string_view as_string_view() const& { return std::basic_string_view(_data, size() - 1); } + constexpr std::basic_string_view as_string_view() const&& = delete; + + constexpr operator const value_type*() const& { return c_str(); } + constexpr operator const value_type*() const&& = delete; + + constexpr const value_type* c_str() const& { return _data; } + constexpr const value_type* c_str() const&& = delete; + + constexpr const value_type* data() const& { return _data; } + constexpr const value_type* data() const&& = delete; + + template + constexpr auto operator+(const string_literal& other) const noexcept { + string_literal result {}; + for (size_type i = 0u; i != N; i++) + result._data[i] = _data[i]; + + for (size_type i = N - 1, i2 = 0; i2 != N2; i++, i2++) + result._data[i] = other._data[i2]; + return result; + } + + template + constexpr auto operator+(const value_type (&rhs)[N2]) const noexcept { + return *this + _to_string(rhs); + } + + template + friend constexpr auto operator+(const value_type (&lhs)[N2], string_literal rhs) noexcept { + return _to_string(lhs) + rhs; + } + }; + template + string_literal(const CharT (&)[N]) -> string_literal; + + template + string_literal(CharT) -> string_literal<1, CharT>; + + template typename T, string_literal Str, std::size_t... Idx> + auto _to_type_string(lexy::_detail::index_sequence) { + return T {}; + } + template typename T, string_literal Str> + using to_type_string = decltype(ovdl::detail::_to_type_string(lexy::_detail::make_index_sequence {})); +} + +namespace ovdl::dsl { + template + constexpr auto keyword(lexyd::_id) { + return ovdl::detail::to_type_string>::template get, Str> {}; + } +} \ No newline at end of file diff --git a/src/openvic-dataloader/detail/Warnings.hpp b/src/openvic-dataloader/detail/Warnings.hpp index 8fc09bd..ab718bc 100644 --- a/src/openvic-dataloader/detail/Warnings.hpp +++ b/src/openvic-dataloader/detail/Warnings.hpp @@ -5,7 +5,7 @@ #include namespace ovdl::v2script::warnings { - inline const ParseWarning make_utf8_warning(std::string_view file_path) { + inline const std::string make_utf8_warning(std::string_view file_path) { constexpr std::string_view message_suffix = "This may cause problems. Prefer Windows-1252 encoding."; std::string message; @@ -15,7 +15,7 @@ namespace ovdl::v2script::warnings { message = "File '" + std::string(file_path) + "' is a UTF-8 encoded file. " + std::string(message_suffix); } - return ParseWarning { message, 1 }; + return message; } } diff --git a/src/openvic-dataloader/detail/dsl.hpp b/src/openvic-dataloader/detail/dsl.hpp new file mode 100644 index 0000000..9b544bc --- /dev/null +++ b/src/openvic-dataloader/detail/dsl.hpp @@ -0,0 +1,150 @@ +#pragma once + +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include "detail/StringLiteral.hpp" + +namespace ovdl::dsl { + template + constexpr auto callback(Callback... cb) { + return lexy::bind(lexy::callback(cb...), lexy::parse_state, lexy::values); + } + + template + constexpr auto sink(Sink sink) { + return lexy::bind_sink(sink, lexy::parse_state); + } + + template + constexpr auto collect(Callback callback) { + return sink(lexy::collect(callback)); + } + + template + constexpr auto collect(Callback callback) { + return sink(lexy::collect(callback)); + } + + template + constexpr auto construct = callback( + [](StateType& state, ovdl::NodeLocation loc, auto&& arg) { + if constexpr (std::is_same_v, lexy::nullopt>) + return state.ast().template create(loc); + else + return state.ast().template create(loc, DRYAD_FWD(arg)); + }, + [](StateType& state, ovdl::NodeLocation loc, auto&&... args) { + return state.ast().template create(loc, DRYAD_FWD(args)...); + }); + + template + constexpr auto construct_list = callback( + [](StateType& state, const char* begin, ListType&& arg, const char* end) { + return state.ast().template create(NodeLocation::make_from(begin, end), DRYAD_FWD(arg)); + }, + [](StateType& state, const char* begin, lexy::nullopt, const char* end) { + return state.ast().template create(NodeLocation::make_from(begin, end)); + }, + [](StateType& state, const char* begin, const char* end) { + return state.ast().template create(NodeLocation::make_from(begin, end)); + }); + + template + constexpr auto construct_list = callback( + [](StateType& state, const char* begin, ListType&& arg, const char* end) { + return state.ast().template create(NodeLocation::make_from(begin, end), DRYAD_FWD(arg)); + }, + [](StateType& state, const char* begin, lexy::nullopt, const char* end) { + return state.ast().template create(NodeLocation::make_from(begin, end)); + }); + + template + consteval auto make_range() { + if constexpr (LOW == HIGH) { + return ::lexy::dsl::lit_c; + } else if constexpr (LOW == (HIGH - 1)) { + return ::lexy::dsl::lit_c / ::lexy::dsl::lit_c; + } else { + return ::lexy::dsl::lit_c / make_range(); + } + } + + template + constexpr auto position_brackets = lexy::dsl::brackets(lexy::dsl::position(lexy::dsl::lit_c), lexy::dsl::position(lexy::dsl::lit_c)); + + constexpr auto round_bracketed = position_brackets<'(', ')'>; + constexpr auto square_bracketed = position_brackets<'[', ']'>; + constexpr auto curly_bracketed = position_brackets<'{', '}'>; + constexpr auto angle_bracketed = position_brackets<'<', '>'>; + + template + constexpr auto p = lexy::dsl::position(lexy::dsl::p); + + template + static constexpr auto default_kw_value = dsl::callback( + [](ParseType& state, NodeLocation loc) { + return state.ast().template create(loc, state.ast().intern(Keyword.data(), Keyword.size())); + }); + + template< + IsParseState ParseType, + typename Identifier, + typename RuleValue, + ovdl::detail::string_literal Keyword, + auto Production, + auto Value> + struct keyword_rule { + struct rule_t { + static constexpr auto keyword = ovdl::dsl::keyword(lexy::dsl::inline_); + static constexpr auto rule = lexy::dsl::position(keyword) >> lexy::dsl::equal_sign; + static constexpr auto value = Value; + }; + static constexpr auto rule = dsl::p >> Production; + static constexpr auto value = construct; + }; + + template< + IsParseState ParseType, + typename Identifier, + typename RuleValue, + ovdl::detail::string_literal Keyword, + auto Production, + auto Value> + struct fkeyword_rule : keyword_rule { + using base_type = keyword_rule; + struct context_t; + struct rule_t : base_type::rule_t { + static constexpr auto flag = lexy::dsl::context_flag; + struct too_many_error { + static constexpr auto name = "expected event " + Keyword + " to only be found once"; + }; + static constexpr auto must = lexy::dsl::must(rule_t::flag.is_reset()) + . +// See https://stackoverflow.com/questions/77144003/use-of-template-keyword-before-dependent-template-name +// THANKS FOR NOTHING MICROSOFT, CAN'T EVEN GET THE STANDARD RIGHT +#if !defined(_MSC_VER) || defined(__clang__) + template +#endif + error; + }; + static constexpr auto make_flag = rule_t::flag.create(); + + static constexpr auto rule = dsl::p >> (rule_t::must >> rule_t::flag.set()) >> Production; + static constexpr auto value = construct; + }; + + template + struct rule_helper { + static constexpr auto flags = (Args::make_flag + ...); + static constexpr auto p = (lexy::dsl::p | ...); + }; +} \ No newline at end of file diff --git a/src/openvic-dataloader/v2script/AbstractSyntaxTree.cpp b/src/openvic-dataloader/v2script/AbstractSyntaxTree.cpp index 182d559..4754d8e 100644 --- a/src/openvic-dataloader/v2script/AbstractSyntaxTree.cpp +++ b/src/openvic-dataloader/v2script/AbstractSyntaxTree.cpp @@ -1,9 +1,3 @@ -#include -#include -#include -#include -#include - #include #include @@ -11,281 +5,146 @@ #include #include -using namespace ovdl::v2script::ast; - -static void _handle_string_characters(std::string& string, bool allow_newline) { - size_t position = 0; - for (auto& c : string) { - switch (c) { - case '\r': - case '\n': - if (allow_newline) goto END_LOOP; - c = ' '; - break; - default: break; - } - END_LOOP: - position++; - } -} - -void ovdl::v2script::ast::copy_into_node_ptr_vector(const std::vector& source, std::vector& dest) { - dest.clear(); - dest.reserve(source.size()); - for (auto&& p : source) { - dest.push_back(NodeUPtr { p }); - } -} - -AbstractStringNode::AbstractStringNode() : Node({}) {} -AbstractStringNode::AbstractStringNode(NodeLocation location, std::string&& name, bool allow_newline) : Node(location), - _name(std::move(name)) { - _handle_string_characters(_name, allow_newline); -} -AbstractStringNode::AbstractStringNode(NodeLocation location) : Node(location) {} -AbstractStringNode::AbstractStringNode(std::string&& name, bool allow_newline) : AbstractStringNode({}, std::move(name), allow_newline) {} - -std::ostream& AbstractStringNode::print(std::ostream& stream, size_t indent) const { - return stream << _name; -} - -#define OVDL_AST_STRING_NODE_DEF(NAME, ...) \ - NAME::NAME() : AbstractStringNode() {} \ - NAME::NAME(std::string&& name, bool allow_newline) : AbstractStringNode(std::move(name), allow_newline) {} \ - NAME::NAME(lexy::nullopt) : AbstractStringNode() {} \ - NAME::NAME(NodeLocation location) : AbstractStringNode(location) {} \ - NAME::NAME(NodeLocation location, std::string&& name, bool allow_newline) : AbstractStringNode(location, std::move(name), allow_newline) {} \ - NAME::NAME(NodeLocation location, lexy::nullopt) : AbstractStringNode(location, {}, true) {} \ - std::ostream& NAME::print(std::ostream& stream, size_t indent) const __VA_ARGS__ - -OVDL_AST_STRING_NODE_DEF(IdentifierNode, { - return stream << _name; -}); - -OVDL_AST_STRING_NODE_DEF(StringNode, { - return stream << '"' << _name << '"'; -}); - -OVDL_AST_STRING_NODE_DEF(FactorNode, { - return stream << "factor = " << _name; -}); - -OVDL_AST_STRING_NODE_DEF(MonthNode, { - return stream << "months = " << _name; -}); - -OVDL_AST_STRING_NODE_DEF(NameNode, { - return stream << "name = " << _name; -}); - -OVDL_AST_STRING_NODE_DEF(FireOnlyNode, { - return stream << "fire_only_once = " << _name; -}); - -OVDL_AST_STRING_NODE_DEF(IdNode, { - return stream << "id = " << _name; -}); - -OVDL_AST_STRING_NODE_DEF(TitleNode, { - return stream << "title = " << _name; -}); - -OVDL_AST_STRING_NODE_DEF(DescNode, { - return stream << "desc = " << _name; -}); - -OVDL_AST_STRING_NODE_DEF(PictureNode, { - return stream << "picture = " << _name; -}); - -OVDL_AST_STRING_NODE_DEF(IsTriggeredNode, { - return stream << "is_triggered_only = " << _name; -}); - -#undef OVDL_AST_STRING_NODE_DEF - -AssignNode::AssignNode(NodeLocation location, NodeCPtr name, NodePtr init) - : Node(location), - _initializer(std::move(init)) { - if (name->is_type()) { - _name = cast_node_cptr(name)._name; - } -} - -std::ostream& Node::print_ptr(std::ostream& stream, NodeCPtr node, size_t indent) { - return node != nullptr ? node->print(stream, indent) : stream << ""; -} - -static std::ostream& print_newline_indent(std::ostream& stream, size_t indent) { - return stream << "\n" - << std::setw(indent) << std::setfill('\t') << ""; -} - -/* Starts with a newline and ends at the end of a line, and so - * should be followed by a call to print_newline_indent. - */ -static std::ostream& print_nodeuptr_vector(const std::vector& nodes, - std::ostream& stream, size_t indent) { - for (NodeUPtr const& node : nodes) { - print_newline_indent(stream, indent); - Node::print_ptr(stream, node.get(), indent); - } - return stream; -} - -AbstractListNode::AbstractListNode(NodeLocation location, const std::vector& statements) : Node(location) { - copy_into_node_ptr_vector(statements, _statements); -} -AbstractListNode::AbstractListNode(const std::vector& statements) : AbstractListNode({}, statements) {} -std::ostream& AbstractListNode::print(std::ostream& stream, size_t indent) const { - stream << '{'; - if (!_statements.empty()) { - print_nodeuptr_vector(_statements, stream, indent + 1); - print_newline_indent(stream, indent); - } - return stream << "}"; -} - -#define OVDL_AST_LIST_NODE_DEF(NAME, ...) \ - NAME::NAME(const std::vector& statements) : AbstractListNode(statements) {} \ - NAME::NAME(lexy::nullopt) : AbstractListNode() {} \ - NAME::NAME(NodeLocation location, const std::vector& statements) : AbstractListNode(location, statements) {} \ - NAME::NAME(NodeLocation location, lexy::nullopt) : AbstractListNode(location, {}) {} \ - std::ostream& NAME::print(std::ostream& stream, size_t indent) const __VA_ARGS__ - -OVDL_AST_LIST_NODE_DEF(FileNode, { - print_nodeuptr_vector(_statements, stream, indent); - return print_newline_indent(stream, indent); -}); +#include +#include -OVDL_AST_LIST_NODE_DEF(ListNode, { - stream << '{'; - if (!_statements.empty()) { - print_nodeuptr_vector(_statements, stream, indent + 1); - print_newline_indent(stream, indent); - } - return stream << "}"; -}); - -OVDL_AST_LIST_NODE_DEF(ModifierNode, { - stream << "modifier = {"; - if (!_statements.empty()) { - print_nodeuptr_vector(_statements, stream, indent + 1); - print_newline_indent(stream, indent); - } - return stream << '}'; -}); - -OVDL_AST_LIST_NODE_DEF(MtthNode, { - stream << "mean_time_to_happen = {"; - if (!_statements.empty()) { - print_nodeuptr_vector(_statements, stream, indent + 1); - print_newline_indent(stream, indent); - } - return stream << '}'; -}); +#include -OVDL_AST_LIST_NODE_DEF(EventOptionNode, { - stream << "option = {"; - if (!_statements.empty()) { - print_nodeuptr_vector(_statements, stream, indent + 1); - print_newline_indent(stream, indent); - } - return stream << '}'; -}); - -OVDL_AST_LIST_NODE_DEF(BehaviorListNode, { - stream << "ai_chance = {"; // may be ai_chance or ai_will_do - if (!_statements.empty()) { - print_nodeuptr_vector(_statements, stream, indent + 1); - print_newline_indent(stream, indent); - } - return stream << '}'; -}); - -OVDL_AST_LIST_NODE_DEF(DecisionListNode, { - stream << "political_decisions = {"; - if (!_statements.empty()) { - print_nodeuptr_vector(_statements, stream, indent + 1); - print_newline_indent(stream, indent); - } - return stream << '}'; -}); - -#undef OVDL_AST_LIST_NODE_DEF - -EventNode::EventNode(NodeLocation location, Type type, const std::vector& statements) : AbstractListNode(location), - _type(type) { - copy_into_node_ptr_vector(statements, _statements); -} -EventNode::EventNode(Type type, const std::vector& statements) : EventNode({}, type, statements) {} -std::ostream& EventNode::print(std::ostream& stream, size_t indent) const { - switch (_type) { - case Type::Country: stream << "country_event = "; break; - case Type::Province: stream << "province_event = "; break; - } - stream << '{'; - if (!_statements.empty()) { - print_nodeuptr_vector(_statements, stream, indent + 1); - print_newline_indent(stream, indent); - } - return stream << '}'; -} - -DecisionNode::DecisionNode(NodeLocation location, NodePtr name, const std::vector& statements) : AbstractListNode(location), - _name(std::move(name)) { - copy_into_node_ptr_vector(statements, _statements); -} -DecisionNode::DecisionNode(NodePtr name, const std::vector& statements) : DecisionNode({}, name, statements) {} -std::ostream& DecisionNode::print(std::ostream& stream, size_t indent) const { - print_ptr(stream, _name.get(), indent) << " = {"; - if (!_statements.empty()) { - print_nodeuptr_vector(_statements, stream, indent + 1); - print_newline_indent(stream, indent); - } - return stream << '}'; -} - -ExecutionNode::ExecutionNode(NodeLocation location, Type type, NodePtr name, NodePtr init) : Node(location), - _type(type), - _name(std::move(name)), - _initializer(std::move(init)) { -} -ExecutionNode::ExecutionNode(Type type, NodePtr name, NodePtr init) : ExecutionNode({}, type, name, init) {} -std::ostream& ExecutionNode::print(std::ostream& stream, size_t indent) const { - print_ptr(stream, _name.get(), indent) << " = "; - if (_initializer) { - Node::print_ptr(stream, _initializer.get(), indent + 1); - } - return stream; -} - -ExecutionListNode::ExecutionListNode(NodeLocation location, ExecutionNode::Type type, const std::vector& statements) : AbstractListNode(location), - _type(type) { - copy_into_node_ptr_vector(statements, _statements); -} -ExecutionListNode::ExecutionListNode(ExecutionNode::Type type, const std::vector& statements) : ExecutionListNode({}, type, statements) {} -std::ostream& ExecutionListNode::print(std::ostream& stream, size_t indent) const { - // Only way to make a valid declared parsable file - stream << "{ "; - switch (_type) { - case ExecutionNode::Type::Effect: stream << "effect = {"; break; - case ExecutionNode::Type::Trigger: stream << "trigger = {"; break; - } - if (!_statements.empty()) { - print_nodeuptr_vector(_statements, stream, indent + 1); - print_newline_indent(stream, indent); - } - return stream << "}}"; -} +using namespace ovdl::v2script::ast; -Node::operator std::string() const { - std::stringstream ss; - ss << *this; - return ss.str(); -} +ListValue::ListValue(dryad::node_ctor ctor, StatementList statements) + : node_base(ctor) { + insert_child_list_after(nullptr, statements); + if (statements.empty()) { + _last_statement = nullptr; + } else { + _last_statement = statements.back(); + } +} + +FileTree::FileTree(dryad::node_ctor ctor, StatementList statements) : node_base(ctor) { + insert_child_list_after(nullptr, statements); + if (statements.empty()) { + _last_node = nullptr; + } else { + _last_node = statements.back(); + } +} + +// static void _handle_string_characters(std::string& string, bool allow_newline) { +// size_t position = 0; +// for (auto& c : string) { +// switch (c) { +// case '\r': +// case '\n': +// if (allow_newline) goto END_LOOP; +// c = ' '; +// break; +// default: break; +// } +// END_LOOP: +// position++; +// } +// } + +std::string AbstractSyntaxTree::make_list_visualizer() const { + const int INDENT_SIZE = 2; + + std::string result; + unsigned int level = 0; + + for (auto [event, node] : dryad::traverse(_tree)) { + if (event == dryad::traverse_event::exit) { + --level; + continue; + } -std::ostream& AssignNode::print(std::ostream& stream, size_t indent) const { - stream << _name << " = "; - return Node::print_ptr(stream, _initializer.get(), indent); + result.append(INDENT_SIZE * level, ' '); + result.append(fmt::format("- {}: ", get_kind_name(node->kind()))); + + dryad::visit_node( + node, + [&](const FlatValue* value) { + result.append(value->value(_symbol_interner)); + }, + [&](const ListValue* value) { + }, + [&](const NullValue* value) { + }, + [&](const EventStatement* statement) { + result.append(statement->is_province_event() ? "province_event" : "country_event"); + }, + [&](const AssignStatement* statement) { + }, + [&](const FileTree* tree) { + }); + + result.append(1, '\n'); + + if (event == dryad::traverse_event::enter) + ++level; + } + + return result; +} + +std::string AbstractSyntaxTree::make_native_visualizer() const { + constexpr int INDENT_SIZE = 2; + + std::string result; + unsigned int level = 0; + + dryad::visit_tree( + _tree, + [&](const IdentifierValue* value) { + result.append(value->value(_symbol_interner)); + }, + [&](const StringValue* value) { + result.append(1, '"').append(value->value(_symbol_interner)).append(1, '"'); + }, + [&](dryad::child_visitor visitor, const ValueStatement* statement) { + visitor(statement->value()); + }, + [&](dryad::child_visitor visitor, const AssignStatement* statement) { + visitor(statement->left()); + if (statement->right()->kind() != NodeKind::NullValue) { + result.append(" = "); + visitor(statement->right()); + } + }, + [&](dryad::child_visitor visitor, const ListValue* value) { + result.append(1, '{'); + level++; + for (const auto& statement : value->statements()) { + result + .append(1, '\n') + .append(INDENT_SIZE * level, ' '); + visitor(statement); + } + level--; + result + .append(1, '\n') + .append(INDENT_SIZE * level, ' ') + .append(1, '}'); + }, + [&](dryad::child_visitor visitor, const EventStatement* statement) { + result.append(statement->is_province_event() ? "province_event" : "country_event"); + if (statement->right()->kind() != NodeKind::NullValue) { + result.append(" = "); + visitor(statement->right()); + } + }, + [&](dryad::child_visitor visitor, const FileTree* value) { + auto statements = value->statements(); + visitor(*statements.begin()); + + for (const auto& statement : statements | ranges::views::drop(1)) { + result + .append(1, '\n') + .append(INDENT_SIZE * level, ' '); + visitor(statement); + } + }); + + return result; } \ No newline at end of file diff --git a/src/openvic-dataloader/v2script/AiBehaviorGrammar.hpp b/src/openvic-dataloader/v2script/AiBehaviorGrammar.hpp index e04f447..7fcd13d 100644 --- a/src/openvic-dataloader/v2script/AiBehaviorGrammar.hpp +++ b/src/openvic-dataloader/v2script/AiBehaviorGrammar.hpp @@ -2,6 +2,7 @@ #include +#include #include #include "ModifierGrammar.hpp" @@ -10,23 +11,12 @@ namespace ovdl::v2script::grammar { struct AiBehaviorList { static constexpr auto rule = lexy::dsl::list(lexy::dsl::p | lexy::dsl::p); - static constexpr auto value = - lexy::as_list> >> - lexy::callback( - [](auto&& list) { - return ast::make_node_ptr(LEXY_MOV(list)); - }); + static constexpr auto value = lexy::as_list; }; struct AiBehaviorBlock { - static constexpr auto rule = lexy::dsl::curly_bracketed.opt(lexy::dsl::p); + static constexpr auto rule = dsl::curly_bracketed.opt(lexy::dsl::p); - static constexpr auto value = lexy::callback( - [](auto&& list) { - return LEXY_MOV(list); - }, - [](lexy::nullopt = {}) { - return lexy::nullopt {}; - }); + static constexpr auto value = construct_list; }; } \ No newline at end of file diff --git a/src/openvic-dataloader/v2script/DecisionGrammar.hpp b/src/openvic-dataloader/v2script/DecisionGrammar.hpp index 3bd5cba..05cb8cc 100644 --- a/src/openvic-dataloader/v2script/DecisionGrammar.hpp +++ b/src/openvic-dataloader/v2script/DecisionGrammar.hpp @@ -1,109 +1,49 @@ #pragma once -#include - #include #include #include +#include #include #include +#include #include +#include +#include -#include "AiBehaviorGrammar.hpp" -#include "SimpleGrammar.hpp" -#include "TriggerGrammar.hpp" +#include "v2script/AiBehaviorGrammar.hpp" +#include "v2script/TriggerGrammar.hpp" // Decision Grammar Definitions // namespace ovdl::v2script::grammar { - ////////////////// - // Macros - ////////////////// -// Produces _rule and _p -#define OVDL_GRAMMAR_KEYWORD_DEFINE(KW_NAME) \ - struct KW_NAME##_rule { \ - static constexpr auto keyword = LEXY_KEYWORD(#KW_NAME, lexy::dsl::inline_>); \ - static constexpr auto rule = keyword >> lexy::dsl::equal_sign; \ - static constexpr auto value = lexy::noop; \ - }; \ - static constexpr auto KW_NAME##_p = lexy::dsl::p - -// Produces _rule and _p and _rule::flag and _rule::too_many_error -#define OVDL_GRAMMAR_KEYWORD_FLAG_DEFINE(KW_NAME) \ - struct KW_NAME##_rule { \ - static constexpr auto keyword = LEXY_KEYWORD(#KW_NAME, lexy::dsl::inline_>); \ - static constexpr auto rule = keyword >> lexy::dsl::equal_sign; \ - static constexpr auto value = lexy::noop; \ - static constexpr auto flag = lexy::dsl::context_flag; \ - struct too_many_error { \ - static constexpr auto name = "expected left side " #KW_NAME " to be found once"; \ - }; \ - }; \ - static constexpr auto KW_NAME##_p = lexy::dsl::p >> (lexy::dsl::must(KW_NAME##_rule::flag.is_reset()).error + KW_NAME##_rule::flag.set()) - ////////////////// - // Macros - ////////////////// struct DecisionStatement { - template - struct _StringStatement { - static constexpr auto rule = Production >> (lexy::dsl::p> | lexy::dsl::p>); - static constexpr auto value = lexy::forward; - }; - template - static constexpr auto StringStatement = lexy::dsl::p<_StringStatement>; + using potential = fkeyword_rule<"potential", lexy::dsl::p>; + using allow = fkeyword_rule<"allow", lexy::dsl::p>; + using effect = fkeyword_rule<"effect", lexy::dsl::p>; + using ai_will_do = fkeyword_rule<"ai_will_do", lexy::dsl::p>; - OVDL_GRAMMAR_KEYWORD_FLAG_DEFINE(potential); - OVDL_GRAMMAR_KEYWORD_FLAG_DEFINE(allow); - OVDL_GRAMMAR_KEYWORD_FLAG_DEFINE(effect); - OVDL_GRAMMAR_KEYWORD_FLAG_DEFINE(ai_will_do); + using helper = dsl::rule_helper; - static constexpr auto rule = [] { - constexpr auto create_flags = - potential_rule::flag.create() + - allow_rule::flag.create() + - effect_rule::flag.create() + - ai_will_do_rule::flag.create(); + struct List { + static constexpr auto rule = dsl::curly_bracketed.opt_list(helper::p | lexy::dsl::p>); - constexpr auto potential_statement = potential_p >> lexy::dsl::p; - constexpr auto allow_statement = allow_p >> lexy::dsl::p; - constexpr auto effect_statement = effect_p >> lexy::dsl::p; - constexpr auto ai_will_do_statement = ai_will_do_p >> lexy::dsl::p; + static constexpr auto value = lexy::as_list >> construct_list; + }; - return lexy::dsl::p> >> - (create_flags + lexy::dsl::equal_sign + - lexy::dsl::curly_bracketed.list( - potential_statement | - allow_statement | - effect_statement | - ai_will_do_statement | - lexy::dsl::p>)); - }(); + static constexpr auto rule = + dsl::p> >> + (helper::flags + lexy::dsl::equal_sign + lexy::dsl::p); - static constexpr auto value = - lexy::as_list> >> - lexy::callback( - [](auto&& name, auto&& list) { - return ast::make_node_ptr(LEXY_MOV(name), LEXY_MOV(list)); - }, - [](auto&& name, lexy::nullopt = {}) { - return ast::make_node_ptr(LEXY_MOV(name)); - }); + static constexpr auto value = construct; }; struct DecisionList { static constexpr auto rule = - LEXY_KEYWORD("political_decisions", lexy::dsl::inline_>) >> - (lexy::dsl::equal_sign + lexy::dsl::curly_bracketed.opt_list(lexy::dsl::p)); + ovdl::dsl::keyword<"political_decisions">(lexy::dsl::inline_>) >> + (lexy::dsl::equal_sign >> lexy::dsl::curly_bracketed.opt_list(lexy::dsl::p)); - static constexpr auto value = - lexy::as_list> >> - lexy::callback( - [](auto&& list) { - return ast::make_node_ptr(LEXY_MOV(list)); - }, - [](lexy::nullopt = {}) { - return lexy::nullopt {}; - }); + static constexpr auto value = lexy::as_list; }; struct DecisionFile { @@ -111,15 +51,8 @@ namespace ovdl::v2script::grammar { static constexpr auto whitespace = whitespace_specifier | comment_specifier; static constexpr auto rule = - lexy::dsl::terminator(lexy::dsl::eof).list( // - lexy::dsl::p | // - lexy::dsl::p>); + lexy::dsl::position + lexy::dsl::terminator(lexy::dsl::eof).opt_list(lexy::dsl::p); - static constexpr auto value = lexy::as_list> >> lexy::new_; + static constexpr auto value = lexy::concat >> construct; }; - -#undef OVDL_GRAMMAR_KEYWORD_DEFINE -#undef OVDL_GRAMMAR_KEYWORD_FLAG_DEFINE -#undef OVDL_GRAMMAR_KEYWORD_STATEMENT -#undef OVDL_GRAMMAR_KEYWORD_FLAG_STATEMENT } \ No newline at end of file diff --git a/src/openvic-dataloader/v2script/EffectGrammar.hpp b/src/openvic-dataloader/v2script/EffectGrammar.hpp index 1b85382..10f8348 100644 --- a/src/openvic-dataloader/v2script/EffectGrammar.hpp +++ b/src/openvic-dataloader/v2script/EffectGrammar.hpp @@ -6,37 +6,24 @@ #include #include "SimpleGrammar.hpp" +#include "detail/dsl.hpp" namespace ovdl::v2script::grammar { struct EffectStatement { - static constexpr auto rule = lexy::dsl::inline_>; + static constexpr auto rule = lexy::dsl::p>; - static constexpr auto value = lexy::callback( - [](auto name, auto&& initalizer) { - return ast::make_node_ptr(ast::ExecutionNode::Type::Effect, LEXY_MOV(name), LEXY_MOV(initalizer)); - }); + static constexpr auto value = lexy::forward; }; struct EffectList { - static constexpr auto rule = lexy::dsl::list(lexy::dsl::p>); - - static constexpr auto value = - lexy::as_list> >> - lexy::callback( - [](auto&& list) { - return ast::make_node_ptr(ast::ExecutionNode::Type::Effect, LEXY_MOV(list)); - }); + static constexpr auto rule = lexy::dsl::list(lexy::dsl::p); + + static constexpr auto value = lexy::as_list; }; struct EffectBlock { - static constexpr auto rule = lexy::dsl::curly_bracketed.opt(lexy::dsl::p); - - static constexpr auto value = lexy::callback( - [](auto&& list) { - return LEXY_MOV(list); - }, - [](lexy::nullopt = {}) { - return lexy::nullopt {}; - }); + static constexpr auto rule = dsl::curly_bracketed.opt(lexy::dsl::p); + + static constexpr auto value = construct_list; }; } \ No newline at end of file diff --git a/src/openvic-dataloader/v2script/EventGrammar.hpp b/src/openvic-dataloader/v2script/EventGrammar.hpp index 57cd170..c81a173 100644 --- a/src/openvic-dataloader/v2script/EventGrammar.hpp +++ b/src/openvic-dataloader/v2script/EventGrammar.hpp @@ -1,168 +1,109 @@ #pragma once -#include -#include +#include +#include #include #include #include +#include + +#include "openvic-dataloader/NodeLocation.hpp" -#include "AiBehaviorGrammar.hpp" -#include "EffectGrammar.hpp" -#include "ModifierGrammar.hpp" #include "SimpleGrammar.hpp" -#include "TriggerGrammar.hpp" +#include "detail/dsl.hpp" +#include "v2script/AiBehaviorGrammar.hpp" +#include "v2script/EffectGrammar.hpp" +#include "v2script/ModifierGrammar.hpp" // Event Grammar Definitions // namespace ovdl::v2script::grammar { - ////////////////// - // Macros - ////////////////// -// Produces _rule and _p -#define OVDL_GRAMMAR_KEYWORD_DEFINE(KW_NAME) \ - struct KW_NAME##_rule { \ - static constexpr auto keyword = LEXY_KEYWORD(#KW_NAME, lexy::dsl::inline_>); \ - static constexpr auto rule = keyword >> lexy::dsl::equal_sign; \ - static constexpr auto value = lexy::noop; \ - }; \ - static constexpr auto KW_NAME##_p = lexy::dsl::p - -// Produces _rule and _p and _rule::flag and _rule::too_many_error -#define OVDL_GRAMMAR_KEYWORD_FLAG_DEFINE(KW_NAME) \ - struct KW_NAME##_rule { \ - static constexpr auto keyword = LEXY_KEYWORD(#KW_NAME, lexy::dsl::inline_>); \ - static constexpr auto rule = keyword >> lexy::dsl::equal_sign; \ - static constexpr auto value = lexy::noop; \ - static constexpr auto flag = lexy::dsl::context_flag; \ - struct too_many_error { \ - static constexpr auto name = "expected left side " #KW_NAME " to be found once"; \ - }; \ - }; \ - static constexpr auto KW_NAME##_p = lexy::dsl::p >> (lexy::dsl::must(KW_NAME##_rule::flag.is_reset()).error + KW_NAME##_rule::flag.set()) - ////////////////// - // Macros - ////////////////// - static constexpr auto event_symbols = lexy::symbol_table // - .map(ast::EventNode::Type::Country) - .map(ast::EventNode::Type::Province); + static constexpr auto event_symbols = lexy::symbol_table // + .map(false) + .map(true); struct EventMtthStatement { - OVDL_GRAMMAR_KEYWORD_DEFINE(months); - struct MonthValue { - static constexpr auto rule = lexy::dsl::inline_>; - static constexpr auto value = lexy::as_string | lexy::new_; + static constexpr auto rule = lexy::dsl::p>; + static constexpr auto value = dsl::callback( + [](ast::ParseState& state, ast::IdentifierValue* value) { + bool is_number = true; + for (auto* current = value->value(state.ast().symbol_interner()); *current; current++) { + is_number = is_number && std::isdigit(*current); + if (!is_number) break; + } + if (!is_number) { + state.logger().warning("month is not an integer") // + .primary(state.ast().location_of(value), "here") + .finish(); + } + return value; + }); }; - static constexpr auto rule = lexy::dsl::list( - (months_p >> lexy::dsl::p) | - lexy::dsl::p); + using months = keyword_rule<"months", lexy::dsl::p>; - static constexpr auto value = - lexy::as_list> >> - lexy::callback( - [](auto&& list) { - return ast::make_node_ptr(LEXY_MOV(list)); - }); - }; + static constexpr auto rule = dsl::curly_bracketed(lexy::dsl::p | lexy::dsl::p); - template - struct _StringStatement { - static constexpr auto rule = Production >> (lexy::dsl::p> | lexy::dsl::p>); - static constexpr auto value = - lexy::callback( - [](auto&& value) { - auto result = ast::make_node_ptr(std::move(static_cast(value)->_name)); - delete value; - return result; - }); + static constexpr auto value = lexy::as_list >> construct_list; }; - template - static constexpr auto StringStatement = lexy::dsl::p<_StringStatement>; + + static constexpr auto str_or_id = lexy::dsl::p::ValueExpression>; struct EventOptionList { - OVDL_GRAMMAR_KEYWORD_FLAG_DEFINE(name); - OVDL_GRAMMAR_KEYWORD_FLAG_DEFINE(ai_chance); + using name = fkeyword_rule<"name", str_or_id>; + using ai_chance = fkeyword_rule<"ai_chance", lexy::dsl::p>; static constexpr auto rule = [] { - constexpr auto create_flags = name_rule::flag.create() + ai_chance_rule::flag.create(); - - constexpr auto name_statement = StringStatement; - constexpr auto ai_chance_statement = ai_chance_p >> lexy::dsl::curly_bracketed(lexy::dsl::p); + using helper = dsl::rule_helper; - return create_flags + lexy::dsl::list(name_statement | ai_chance_statement | lexy::dsl::p); + return dsl::curly_bracketed(helper::flags + lexy::dsl::list(helper::p | lexy::dsl::p)); }(); - static constexpr auto value = - lexy::as_list> >> - lexy::callback( - [](auto&& list) { - return ast::make_node_ptr(LEXY_MOV(list)); - }); + static constexpr auto value = lexy::as_list >> construct_list; }; struct EventStatement { - OVDL_GRAMMAR_KEYWORD_FLAG_DEFINE(id); - OVDL_GRAMMAR_KEYWORD_FLAG_DEFINE(title); - OVDL_GRAMMAR_KEYWORD_FLAG_DEFINE(desc); - OVDL_GRAMMAR_KEYWORD_FLAG_DEFINE(picture); - OVDL_GRAMMAR_KEYWORD_FLAG_DEFINE(is_triggered_only); - OVDL_GRAMMAR_KEYWORD_FLAG_DEFINE(fire_only_once); - OVDL_GRAMMAR_KEYWORD_FLAG_DEFINE(immediate); - OVDL_GRAMMAR_KEYWORD_FLAG_DEFINE(mean_time_to_happen); - OVDL_GRAMMAR_KEYWORD_DEFINE(trigger); - OVDL_GRAMMAR_KEYWORD_DEFINE(option); + using id = fkeyword_rule<"id", str_or_id>; + using title = fkeyword_rule<"title", str_or_id>; + using desc = fkeyword_rule<"desc", str_or_id>; + using picture = fkeyword_rule<"picture", str_or_id>; + using is_triggered_only = fkeyword_rule<"is_triggered_only", str_or_id>; + using fire_only_once = fkeyword_rule<"fire_only_once", str_or_id>; + using immediate = fkeyword_rule<"immediate", lexy::dsl::p>; + using mean_time_to_happen = fkeyword_rule<"mean_time_to_happen", lexy::dsl::p>; + using trigger = keyword_rule<"trigger", lexy::dsl::p>; + using option = keyword_rule<"option", lexy::dsl::p>; + + struct EventList { + static constexpr auto rule = [] { + using helper = dsl::rule_helper; + + return helper::flags + + dsl::curly_bracketed.opt_list( + helper::p | lexy::dsl::p | lexy::dsl::p