diff options
author | Spartan322 <Megacake1234@gmail.com> | 2023-11-28 11:09:26 +0100 |
---|---|---|
committer | Spartan322 <Megacake1234@gmail.com> | 2024-05-09 22:11:26 +0200 |
commit | 757114a3c5b748567b42f273c7b78ca039ae983c (patch) | |
tree | e07390b682052129c91f4b157068bcdd84ceecb4 /src/openvic-dataloader/detail | |
parent | 7211a228e68c8a6b1ad1c1c5ec68c8d720b6d2ba (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/detail')
-rw-r--r-- | src/openvic-dataloader/detail/BasicBufferHandler.hpp | 51 | ||||
-rw-r--r-- | src/openvic-dataloader/detail/BufferError.hpp | 17 | ||||
-rw-r--r-- | src/openvic-dataloader/detail/DetectUtf8.hpp | 12 | ||||
-rw-r--r-- | src/openvic-dataloader/detail/LexyLitRange.hpp | 16 | ||||
-rw-r--r-- | src/openvic-dataloader/detail/LexyReportError.hpp | 106 | ||||
-rw-r--r-- | src/openvic-dataloader/detail/NullBuff.hpp | 8 | ||||
-rw-r--r-- | src/openvic-dataloader/detail/OStreamOutputIterator.hpp | 21 | ||||
-rw-r--r-- | src/openvic-dataloader/detail/ParseHandler.hpp | 145 | ||||
-rw-r--r-- | src/openvic-dataloader/detail/Parser.cpp (renamed from src/openvic-dataloader/detail/BasicParser.cpp) | 14 | ||||
-rw-r--r-- | src/openvic-dataloader/detail/StringLiteral.hpp | 232 | ||||
-rw-r--r-- | src/openvic-dataloader/detail/Warnings.hpp | 4 | ||||
-rw-r--r-- | src/openvic-dataloader/detail/dsl.hpp | 150 |
12 files changed, 559 insertions, 217 deletions
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 <optional> - -#include <openvic-dataloader/ParseError.hpp> -#include <openvic-dataloader/detail/OptionalConstexpr.hpp> - -#include <lexy/encoding.hpp> -#include <lexy/input/buffer.hpp> -#include <lexy/input/file.hpp> - -#include "detail/Errors.hpp" - -namespace ovdl::detail { - template<typename Encoding = lexy::default_encoding, typename MemoryResource = void> - class BasicBufferHandler { - public: - using encoding_type = Encoding; - - OVDL_OPTIONAL_CONSTEXPR bool is_valid() const { - return _buffer.data() != nullptr; - } - - OVDL_OPTIONAL_CONSTEXPR std::optional<ovdl::ParseError> load_buffer_size(const char* data, std::size_t size) { - _buffer = lexy::buffer<Encoding, MemoryResource>(data, size); - return std::nullopt; - } - - OVDL_OPTIONAL_CONSTEXPR std::optional<ovdl::ParseError> load_buffer(const char* start, const char* end) { - _buffer = lexy::buffer<Encoding, MemoryResource>(start, end); - return std::nullopt; - } - - std::optional<ovdl::ParseError> load_file(const char* path) { - auto file = lexy::read_file<Encoding, lexy::encoding_endianness::bom, MemoryResource>(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<Encoding, MemoryResource> _buffer; - }; -}
\ 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 <cstdint> + +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 <lexy/action/match.hpp> #include <lexy/dsl.hpp> -#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<DetectUtf8>; // & 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 <lexy/dsl/literal.hpp> - -namespace ovdl::detail::lexydsl { - template<unsigned char LOW, unsigned char HIGH> - consteval auto make_range() { - if constexpr (LOW == HIGH) { - return lexy::dsl::lit_c<LOW>; - } else if constexpr (LOW == (HIGH - 1)) { - return lexy::dsl::lit_c<LOW> / lexy::dsl::lit_c<HIGH>; - } else { - return lexy::dsl::lit_c<LOW> / make_range<LOW + 1, HIGH>(); - } - } -}
\ 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 <cstddef> -#include <sstream> -#include <utility> -#include <vector> - -#include <openvic-dataloader/ParseData.hpp> -#include <openvic-dataloader/ParseError.hpp> -#include <openvic-dataloader/detail/Concepts.hpp> - -#include <lexy/input_location.hpp> -#include <lexy/visualize.hpp> - -#include <lexy_ext/report_error.hpp> - -namespace ovdl::detail { - template<typename OutputIterator> - struct _ReportError { - OutputIterator _iter; - lexy::visualization_options _opts; - const char* _path; - - struct _sink { - OutputIterator _iter; - lexy::visualization_options _opts; - const char* _path; - std::size_t _count; - std::vector<ParseError> _errors; - - using return_type = std::vector<ParseError>; - - template<typename Input, typename Reader, typename Tag> - void operator()(const lexy::error_context<Input>& context, const lexy::error<Reader, Tag>& error) { - _iter = lexy_ext::_detail::write_error(_iter, context, error, _opts, _path); - ++_count; - - // Convert the context location and error location into line/column information. - auto context_location = lexy::get_input_location(context.input(), context.position()); - auto location = lexy::get_input_location(context.input(), error.position(), context_location.anchor()); - - std::basic_stringstream<typename Reader::encoding::char_type> message; - - // Write the main annotation. - if constexpr (std::is_same_v<Tag, lexy::expected_literal>) { - auto string = lexy::_detail::make_literal_lexeme<typename Reader::encoding>(error.string(), error.length()); - - message << "expected '" << string.data() << '\''; - } else if constexpr (std::is_same_v<Tag, lexy::expected_keyword>) { - auto string = lexy::_detail::make_literal_lexeme<typename Reader::encoding>(error.string(), error.length()); - - message << "expected keyword '" << string.data() << '\''; - } else if constexpr (std::is_same_v<Tag, lexy::expected_char_class>) { - 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<typename OI> - constexpr _ReportError<OI> to(OI out) const { - return { out, _opts, _path }; - } - - /// Overrides visualization options. - constexpr _ReportError opts(lexy::visualization_options opts) const { - return { _iter, opts, _path }; - } - }; - - constexpr auto ReporError = _ReportError<lexy::stderr_output_iterator> {}; -}
\ No newline at end of file diff --git a/src/openvic-dataloader/detail/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<cT, traits> m_sbuf; }; - typedef basic_onullstream<char> onullstream; - typedef basic_onullstream<wchar_t> wonullstream; + using onullstream = basic_onullstream<char>; + using wonullstream = basic_onullstream<wchar_t>; - 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 <ostream> - -namespace ovdl::detail { - struct OStreamOutputIterator { - std::reference_wrapper<std::ostream> _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 <utility> + +#include <openvic-dataloader/ParseState.hpp> +#include <openvic-dataloader/detail/utility/Concepts.hpp> + +#include <lexy/encoding.hpp> +#include <lexy/input/buffer.hpp> +#include <lexy/input/file.hpp> + +#include "detail/BufferError.hpp" + +namespace ovdl::detail { + template<typename Derived> + 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<typename... Args> + constexpr void _run_load_func(detail::LoadCallback<Derived, Args...> auto func, Args... args); + }; + + template<IsFileParseState ParseState, typename MemoryResource = void> + struct BasicFileParseHandler : ParseHandler<BasicFileParseHandler<ParseState, MemoryResource>> { + 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<encoding_type, MemoryResource> 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<encoding_type, MemoryResource> 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<encoding_type, lexy::encoding_endianness::bom, MemoryResource>(path); + if (!file) { + _parse_state.reset(new parse_state_type { path, lexy::buffer<typename parse_state_type::file_type::encoding_type>() }); + return ovdl::detail::from_underlying<buffer_error>(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_type> _parse_state; + }; + + template<IsParseState ParseState, typename MemoryResource = void> + struct BasicStateParseHandler : ParseHandler<BasicStateParseHandler<ParseState, MemoryResource>> { + 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<encoding_type, MemoryResource> 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<encoding_type, MemoryResource> 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<encoding_type, lexy::encoding_endianness::bom, MemoryResource>(path); + if (!file) { + _parse_state.reset(new parse_state_type { path, lexy::buffer<typename parse_state_type::ast_type::file_type::encoding_type>() }); + return ovdl::detail::from_underlying<buffer_error>(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_type> _parse_state; + }; +}
\ No newline at end of file diff --git a/src/openvic-dataloader/detail/BasicParser.cpp b/src/openvic-dataloader/detail/Parser.cpp index 212bf00..fd87687 100644 --- a/src/openvic-dataloader/detail/BasicParser.cpp +++ b/src/openvic-dataloader/detail/Parser.cpp @@ -1,7 +1,7 @@ #include <iostream> #include <ostream> -#include <openvic-dataloader/detail/BasicParser.hpp> +#include <openvic-dataloader/Parser.hpp> #include "detail/NullBuff.hpp" @@ -27,7 +27,7 @@ void BasicParser::set_error_log_to(std::basic_ostream<char>& stream) { } bool BasicParser::has_error() const { - return !_errors.empty(); + return _has_error; } bool BasicParser::has_fatal_error() const { @@ -35,15 +35,7 @@ bool BasicParser::has_fatal_error() const { } bool BasicParser::has_warning() const { - return !_warnings.empty(); -} - -const std::vector<ovdl::ParseError>& BasicParser::get_errors() const { - return _errors; -} - -const std::vector<ovdl::ParseWarning>& BasicParser::get_warnings() const { - return _warnings; + return _has_warning; } std::string_view BasicParser::get_file_path() const { 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 <algorithm> +#include <array> +#include <cstddef> +#include <string> +#include <string_view> +#include <type_traits> + +#include <lexy/_detail/config.hpp> +#include <lexy/_detail/integer_sequence.hpp> +#include <lexy/dsl/identifier.hpp> + +namespace ovdl::detail { + + template<std::size_t N, typename CharT> + 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<std::size_t N, typename CharT = char> + 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<value_type>; + + static constexpr size_type npos = size_type(-1); + + static constexpr auto size = std::integral_constant<std::size_t, N - 1> {}; + 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<size_type N2> + constexpr bool operator==(const string_literal<N2, value_type>& other) const { + return as_string_view() == other.as_string_view(); + } + + constexpr bool starts_with(std::basic_string_view<value_type> 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<size_type N2> + constexpr bool starts_with(const string_literal<N2, value_type>& other) const { + return starts_with(other.as_string_view()); + } + + constexpr bool ends_with(std::basic_string_view<value_type> 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<size_type N2> + constexpr bool ends_with(const string_literal<N2, value_type>& 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<N - 1, value_type> result {}; + for (auto i = 0u; i != N - 2; i++) + result._data[i] = _data[i]; + return result; + } + + template<size_type count> + constexpr auto append(value_type ch) const noexcept { + string_literal<N + count, value_type> 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<size_type N2> + constexpr auto append(string_literal<N2, value_type> str) const noexcept { + return *this + str; + } + + template<size_type N2> + constexpr auto append(const value_type (&literal)[N2]) const noexcept { + return *this + literal; + } + + template<size_type pos = 0, size_type count = npos> + 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_size, value_type> 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<size_type N2> + 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<size_type N2> + 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<size_type N2> + 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<value_type>() const& { return as_string_view(); } + constexpr operator std::basic_string_view<value_type>() const&& = delete; + + constexpr std::basic_string_view<value_type> as_string_view() const& { return std::basic_string_view<value_type>(_data, size() - 1); } + constexpr std::basic_string_view<value_type> 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<size_type N2> + constexpr auto operator+(const string_literal<N2, value_type>& other) const noexcept { + string_literal<N + N2 - 1, value_type> 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<size_type N2> + constexpr auto operator+(const value_type (&rhs)[N2]) const noexcept { + return *this + _to_string(rhs); + } + + template<size_type N2> + friend constexpr auto operator+(const value_type (&lhs)[N2], string_literal<N, value_type> rhs) noexcept { + return _to_string(lhs) + rhs; + } + }; + template<std::size_t N, typename CharT = char> + string_literal(const CharT (&)[N]) -> string_literal<N, CharT>; + + template<typename CharT = char> + string_literal(CharT) -> string_literal<1, CharT>; + + template<template<typename C, C... Cs> typename T, string_literal Str, std::size_t... Idx> + auto _to_type_string(lexy::_detail::index_sequence<Idx...>) { + return T<typename decltype(Str)::value_type, Str._data[Idx]...> {}; + } + template<template<typename C, C... Cs> typename T, string_literal Str> + using to_type_string = decltype(ovdl::detail::_to_type_string<T, Str>(lexy::_detail::make_index_sequence<decltype(Str)::size()> {})); +} + +namespace ovdl::dsl { + template<ovdl::detail::string_literal Str, typename L, typename T, typename... R> + constexpr auto keyword(lexyd::_id<L, T, R...>) { + return ovdl::detail::to_type_string<lexyd::_keyword<lexyd::_id<L, T>>::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 <openvic-dataloader/ParseWarning.hpp> 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 <type_traits> + +#include <openvic-dataloader/NodeLocation.hpp> +#include <openvic-dataloader/ParseState.hpp> + +#include <lexy/callback/adapter.hpp> +#include <lexy/callback/bind.hpp> +#include <lexy/callback/container.hpp> +#include <lexy/callback/fold.hpp> +#include <lexy/dsl.hpp> + +#include "detail/StringLiteral.hpp" + +namespace ovdl::dsl { + template<typename ReturnType, typename... Callback> + constexpr auto callback(Callback... cb) { + return lexy::bind(lexy::callback<ReturnType>(cb...), lexy::parse_state, lexy::values); + } + + template<typename Sink> + constexpr auto sink(Sink sink) { + return lexy::bind_sink(sink, lexy::parse_state); + } + + template<typename Container, typename Callback> + constexpr auto collect(Callback callback) { + return sink(lexy::collect<Container>(callback)); + } + + template<typename Callback> + constexpr auto collect(Callback callback) { + return sink(lexy::collect(callback)); + } + + template<IsParseState StateType, typename T> + constexpr auto construct = callback<T*>( + [](StateType& state, ovdl::NodeLocation loc, auto&& arg) { + if constexpr (std::is_same_v<std::decay_t<decltype(arg)>, lexy::nullopt>) + return state.ast().template create<T>(loc); + else + return state.ast().template create<T>(loc, DRYAD_FWD(arg)); + }, + [](StateType& state, ovdl::NodeLocation loc, auto&&... args) { + return state.ast().template create<T>(loc, DRYAD_FWD(args)...); + }); + + template<IsParseState StateType, typename T, typename ListType, bool DisableEmpty = false> + constexpr auto construct_list = callback<T*>( + [](StateType& state, const char* begin, ListType&& arg, const char* end) { + return state.ast().template create<T>(NodeLocation::make_from(begin, end), DRYAD_FWD(arg)); + }, + [](StateType& state, const char* begin, lexy::nullopt, const char* end) { + return state.ast().template create<T>(NodeLocation::make_from(begin, end)); + }, + [](StateType& state, const char* begin, const char* end) { + return state.ast().template create<T>(NodeLocation::make_from(begin, end)); + }); + + template<IsParseState StateType, typename T, typename ListType> + constexpr auto construct_list<StateType, T, ListType, true> = callback<T*>( + [](StateType& state, const char* begin, ListType&& arg, const char* end) { + return state.ast().template create<T>(NodeLocation::make_from(begin, end), DRYAD_FWD(arg)); + }, + [](StateType& state, const char* begin, lexy::nullopt, const char* end) { + return state.ast().template create<T>(NodeLocation::make_from(begin, end)); + }); + + template<unsigned char LOW, unsigned char HIGH> + consteval auto make_range() { + if constexpr (LOW == HIGH) { + return ::lexy::dsl::lit_c<LOW>; + } else if constexpr (LOW == (HIGH - 1)) { + return ::lexy::dsl::lit_c<LOW> / ::lexy::dsl::lit_c<HIGH>; + } else { + return ::lexy::dsl::lit_c<LOW> / make_range<LOW + 1, HIGH>(); + } + } + + template<auto Open, auto Close> + constexpr auto position_brackets = lexy::dsl::brackets(lexy::dsl::position(lexy::dsl::lit_c<Open>), lexy::dsl::position(lexy::dsl::lit_c<Close>)); + + 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<typename Production> + constexpr auto p = lexy::dsl::position(lexy::dsl::p<Production>); + + template<IsParseState ParseType, typename ReturnType, ovdl::detail::string_literal Keyword> + static constexpr auto default_kw_value = dsl::callback<ReturnType*>( + [](ParseType& state, NodeLocation loc) { + return state.ast().template create<ReturnType>(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<Keyword>(lexy::dsl::inline_<Identifier>); + static constexpr auto rule = lexy::dsl::position(keyword) >> lexy::dsl::equal_sign; + static constexpr auto value = Value; + }; + static constexpr auto rule = dsl::p<rule_t> >> Production; + static constexpr auto value = construct<ParseType, RuleValue>; + }; + + template< + IsParseState ParseType, + typename Identifier, + typename RuleValue, + ovdl::detail::string_literal Keyword, + auto Production, + auto Value> + struct fkeyword_rule : keyword_rule<ParseType, Identifier, RuleValue, Keyword, Production, Value> { + using base_type = keyword_rule<ParseType, Identifier, RuleValue, Keyword, Production, Value>; + struct context_t; + struct rule_t : base_type::rule_t { + static constexpr auto flag = lexy::dsl::context_flag<context_t>; + 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<too_many_error>; + }; + static constexpr auto make_flag = rule_t::flag.create(); + + static constexpr auto rule = dsl::p<rule_t> >> (rule_t::must >> rule_t::flag.set()) >> Production; + static constexpr auto value = construct<ParseType, RuleValue>; + }; + + template<typename... Args> + struct rule_helper { + static constexpr auto flags = (Args::make_flag + ...); + static constexpr auto p = (lexy::dsl::p<Args> | ...); + }; +}
\ No newline at end of file |