aboutsummaryrefslogtreecommitdiff
path: root/src/openvic-dataloader/detail
diff options
context:
space:
mode:
author Spartan322 <Megacake1234@gmail.com>2023-11-28 11:09:26 +0100
committer Spartan322 <Megacake1234@gmail.com>2024-05-09 22:11:26 +0200
commit757114a3c5b748567b42f273c7b78ca039ae983c (patch)
treee07390b682052129c91f4b157068bcdd84ceecb4 /src/openvic-dataloader/detail
parent7211a228e68c8a6b1ad1c1c5ec68c8d720b6d2ba (diff)
Add `deps/dryad` -> https://github.com/Spartan322/dryadadd/dryad
Add `deps/fmt` -> https://github.com/fmtlib/fmt Add `deps/range-v3` -> https://github.com/ericniebler/range-v3 Improve parser error and warning support Update .clang-format Update `deps/SCsub`
Diffstat (limited to 'src/openvic-dataloader/detail')
-rw-r--r--src/openvic-dataloader/detail/BasicBufferHandler.hpp51
-rw-r--r--src/openvic-dataloader/detail/BufferError.hpp17
-rw-r--r--src/openvic-dataloader/detail/DetectUtf8.hpp12
-rw-r--r--src/openvic-dataloader/detail/LexyLitRange.hpp16
-rw-r--r--src/openvic-dataloader/detail/LexyReportError.hpp106
-rw-r--r--src/openvic-dataloader/detail/NullBuff.hpp8
-rw-r--r--src/openvic-dataloader/detail/OStreamOutputIterator.hpp21
-rw-r--r--src/openvic-dataloader/detail/ParseHandler.hpp145
-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.hpp232
-rw-r--r--src/openvic-dataloader/detail/Warnings.hpp4
-rw-r--r--src/openvic-dataloader/detail/dsl.hpp150
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