diff options
author | Spartan322 <Megacake1234@gmail.com> | 2023-11-28 11:09:26 +0100 |
---|---|---|
committer | Spartan322 <Megacake1234@gmail.com> | 2024-05-09 22:11:26 +0200 |
commit | 757114a3c5b748567b42f273c7b78ca039ae983c (patch) | |
tree | e07390b682052129c91f4b157068bcdd84ceecb4 /include | |
parent | 7211a228e68c8a6b1ad1c1c5ec68c8d720b6d2ba (diff) |
Add `deps/dryad` -> https://github.com/Spartan322/dryadadd/dryad
Add `deps/fmt` -> https://github.com/fmtlib/fmt
Add `deps/range-v3` -> https://github.com/ericniebler/range-v3
Improve parser error and warning support
Update .clang-format
Update `deps/SCsub`
Diffstat (limited to 'include')
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 |