aboutsummaryrefslogtreecommitdiff
path: root/include/openvic-dataloader
diff options
context:
space:
mode:
Diffstat (limited to 'include/openvic-dataloader')
-rw-r--r--include/openvic-dataloader/AbstractSyntaxTree.hpp111
-rw-r--r--include/openvic-dataloader/DiagnosticLogger.hpp390
-rw-r--r--include/openvic-dataloader/Error.hpp195
-rw-r--r--include/openvic-dataloader/File.hpp69
-rw-r--r--include/openvic-dataloader/NodeLocation.hpp33
-rw-r--r--include/openvic-dataloader/ParseState.hpp120
-rw-r--r--include/openvic-dataloader/Parser.hpp (renamed from include/openvic-dataloader/detail/BasicParser.hpp)12
-rw-r--r--include/openvic-dataloader/csv/LineObject.hpp2
-rw-r--r--include/openvic-dataloader/csv/Parser.hpp25
-rw-r--r--include/openvic-dataloader/detail/CallbackOStream.hpp31
-rw-r--r--include/openvic-dataloader/detail/ClassExport.hpp9
-rw-r--r--include/openvic-dataloader/detail/Concepts.hpp21
-rw-r--r--include/openvic-dataloader/detail/LexyFwdDeclaration.hpp8
-rw-r--r--include/openvic-dataloader/detail/LexyReportError.hpp107
-rw-r--r--include/openvic-dataloader/detail/OStreamOutputIterator.hpp22
-rw-r--r--include/openvic-dataloader/detail/OptionalConstexpr.hpp9
-rw-r--r--include/openvic-dataloader/detail/utility/Concepts.hpp45
-rw-r--r--include/openvic-dataloader/detail/utility/Constexpr.hpp (renamed from include/openvic-dataloader/detail/VectorConstexpr.hpp)6
-rw-r--r--include/openvic-dataloader/detail/utility/ErrorRange.hpp11
-rw-r--r--include/openvic-dataloader/detail/utility/PointerHash.hpp (renamed from include/openvic-dataloader/detail/PointerHash.hpp)0
-rw-r--r--include/openvic-dataloader/detail/utility/SelfType.hpp (renamed from include/openvic-dataloader/detail/SelfType.hpp)0
-rw-r--r--include/openvic-dataloader/detail/utility/TypeName.hpp (renamed from include/openvic-dataloader/detail/TypeName.hpp)0
-rw-r--r--include/openvic-dataloader/detail/utility/Utility.hpp38
-rw-r--r--include/openvic-dataloader/v2script/AbstractSyntaxTree.hpp398
-rw-r--r--include/openvic-dataloader/v2script/NodeLocationMap.hpp91
-rw-r--r--include/openvic-dataloader/v2script/Parser.hpp46
26 files changed, 1372 insertions, 427 deletions
diff --git a/include/openvic-dataloader/AbstractSyntaxTree.hpp b/include/openvic-dataloader/AbstractSyntaxTree.hpp
new file mode 100644
index 0000000..db81eeb
--- /dev/null
+++ b/include/openvic-dataloader/AbstractSyntaxTree.hpp
@@ -0,0 +1,111 @@
+#pragma once
+
+#include <concepts>
+#include <cstdio>
+#include <string_view>
+#include <utility>
+
+#include <openvic-dataloader/File.hpp>
+#include <openvic-dataloader/NodeLocation.hpp>
+#include <openvic-dataloader/detail/utility/Utility.hpp>
+
+#include <dryad/node.hpp>
+#include <dryad/node_map.hpp>
+#include <dryad/symbol.hpp>
+#include <dryad/tree.hpp>
+
+#include <fmt/core.h>
+
+namespace ovdl {
+ struct AbstractSyntaxTree {
+ struct SymbolId;
+ using index_type = std::uint32_t;
+ using symbol_type = dryad::symbol<SymbolId, index_type>;
+ using symbol_interner_type = dryad::symbol_interner<SymbolId, char, index_type>;
+
+ symbol_type intern(const char* str, std::size_t length);
+ symbol_type intern(std::string_view str);
+ const char* intern_cstr(const char* str, std::size_t length);
+ const char* intern_cstr(std::string_view str);
+ symbol_interner_type& symbol_interner();
+ const symbol_interner_type& symbol_interner() const;
+
+ protected:
+ symbol_interner_type _symbol_interner;
+ };
+
+ template<typename T>
+ concept IsAst =
+ std::derived_from<T, AbstractSyntaxTree> &&
+ requires(
+ T t,
+ const T ct,
+ const typename T::node_type* node,
+ NodeLocation loc //
+ ) {
+ requires IsFile<typename T::file_type>;
+ typename T::root_node_type;
+ typename T::node_type;
+ requires std::derived_from<typename T::root_node_type, typename T::node_type>;
+ { t.set_location(node, loc) } -> std::same_as<void>;
+ { t.location_of(node) } -> std::same_as<NodeLocation>;
+ { t.root() } -> std::same_as<typename T::root_node_type*>;
+ { ct.root() } -> std::same_as<const typename T::root_node_type*>;
+ { t.file() } -> std::same_as<typename T::file_type&>;
+ { ct.file() } -> std::same_as<const typename T::file_type&>;
+ };
+
+ template<IsFile FileT, std::derived_from<typename FileT::node_type> RootNodeT>
+ struct BasicAbstractSyntaxTree : AbstractSyntaxTree {
+ using file_type = FileT;
+ using root_node_type = RootNodeT;
+ using node_type = typename file_type::node_type;
+
+ explicit BasicAbstractSyntaxTree(file_type&& file) : _file(std::move(file)) {}
+ explicit BasicAbstractSyntaxTree(lexy::buffer<typename file_type::encoding_type, void>&& buffer) : _file(std::move(buffer)) {}
+
+ void set_location(const node_type* n, NodeLocation loc) {
+ _file.set_location(n, loc);
+ }
+
+ NodeLocation location_of(const node_type* n) const {
+ return _file.location_of(n);
+ }
+
+ root_node_type* root() {
+ return _tree.root();
+ }
+
+ const root_node_type* root() const {
+ return _tree.root();
+ }
+
+ file_type& file() {
+ return _file;
+ }
+
+ const file_type& file() const {
+ return _file;
+ }
+
+ template<typename T, typename... Args>
+ T* create(NodeLocation loc, Args&&... args) {
+ auto node = _tree.template create<T>(DRYAD_FWD(args)...);
+ set_location(node, loc);
+ return node;
+ }
+
+ template<typename T, typename... Args>
+ T* create(const char* begin, const char* end, Args&&... args) {
+ return create<T>(NodeLocation::make_from(begin, end), DRYAD_FWD(args)...);
+ }
+
+ void set_root(root_node_type* node) {
+ _tree.set_root(node);
+ }
+
+ protected:
+ dryad::tree<root_node_type> _tree;
+ file_type _file;
+ };
+} \ No newline at end of file
diff --git a/include/openvic-dataloader/DiagnosticLogger.hpp b/include/openvic-dataloader/DiagnosticLogger.hpp
new file mode 100644
index 0000000..1fa2784
--- /dev/null
+++ b/include/openvic-dataloader/DiagnosticLogger.hpp
@@ -0,0 +1,390 @@
+#pragma once
+
+#include <concepts>
+#include <cstdarg>
+#include <cstdio>
+#include <ostream>
+#include <string>
+#include <utility>
+
+#include <openvic-dataloader/AbstractSyntaxTree.hpp>
+#include <openvic-dataloader/Error.hpp>
+#include <openvic-dataloader/File.hpp>
+#include <openvic-dataloader/NodeLocation.hpp>
+#include <openvic-dataloader/detail/LexyReportError.hpp>
+#include <openvic-dataloader/detail/OStreamOutputIterator.hpp>
+
+#include <lexy/input/base.hpp>
+#include <lexy/input/buffer.hpp>
+#include <lexy/visualize.hpp>
+
+#include <dryad/_detail/config.hpp>
+#include <dryad/abstract_node.hpp>
+#include <dryad/arena.hpp>
+#include <dryad/node.hpp>
+#include <dryad/tree.hpp>
+
+#include <fmt/core.h>
+
+#include "openvic-dataloader/detail/CallbackOStream.hpp"
+#include "openvic-dataloader/detail/utility/ErrorRange.hpp"
+#include "openvic-dataloader/detail/utility/Utility.hpp"
+
+#include <lexy_ext/report_error.hpp>
+
+namespace ovdl {
+ struct DiagnosticLogger {
+ using AnnotationKind = lexy_ext::annotation_kind;
+ using DiagnosticKind = lexy_ext::diagnostic_kind;
+
+ using error_range = detail::error_range;
+
+ explicit operator bool() const;
+ bool errored() const;
+ bool warned() const;
+
+ NodeLocation location_of(const error::Error* error) const;
+
+ template<std::derived_from<DiagnosticLogger> Logger>
+ struct ErrorCallback {
+ ErrorCallback(Logger& logger) : _logger(&logger) {}
+
+ struct sink_t {
+ using return_type = std::size_t;
+
+ template<typename Input, typename Tag>
+ void operator()(lexy::error_context<Input> const& context, lexy::error_for<Input, Tag> const& error) {
+ using Reader = lexy::input_reader<Input>;
+ error::Error* result;
+
+ if constexpr (std::is_same_v<Tag, lexy::expected_literal>) {
+ auto string = lexy::_detail::make_literal_lexeme<typename Reader::encoding>(error.string(), error.length());
+ NodeLocation loc = NodeLocation::make_from(string.begin(), string.end());
+ auto message = _logger.intern_cstr(fmt::format("expected '{}'", string.data()));
+ result = _logger.template create<error::ExpectedLiteral>(loc, message, context.production());
+ } 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());
+ NodeLocation loc = NodeLocation::make_from(string.begin(), string.end());
+ auto message = _logger.intern_cstr(fmt::format("expected keyword '{}'", string.data()));
+ result = _logger.template create<error::ExpectedKeyword>(loc, message, context.production());
+ } else if constexpr (std::is_same_v<Tag, lexy::expected_char_class>) {
+ auto message = _logger.intern_cstr(fmt::format("expected {}", error.name()));
+ result = _logger.template create<error::ExpectedCharClass>(error.position(), message, context.production());
+ } else {
+ NodeLocation loc = NodeLocation::make_from(error.begin(), error.end());
+ auto message = _logger.intern_cstr(error.message());
+ result = _logger.template create<error::GenericParseError>(loc, message, context.production());
+ }
+
+ if constexpr (requires { _logger.insert(result); }) {
+ _logger.insert(result);
+ }
+
+ _count++;
+ }
+
+ std::size_t finish() && {
+ return _count;
+ }
+
+ Logger& _logger;
+ std::size_t _count;
+ };
+
+ constexpr auto sink() const {
+ return sink_t { *_logger, 0 };
+ }
+
+ mutable Logger* _logger;
+ };
+
+ template<typename T, typename... Args>
+ T* create(NodeLocation loc, Args&&... args) {
+ using node_creator = dryad::node_creator<decltype(DRYAD_DECLVAL(T).kind()), void>;
+ T* result = _tree.create<T>(DRYAD_FWD(args)...);
+ _map.insert(result, loc);
+ return result;
+ }
+
+ template<typename T>
+ T* create() {
+ using node_creator = dryad::node_creator<decltype(DRYAD_DECLVAL(T).kind()), void>;
+ T* result = _tree.create<T>();
+ return result;
+ }
+
+ protected:
+ bool _errored = false;
+ bool _warned = false;
+ dryad::node_map<const error::Error, NodeLocation> _map;
+ dryad::tree<error::Root> _tree;
+
+ struct SymbolId;
+ using index_type = std::uint32_t;
+ using symbol_type = dryad::symbol<SymbolId, index_type>;
+ using symbol_interner_type = dryad::symbol_interner<SymbolId, char, index_type>;
+ symbol_interner_type _symbol_interner;
+
+ public:
+ symbol_type intern(const char* str, std::size_t length) {
+ return _symbol_interner.intern(str, length);
+ }
+ symbol_type intern(std::string_view str) {
+ return intern(str.data(), str.size());
+ }
+ const char* intern_cstr(const char* str, std::size_t length) {
+ return intern(str, length).c_str(_symbol_interner);
+ }
+ const char* intern_cstr(std::string_view str) {
+ return intern_cstr(str.data(), str.size());
+ }
+ symbol_interner_type& symbol_interner() {
+ return _symbol_interner;
+ }
+ const symbol_interner_type& symbol_interner() const {
+ return _symbol_interner;
+ }
+ };
+
+ template<IsFile FileT>
+ struct BasicDiagnosticLogger : DiagnosticLogger {
+ using file_type = FileT;
+
+ template<typename... Args>
+ using format_str = fmt::basic_format_string<char, fmt::type_identity_t<Args>...>;
+
+ explicit BasicDiagnosticLogger(const file_type& file)
+ : _file(&file) {
+ _tree.set_root(_tree.create<error::Root>());
+ }
+
+ struct Writer;
+
+ template<typename... Args>
+ Writer error(format_str<Args...> fmt, Args&&... args) {
+ return log(DiagnosticKind::error, fmt, std::forward<Args>(args)...);
+ }
+
+ template<typename... Args>
+ Writer warning(format_str<Args...> fmt, Args&&... args) {
+ return log(DiagnosticKind::warning, fmt, std::forward<Args>(args)...);
+ }
+
+ template<typename... Args>
+ Writer note(format_str<Args...> fmt, Args&&... args) {
+ return log(DiagnosticKind::note, fmt, std::forward<Args>(args)...);
+ }
+
+ template<typename... Args>
+ Writer info(format_str<Args...> fmt, Args&&... args) {
+ return log(DiagnosticKind::info, fmt, std::forward<Args>(args)...);
+ }
+
+ template<typename... Args>
+ Writer debug(format_str<Args...> fmt, Args&&... args) {
+ return log(DiagnosticKind::debug, fmt, std::forward<Args>(args)...);
+ }
+
+ template<typename... Args>
+ Writer fixit(format_str<Args...> fmt, Args&&... args) {
+ return log(DiagnosticKind::fixit, fmt, std::forward<Args>(args)...);
+ }
+
+ template<typename... Args>
+ Writer help(format_str<Args...> fmt, Args&&... args) {
+ return log(DiagnosticKind::help, fmt, std::forward<Args>(args)...);
+ }
+
+ Writer error(std::string_view sv) {
+ return log(DiagnosticKind::error, fmt::runtime(sv));
+ }
+
+ Writer warning(std::string_view sv) {
+ return log(DiagnosticKind::warning, fmt::runtime(sv));
+ }
+
+ Writer note(std::string_view sv) {
+ return log(DiagnosticKind::note, fmt::runtime(sv));
+ }
+
+ Writer info(std::string_view sv) {
+ return log(DiagnosticKind::info, fmt::runtime(sv));
+ }
+
+ Writer debug(std::string_view sv) {
+ return log(DiagnosticKind::debug, fmt::runtime(sv));
+ }
+
+ Writer fixit(std::string_view sv) {
+ return log(DiagnosticKind::fixit, fmt::runtime(sv));
+ }
+
+ Writer help(std::string_view sv) {
+ return log(DiagnosticKind::help, fmt::runtime(sv));
+ }
+
+ auto error_callback() {
+ return ErrorCallback(*this);
+ }
+
+ template<typename CharT>
+ static void _write_to_buffer(const CharT* s, std::streamsize n, void* output_str) {
+ auto* output = reinterpret_cast<std::basic_string<CharT>*>(output_str);
+ output->append(s, n);
+ }
+
+ template<typename CharT>
+ auto make_callback_stream(std::basic_string<CharT>& output) {
+ return detail::make_callback_stream<CharT>(&_write_to_buffer<CharT>, reinterpret_cast<void*>(&output));
+ }
+
+ template<typename CharT>
+ detail::OStreamOutputIterator make_ostream_iterator(std::basic_ostream<CharT>& stream) {
+ return detail::OStreamOutputIterator { stream };
+ }
+
+ struct Writer {
+ template<typename... Args>
+ [[nodiscard]] Writer& primary(NodeLocation loc, format_str<Args...> fmt, Args&&... args) {
+ return annotation(AnnotationKind::primary, loc, fmt, std::forward<Args>(args)...);
+ }
+
+ template<typename... Args>
+ [[nodiscard]] Writer& secondary(NodeLocation loc, format_str<Args...> fmt, Args&&... args) {
+ return annotation(AnnotationKind::secondary, loc, fmt, std::forward<Args>(args)...);
+ }
+
+ [[nodiscard]] Writer& primary(NodeLocation loc, std::string_view sv) {
+ return annotation(AnnotationKind::primary, loc, fmt::runtime(sv));
+ }
+
+ [[nodiscard]] Writer& secondary(NodeLocation loc, std::string_view sv) {
+ return annotation(AnnotationKind::secondary, loc, fmt::runtime(sv));
+ }
+
+ void finish() {}
+
+ template<typename... Args>
+ [[nodiscard]] Writer& annotation(AnnotationKind kind, NodeLocation loc, format_str<Args...> fmt, Args&&... args) {
+ auto begin_loc = lexy::get_input_location(_file->buffer(), loc.begin());
+
+ std::basic_string<typename decltype(fmt.get())::value_type> output;
+ auto stream = _logger.make_callback_stream(output);
+ auto iter = _logger.make_ostream_iterator(stream);
+
+ _impl.write_empty_annotation(iter);
+ _impl.write_annotation(iter, kind, begin_loc, loc.end(),
+ [&](auto out, lexy::visualization_options) {
+ return lexy::_detail::write_str(out, fmt::format(fmt, std::forward<Args>(args)...).c_str());
+ });
+
+ error::Annotation* annotation;
+ auto message = _logger.intern_cstr(output);
+ switch (kind) {
+ case AnnotationKind::primary:
+ _logger.create<error::PrimaryAnnotation>(loc, message);
+ break;
+ case AnnotationKind::secondary:
+ _logger.create<error::SecondaryAnnotation>(loc, message);
+ break;
+ default: detail::unreachable();
+ }
+ _semantic->push_back(annotation);
+ return *this;
+ }
+
+ private:
+ Writer(BasicDiagnosticLogger& logger, const file_type* file, error::Semantic* semantic)
+ : _file(file),
+ _impl(file->buffer(), { lexy::visualize_fancy }),
+ _logger(logger),
+ _semantic(semantic) {}
+
+ const file_type* _file;
+ lexy_ext::diagnostic_writer<lexy::buffer<typename file_type::encoding_type>> _impl;
+ BasicDiagnosticLogger& _logger;
+ error::Semantic* _semantic;
+
+ friend BasicDiagnosticLogger;
+ };
+
+ using diagnostic_writer = lexy_ext::diagnostic_writer<lexy::buffer<typename file_type::encoding_type>>;
+
+ template<std::derived_from<error::Error> T, typename... Args>
+ void log_with_impl(diagnostic_writer& impl, T* error, DiagnosticKind kind, format_str<Args...> fmt, Args&&... args) {
+ std::basic_string<typename decltype(fmt.get())::value_type> output;
+ auto stream = make_callback_stream(output);
+ auto iter = make_ostream_iterator(stream);
+
+ impl.write_message(iter, kind,
+ [&](auto out, lexy::visualization_options) {
+ return lexy::_detail::write_str(out, fmt::format(fmt, std::forward<Args>(args)...).c_str());
+ });
+ impl.write_path(iter, _file->path());
+
+ auto message = intern_cstr(output);
+ error->_set_message(message);
+ insert(error);
+ }
+
+ template<std::derived_from<error::Error> T, typename... Args>
+ void log_with_error(T* error, DiagnosticKind kind, format_str<Args...> fmt, Args&&... args) {
+ auto impl = diagnostic_writer { _file->buffer() };
+ log_with_impl(impl, error, kind, fmt, std::forward<Args>(args)...);
+ }
+
+ template<std::derived_from<error::Error> T, typename... Args>
+ void create_log(DiagnosticKind kind, format_str<Args...> fmt, Args&&... args) {
+ log_with_error(create<T>(), kind, fmt, std::forward<Args>(args)...);
+ }
+
+ template<typename... Args>
+ Writer log(DiagnosticKind kind, format_str<Args...> fmt, Args&&... args) {
+ error::Semantic* semantic;
+
+ switch (kind) {
+ case DiagnosticKind::error:
+ semantic = create<error::SemanticError>();
+ break;
+ case DiagnosticKind::warning:
+ semantic = create<error::SemanticWarning>();
+ break;
+ case DiagnosticKind::info:
+ semantic = create<error::SemanticInfo>();
+ break;
+ case DiagnosticKind::debug:
+ semantic = create<error::SemanticDebug>();
+ break;
+ case DiagnosticKind::fixit:
+ semantic = create<error::SemanticFixit>();
+ break;
+ case DiagnosticKind::help:
+ semantic = create<error::SemanticHelp>();
+ break;
+ default: detail::unreachable();
+ }
+
+ Writer result(*this, _file, semantic);
+
+ log_with_impl(result._impl, semantic, kind, fmt, std::forward<Args>(args)...);
+
+ if (kind == DiagnosticKind::error)
+ _errored = true;
+ if (kind == DiagnosticKind::warning)
+ _warned = true;
+
+ return result;
+ }
+
+ error_range get_errors() const {
+ return _tree.root()->errors();
+ }
+
+ private:
+ void insert(error::Error* root) {
+ _tree.root()->insert_back(root);
+ }
+
+ const file_type* _file;
+ };
+} \ No newline at end of file
diff --git a/include/openvic-dataloader/Error.hpp b/include/openvic-dataloader/Error.hpp
new file mode 100644
index 0000000..fd3254d
--- /dev/null
+++ b/include/openvic-dataloader/Error.hpp
@@ -0,0 +1,195 @@
+#pragma once
+
+#include <cstdint>
+#include <string_view>
+
+#include <openvic-dataloader/File.hpp>
+#include <openvic-dataloader/detail/utility/Utility.hpp>
+
+#include <dryad/abstract_node.hpp>
+#include <dryad/node.hpp>
+
+namespace ovdl {
+ template<IsFile>
+ struct BasicDiagnosticLogger;
+}
+
+namespace ovdl::error {
+ enum class [[nodiscard]] ErrorKind : std::uint64_t {
+ Root,
+
+ BufferError,
+
+ // Parse Error //
+ ExpectedLiteral,
+ ExpectedKeyword,
+ ExpectedCharClass,
+ GenericParseError,
+
+ FirstParseError = ExpectedLiteral,
+ LastParseError = GenericParseError,
+
+ // Semantic Diagnostic //
+ SemanticError,
+ SemanticWarning,
+ SemanticInfo,
+ SemanticDebug,
+ SemanticFixit,
+ SemanticHelp,
+
+ FirstSemantic = SemanticError,
+ LastSemantic = SemanticHelp,
+
+ PrimaryAnnotation,
+ SecondaryAnnotation,
+
+ FirstAnnotation = PrimaryAnnotation,
+ LastAnnotation = SecondaryAnnotation,
+ };
+
+ static constexpr std::string_view get_kind_name(ErrorKind kind) {
+ switch (kind) {
+ using enum ErrorKind;
+ case ExpectedLiteral: return "expected literal";
+ case ExpectedKeyword: return "expected keyword";
+ case ExpectedCharClass: return "expected char class";
+ case GenericParseError: return "generic";
+ default: detail::unreachable();
+ }
+ }
+
+ struct Error : dryad::abstract_node_all<ErrorKind> {
+ const char* message() const { return _message; }
+
+ protected:
+ DRYAD_ABSTRACT_NODE_CTOR(Error);
+
+ void _set_message(const char* message) { _message = message; }
+ const char* _message;
+
+ template<IsFile>
+ friend struct ovdl::BasicDiagnosticLogger;
+ };
+
+ using ErrorList = dryad::unlinked_node_list<Error>;
+
+ struct Annotation;
+ using AnnotationList = dryad::unlinked_node_list<Annotation>;
+
+ struct Root : dryad::basic_node<ErrorKind::Root, dryad::container_node<Error>> {
+ explicit Root(dryad::node_ctor ctor) : node_base(ctor) {}
+
+ DRYAD_CHILD_NODE_RANGE_GETTER(Error, errors, nullptr, this);
+
+ void insert_back(Error* error) {
+ insert_child_after(_last, error);
+ _last = error;
+ }
+
+ private:
+ Error* _last = nullptr;
+ };
+
+ struct BufferError : dryad::basic_node<ErrorKind::BufferError, Error> {
+ explicit BufferError(dryad::node_ctor ctor, const char* message) : node_base(ctor) {
+ _set_message(message);
+ }
+
+ explicit BufferError(dryad::node_ctor ctor) : node_base(ctor) {}
+ };
+
+ struct ParseError : dryad::abstract_node_range<Error, ErrorKind::FirstParseError, ErrorKind::LastParseError> {
+ const char* production_name() const { return _production_name; }
+
+ protected:
+ explicit ParseError(dryad::node_ctor ctor,
+ ErrorKind kind,
+ const char* message,
+ const char* production_name)
+ : node_base(ctor, kind),
+ _production_name(production_name) {
+ _set_message(message);
+ };
+
+ const char* _production_name;
+ };
+
+ template<ErrorKind NodeKind>
+ struct _ParseError_t : dryad::basic_node<NodeKind, ParseError> {
+ explicit _ParseError_t(dryad::node_ctor ctor, const char* message, const char* production_name)
+ : dryad::basic_node<NodeKind, ParseError>(ctor, message, production_name) {}
+ };
+
+ using ExpectedLiteral = _ParseError_t<ErrorKind::ExpectedLiteral>;
+ using ExpectedKeyword = _ParseError_t<ErrorKind::ExpectedKeyword>;
+ using ExpectedCharClass = _ParseError_t<ErrorKind::ExpectedCharClass>;
+ using GenericParseError = _ParseError_t<ErrorKind::GenericParseError>;
+
+ struct Semantic : dryad::abstract_node_range<dryad::container_node<Error>, ErrorKind::FirstSemantic, ErrorKind::LastSemantic> {
+ DRYAD_CHILD_NODE_RANGE_GETTER(Annotation, annotations, nullptr, this);
+
+ void push_back(Annotation* annotation);
+ void push_back(AnnotationList p_annotations);
+
+ protected:
+ explicit Semantic(dryad::node_ctor ctor, ErrorKind kind)
+ : node_base(ctor, kind) {};
+
+ explicit Semantic(dryad::node_ctor ctor, ErrorKind kind, const char* message)
+ : node_base(ctor, kind) {
+ insert_child_list_after(nullptr, AnnotationList {});
+ _set_message(message);
+ };
+
+ explicit Semantic(dryad::node_ctor ctor, ErrorKind kind, const char* message, AnnotationList annotations)
+ : node_base(ctor, kind) {
+ insert_child_list_after(nullptr, annotations);
+ _set_message(message);
+ };
+ };
+
+ template<ErrorKind NodeKind>
+ struct _SemanticError_t : dryad::basic_node<NodeKind, Semantic> {
+ using base_node = dryad::basic_node<NodeKind, Semantic>;
+
+ explicit _SemanticError_t(dryad::node_ctor ctor)
+ : base_node(ctor) {}
+
+ explicit _SemanticError_t(dryad::node_ctor ctor, const char* message)
+ : base_node(ctor, message) {}
+
+ explicit _SemanticError_t(dryad::node_ctor ctor, const char* message, AnnotationList annotations)
+ : base_node(ctor, message, annotations) {}
+ };
+
+ using SemanticError = _SemanticError_t<ErrorKind::SemanticError>;
+ using SemanticWarning = _SemanticError_t<ErrorKind::SemanticWarning>;
+ using SemanticInfo = _SemanticError_t<ErrorKind::SemanticInfo>;
+ using SemanticDebug = _SemanticError_t<ErrorKind::SemanticDebug>;
+ using SemanticFixit = _SemanticError_t<ErrorKind::SemanticFixit>;
+ using SemanticHelp = _SemanticError_t<ErrorKind::SemanticHelp>;
+
+ struct Annotation : dryad::abstract_node_range<Error, ErrorKind::FirstAnnotation, ErrorKind::LastAnnotation> {
+ protected:
+ explicit Annotation(dryad::node_ctor ctor, ErrorKind kind, const char* message) : node_base(ctor, kind) {
+ _set_message(message);
+ }
+ };
+
+ template<ErrorKind NodeKind>
+ struct _Annotation_t : dryad::basic_node<NodeKind, Annotation> {
+ explicit _Annotation_t(dryad::node_ctor ctor, const char* message)
+ : dryad::basic_node<NodeKind, Annotation>(ctor, message) {}
+ };
+
+ using PrimaryAnnotation = _Annotation_t<ErrorKind::PrimaryAnnotation>;
+ using SecondaryAnnotation = _Annotation_t<ErrorKind::SecondaryAnnotation>;
+
+ inline void Semantic::push_back(Annotation* annotation) {
+ insert_child_after(annotations().end().deref(), annotation);
+ }
+
+ inline void Semantic::push_back(AnnotationList p_annotations) {
+ insert_child_list_after(annotations().end().deref(), p_annotations);
+ }
+} \ No newline at end of file
diff --git a/include/openvic-dataloader/File.hpp b/include/openvic-dataloader/File.hpp
new file mode 100644
index 0000000..caa4a0a
--- /dev/null
+++ b/include/openvic-dataloader/File.hpp
@@ -0,0 +1,69 @@
+#pragma once
+
+#include <concepts>
+
+#include <openvic-dataloader/NodeLocation.hpp>
+#include <openvic-dataloader/detail/LexyFwdDeclaration.hpp>
+
+#include <dryad/node_map.hpp>
+
+namespace ovdl {
+ template<typename T>
+ concept IsEncoding = requires(T t) {
+ typename T::char_type;
+ typename T::int_type;
+ { T::template is_secondary_char_type<typename T::char_type>() } -> std::same_as<bool>;
+ { T::eof() } -> std::same_as<typename T::int_type>;
+ { T::to_int_type(typename T::char_type {}) } -> std::same_as<typename T::int_type>;
+ };
+
+ struct File {
+ explicit File(const char* path);
+
+ const char* path() const noexcept;
+
+ protected:
+ const char* _path;
+ };
+
+ template<typename T>
+ concept IsFile =
+ std::derived_from<T, File> && IsEncoding<typename T::encoding_type> &&
+ requires(T t, const typename T::node_type* node, NodeLocation location) {
+ { t.buffer() } -> std::same_as<const lexy::buffer<typename T::encoding_type, void>&>;
+ { t.set_location(node, location) } -> std::same_as<void>;
+ { t.location_of(node) } -> std::same_as<NodeLocation>;
+ };
+
+ template<typename EncodingT, typename NodeT>
+ struct BasicFile : File {
+ using encoding_type = EncodingT;
+ using node_type = NodeT;
+
+ explicit BasicFile(const char* path, lexy::buffer<encoding_type, void>&& buffer)
+ : File(path),
+ _buffer(static_cast<std ::remove_reference_t<decltype(buffer)>&&>(buffer)) {}
+
+ explicit BasicFile(lexy::buffer<encoding_type, void>&& buffer)
+ : File(""),
+ _buffer(static_cast<std ::remove_reference_t<decltype(buffer)>&&>(buffer)) {}
+
+ const lexy::buffer<encoding_type, void>& buffer() const {
+ return _buffer;
+ }
+
+ void set_location(const node_type* n, NodeLocation loc) {
+ _map.insert(n, loc);
+ }
+
+ NodeLocation location_of(const node_type* n) const {
+ auto result = _map.lookup(n);
+ DRYAD_ASSERT(result != nullptr, "every Node should have a NodeLocation");
+ return *result;
+ }
+
+ protected:
+ lexy::buffer<encoding_type, void> _buffer;
+ dryad::node_map<const node_type, NodeLocation> _map;
+ };
+} \ No newline at end of file
diff --git a/include/openvic-dataloader/NodeLocation.hpp b/include/openvic-dataloader/NodeLocation.hpp
new file mode 100644
index 0000000..117560b
--- /dev/null
+++ b/include/openvic-dataloader/NodeLocation.hpp
@@ -0,0 +1,33 @@
+#pragma once
+
+#include <cstdint>
+
+namespace ovdl {
+ struct NodeLocation {
+ const char* _begin = nullptr;
+ const char* _end = nullptr;
+
+ NodeLocation();
+ NodeLocation(const char* pos);
+ NodeLocation(const char* begin, const char* end);
+
+ NodeLocation(const NodeLocation&) noexcept;
+ NodeLocation& operator=(const NodeLocation&);
+
+ NodeLocation(NodeLocation&&);
+ NodeLocation& operator=(NodeLocation&&);
+
+ const char* begin() const;
+ const char* end() const;
+
+ bool is_synthesized() const;
+
+ static NodeLocation make_from(const char* begin, const char* end);
+ };
+
+ struct FilePosition {
+ std::uint32_t start_line = std::uint32_t(-1), end_line = std::uint32_t(-1), start_column = std::uint32_t(-1), end_column = std::uint32_t(-1);
+
+ inline constexpr bool is_empty() { return start_line == std::uint32_t(-1) && end_line == std::uint32_t(-1) && start_column == std::uint32_t(-1) && end_column == std::uint32_t(-1); }
+ };
+} \ No newline at end of file
diff --git a/include/openvic-dataloader/ParseState.hpp b/include/openvic-dataloader/ParseState.hpp
new file mode 100644
index 0000000..5655606
--- /dev/null
+++ b/include/openvic-dataloader/ParseState.hpp
@@ -0,0 +1,120 @@
+#pragma once
+
+#include <concepts>
+
+#include <openvic-dataloader/AbstractSyntaxTree.hpp>
+#include <openvic-dataloader/DiagnosticLogger.hpp>
+
+#include <dryad/tree.hpp>
+
+namespace ovdl {
+ template<typename T>
+ concept IsParseState = requires(
+ T t,
+ const T ct,
+ typename T::ast_type::file_type&& file,
+ lexy::buffer<typename T::ast_type::file_type::encoding_type>&& buffer,
+ const char* path //
+ ) {
+ requires IsAst<typename T::ast_type>;
+ requires std::derived_from<typename T::diagnostic_logger_type, DiagnosticLogger>;
+ { T { std::move(file) } } -> std::same_as<T>;
+ { T { std::move(buffer) } } -> std::same_as<T>;
+ { T { path, std::move(buffer) } } -> std::same_as<T>;
+ { t.ast() } -> std::same_as<typename T::ast_type&>;
+ { ct.ast() } -> std::same_as<const typename T::ast_type&>;
+ { t.logger() } -> std::same_as<typename T::diagnostic_logger_type&>;
+ { ct.logger() } -> std::same_as<const typename T::diagnostic_logger_type&>;
+ };
+
+ template<IsAst AstT>
+ struct ParseState {
+ using ast_type = AstT;
+ using diagnostic_logger_type = BasicDiagnosticLogger<typename ast_type::file_type>;
+
+ ParseState(typename ast_type::file_type&& file)
+ : _ast { std::move(file) },
+ _logger { _ast.file() } {}
+
+ ParseState(lexy::buffer<typename ast_type::file_type::encoding_type>&& buffer)
+ : ParseState(typename ast_type::file_type { std::move(buffer) }) {}
+
+ ParseState(const char* path, lexy::buffer<typename ast_type::file_type::encoding_type>&& buffer)
+ : ParseState(typename ast_type::file_type { path, std::move(buffer) }) {}
+
+ ast_type& ast() {
+ return _ast;
+ }
+
+ const ast_type& ast() const {
+ return _ast;
+ }
+
+ diagnostic_logger_type& logger() {
+ return _logger;
+ }
+
+ const diagnostic_logger_type& logger() const {
+ return _logger;
+ }
+
+ private:
+ ast_type _ast;
+ diagnostic_logger_type _logger;
+ };
+
+ template<typename T>
+ concept IsFileParseState = requires(
+ T t,
+ const T ct,
+ typename T::file_type&& file,
+ lexy::buffer<typename T::file_type::encoding_type>&& buffer,
+ const char* path //
+ ) {
+ requires IsFile<typename T::file_type>;
+ requires std::derived_from<typename T::diagnostic_logger_type, DiagnosticLogger>;
+ { T { std::move(file) } } -> std::same_as<T>;
+ { T { std::move(buffer) } } -> std::same_as<T>;
+ { T { path, std::move(buffer) } } -> std::same_as<T>;
+ { t.file() } -> std::same_as<typename T::file_type&>;
+ { ct.file() } -> std::same_as<const typename T::file_type&>;
+ { t.logger() } -> std::same_as<typename T::diagnostic_logger_type&>;
+ { ct.logger() } -> std::same_as<const typename T::diagnostic_logger_type&>;
+ };
+
+ template<IsFile FileT>
+ struct FileParseState {
+ using file_type = FileT;
+ using diagnostic_logger_type = BasicDiagnosticLogger<file_type>;
+
+ FileParseState(file_type&& file)
+ : _file { std::move(file) },
+ _logger { file } {}
+
+ FileParseState(lexy::buffer<typename file_type::encoding_type>&& buffer)
+ : FileParseState(file_type { std::move(buffer) }) {}
+
+ FileParseState(const char* path, lexy::buffer<typename file_type::encoding_type>&& buffer)
+ : FileParseState(file_type { path, std::move(buffer) }) {}
+
+ file_type& file() {
+ return _file;
+ }
+
+ const file_type& file() const {
+ return _file;
+ }
+
+ diagnostic_logger_type& logger() {
+ return _logger;
+ }
+
+ const diagnostic_logger_type& logger() const {
+ return _logger;
+ }
+
+ private:
+ file_type _file;
+ diagnostic_logger_type _logger;
+ };
+} \ No newline at end of file
diff --git a/include/openvic-dataloader/detail/BasicParser.hpp b/include/openvic-dataloader/Parser.hpp
index 7524bb5..c1f266b 100644
--- a/include/openvic-dataloader/detail/BasicParser.hpp
+++ b/include/openvic-dataloader/Parser.hpp
@@ -2,15 +2,12 @@
#include <string>
#include <string_view>
-#include <vector>
#include <openvic-dataloader/ParseError.hpp>
#include <openvic-dataloader/ParseWarning.hpp>
-#include <openvic-dataloader/detail/Concepts.hpp>
namespace ovdl::detail {
- class BasicParser {
- public:
+ struct BasicParser {
BasicParser();
void set_error_log_to_null();
@@ -22,16 +19,13 @@ namespace ovdl::detail {
bool has_fatal_error() const;
bool has_warning() const;
- const std::vector<ParseError>& get_errors() const;
- const std::vector<ParseWarning>& get_warnings() const;
std::string_view get_file_path() const;
protected:
- std::vector<ParseError> _errors;
- std::vector<ParseWarning> _warnings;
-
std::reference_wrapper<std::ostream> _error_stream;
std::string _file_path;
bool _has_fatal_error = false;
+ bool _has_error = false;
+ bool _has_warning = false;
};
} \ No newline at end of file
diff --git a/include/openvic-dataloader/csv/LineObject.hpp b/include/openvic-dataloader/csv/LineObject.hpp
index 87b4d31..ca632cd 100644
--- a/include/openvic-dataloader/csv/LineObject.hpp
+++ b/include/openvic-dataloader/csv/LineObject.hpp
@@ -13,7 +13,7 @@
#include <utility>
#include <vector>
-#include <openvic-dataloader/detail/VectorConstexpr.hpp>
+#include <openvic-dataloader/detail/utility/Constexpr.hpp>
namespace ovdl::csv {
/// LineObject should be able to recognize the differences between:
diff --git a/include/openvic-dataloader/csv/Parser.hpp b/include/openvic-dataloader/csv/Parser.hpp
index aa2a0fe..ccf732a 100644
--- a/include/openvic-dataloader/csv/Parser.hpp
+++ b/include/openvic-dataloader/csv/Parser.hpp
@@ -2,8 +2,13 @@
#include <filesystem>
+#include <openvic-dataloader/Error.hpp>
+#include <openvic-dataloader/Parser.hpp>
#include <openvic-dataloader/csv/LineObject.hpp>
-#include <openvic-dataloader/detail/BasicParser.hpp>
+#include <openvic-dataloader/detail/utility/Concepts.hpp>
+#include <openvic-dataloader/detail/utility/ErrorRange.hpp>
+
+#include <dryad/node.hpp>
namespace ovdl::csv {
enum class EncodingType {
@@ -15,6 +20,7 @@ namespace ovdl::csv {
class Parser final : public detail::BasicParser {
public:
Parser();
+ Parser(std::basic_ostream<char>& error_stream);
static Parser from_buffer(const char* data, std::size_t size);
static Parser from_buffer(const char* start, const char* end);
@@ -28,24 +34,33 @@ namespace ovdl::csv {
constexpr Parser& load_from_file(const char* path);
Parser& load_from_file(const std::filesystem::path& path);
- constexpr Parser& load_from_file(const detail::Has_c_str auto& path);
+ constexpr Parser& load_from_file(const detail::HasCstr auto& path) {
+ return load_from_file(path.c_str());
+ }
bool parse_csv(bool handle_strings = false);
const std::vector<csv::LineObject>& get_lines() const;
+ using error_range = ovdl::detail::error_range;
+ Parser::error_range get_errors() const;
+
+ const FilePosition get_error_position(const error::Error* error) const;
+
+ void print_errors_to(std::basic_ostream<char>& stream) const;
+
Parser(Parser&&);
Parser& operator=(Parser&&);
~Parser();
private:
- class BufferHandler;
- std::unique_ptr<BufferHandler> _buffer_handler;
+ class ParseHandler;
+ std::unique_ptr<ParseHandler> _parse_handler;
std::vector<csv::LineObject> _lines;
template<typename... Args>
- constexpr void _run_load_func(detail::LoadCallback<BufferHandler, Args...> auto func, Args... args);
+ constexpr void _run_load_func(detail::LoadCallback<ParseHandler, Args...> auto func, Args... args);
};
using Windows1252Parser = Parser<EncodingType::Windows1252>;
diff --git a/include/openvic-dataloader/detail/CallbackOStream.hpp b/include/openvic-dataloader/detail/CallbackOStream.hpp
index 641d53f..f7cfc4a 100644
--- a/include/openvic-dataloader/detail/CallbackOStream.hpp
+++ b/include/openvic-dataloader/detail/CallbackOStream.hpp
@@ -6,10 +6,10 @@
#include <type_traits>
namespace ovdl::detail {
- template<typename Callback, class CHAR_T, class traits = std::char_traits<CHAR_T>>
- class BasicCallbackStreamBuffer : public std::basic_streambuf<CHAR_T, traits> {
+ template<typename Callback, class CharT, class traits = std::char_traits<CharT>>
+ class BasicCallbackStreamBuffer : public std::basic_streambuf<CharT, traits> {
public:
- using base_type = std::basic_streambuf<CHAR_T, traits>;
+ using base_type = std::basic_streambuf<CharT, traits>;
using callback_type = Callback;
using char_type = typename base_type::char_type;
using int_type = typename base_type::int_type;
@@ -29,11 +29,12 @@ namespace ovdl::detail {
};
int_type overflow(int_type ch) override {
+ auto c = static_cast<char_type>(ch);
if constexpr (std::is_same_v<void, typename decltype(std::function { _callback })::result_type>) {
- _callback(&ch, 1, _user_data);
+ _callback(&c, 1, _user_data);
return 1;
} else {
- return _callback(&ch, 1, _user_data); // returns the number of characters successfully written.
+ return _callback(&c, 1, _user_data); // returns the number of characters successfully written.
}
}
@@ -64,22 +65,28 @@ namespace ovdl::detail {
CallbackWStreamBuffer(Callback cb, void* user_data = nullptr) : base_type(cb, user_data) {}
};
- template<typename Callback, class CHAR_T, class traits = std::char_traits<CHAR_T>>
- class BasicCallbackStream : public std::basic_ostream<CHAR_T, traits> {
+ template<class CharT, typename Callback, class traits = std::char_traits<CharT>>
+ class BasicCallbackStream : public std::basic_ostream<CharT, traits> {
public:
- using base_type = std::basic_ostream<CHAR_T, traits>;
+ using base_type = std::basic_ostream<CharT, traits>;
BasicCallbackStream(Callback cb, void* user_data = nullptr)
: m_sbuf(cb, user_data),
- std::basic_ios<CHAR_T, traits>(&m_sbuf),
- std::basic_ostream<CHAR_T, traits>(&m_sbuf) {
- std::basic_ios<CHAR_T, traits>::init(&m_sbuf);
+ std::basic_ios<CharT, traits>(&m_sbuf),
+ std::basic_ostream<CharT, traits>(&m_sbuf) {
+ std::basic_ios<CharT, traits>::init(&m_sbuf);
}
private:
- BasicCallbackStreamBuffer<Callback, CHAR_T, traits> m_sbuf;
+ BasicCallbackStreamBuffer<Callback, CharT, traits> m_sbuf;
};
+ template<typename CharT>
+ auto make_callback_stream(auto&& cb, void* user_data = nullptr) {
+ using Callback = std::decay_t<decltype(cb)>;
+ return BasicCallbackStream<CharT, Callback> { std::forward<Callback>(cb), user_data };
+ }
+
template<typename Callback>
class CallbackStream : public BasicCallbackStream<Callback, char> {
public:
diff --git a/include/openvic-dataloader/detail/ClassExport.hpp b/include/openvic-dataloader/detail/ClassExport.hpp
deleted file mode 100644
index 27098ed..0000000
--- a/include/openvic-dataloader/detail/ClassExport.hpp
+++ /dev/null
@@ -1,9 +0,0 @@
-#pragma once
-
-#ifdef _MSC_VER
-#define OVDL_EXPORT __declspec(dllexport)
-#elif defined(__GNUC__)
-#define OVDL_EXPORT __attribute__((visibility("default")))
-#else
-#define OVDL_EXPORT
-#endif \ No newline at end of file
diff --git a/include/openvic-dataloader/detail/Concepts.hpp b/include/openvic-dataloader/detail/Concepts.hpp
deleted file mode 100644
index 3ca210c..0000000
--- a/include/openvic-dataloader/detail/Concepts.hpp
+++ /dev/null
@@ -1,21 +0,0 @@
-#pragma once
-
-#include <concepts>
-#include <optional>
-#include <utility>
-
-#include <openvic-dataloader/ParseError.hpp>
-
-namespace ovdl::detail {
- template<typename T, typename Self, typename... Args>
- concept LoadCallback =
- requires(T t, Self* self, Args... args) {
- { t(self, std::forward<Args>(args)...) } -> std::same_as<std::optional<ParseError>>;
- };
-
- template<typename T>
- concept Has_c_str =
- requires(T t) {
- { t.c_str() } -> std::same_as<const char*>;
- };
-} \ No newline at end of file
diff --git a/include/openvic-dataloader/detail/LexyFwdDeclaration.hpp b/include/openvic-dataloader/detail/LexyFwdDeclaration.hpp
new file mode 100644
index 0000000..554c88d
--- /dev/null
+++ b/include/openvic-dataloader/detail/LexyFwdDeclaration.hpp
@@ -0,0 +1,8 @@
+#pragma once
+
+namespace lexy {
+ struct default_encoding;
+
+ template<typename Encoding, typename MemoryResource>
+ struct buffer;
+} \ No newline at end of file
diff --git a/include/openvic-dataloader/detail/LexyReportError.hpp b/include/openvic-dataloader/detail/LexyReportError.hpp
new file mode 100644
index 0000000..3c32bd1
--- /dev/null
+++ b/include/openvic-dataloader/detail/LexyReportError.hpp
@@ -0,0 +1,107 @@
+#pragma once
+
+#include <cstddef>
+#include <sstream>
+#include <utility>
+#include <vector>
+
+#include <openvic-dataloader/ParseData.hpp>
+#include <openvic-dataloader/ParseError.hpp>
+
+#include <lexy/input_location.hpp>
+#include <lexy/visualize.hpp>
+
+#include "openvic-dataloader/detail/utility/Concepts.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::HasCstr 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/include/openvic-dataloader/detail/OStreamOutputIterator.hpp b/include/openvic-dataloader/detail/OStreamOutputIterator.hpp
new file mode 100644
index 0000000..8f120c7
--- /dev/null
+++ b/include/openvic-dataloader/detail/OStreamOutputIterator.hpp
@@ -0,0 +1,22 @@
+#pragma once
+
+#include <memory>
+#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/include/openvic-dataloader/detail/OptionalConstexpr.hpp b/include/openvic-dataloader/detail/OptionalConstexpr.hpp
deleted file mode 100644
index bcb12a7..0000000
--- a/include/openvic-dataloader/detail/OptionalConstexpr.hpp
+++ /dev/null
@@ -1,9 +0,0 @@
-#pragma once
-
-// THANK YOU APPLE FOR YOUR UTTER DISREGARD FOR C++20
-
-#if __cpp_lib_optional >= 202106L
-#define OVDL_OPTIONAL_CONSTEXPR constexpr
-#else
-#define OVDL_OPTIONAL_CONSTEXPR inline
-#endif \ No newline at end of file
diff --git a/include/openvic-dataloader/detail/utility/Concepts.hpp b/include/openvic-dataloader/detail/utility/Concepts.hpp
new file mode 100644
index 0000000..0ba91cc
--- /dev/null
+++ b/include/openvic-dataloader/detail/utility/Concepts.hpp
@@ -0,0 +1,45 @@
+#pragma once
+
+#include <concepts>
+#include <cstdint>
+#include <functional>
+#include <utility>
+
+namespace ovdl {
+ struct NodeLocation;
+ struct File;
+ namespace detail {
+ enum class buffer_error : std::uint8_t;
+ }
+}
+
+namespace ovdl::detail {
+ template<typename T, typename... Ts>
+ concept any_of = (std::same_as<T, Ts> || ...);
+
+ template<typename T>
+ concept HasCstr =
+ requires(T t) {
+ { t.c_str() } -> std::same_as<const char*>;
+ };
+
+ template<typename T>
+ concept HasPath = requires(T& t) {
+ { t.path() } -> std::same_as<const char*>;
+ };
+
+ template<typename T, typename Self, typename... Args>
+ concept LoadCallback =
+ requires(T&& t, Self&& self, Args&&... args) {
+ { std::invoke(std::forward<T>(t), std::forward<Self>(self), std::forward<Args>(args)...) } -> std::same_as<ovdl::detail::buffer_error>;
+ };
+
+ template<typename T>
+ concept IsEncoding = requires(T t) {
+ typename T::char_type;
+ typename T::int_type;
+ { T::template is_secondary_char_type<typename T::char_type>() } -> std::same_as<bool>;
+ { T::eof() } -> std::same_as<typename T::int_type>;
+ { T::to_int_type(typename T::char_type {}) } -> std::same_as<typename T::int_type>;
+ };
+} \ No newline at end of file
diff --git a/include/openvic-dataloader/detail/VectorConstexpr.hpp b/include/openvic-dataloader/detail/utility/Constexpr.hpp
index 7e7fa34..49479c5 100644
--- a/include/openvic-dataloader/detail/VectorConstexpr.hpp
+++ b/include/openvic-dataloader/detail/utility/Constexpr.hpp
@@ -2,6 +2,12 @@
// THANK YOU APPLE FOR YOUR UTTER DISREGARD FOR C++20
+#if __cpp_lib_optional >= 202106L
+#define OVDL_OPTIONAL_CONSTEXPR constexpr
+#else
+#define OVDL_OPTIONAL_CONSTEXPR inline
+#endif
+
#if __cpp_lib_constexpr_vector >= 201907L
#define OVDL_VECTOR_CONSTEXPR constexpr
#else
diff --git a/include/openvic-dataloader/detail/utility/ErrorRange.hpp b/include/openvic-dataloader/detail/utility/ErrorRange.hpp
new file mode 100644
index 0000000..a427f6c
--- /dev/null
+++ b/include/openvic-dataloader/detail/utility/ErrorRange.hpp
@@ -0,0 +1,11 @@
+#pragma once
+
+#include <utility>
+
+#include <openvic-dataloader/Error.hpp>
+
+#include <dryad/node.hpp>
+
+namespace ovdl::detail {
+ using error_range = decltype(std::declval<const error::Root*>()->errors());
+} \ No newline at end of file
diff --git a/include/openvic-dataloader/detail/PointerHash.hpp b/include/openvic-dataloader/detail/utility/PointerHash.hpp
index c0d28bc..c0d28bc 100644
--- a/include/openvic-dataloader/detail/PointerHash.hpp
+++ b/include/openvic-dataloader/detail/utility/PointerHash.hpp
diff --git a/include/openvic-dataloader/detail/SelfType.hpp b/include/openvic-dataloader/detail/utility/SelfType.hpp
index 5209700..5209700 100644
--- a/include/openvic-dataloader/detail/SelfType.hpp
+++ b/include/openvic-dataloader/detail/utility/SelfType.hpp
diff --git a/include/openvic-dataloader/detail/TypeName.hpp b/include/openvic-dataloader/detail/utility/TypeName.hpp
index 1a34a0f..1a34a0f 100644
--- a/include/openvic-dataloader/detail/TypeName.hpp
+++ b/include/openvic-dataloader/detail/utility/TypeName.hpp
diff --git a/include/openvic-dataloader/detail/utility/Utility.hpp b/include/openvic-dataloader/detail/utility/Utility.hpp
new file mode 100644
index 0000000..138a029
--- /dev/null
+++ b/include/openvic-dataloader/detail/utility/Utility.hpp
@@ -0,0 +1,38 @@
+#pragma once
+
+#include <string_view>
+#include <type_traits>
+
+#include "openvic-dataloader/detail/utility/TypeName.hpp"
+
+namespace ovdl::detail {
+ [[noreturn]] inline void unreachable() {
+ // Uses compiler specific extensions if possible.
+ // Even if no extension is used, undefined behavior is still raised by
+ // an empty function body and the noreturn attribute.
+#ifdef __GNUC__ // GCC, Clang, ICC
+ __builtin_unreachable();
+#elif defined(_MSC_VER) // MSVC
+ __assume(false);
+#endif
+ }
+
+ template<typename Kind>
+ constexpr std::string_view get_kind_name() {
+ constexpr auto name = type_name<Kind>();
+
+ return name;
+ }
+
+ template<typename EnumT>
+ requires std::is_enum_v<EnumT>
+ constexpr std::underlying_type_t<EnumT> to_underlying(EnumT e) {
+ return static_cast<std::underlying_type_t<EnumT>>(e);
+ }
+
+ template<typename EnumT>
+ requires std::is_enum_v<EnumT>
+ constexpr EnumT from_underlying(std::underlying_type_t<EnumT> ut) {
+ return static_cast<EnumT>(ut);
+ }
+} \ No newline at end of file
diff --git a/include/openvic-dataloader/v2script/AbstractSyntaxTree.hpp b/include/openvic-dataloader/v2script/AbstractSyntaxTree.hpp
index 689ab6e..1e7b2c3 100644
--- a/include/openvic-dataloader/v2script/AbstractSyntaxTree.hpp
+++ b/include/openvic-dataloader/v2script/AbstractSyntaxTree.hpp
@@ -1,310 +1,200 @@
#pragma once
-#include <cstddef>
-#include <cstdint>
-#include <iostream>
-#include <memory>
-#include <string>
+#include <cstdio>
#include <string_view>
-#include <type_traits>
-#include <utility>
-#include <vector>
-#include <openvic-dataloader/detail/OptionalConstexpr.hpp>
-#include <openvic-dataloader/detail/SelfType.hpp>
-#include <openvic-dataloader/detail/TypeName.hpp>
+#include <openvic-dataloader/AbstractSyntaxTree.hpp>
+#include <openvic-dataloader/File.hpp>
+#include <openvic-dataloader/NodeLocation.hpp>
+#include <openvic-dataloader/ParseState.hpp>
+#include <openvic-dataloader/detail/LexyFwdDeclaration.hpp>
-namespace lexy {
- struct nullopt;
-}
+#include <dryad/_detail/assert.hpp>
+#include <dryad/_detail/config.hpp>
+#include <dryad/abstract_node.hpp>
+#include <dryad/node.hpp>
+#include <dryad/symbol.hpp>
+#include <dryad/tree.hpp>
-namespace ovdl::v2script {
- class Parser;
-}
+namespace ovdl::v2script::ast {
+ enum class NodeKind {
+ FileTree,
-#define OVDL_PRINT_FUNC_DEF std::ostream& print(std::ostream& stream, std::size_t indent) const override
+ // FlatValues //
+ IdentifierValue, // straight_identifier_value
+ StringValue, // "plain string value"
-// defines get_type_static and get_type for string type naming
-#define OVDL_RT_TYPE_DEF \
- static constexpr std::string_view get_type_static() { return ::ovdl::detail::type_name<type>(); } \
- constexpr std::string_view get_type() const override { return ::ovdl::detail::type_name<std::decay_t<decltype(*this)>>(); }
+ FirstFlatValue = IdentifierValue,
+ LastFlatValue = StringValue,
-// defines type for self-class referencing
-#define OVDL_TYPE_DEFINE_SELF \
- struct _self_type_tag {}; \
- constexpr auto _self_type_helper() -> decltype(::ovdl::detail::Writer<_self_type_tag, decltype(this)> {}); \
- using type = ::ovdl::detail::Read<_self_type_tag>;
+ // Values //
+ ListValue, // { <StatementList> }
+ NullValue,
-namespace ovdl::v2script::ast {
+ FirstValue = FirstFlatValue,
+ LastValue = NullValue,
- struct Node;
- using NodePtr = Node*;
- using NodeCPtr = const Node*;
- using NodeUPtr = std::unique_ptr<Node>;
+ // Statements //
+ EventStatement, // (country_event|province_event) = { id = <FlatValue> ... }
+ AssignStatement, // <IdentifierValue> = <Value>
+ ValueStatement, // <Value>
- struct NodeLocation {
- const char* _begin = nullptr;
- const char* _end = nullptr;
+ FirstStatement = EventStatement,
+ LastStatement = ValueStatement,
+ };
- NodeLocation() = default;
- NodeLocation(const char* pos) : _begin(pos),
- _end(pos) {}
- NodeLocation(const char* begin, const char* end) : _begin(begin),
- _end(end) {}
+ constexpr std::string_view get_kind_name(NodeKind kind) {
+ switch (kind) {
+ using enum NodeKind;
+ case FileTree: return "file tree";
+ case IdentifierValue: return "identifier value";
+ case StringValue: return "string value";
+ case ListValue: return "list value";
+ case NullValue: return "null value";
+ case EventStatement: return "event statement";
+ case AssignStatement: return "assign statement";
+ case ValueStatement: return "value statement";
+ default: detail::unreachable();
+ }
+ }
- NodeLocation(const NodeLocation&) = default;
- NodeLocation& operator=(const NodeLocation&) = default;
+ using Node = dryad::node<NodeKind>;
+ using NodeList = dryad::unlinked_node_list<Node>;
- NodeLocation(NodeLocation&&) = default;
- NodeLocation& operator=(NodeLocation&&) = default;
+ struct Value;
- const char* begin() const { return _begin; }
- const char* end() const { return _end; }
+ struct FlatValue;
+ struct IdentifierValue;
+ struct StringValue;
- static inline NodeLocation make_from(const char* begin, const char* end) {
- end++;
- if (begin >= end) return NodeLocation(begin);
- return NodeLocation(begin, end);
- }
- };
+ struct ListValue;
- struct Node {
- Node(const Node&) = delete;
- Node& operator=(const Node&) = delete;
- Node(NodeLocation location) : _location(location) {}
- Node(Node&&) = default;
- Node& operator=(Node&&) = default;
- virtual ~Node() = default;
+ struct Statement;
+ using StatementList = dryad::unlinked_node_list<Statement>;
- virtual std::ostream& print(std::ostream& stream, std::size_t indent) const = 0;
- static std::ostream& print_ptr(std::ostream& stream, NodeCPtr node, std::size_t indent);
- explicit operator std::string() const;
+ struct EventStatement;
+ using EventStatementList = dryad::unlinked_node_list<EventStatement>;
- static constexpr std::string_view get_type_static() { return detail::type_name<Node>(); }
- constexpr virtual std::string_view get_type() const = 0;
+ struct AssignStatement;
+ using AssignStatementList = dryad::unlinked_node_list<AssignStatement>;
- static constexpr std::string_view get_base_type_static() { return detail::type_name<Node>(); }
- constexpr virtual std::string_view get_base_type() const { return get_base_type_static(); }
+ struct Value : dryad::abstract_node_range<Node, NodeKind::FirstValue, NodeKind::LastValue> {
+ DRYAD_ABSTRACT_NODE_CTOR(Value);
+ };
- template<typename T>
- constexpr bool is_type() const {
- return get_type().compare(detail::type_name<T>()) == 0;
+ struct FlatValue : dryad::abstract_node_range<Value, NodeKind::FirstFlatValue, NodeKind::LastFlatValue> {
+ AbstractSyntaxTree::symbol_type value() const {
+ return _value;
}
- template<typename T>
- constexpr bool is_derived_from() const {
- return is_type<T>() || get_base_type().compare(detail::type_name<T>()) == 0;
+ const char* value(const AbstractSyntaxTree::symbol_interner_type& symbols) const {
+ return _value.c_str(symbols);
}
- template<typename T>
- constexpr T* cast_to() {
- if (is_derived_from<T>() || is_type<Node>()) return (static_cast<T*>(this));
- return nullptr;
- }
+ protected:
+ explicit FlatValue(dryad::node_ctor ctor, NodeKind kind, AbstractSyntaxTree::symbol_type value)
+ : node_base(ctor, kind),
+ _value(value) {}
- template<typename T>
- constexpr const T* const cast_to() const {
- if (is_derived_from<T>() || is_type<Node>()) return (static_cast<const T*>(this));
- return nullptr;
- }
+ protected:
+ AbstractSyntaxTree::symbol_type _value;
+ };
- const NodeLocation location() const { return _location; }
+ struct IdentifierValue : dryad::basic_node<NodeKind::IdentifierValue, FlatValue> {
+ explicit IdentifierValue(dryad::node_ctor ctor, AbstractSyntaxTree::symbol_type value) : node_base(ctor, value) {}
+ };
- struct line_col {
- uint32_t line;
- uint32_t column;
- };
+ struct StringValue : dryad::basic_node<NodeKind::StringValue, FlatValue> {
+ explicit StringValue(dryad::node_ctor ctor, AbstractSyntaxTree::symbol_type value) : node_base(ctor, value) {}
+ };
- private:
- friend class ::ovdl::v2script::Parser;
- const line_col get_begin_line_col(const Parser& parser) const;
- const line_col get_end_line_col(const Parser& parser) const;
+ struct ListValue : dryad::basic_node<NodeKind::ListValue, dryad::container_node<Value>> {
+ explicit ListValue(dryad::node_ctor ctor, StatementList statements);
+ explicit ListValue(dryad::node_ctor ctor, AssignStatementList statements)
+ : node_base(ctor) {
+ insert_child_list_after(nullptr, statements);
+ }
+
+ explicit ListValue(dryad::node_ctor ctor) : ListValue(ctor, StatementList {}) {
+ }
+
+ DRYAD_CHILD_NODE_RANGE_GETTER(Statement, statements, nullptr, this->node_after(_last_statement));
private:
- NodeLocation _location;
+ Node* _last_statement;
};
- inline std::ostream& operator<<(std::ostream& stream, Node const& node) {
- return node.print(stream, 0);
- }
- inline std::ostream& operator<<(std::ostream& stream, NodeCPtr node) {
- return Node::print_ptr(stream, node, 0);
- }
- inline std::ostream& operator<<(std::ostream& stream, Node::line_col const& val) {
- return stream << '(' << val.line << ':' << val.column << ')';
- }
+ struct NullValue : dryad::basic_node<NodeKind::NullValue, Value> {
+ explicit NullValue(dryad::node_ctor ctor) : node_base(ctor) {}
+ };
- template<class T, class... Args>
- NodePtr make_node_ptr(Args&&... args) {
- if constexpr (std::is_pointer_v<NodePtr>) {
- return new T(std::forward<Args>(args)...);
- } else {
- return NodePtr(new T(std::forward<Args>(args)...));
+ struct Statement : dryad::abstract_node_range<dryad::container_node<Node>, NodeKind::FirstStatement, NodeKind::LastStatement> {
+ explicit Statement(dryad::node_ctor ctor, NodeKind kind, Value* right)
+ : node_base(ctor, kind) {
+ insert_child_after(nullptr, right);
}
- }
- template<typename To, typename From>
- To& cast_node_ptr(const From& from) {
- if constexpr (std::is_pointer_v<NodePtr>) {
- return *static_cast<To*>(from);
- } else {
- return *static_cast<To*>(from.get());
+ explicit Statement(dryad::node_ctor ctor, NodeKind kind, Value* left, Value* right)
+ : node_base(ctor, kind) {
+ insert_child_after(nullptr, left);
+ insert_child_after(left, right);
}
- }
+ };
- template<typename To, typename From>
- const To& cast_node_cptr(const From& from) {
- if constexpr (std::is_pointer_v<NodePtr>) {
- return *static_cast<const To*>(from);
- } else {
- return *static_cast<const To*>(from.get());
+ struct EventStatement : dryad::basic_node<NodeKind::EventStatement, Statement> {
+ explicit EventStatement(dryad::node_ctor ctor, bool is_province_event, ListValue* list)
+ : basic_node(ctor, list),
+ _is_province_event(is_province_event) {
}
- }
- void copy_into_node_ptr_vector(const std::vector<NodePtr>& source, std::vector<NodeUPtr>& dest);
-
- struct AbstractStringNode : public Node {
- std::string _name;
- AbstractStringNode();
- AbstractStringNode(std::string&& name, bool allow_newline);
- AbstractStringNode(NodeLocation location);
- AbstractStringNode(NodeLocation location, std::string&& name, bool allow_newline);
- OVDL_TYPE_DEFINE_SELF;
- OVDL_RT_TYPE_DEF;
- OVDL_PRINT_FUNC_DEF;
- static constexpr std::string_view get_base_type_static() { return detail::type_name<AbstractStringNode>(); }
- constexpr std::string_view get_base_type() const override { return ::ovdl::detail::type_name<std::decay_t<decltype(*this)>>(); }
- };
+ bool is_province_event() const { return _is_province_event; }
-#define OVDL_AST_STRING_NODE(NAME) \
- struct NAME final : public AbstractStringNode { \
- NAME(); \
- NAME(std::string&& name, bool allow_newline = true); \
- NAME(lexy::nullopt); \
- NAME(NodeLocation location); \
- NAME(NodeLocation location, std::string&& name, bool allow_newline = true); \
- NAME(NodeLocation location, lexy::nullopt); \
- OVDL_TYPE_DEFINE_SELF; \
- OVDL_RT_TYPE_DEF; \
- OVDL_PRINT_FUNC_DEF; \
- }
+ DRYAD_CHILD_NODE_GETTER(Value, right, nullptr);
- // Value Expression Nodes
- OVDL_AST_STRING_NODE(IdentifierNode);
- OVDL_AST_STRING_NODE(StringNode);
-
- // Assignment Nodes
- OVDL_AST_STRING_NODE(FactorNode);
- OVDL_AST_STRING_NODE(MonthNode);
- OVDL_AST_STRING_NODE(NameNode);
- OVDL_AST_STRING_NODE(FireOnlyNode);
- OVDL_AST_STRING_NODE(IdNode);
- OVDL_AST_STRING_NODE(TitleNode);
- OVDL_AST_STRING_NODE(DescNode);
- OVDL_AST_STRING_NODE(PictureNode);
- OVDL_AST_STRING_NODE(IsTriggeredNode);
-
-#undef OVDL_AST_STRING_NODE
-
- struct AssignNode final : public Node {
- std::string _name;
- NodeUPtr _initializer;
- AssignNode(NodeLocation location, NodeCPtr name, NodePtr init);
- OVDL_TYPE_DEFINE_SELF;
- OVDL_RT_TYPE_DEF;
- OVDL_PRINT_FUNC_DEF;
+ private:
+ bool _is_province_event;
};
- struct AbstractListNode : public Node {
- std::vector<NodeUPtr> _statements;
- AbstractListNode(const std::vector<NodePtr>& statements = std::vector<NodePtr> {});
- AbstractListNode(NodeLocation location, const std::vector<NodePtr>& statements = std::vector<NodePtr> {});
- OVDL_TYPE_DEFINE_SELF;
- OVDL_RT_TYPE_DEF;
- OVDL_PRINT_FUNC_DEF;
- static constexpr std::string_view get_base_type_static() { return detail::type_name<AbstractListNode>(); }
- constexpr std::string_view get_base_type() const override { return ::ovdl::detail::type_name<std::decay_t<decltype(*this)>>(); }
+ struct AssignStatement : dryad::basic_node<NodeKind::AssignStatement, Statement> {
+ explicit AssignStatement(dryad::node_ctor ctor, Value* left, Value* right)
+ : node_base(ctor, left, right) {
+ }
+ DRYAD_CHILD_NODE_GETTER(Value, left, nullptr);
+ DRYAD_CHILD_NODE_GETTER(Value, right, left());
};
-#define OVDL_AST_LIST_NODE(NAME) \
- struct NAME final : public AbstractListNode { \
- NAME(const std::vector<NodePtr>& statements = std::vector<NodePtr> {}); \
- NAME(lexy::nullopt); \
- NAME(NodeLocation location, const std::vector<NodePtr>& statements = std::vector<NodePtr> {}); \
- NAME(NodeLocation location, lexy::nullopt); \
- OVDL_TYPE_DEFINE_SELF; \
- OVDL_RT_TYPE_DEF; \
- OVDL_PRINT_FUNC_DEF; \
- }
-
- OVDL_AST_LIST_NODE(FileNode);
- OVDL_AST_LIST_NODE(ListNode);
-
- OVDL_AST_LIST_NODE(ModifierNode);
- OVDL_AST_LIST_NODE(MtthNode);
- OVDL_AST_LIST_NODE(EventOptionNode);
- OVDL_AST_LIST_NODE(BehaviorListNode);
- OVDL_AST_LIST_NODE(DecisionListNode);
-
-#undef OVDL_AST_LIST_NODE
-
-#define OVDL_AST_LIST_EXTEND(NAME) \
- NAME(lexy::nullopt); \
- NAME(NodeLocation location, lexy::nullopt); \
- OVDL_TYPE_DEFINE_SELF; \
- OVDL_RT_TYPE_DEF; \
- OVDL_PRINT_FUNC_DEF
-
- struct EventNode final : public AbstractListNode {
- OVDL_AST_LIST_EXTEND(EventNode);
- enum class Type {
- Country,
- Province
- } _type;
- EventNode(Type type, const std::vector<NodePtr>& statements = {});
- EventNode(NodeLocation location, Type type, const std::vector<NodePtr>& statements = {});
+ struct ValueStatement : dryad::basic_node<NodeKind::ValueStatement, Statement> {
+ explicit ValueStatement(dryad::node_ctor ctor, Value* value)
+ : node_base(ctor, value) {
+ }
+ DRYAD_CHILD_NODE_GETTER(Value, value, nullptr);
};
- struct DecisionNode final : public AbstractListNode {
- OVDL_AST_LIST_EXTEND(DecisionNode);
- NodeUPtr _name;
- DecisionNode(NodePtr name, const std::vector<NodePtr>& statements = {});
- DecisionNode(NodeLocation location, NodePtr name, const std::vector<NodePtr>& statements = {});
- };
+ struct FileTree : dryad::basic_node<NodeKind::FileTree, dryad::container_node<Node>> {
+ explicit FileTree(dryad::node_ctor ctor, StatementList statements);
+ explicit FileTree(dryad::node_ctor ctor, AssignStatementList statements) : node_base(ctor) {
+ insert_child_list_after(nullptr, statements);
+ }
- struct EventMtthModifierNode final : public AbstractListNode {
- OVDL_AST_LIST_EXTEND(EventMtthModifierNode);
- NodeUPtr _factor_value;
- EventMtthModifierNode() : AbstractListNode() {}
- EventMtthModifierNode(NodeLocation location) : AbstractListNode(location) {}
- };
+ explicit FileTree(dryad::node_ctor ctor) : FileTree(ctor, StatementList {}) {
+ }
- // Packed single case
- struct ExecutionNode final : public Node {
- enum class Type {
- Effect,
- Trigger
- } _type;
- NodeUPtr _name;
- NodeUPtr _initializer;
- ExecutionNode(Type type, NodePtr name, NodePtr init);
- ExecutionNode(NodeLocation location, Type type, NodePtr name, NodePtr init);
- OVDL_TYPE_DEFINE_SELF;
- OVDL_RT_TYPE_DEF;
- OVDL_PRINT_FUNC_DEF;
- };
+ DRYAD_CHILD_NODE_RANGE_GETTER(Statement, statements, nullptr, this->node_after(_last_node));
- struct ExecutionListNode final : public AbstractListNode {
- OVDL_AST_LIST_EXTEND(ExecutionListNode);
- ExecutionNode::Type _type;
- ExecutionListNode(ExecutionNode::Type type, const std::vector<NodePtr>& statements);
- ExecutionListNode(NodeLocation location, ExecutionNode::Type type, const std::vector<NodePtr>& statements);
+ private:
+ Node* _last_node;
};
-#undef OVDL_AST_LIST_EXTEND
+ using File = ovdl::BasicFile<lexy::default_encoding, Node>;
+ struct AbstractSyntaxTree : ovdl::BasicAbstractSyntaxTree<File, FileTree> {
+ using BasicAbstractSyntaxTree::BasicAbstractSyntaxTree;
-}
+ std::string make_list_visualizer() const;
+ std::string make_native_visualizer() const;
+ };
+ using ParseState = ovdl::ParseState<AbstractSyntaxTree>;
-#undef OVDL_PRINT_FUNC_DECL
-#undef OVDL_PRINT_FUNC_DEF
-#undef OVDL_TYPE_DEFINE_SELF \ No newline at end of file
+ static_assert(IsFile<ast::File>, "File failed IsFile concept");
+ static_assert(IsAst<ast::AbstractSyntaxTree>, "AbstractSyntaxTree failed IsAst concept");
+ static_assert(IsParseState<ast::ParseState>, "ParseState failed IsParseState concept");
+} \ No newline at end of file
diff --git a/include/openvic-dataloader/v2script/NodeLocationMap.hpp b/include/openvic-dataloader/v2script/NodeLocationMap.hpp
deleted file mode 100644
index aa88d62..0000000
--- a/include/openvic-dataloader/v2script/NodeLocationMap.hpp
+++ /dev/null
@@ -1,91 +0,0 @@
-#pragma once
-
-#include <unordered_map>
-
-#include <openvic-dataloader/detail/PointerHash.hpp>
-#include <openvic-dataloader/v2script/AbstractSyntaxTree.hpp>
-
-#include <lexy/input_location.hpp>
-
-namespace ovdl::v2script::ast {
- // TODO: FOR THE LOVE OF GOD USE A DIFFERENT HASH MULTIMAP TYPE
- // See src/openvic-dataloader/v2script/Parser.cpp#252
- template<typename Input>
- struct NodeLocationMap : public std::unordered_multimap<NodeCPtr, const lexy::input_location<Input>, detail::PointerHash<Node>> {
- NodeLocationMap() = default;
- NodeLocationMap(const Input& input, const Node& top_node) {
- generate_location_map(input, top_node);
- }
-
- NodeLocationMap(const NodeLocationMap&) = default;
- NodeLocationMap(NodeLocationMap&&) = default;
-
- NodeLocationMap& operator=(const NodeLocationMap&) = default;
- NodeLocationMap& operator=(NodeLocationMap&&) = default;
-
- lexy::input_location_anchor<Input> generate_location_map(const Input& input, NodeCPtr node);
- lexy::input_location_anchor<Input> generate_location_map(const Input& input, NodeCPtr node, lexy::input_location_anchor<Input> anchor);
- lexy::input_location_anchor<Input> generate_begin_location_for(const Input& input, NodeCPtr node, lexy::input_location_anchor<Input> anchor);
- lexy::input_location_anchor<Input> generate_end_location_for(const Input& input, NodeCPtr node, lexy::input_location_anchor<Input> anchor);
- };
-
- template<typename Input>
- constexpr const lexy::input_location<Input> make_begin_loc(const NodeLocation location, const Input& input, lexy::input_location_anchor<Input> anchor) {
- return lexy::get_input_location(input, location.begin(), anchor);
- }
-
- template<typename Input>
- constexpr const lexy::input_location<Input> make_begin_loc(const NodeLocation location, const Input& input) {
- return lexy::get_input_location(input, location.begin());
- }
-
- template<typename Input>
- constexpr const lexy::input_location<Input> make_end_loc(const NodeLocation location, const Input& input, lexy::input_location_anchor<Input> anchor) {
- return lexy::get_input_location(input, location.end(), anchor);
- }
-
- template<typename Input>
- constexpr const lexy::input_location<Input> make_end_loc(const NodeLocation location, const Input& input) {
- return lexy::get_input_location(input, location.end());
- }
-}
-
-namespace ovdl::v2script::ast {
- template<typename Input>
- lexy::input_location_anchor<Input> NodeLocationMap<Input>::generate_location_map(const Input& input, NodeCPtr node) {
- return generate_location_map(input, node, lexy::input_location_anchor(input));
- }
-
- template<typename Input>
- lexy::input_location_anchor<Input> NodeLocationMap<Input>::generate_location_map(const Input& input, NodeCPtr node, lexy::input_location_anchor<Input> anchor) {
- if (!node) return anchor;
- anchor = generate_begin_location_for(input, node, anchor);
- if (auto list_node = node->cast_to<ast::AbstractListNode>(); list_node) {
- for (auto& inner_node : list_node->_statements) {
- anchor = generate_location_map(input, inner_node.get(), anchor);
- }
- } else if (auto assign_node = node->cast_to<ast::AssignNode>(); assign_node) {
- anchor = generate_location_map(input, assign_node->_initializer.get(), anchor);
- }
- // TODO: implement for EventNode, DecisionNode, EventMtthModifierNode, ExecutionNode, ExecutionListNode
- if (!node->location().end() || node->location().begin() >= node->location().end())
- return anchor;
- return generate_end_location_for(input, node, anchor);
- }
-
- template<typename Input>
- lexy::input_location_anchor<Input> NodeLocationMap<Input>::generate_begin_location_for(const Input& input, NodeCPtr node, lexy::input_location_anchor<Input> anchor) {
- if (node->location().begin() == nullptr) return anchor;
- lexy::input_location<Input> next_loc = make_begin_loc(node->location(), input, anchor);
- this->emplace(node, next_loc);
- return next_loc.anchor();
- }
-
- template<typename Input>
- lexy::input_location_anchor<Input> NodeLocationMap<Input>::generate_end_location_for(const Input& input, NodeCPtr node, lexy::input_location_anchor<Input> anchor) {
- if (node->location().end() == nullptr) return anchor;
- lexy::input_location<Input> next_loc = make_end_loc(node->location(), input, anchor);
- this->emplace(node, next_loc);
- return next_loc.anchor();
- }
-} \ No newline at end of file
diff --git a/include/openvic-dataloader/v2script/Parser.hpp b/include/openvic-dataloader/v2script/Parser.hpp
index 885946d..cef1faf 100644
--- a/include/openvic-dataloader/v2script/Parser.hpp
+++ b/include/openvic-dataloader/v2script/Parser.hpp
@@ -3,21 +3,26 @@
#include <cstddef>
#include <filesystem>
#include <memory>
+#include <ostream>
+#include <string>
#include <string_view>
-#include <openvic-dataloader/ParseError.hpp>
-#include <openvic-dataloader/ParseWarning.hpp>
-#include <openvic-dataloader/detail/BasicParser.hpp>
-#include <openvic-dataloader/detail/Concepts.hpp>
+#include <openvic-dataloader/Error.hpp>
+#include <openvic-dataloader/NodeLocation.hpp>
+#include <openvic-dataloader/Parser.hpp>
+#include <openvic-dataloader/detail/utility/Concepts.hpp>
#include <openvic-dataloader/v2script/AbstractSyntaxTree.hpp>
-namespace ovdl::v2script {
+#include <dryad/node.hpp>
- using FileNode = ast::FileNode;
+namespace ovdl::v2script {
+ using FileTree = ast::FileTree;
+ using FilePosition = ovdl::FilePosition;
class Parser final : public detail::BasicParser {
public:
Parser();
+ Parser(std::basic_ostream<char>& error_stream);
static Parser from_buffer(const char* data, std::size_t size);
static Parser from_buffer(const char* start, const char* end);
@@ -31,19 +36,30 @@ namespace ovdl::v2script {
constexpr Parser& load_from_file(const char* path);
Parser& load_from_file(const std::filesystem::path& path);
- constexpr Parser& load_from_file(const detail::Has_c_str auto& path);
+ constexpr Parser& load_from_file(const detail::HasCstr auto& path) {
+ return load_from_file(path.c_str());
+ }
bool simple_parse();
bool event_parse();
bool decision_parse();
bool lua_defines_parse();
- const FileNode* get_file_node() const;
+ const FileTree* get_file_node() const;
+
+ std::string_view value(const ovdl::v2script::ast::FlatValue& node) const;
+
+ std::string make_native_string() const;
+ std::string make_list_string() const;
+
+ const FilePosition get_position(const ast::Node* node) const;
+
+ using error_range = ovdl::detail::error_range;
+ Parser::error_range get_errors() const;
- void generate_node_location_map();
+ const FilePosition get_error_position(const error::Error* error) const;
- const ast::Node::line_col get_node_begin(const ast::NodeCPtr node) const;
- const ast::Node::line_col get_node_end(const ast::NodeCPtr node) const;
+ void print_errors_to(std::basic_ostream<char>& stream) const;
Parser(Parser&&);
Parser& operator=(Parser&&);
@@ -51,12 +67,10 @@ namespace ovdl::v2script {
~Parser();
private:
- friend class ::ovdl::v2script::ast::Node;
- class BufferHandler;
- std::unique_ptr<BufferHandler> _buffer_handler;
- std::unique_ptr<FileNode> _file_node;
+ class ParseHandler;
+ std::unique_ptr<ParseHandler> _parse_handler;
template<typename... Args>
- constexpr void _run_load_func(detail::LoadCallback<BufferHandler, Args...> auto func, Args... args);
+ constexpr void _run_load_func(detail::LoadCallback<Parser::ParseHandler*, Args...> auto func, Args... args);
};
} \ No newline at end of file