From b88cfd5eb23ed03d9741a6f2145f89044220bee3 Mon Sep 17 00:00:00 2001 From: Spartan322 Date: Wed, 29 Nov 2023 04:25:25 -0500 Subject: [PATCH] Move ast to dryad --- .github/workflows/builds.yml | 8 + .../openvic-dataloader/AbstractSyntaxTree.hpp | 31 +- include/openvic-dataloader/NodeLocation.hpp | 4 +- include/openvic-dataloader/ParseState.hpp | 14 +- .../{detail/BasicParser.hpp => Parser.hpp} | 4 +- include/openvic-dataloader/csv/Parser.hpp | 9 +- .../detail/OptionalConstexpr.hpp | 9 - .../detail/VectorConstexpr.hpp | 9 - .../detail/utility/Concepts.hpp | 8 +- .../detail/{ => utility}/PointerHash.hpp | 0 .../detail/{ => utility}/SelfType.hpp | 0 .../v2script/AbstractSyntaxTree.hpp | 401 +++++++----------- .../v2script/NodeLocationMap.hpp | 91 ---- .../openvic-dataloader/v2script/Parser.hpp | 23 +- src/headless/main.cpp | 90 ++-- src/openvic-dataloader/csv/CsvGrammar.hpp | 195 +++++---- src/openvic-dataloader/csv/CsvParseState.hpp | 28 ++ src/openvic-dataloader/csv/Parser.cpp | 62 ++- .../detail/BasicBufferHandler.hpp | 51 --- .../detail/ParseHandler.hpp | 2 +- .../detail/{BasicParser.cpp => Parser.cpp} | 2 +- .../detail/StringLiteral.hpp | 216 ++++++++-- src/openvic-dataloader/detail/dsl.hpp | 112 ++++- .../v2script/AbstractSyntaxTree.cpp | 391 ++++++----------- .../v2script/AiBehaviorGrammar.hpp | 20 +- .../v2script/DecisionGrammar.hpp | 123 ++---- .../v2script/EffectGrammar.hpp | 31 +- .../v2script/EventGrammar.hpp | 212 ++++----- .../v2script/LuaDefinesGrammar.hpp | 80 ++-- .../v2script/ModifierGrammar.hpp | 52 ++- src/openvic-dataloader/v2script/Parser.cpp | 148 +++---- .../v2script/SimpleGrammar.hpp | 243 ++++++----- .../v2script/TriggerGrammar.hpp | 31 +- 33 files changed, 1213 insertions(+), 1487 deletions(-) rename include/openvic-dataloader/{detail/BasicParser.hpp => Parser.hpp} (90%) delete mode 100644 include/openvic-dataloader/detail/OptionalConstexpr.hpp delete mode 100644 include/openvic-dataloader/detail/VectorConstexpr.hpp rename include/openvic-dataloader/detail/{ => utility}/PointerHash.hpp (100%) rename include/openvic-dataloader/detail/{ => utility}/SelfType.hpp (100%) delete mode 100644 include/openvic-dataloader/v2script/NodeLocationMap.hpp create mode 100644 src/openvic-dataloader/csv/CsvParseState.hpp delete mode 100644 src/openvic-dataloader/detail/BasicBufferHandler.hpp rename src/openvic-dataloader/detail/{BasicParser.cpp => Parser.cpp} (94%) diff --git a/.github/workflows/builds.yml b/.github/workflows/builds.yml index 0ca03ce..35f71b7 100644 --- a/.github/workflows/builds.yml +++ b/.github/workflows/builds.yml @@ -82,6 +82,14 @@ jobs: python -m pip install scons scons --version + - name: macOS dependencies + if: ${{ matrix.platform == 'macos' }} + run: | + clang++ --version + echo 'alias clang="$(brew --prefix llvm@15)/bin/clang"' >> /Users/runner/.bash_profile + echo 'alias clang++="$(brew --prefix llvm@15)/bin/clang++"' >> /Users/runner/.bash_profile + clang++ --version + - name: Linux dependencies if: ${{ matrix.platform == 'linux' }} run: | diff --git a/include/openvic-dataloader/AbstractSyntaxTree.hpp b/include/openvic-dataloader/AbstractSyntaxTree.hpp index dbb8bb4..e92cda3 100644 --- a/include/openvic-dataloader/AbstractSyntaxTree.hpp +++ b/include/openvic-dataloader/AbstractSyntaxTree.hpp @@ -36,18 +36,25 @@ namespace ovdl { }; template - concept IsAst = std::derived_from && requires(T t, const typename T::node_type* node, NodeLocation loc) { - requires IsFile; - typename T::root_node_type; - typename T::node_type; - requires std::derived_from; - { t.set_location(node, loc) } -> std::same_as; - { t.location_of(node) } -> std::same_as; - { t.root() } -> std::same_as; - { const_cast(t).root() } -> std::same_as; - { t.file() } -> std::same_as; - { const_cast(t).file() } -> std::same_as; - }; + concept IsAst = + std::derived_from && + requires( + T t, + const T ct, + const typename T::node_type* node, + NodeLocation loc // + ) { + requires IsFile; + typename T::root_node_type; + typename T::node_type; + requires std::derived_from; + { t.set_location(node, loc) } -> std::same_as; + { t.location_of(node) } -> std::same_as; + { t.root() } -> std::same_as; + { ct.root() } -> std::same_as; + { t.file() } -> std::same_as; + { ct.file() } -> std::same_as; + }; template RootNodeT> struct BasicAbstractSyntaxTree : AbstractSyntaxTree { diff --git a/include/openvic-dataloader/NodeLocation.hpp b/include/openvic-dataloader/NodeLocation.hpp index a253b1c..117560b 100644 --- a/include/openvic-dataloader/NodeLocation.hpp +++ b/include/openvic-dataloader/NodeLocation.hpp @@ -26,8 +26,8 @@ namespace ovdl { }; struct FilePosition { - std::uint32_t start_line = -1, end_line = -1, start_column = -1, end_column = -1; + 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 == -1 && end_line == -1 && start_column == -1 && end_column == -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 index 079674d..fd962a5 100644 --- a/include/openvic-dataloader/ParseState.hpp +++ b/include/openvic-dataloader/ParseState.hpp @@ -12,6 +12,7 @@ namespace ovdl { template concept IsParseState = requires( T t, + const T ct, typename T::ast_type::file_type&& file, std::ostream& error_stream, lexy::buffer&& buffer, @@ -23,9 +24,9 @@ namespace ovdl { { T { std::move(buffer), error_stream } } -> std::same_as; { T { path, std::move(buffer), error_stream } } -> std::same_as; { t.ast() } -> std::same_as; - { const_cast(t).ast() } -> std::same_as; + { ct.ast() } -> std::same_as; { t.logger() } -> std::same_as; - { const_cast(t).logger() } -> std::same_as; + { ct.logger() } -> std::same_as; }; template @@ -67,6 +68,7 @@ namespace ovdl { template concept IsFileParseState = requires( T t, + const T ct, typename T::file_type&& file, std::ostream& error_stream, lexy::buffer&& buffer, @@ -78,9 +80,9 @@ namespace ovdl { { T { std::move(buffer), error_stream } } -> std::same_as; { T { path, std::move(buffer), error_stream } } -> std::same_as; { t.file() } -> std::same_as; - { const_cast(t).file() } -> std::same_as; + { ct.file() } -> std::same_as; { t.logger() } -> std::same_as; - { const_cast(t).logger() } -> std::same_as; + { ct.logger() } -> std::same_as; }; template @@ -89,8 +91,8 @@ namespace ovdl { using diagnostic_logger_type = BasicDiagnosticLogger; FileParseState(file_type&& file, std::ostream& error_stream) - : _file { file }, - _logger { file(), error_stream } {} + : _file { std::move(file) }, + _logger { file, error_stream } {} FileParseState(lexy::buffer&& buffer, std::ostream& error_stream) : FileParseState(file_type { std::move(buffer) }, error_stream) {} diff --git a/include/openvic-dataloader/detail/BasicParser.hpp b/include/openvic-dataloader/Parser.hpp similarity index 90% rename from include/openvic-dataloader/detail/BasicParser.hpp rename to include/openvic-dataloader/Parser.hpp index b7efe36..2734b3f 100644 --- a/include/openvic-dataloader/detail/BasicParser.hpp +++ b/include/openvic-dataloader/Parser.hpp @@ -7,11 +7,9 @@ #include #include -#include namespace ovdl::detail { - class BasicParser { - public: + struct BasicParser { BasicParser(); void set_error_log_to_null(); diff --git a/include/openvic-dataloader/csv/Parser.hpp b/include/openvic-dataloader/csv/Parser.hpp index 182e2b6..e8885a9 100644 --- a/include/openvic-dataloader/csv/Parser.hpp +++ b/include/openvic-dataloader/csv/Parser.hpp @@ -2,11 +2,10 @@ #include +#include #include #include -#include "openvic-dataloader/detail/BasicParser.hpp" - namespace ovdl::csv { enum class EncodingType { Windows1252, @@ -44,12 +43,12 @@ namespace ovdl::csv { ~Parser(); private: - class BufferHandler; - std::unique_ptr _buffer_handler; + class ParseHandler; + std::unique_ptr _buffer_handler; std::vector _lines; template - constexpr void _run_load_func(detail::LoadCallback auto func, Args... args); + constexpr void _run_load_func(detail::LoadCallback auto func, Args... args); }; using Windows1252Parser = Parser; 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/VectorConstexpr.hpp b/include/openvic-dataloader/detail/VectorConstexpr.hpp deleted file mode 100644 index 7e7fa34..0000000 --- a/include/openvic-dataloader/detail/VectorConstexpr.hpp +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -// THANK YOU APPLE FOR YOUR UTTER DISREGARD FOR C++20 - -#if __cpp_lib_constexpr_vector >= 201907L -#define OVDL_VECTOR_CONSTEXPR constexpr -#else -#define OVDL_VECTOR_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 index 9a2608f..0ba91cc 100644 --- a/include/openvic-dataloader/detail/utility/Concepts.hpp +++ b/include/openvic-dataloader/detail/utility/Concepts.hpp @@ -3,9 +3,7 @@ #include #include #include -#include #include -#include "openvic-dataloader/ParseError.hpp" namespace ovdl { struct NodeLocation; @@ -26,14 +24,14 @@ namespace ovdl::detail { }; template - concept HasPath = requires(const T* t) { - { t->path() } -> std::convertible_to; + concept HasPath = requires(T& t) { + { t.path() } -> std::same_as; }; template concept LoadCallback = requires(T&& t, Self&& self, Args&&... args) { - { std::invoke(std::forward(t), std::forward(self), std::forward(args)...) } -> std::same_as>; + { std::invoke(std::forward(t), std::forward(self), std::forward(args)...) } -> std::same_as; }; template diff --git a/include/openvic-dataloader/detail/PointerHash.hpp b/include/openvic-dataloader/detail/utility/PointerHash.hpp similarity index 100% rename from include/openvic-dataloader/detail/PointerHash.hpp rename to include/openvic-dataloader/detail/utility/PointerHash.hpp diff --git a/include/openvic-dataloader/detail/SelfType.hpp b/include/openvic-dataloader/detail/utility/SelfType.hpp similarity index 100% rename from include/openvic-dataloader/detail/SelfType.hpp rename to include/openvic-dataloader/detail/utility/SelfType.hpp diff --git a/include/openvic-dataloader/v2script/AbstractSyntaxTree.hpp b/include/openvic-dataloader/v2script/AbstractSyntaxTree.hpp index 0e8e8ae..de3ef0d 100644 --- a/include/openvic-dataloader/v2script/AbstractSyntaxTree.hpp +++ b/include/openvic-dataloader/v2script/AbstractSyntaxTree.hpp @@ -1,310 +1,203 @@ #pragma once -#include +#include #include -#include -#include -#include +#include #include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include -namespace lexy { - struct nullopt; -} +#include +#include -namespace ovdl::v2script { - class Parser; -} +#include +#include +#include +#include +#include -#define OVDL_PRINT_FUNC_DEF std::ostream& print(std::ostream& stream, std::size_t indent) const override +namespace ovdl::v2script::ast { + enum class NodeKind { + FileTree, -// 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(); } \ - constexpr std::string_view get_type() const override { return ::ovdl::detail::type_name>(); } + // FlatValues // + IdentifierValue, // straight_identifier_value + StringValue, // "plain string value" -// 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>; + FirstFlatValue = IdentifierValue, + LastFlatValue = StringValue, -namespace ovdl::v2script::ast { + // Values // + ListValue, // { } + NullValue, - struct Node; - using NodePtr = Node*; - using NodeCPtr = const Node*; - using NodeUPtr = std::unique_ptr; + FirstValue = FirstFlatValue, + LastValue = NullValue, - struct NodeLocation { - const char* _begin = nullptr; - const char* _end = nullptr; + // Statements // + EventStatement, // (country_event|province_event) = { id = ... } + AssignStatement, // = + ValueStatement, // - NodeLocation() = default; - NodeLocation(const char* pos) : _begin(pos), - _end(pos) {} - NodeLocation(const char* begin, const char* end) : _begin(begin), - _end(end) {} + FirstStatement = EventStatement, + LastStatement = ValueStatement, + }; - NodeLocation(const NodeLocation&) = default; - NodeLocation& operator=(const NodeLocation&) = default; + 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(NodeLocation&&) = default; - NodeLocation& operator=(NodeLocation&&) = default; + using Node = dryad::node; + using NodeList = dryad::unlinked_node_list; - const char* begin() const { return _begin; } - const char* end() const { return _end; } + struct Value; - static inline NodeLocation make_from(const char* begin, const char* end) { - end++; - if (begin >= end) return NodeLocation(begin); - return NodeLocation(begin, end); - } - }; + struct FlatValue; + struct IdentifierValue; + struct StringValue; - 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 ListValue; - 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 Statement; + using StatementList = dryad::unlinked_node_list; - static constexpr std::string_view get_type_static() { return detail::type_name(); } - constexpr virtual std::string_view get_type() const = 0; + struct EventStatement; + using EventStatementList = dryad::unlinked_node_list; - static constexpr std::string_view get_base_type_static() { return detail::type_name(); } - constexpr virtual std::string_view get_base_type() const { return get_base_type_static(); } + struct AssignStatement; + using AssignStatementList = dryad::unlinked_node_list; - template - constexpr bool is_type() const { - return get_type().compare(detail::type_name()) == 0; - } + struct Value : dryad::abstract_node_range { + DRYAD_ABSTRACT_NODE_CTOR(Value); + }; - template - constexpr bool is_derived_from() const { - return is_type() || get_base_type().compare(detail::type_name()) == 0; + struct FlatValue : dryad::abstract_node_range { + const char* value() const { + return _value; } - template - constexpr T* cast_to() { - if (is_derived_from() || is_type()) return (static_cast(this)); - return nullptr; + operator const char*() const { + return _value; } - template - constexpr const T* const cast_to() const { - if (is_derived_from() || is_type()) return (static_cast(this)); - return nullptr; - } + protected: + explicit FlatValue(dryad::node_ctor ctor, NodeKind kind, const char* value) + : node_base(ctor, kind), + _value(value) {} - const NodeLocation location() const { return _location; } + protected: + const char* _value; + }; - struct line_col { - uint32_t line; - uint32_t column; - }; + struct IdentifierValue : dryad::basic_node { + explicit IdentifierValue(dryad::node_ctor ctor, const char* 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 StringValue : dryad::basic_node { + explicit StringValue(dryad::node_ctor ctor, const char* value) : node_base(ctor, value) {} + }; - private: - NodeLocation _location; + struct ListValue : dryad::basic_node> { + explicit ListValue(dryad::node_ctor ctor, StatementList statements) + : node_base(ctor) { + insert_child_list_after(nullptr, statements); + } + explicit ListValue(dryad::node_ctor ctor, AssignStatementList statements) + : node_base(ctor) { + insert_child_list_after(nullptr, statements); + } + explicit ListValue(dryad::node_ctor ctor) + : basic_node(ctor) { + } + + DRYAD_CHILD_NODE_RANGE_GETTER(Statement, statements, nullptr, this); }; - 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 { + explicit NullValue(dryad::node_ctor ctor) : node_base(ctor) {} + }; - template - NodePtr make_node_ptr(Args&&... args) { - if constexpr (std::is_pointer_v) { - return new T(std::forward(args)...); - } else { - return NodePtr(new T(std::forward(args)...)); + struct Statement : dryad::abstract_node_range, NodeKind::FirstStatement, NodeKind::LastStatement> { + explicit Statement(dryad::node_ctor ctor, NodeKind kind, Value* right) + : node_base(ctor, kind) { + insert_child_after(nullptr, right); } - } - template - To& cast_node_ptr(const From& from) { - if constexpr (std::is_pointer_v) { - return *static_cast(from); - } else { - return *static_cast(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 - const To& cast_node_cptr(const From& from) { - if constexpr (std::is_pointer_v) { - return *static_cast(from); - } else { - return *static_cast(from.get()); + struct EventStatement : dryad::basic_node { + 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& source, std::vector& 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(); } - constexpr std::string_view get_base_type() const override { return ::ovdl::detail::type_name>(); } - }; + 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 _statements; - AbstractListNode(const std::vector& statements = std::vector {}); - AbstractListNode(NodeLocation location, const std::vector& statements = std::vector {}); - 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(); } - constexpr std::string_view get_base_type() const override { return ::ovdl::detail::type_name>(); } + struct AssignStatement : dryad::basic_node { + 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& statements = std::vector {}); \ - NAME(lexy::nullopt); \ - NAME(NodeLocation location, const std::vector& statements = std::vector {}); \ - 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& statements = {}); - EventNode(NodeLocation location, Type type, const std::vector& statements = {}); + struct ValueStatement : dryad::basic_node { + 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& statements = {}); - DecisionNode(NodeLocation location, NodePtr name, const std::vector& statements = {}); - }; + struct FileTree : dryad::basic_node> { + explicit FileTree(dryad::node_ctor ctor, StatementList 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, AssignStatementList statements) : node_base(ctor) { + insert_child_list_after(nullptr, statements); + } - // 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; - }; + explicit FileTree(dryad::node_ctor ctor) : node_base(ctor) { + } - struct ExecutionListNode final : public AbstractListNode { - OVDL_AST_LIST_EXTEND(ExecutionListNode); - ExecutionNode::Type _type; - ExecutionListNode(ExecutionNode::Type type, const std::vector& statements); - ExecutionListNode(NodeLocation location, ExecutionNode::Type type, const std::vector& statements); + DRYAD_CHILD_NODE_RANGE_GETTER(Statement, statements, nullptr, this); }; -#undef OVDL_AST_LIST_EXTEND + using File = ovdl::BasicFile; + struct AbstractSyntaxTree : ovdl::BasicAbstractSyntaxTree { + using BasicAbstractSyntaxTree::BasicAbstractSyntaxTree; -} + std::string make_list_visualizer() const; + std::string make_native_visualizer() const; + }; + using ParseState = ovdl::ParseState; -#undef OVDL_PRINT_FUNC_DECL -#undef OVDL_PRINT_FUNC_DEF -#undef OVDL_TYPE_DEFINE_SELF \ No newline at end of file + static_assert(IsFile, "File failed IsFile concept"); + static_assert(IsAst, "AbstractSyntaxTree failed IsAst concept"); + static_assert(IsParseState, "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 - -#include -#include - -#include - -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 - struct NodeLocationMap : public std::unordered_multimap, detail::PointerHash> { - 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 generate_location_map(const Input& input, NodeCPtr node); - lexy::input_location_anchor generate_location_map(const Input& input, NodeCPtr node, lexy::input_location_anchor anchor); - lexy::input_location_anchor generate_begin_location_for(const Input& input, NodeCPtr node, lexy::input_location_anchor anchor); - lexy::input_location_anchor generate_end_location_for(const Input& input, NodeCPtr node, lexy::input_location_anchor anchor); - }; - - template - constexpr const lexy::input_location make_begin_loc(const NodeLocation location, const Input& input, lexy::input_location_anchor anchor) { - return lexy::get_input_location(input, location.begin(), anchor); - } - - template - constexpr const lexy::input_location make_begin_loc(const NodeLocation location, const Input& input) { - return lexy::get_input_location(input, location.begin()); - } - - template - constexpr const lexy::input_location make_end_loc(const NodeLocation location, const Input& input, lexy::input_location_anchor anchor) { - return lexy::get_input_location(input, location.end(), anchor); - } - - template - constexpr const lexy::input_location make_end_loc(const NodeLocation location, const Input& input) { - return lexy::get_input_location(input, location.end()); - } -} - -namespace ovdl::v2script::ast { - template - lexy::input_location_anchor NodeLocationMap::generate_location_map(const Input& input, NodeCPtr node) { - return generate_location_map(input, node, lexy::input_location_anchor(input)); - } - - template - lexy::input_location_anchor NodeLocationMap::generate_location_map(const Input& input, NodeCPtr node, lexy::input_location_anchor anchor) { - if (!node) return anchor; - anchor = generate_begin_location_for(input, node, anchor); - if (auto list_node = node->cast_to(); 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(); 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 - lexy::input_location_anchor NodeLocationMap::generate_begin_location_for(const Input& input, NodeCPtr node, lexy::input_location_anchor anchor) { - if (node->location().begin() == nullptr) return anchor; - lexy::input_location next_loc = make_begin_loc(node->location(), input, anchor); - this->emplace(node, next_loc); - return next_loc.anchor(); - } - - template - lexy::input_location_anchor NodeLocationMap::generate_end_location_for(const Input& input, NodeCPtr node, lexy::input_location_anchor anchor) { - if (node->location().end() == nullptr) return anchor; - lexy::input_location 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 fbea184..b45d950 100644 --- a/include/openvic-dataloader/v2script/Parser.hpp +++ b/include/openvic-dataloader/v2script/Parser.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -11,13 +12,15 @@ #include #include -#include +#include #include #include namespace ovdl::v2script { - using FileNode = ast::FileNode; + // using FileNode = ast::FileNode; + using FileTree = ast::FileTree; + using FilePosition = ovdl::FilePosition; class Parser final : public detail::BasicParser { public: @@ -44,12 +47,12 @@ namespace ovdl::v2script { bool decision_parse(); bool lua_defines_parse(); - const FileNode* get_file_node() const; + const FileTree* get_file_node() const; - void generate_node_location_map(); + std::string make_native_string() const; + std::string make_list_string() 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; + const FilePosition get_position(const ast::Node* node) const; Parser(Parser&&); Parser& operator=(Parser&&); @@ -57,12 +60,10 @@ namespace ovdl::v2script { ~Parser(); private: - friend class ::ovdl::v2script::ast::Node; - class BufferHandler; - std::unique_ptr _buffer_handler; - std::unique_ptr _file_node; + class ParseHandler; + std::unique_ptr _parse_handler; template - constexpr void _run_load_func(detail::LoadCallback auto func, Args... args); + constexpr void _run_load_func(detail::LoadCallback auto func, Args... args); }; } \ No newline at end of file diff --git a/src/headless/main.cpp b/src/headless/main.cpp index 1f0b4c3..8c07b11 100644 --- a/src/headless/main.cpp +++ b/src/headless/main.cpp @@ -14,6 +14,11 @@ #include #include +enum class VisualizationType { + Native, // = { } + List // - : +}; + std::string_view trim(std::string_view str) { std::string_view::iterator begin = str.begin(); std::string_view::iterator end = str.end(); @@ -64,7 +69,7 @@ int print_csv(const std::string_view path) { return EXIT_SUCCESS; } -int print_lua(const std::string_view path) { +int print_lua(const std::string_view path, VisualizationType visual_type) { auto parser = ovdl::v2script::Parser::from_file(path); if (parser.has_error()) { return 1; @@ -81,26 +86,15 @@ int print_lua(const std::string_view path) { } } - parser.generate_node_location_map(); - - for (const auto& node : parser.get_file_node()->_statements) { - std::cout << node->get_type() << ": " << parser.get_node_begin(node.get()) << std::endl; - if (auto assign_node = node->cast_to(); assign_node) { - auto lnode_ptr = assign_node->_initializer.get(); - std::cout << lnode_ptr->get_type() << " begin: " << parser.get_node_begin(lnode_ptr) << std::endl; - std::cout << lnode_ptr->get_type() << " end: " << parser.get_node_end(lnode_ptr) << std::endl; - if (auto list_node = lnode_ptr->cast_to(); list_node) { - for (const auto& inode : list_node->_statements) { - std::cout << inode->get_type() << ": " << parser.get_node_begin(inode.get()) << std::endl; - } - } - } + switch (visual_type) { + using enum VisualizationType; + case Native: std::cout << parser.make_native_string() << '\n'; break; + case List: std::cout << parser.make_list_string() << '\n'; break; } - std::cout << parser.get_file_node() << std::endl; return EXIT_SUCCESS; } -int print_v2script_simple(const std::string_view path) { +int print_v2script_simple(const std::string_view path, VisualizationType visual_type) { auto parser = ovdl::v2script::Parser::from_file(path); if (parser.has_error()) { return 1; @@ -117,45 +111,55 @@ int print_v2script_simple(const std::string_view path) { } } - parser.generate_node_location_map(); - - for (const auto& node : parser.get_file_node()->_statements) { - std::cout << node->get_type() << ": " << parser.get_node_begin(node.get()) << std::endl; - if (auto assign_node = node->cast_to(); assign_node) { - auto lnode_ptr = assign_node->_initializer.get(); - std::cout << lnode_ptr->get_type() << " begin: " << parser.get_node_begin(lnode_ptr) << std::endl; - std::cout << lnode_ptr->get_type() << " end: " << parser.get_node_end(lnode_ptr) << std::endl; - if (auto list_node = lnode_ptr->cast_to(); list_node) { - for (const auto& inode : list_node->_statements) { - std::cout << inode->get_type() << ": " << parser.get_node_begin(inode.get()) << std::endl; - } - } - } + switch (visual_type) { + using enum VisualizationType; + case Native: std::cout << parser.make_native_string() << '\n'; break; + case List: std::cout << parser.make_list_string() << '\n'; break; } - std::cout << parser.get_file_node() << std::endl; return EXIT_SUCCESS; } int main(int argc, char** argv) { - switch (argc) { + std::vector args; + for (size_t index = 0; index < argc; index++) { + args.push_back(argv[index]); + } + + VisualizationType type = VisualizationType::Native; + if (args.size() >= 2) { + std::string_view type_str = args[1]; + if (insenitive_trim_eq(type_str, "list")) { + type = VisualizationType::List; + args.erase(args.begin() + 1); + } else if (insenitive_trim_eq(type_str, "native")) { + type = VisualizationType::Native; + args.erase(args.begin() + 1); + } + } + + switch (args.size()) { case 2: - if (insenitive_trim_eq(std::filesystem::path(argv[1]).extension().string(), ".lua")) { - return print_lua(argv[1]); + if (insenitive_trim_eq(std::filesystem::path(args[1]).extension().string(), ".lua")) { + return print_lua(args[1], type); } - return print_v2script_simple(argv[1]); + return print_v2script_simple(args[1], type); case 4: - if (insenitive_trim_eq(argv[1], "csv") && insenitive_trim_eq(argv[2], "utf")) - return print_csv(argv[3]); + if (insenitive_trim_eq(args[1], "csv") && insenitive_trim_eq(args[2], "utf")) + return print_csv(args[3]); goto default_jump; case 3: - if (insenitive_trim_eq(argv[1], "csv")) - return print_csv(argv[2]); + if (insenitive_trim_eq(args[1], "csv")) + return print_csv(args[2]); + if (insenitive_trim_eq(args[1], "lua")) + return print_lua(args[2], type); [[fallthrough]]; default: default_jump: - std::fprintf(stderr, "usage: %s \n", argv[0]); - std::fprintf(stderr, "usage: %s csv \n", argv[0]); - std::fprintf(stderr, "usage: %s csv utf ", argv[0]); + std::fprintf(stderr, "usage: %s \n", args[0].c_str()); + std::fprintf(stderr, "usage: %s list \n", args[0].c_str()); + std::fprintf(stderr, "usage: %s native \n", args[0].c_str()); + std::fprintf(stderr, "usage: %s lua \n", args[0].c_str()); + std::fprintf(stderr, "usage: %s csv [utf] \n", args[0].c_str()); return EXIT_FAILURE; } diff --git a/src/openvic-dataloader/csv/CsvGrammar.hpp b/src/openvic-dataloader/csv/CsvGrammar.hpp index cd4f852..d6cd1ae 100644 --- a/src/openvic-dataloader/csv/CsvGrammar.hpp +++ b/src/openvic-dataloader/csv/CsvGrammar.hpp @@ -11,10 +11,13 @@ #include #include +#include "csv/CsvParseState.hpp" #include "detail/dsl.hpp" // Grammar Definitions // namespace ovdl::csv::grammar { + using EncodingType = ovdl::csv::EncodingType; + template concept ParseChars = requires() { { T::character }; @@ -51,123 +54,119 @@ namespace ovdl::csv::grammar { .map<'"'>('"'); template - struct StringValue { - static constexpr auto rule = [] { - // Arbitrary code points - auto c = Options.character - Options.control; - - auto back_escape = lexy::dsl::backslash_escape // - .symbol(); + struct CsvGrammar { + struct StringValue { + static constexpr auto rule = [] { + // Arbitrary code points + auto c = Options.character - Options.control; - auto quote_escape = lexy::dsl::escape(lexy::dsl::lit_c<'"'>) // - .template symbol(); + auto back_escape = lexy::dsl::backslash_escape // + .symbol(); - return lexy::dsl::delimited(lexy::dsl::lit_c<'"'>, lexy::dsl::not_followed_by(lexy::dsl::lit_c<'"'>, lexy::dsl::lit_c<'"'>))(c, back_escape, quote_escape); - }(); - - static constexpr auto value = lexy::as_string; - }; + auto quote_escape = lexy::dsl::escape(lexy::dsl::lit_c<'"'>) // + .template symbol(); - template - struct PlainValue { - static constexpr auto rule = [] { - if constexpr (Options.SupportStrings) { - return lexy::dsl::identifier(Options.character - (lexy::dsl::lit_b / lexy::dsl::ascii::newline)); - } else { - auto escape_check_char = Options.character - (lexy::dsl::lit_b / lexy::dsl::ascii::newline); - auto id_check_char = escape_check_char - lexy::dsl::lit_b<'\\'>; - auto id_segment = lexy::dsl::identifier(id_check_char); - auto escape_segement = lexy::dsl::token(escape_check_char); - auto escape_sym = lexy::dsl::symbol(escape_segement); - auto escape_rule = lexy::dsl::lit_b<'\\'> >> escape_sym; - return lexy::dsl::list(id_segment | escape_rule); - } - }(); - static constexpr auto value = lexy::as_string; - }; + return lexy::dsl::delimited(lexy::dsl::lit_c<'"'>, lexy::dsl::not_followed_by(lexy::dsl::lit_c<'"'>, lexy::dsl::lit_c<'"'>))(c, back_escape, quote_escape); + }(); - template - struct Value { - static constexpr auto rule = [] { - if constexpr (Options.SupportStrings) { - return lexy::dsl::p> | lexy::dsl::p>; - } else { - return lexy::dsl::p>; - } - }(); - static constexpr auto value = lexy::forward; - }; - - template - struct SepConst { - static constexpr auto rule = lexy::dsl::lit_b; - static constexpr auto value = lexy::constant(1); - }; + static constexpr auto value = lexy::as_string; + }; - template - struct Seperator { - static constexpr auto rule = lexy::dsl::list(lexy::dsl::p>); - static constexpr auto value = lexy::count; - }; + struct PlainValue { + static constexpr auto rule = [] { + if constexpr (Options.SupportStrings) { + return lexy::dsl::identifier(Options.character - (lexy::dsl::lit_b / lexy::dsl::ascii::newline)); + } else { + auto escape_check_char = Options.character - (lexy::dsl::lit_b / lexy::dsl::ascii::newline); + auto id_check_char = escape_check_char - lexy::dsl::lit_b<'\\'>; + auto id_segment = lexy::dsl::identifier(id_check_char); + auto escape_segement = lexy::dsl::token(escape_check_char); + auto escape_sym = lexy::dsl::symbol(escape_segement); + auto escape_rule = lexy::dsl::lit_b<'\\'> >> escape_sym; + return lexy::dsl::list(id_segment | escape_rule); + } + }(); + static constexpr auto value = lexy::as_string; + }; - template - struct LineEnd { - static constexpr auto rule = lexy::dsl::list(lexy::dsl::p>, lexy::dsl::trailing_sep(lexy::dsl::p>)); - static constexpr auto value = lexy::fold_inplace( - std::initializer_list {}, - [](ovdl::csv::LineObject& result, auto&& arg) { - if constexpr (std::is_same_v, std::size_t>) { - // Count seperators, adds to previous value, making it a position - using position_type = ovdl::csv::LineObject::position_type; - result.emplace_back(static_cast(arg + result.back().first), ""); + struct Value { + static constexpr auto rule = [] { + if constexpr (Options.SupportStrings) { + return lexy::dsl::p | lexy::dsl::p; } else { - if (result.empty()) result.emplace_back(0u, LEXY_MOV(arg)); - else { - auto& [pos, value] = result.back(); - value = arg; - } + return lexy::dsl::p; } - }); - }; + }(); + static constexpr auto value = lexy::forward; + }; - template - struct Line { - static constexpr auto suffix_setter(ovdl::csv::LineObject& line) { - auto& [position, value] = line.back(); - if (value.empty()) { - line.set_suffix_end(position); - line.pop_back(); - } else { - line.set_suffix_end(position + 1); - } + struct SepConst { + static constexpr auto rule = lexy::dsl::lit_b; + static constexpr auto value = lexy::constant(1); }; - static constexpr auto rule = lexy::dsl::p> | lexy::dsl::p> >> lexy::dsl::opt(lexy::dsl::p>); - static constexpr auto value = - lexy::callback( - [](ovdl::csv::LineObject&& line) { - suffix_setter(line); - return LEXY_MOV(line); - }, - [](std::size_t prefix_count, ovdl::csv::LineObject&& line) { - line.set_prefix_end(prefix_count); - // position needs to be adjusted to prefix - for (auto& [position, value] : line) { - position += prefix_count; + struct Seperator { + static constexpr auto rule = lexy::dsl::list(lexy::dsl::p); + static constexpr auto value = lexy::count; + }; + + struct LineEnd { + static constexpr auto rule = lexy::dsl::list(lexy::dsl::p, lexy::dsl::trailing_sep(lexy::dsl::p)); + static constexpr auto value = lexy::fold_inplace( + std::initializer_list {}, + [](ovdl::csv::LineObject& result, auto&& arg) { + if constexpr (std::is_same_v, std::size_t>) { + // Count seperators, adds to previous value, making it a position + using position_type = ovdl::csv::LineObject::position_type; + result.emplace_back(static_cast(arg + result.back().first), ""); + } else { + if (result.empty()) result.emplace_back(0u, LEXY_MOV(arg)); + else { + auto& [pos, value] = result.back(); + value = arg; + } } - suffix_setter(line); - return LEXY_MOV(line); - }, - [](std::size_t suffix_count, lexy::nullopt = {}) { - return ovdl::csv::LineObject(0, {}, suffix_count + 1); }); + }; + + struct Line { + static constexpr auto suffix_setter(ovdl::csv::LineObject& line) { + auto& [position, value] = line.back(); + if (value.empty()) { + line.set_suffix_end(position); + line.pop_back(); + } else { + line.set_suffix_end(position + 1); + } + }; + + static constexpr auto rule = lexy::dsl::p | lexy::dsl::p >> lexy::dsl::opt(lexy::dsl::p); + static constexpr auto value = + lexy::callback( + [](ovdl::csv::LineObject&& line) { + suffix_setter(line); + return LEXY_MOV(line); + }, + [](std::size_t prefix_count, ovdl::csv::LineObject&& line) { + line.set_prefix_end(prefix_count); + // position needs to be adjusted to prefix + for (auto& [position, value] : line) { + position += prefix_count; + } + suffix_setter(line); + return LEXY_MOV(line); + }, + [](std::size_t suffix_count, lexy::nullopt = {}) { + return ovdl::csv::LineObject(0, {}, suffix_count + 1); + }); + }; }; template struct File { static constexpr auto rule = lexy::dsl::whitespace(lexy::dsl::newline) + - lexy::dsl::opt(lexy::dsl::list(lexy::dsl::p>, lexy::dsl::trailing_sep(lexy::dsl::eol))); + lexy::dsl::opt(lexy::dsl::list(lexy::dsl::p::Line>, lexy::dsl::trailing_sep(lexy::dsl::eol))); static constexpr auto value = lexy::as_list>; }; diff --git a/src/openvic-dataloader/csv/CsvParseState.hpp b/src/openvic-dataloader/csv/CsvParseState.hpp new file mode 100644 index 0000000..2390453 --- /dev/null +++ b/src/openvic-dataloader/csv/CsvParseState.hpp @@ -0,0 +1,28 @@ +#pragma once + +#include +#include +#include +#include + +#include + +template +struct LexyEncodingFrom { +}; + +template<> +struct LexyEncodingFrom { + using encoding = lexy::default_encoding; +}; + +template<> +struct LexyEncodingFrom { + using encoding = lexy::utf8_char_encoding; +}; + +template +using CsvFile = ovdl::BasicFile::encoding, std::vector>; + +template +using CsvParseState = ovdl::FileParseState>; \ No newline at end of file diff --git a/src/openvic-dataloader/csv/Parser.cpp b/src/openvic-dataloader/csv/Parser.cpp index 6cd2e9d..fc78805 100644 --- a/src/openvic-dataloader/csv/Parser.cpp +++ b/src/openvic-dataloader/csv/Parser.cpp @@ -1,45 +1,35 @@ #include #include +#include #include #include #include #include +#include #include #include #include #include +#include "openvic-dataloader/ParseState.hpp" + #include "csv/CsvGrammar.hpp" -#include "detail/BasicBufferHandler.hpp" +#include "csv/CsvParseState.hpp" #include "detail/Errors.hpp" +#include "detail/ParseHandler.hpp" using namespace ovdl; using namespace ovdl::csv; -/// BufferHandler /// - -template -struct LexyEncodingFrom { -}; - -template<> -struct LexyEncodingFrom { - using encoding = lexy::default_encoding; -}; - -template<> -struct LexyEncodingFrom { - using encoding = lexy::utf8_char_encoding; -}; +/// ParseHandler /// template -class Parser::BufferHandler final : public detail::BasicBufferHandler::encoding> { -public: - template - std::optional> parse(const ErrorCallback& callback) { - auto result = lexy::parse(this->_buffer, callback); +struct Parser::ParseHandler final : detail::BasicFileParseHandler> { + template + std::optional> parse() { + auto result = lexy::parse(this->buffer(), *this->_parse_state, this->_parse_state->logger().error_callback()); if (!result) { return result.errors(); } @@ -59,7 +49,7 @@ class Parser::BufferHandler final : public detail::BasicBufferHandler< template Parser::Parser() - : _buffer_handler(std::make_unique()) { + : _buffer_handler(std::make_unique()) { set_error_log_to_stderr(); } @@ -115,28 +105,30 @@ Parser Parser::from_file(const std::filesystem::path& path) /// template template -constexpr void Parser::_run_load_func(detail::LoadCallback auto func, Args... args) { +constexpr void Parser::_run_load_func(detail::LoadCallback auto func, Args... args) { _warnings.clear(); _errors.clear(); _has_fatal_error = false; - if (auto error = func(_buffer_handler.get(), std::forward(args)...); error) { - _has_fatal_error = error.value().type == ParseError::Type::Fatal; - _errors.push_back(error.value()); - _error_stream.get() << "Error: " << _errors.back().message << '\n'; + auto error = func(_buffer_handler.get(), std::forward(args)...); + auto error_message = _buffer_handler->make_error_from(error); + if (!error_message.empty()) { + _has_fatal_error = true; + // _errors.push_back(error.value()); + _error_stream.get() << "Error: " << error_message << '\n'; } } template constexpr Parser& Parser::load_from_buffer(const char* data, std::size_t size) { // Type can't be deduced? - _run_load_func(std::mem_fn(&BufferHandler::load_buffer_size), data, size); + _run_load_func(std::mem_fn(&ParseHandler::load_buffer_size), _error_stream, data, size); return *this; } template constexpr Parser& Parser::load_from_buffer(const char* start, const char* end) { // Type can't be deduced? - _run_load_func(std::mem_fn(&BufferHandler::load_buffer), start, end); + _run_load_func(std::mem_fn(&ParseHandler::load_buffer), _error_stream, start, end); return *this; } @@ -149,7 +141,7 @@ template constexpr Parser& Parser::load_from_file(const char* path) { _file_path = path; // Type can be deduced?? - _run_load_func(std::mem_fn(&BufferHandler::load_file), path); + _run_load_func(std::mem_fn(&ParseHandler::load_file), _error_stream, path); return *this; } @@ -165,17 +157,17 @@ bool Parser::parse_csv(bool handle_strings) { } std::optional> errors; - auto report_error = ovdl::detail::ReporError.path(_file_path).to(detail::OStreamOutputIterator { _error_stream }); + // auto report_error = ovdl::detail::ReporError.path(_file_path).to(detail::OStreamOutputIterator { _error_stream }); if constexpr (Encoding == EncodingType::Windows1252) { if (handle_strings) - errors = _buffer_handler->template parse(report_error); + errors = _buffer_handler->template parse(); else - errors = _buffer_handler->template parse(report_error); + errors = _buffer_handler->template parse(); } else { if (handle_strings) - errors = _buffer_handler->template parse(report_error); + errors = _buffer_handler->template parse(); else - errors = _buffer_handler->template parse(report_error); + errors = _buffer_handler->template parse(); } if (errors) { _errors.reserve(errors->size()); diff --git a/src/openvic-dataloader/detail/BasicBufferHandler.hpp b/src/openvic-dataloader/detail/BasicBufferHandler.hpp deleted file mode 100644 index f26544b..0000000 --- a/src/openvic-dataloader/detail/BasicBufferHandler.hpp +++ /dev/null @@ -1,51 +0,0 @@ -#pragma once - -#include - -#include -#include - -#include -#include -#include - -#include "detail/Errors.hpp" - -namespace ovdl::detail { - template - class BasicBufferHandler { - public: - using encoding_type = Encoding; - - OVDL_OPTIONAL_CONSTEXPR bool is_valid() const { - return _buffer.data() != nullptr; - } - - OVDL_OPTIONAL_CONSTEXPR std::optional load_buffer_size(const char* data, std::size_t size) { - _buffer = lexy::buffer(data, size); - return std::nullopt; - } - - OVDL_OPTIONAL_CONSTEXPR std::optional load_buffer(const char* start, const char* end) { - _buffer = lexy::buffer(start, end); - return std::nullopt; - } - - std::optional load_file(const char* path) { - auto file = lexy::read_file(path); - if (!file) { - return ovdl::errors::make_no_file_error(path); - } - - _buffer = file.buffer(); - return std::nullopt; - } - - const auto& get_buffer() const { - return _buffer; - } - - protected: - lexy::buffer _buffer; - }; -} \ No newline at end of file diff --git a/src/openvic-dataloader/detail/ParseHandler.hpp b/src/openvic-dataloader/detail/ParseHandler.hpp index 2464b3c..17b8f5d 100644 --- a/src/openvic-dataloader/detail/ParseHandler.hpp +++ b/src/openvic-dataloader/detail/ParseHandler.hpp @@ -70,7 +70,7 @@ namespace ovdl::detail { return ovdl::detail::from_underlying(ovdl::detail::to_underlying(file.error())); } - _parse_state.reset(new parse_state_type { path, std::move(file).buffer() }); + _parse_state.reset(new parse_state_type { path, std::move(file).buffer(), error_stream }); return is_valid() ? buffer_error::success : buffer_error::buffer_is_null; } diff --git a/src/openvic-dataloader/detail/BasicParser.cpp b/src/openvic-dataloader/detail/Parser.cpp similarity index 94% rename from src/openvic-dataloader/detail/BasicParser.cpp rename to src/openvic-dataloader/detail/Parser.cpp index ee1b516..3f3b878 100644 --- a/src/openvic-dataloader/detail/BasicParser.cpp +++ b/src/openvic-dataloader/detail/Parser.cpp @@ -1,7 +1,7 @@ #include #include -#include +#include #include "detail/NullBuff.hpp" diff --git a/src/openvic-dataloader/detail/StringLiteral.hpp b/src/openvic-dataloader/detail/StringLiteral.hpp index ae172a1..f979301 100644 --- a/src/openvic-dataloader/detail/StringLiteral.hpp +++ b/src/openvic-dataloader/detail/StringLiteral.hpp @@ -1,8 +1,13 @@ #pragma once #include +#include +#include #include +#include +#include #include +#include #include #include @@ -15,70 +20,209 @@ namespace ovdl::detail { struct _string_literal { protected: - static LEXY_CONSTEVAL auto _to_string(const auto& input) { return string_literal(input); } - static LEXY_CONSTEVAL auto _concat(const auto&... input) { return string_literal(_to_string(input)...); } + static constexpr auto _to_string(const auto& input) { return string_literal(input); } + static constexpr auto _concat(const auto&... input) { return string_literal(_to_string(input)...); } }; - template + template struct string_literal : _string_literal { - CharT data[N]; + using value_type = CharT; + using pointer = value_type*; + using const_pointer = const value_type*; + using reference = value_type&; + using const_reference = const value_type&; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + using traits_type = std::char_traits; + + static constexpr size_type npos = size_type(-1); + + static constexpr auto size = std::integral_constant {}; + static constexpr auto length = size; + + value_type _data[N]; + + constexpr string_literal() noexcept = default; + + constexpr string_literal(const value_type (&literal)[N]) noexcept { + std::ranges::copy(literal, _data); + } + + constexpr string_literal(value_type c) noexcept : _data {} { + _data[0] = c; + } + + constexpr auto begin() noexcept { return std::begin(_data); } + constexpr auto end() noexcept { return std::end(_data); } + constexpr auto cbegin() const noexcept { return std::cbegin(_data); } + constexpr auto cend() const noexcept { return std::cend(_data); } + constexpr auto rbegin() noexcept { return std::rbegin(_data); } + constexpr auto rend() noexcept { return std::rend(_data); } + constexpr auto crbegin() const noexcept { return std::crbegin(_data); } + constexpr auto crend() const noexcept { return std::crend(_data); } + + constexpr auto front() const noexcept { return as_string_view().front(); } + constexpr auto back() const noexcept { return as_string_view().back(); } + constexpr auto at(size_type pos) const { return as_string_view().at(pos); } + + constexpr auto operator[](size_type pos) const noexcept { return as_string_view()[pos]; } + + constexpr bool empty() const { return as_string_view().empty(); } + + template + constexpr bool operator==(const string_literal& other) const { + return as_string_view() == other.as_string_view(); + } + + constexpr bool starts_with(std::basic_string_view sv) const noexcept { return as_string_view().starts_with(sv); } + constexpr bool starts_with(value_type ch) const noexcept { return as_string_view().starts_with(ch); } + constexpr bool starts_with(const value_type* s) const { return as_string_view().starts_with(s); } + + template + constexpr bool starts_with(const string_literal& other) const { + return starts_with(other.as_string_view()); + } + + constexpr bool ends_with(std::basic_string_view sv) const noexcept { return as_string_view().ends_with(sv); } + constexpr bool ends_with(value_type ch) const noexcept { return as_string_view().ends_with(ch); } + constexpr bool ends_with(const value_type* s) const { return as_string_view().ends_with(s); } + + template + constexpr bool ends_with(const string_literal& other) const { + return ends_with(other.as_string_view()); + } + + constexpr auto clear() const noexcept { + return string_literal<0, value_type> {}; + } + + constexpr auto push_back(value_type c) const noexcept { + return *this + string_literal { c }; + } + + constexpr auto pop_back() const noexcept { + string_literal result {}; + for (auto i = 0u; i != N - 2; i++) + result._data[i] = _data[i]; + return result; + } + + template + constexpr auto append(value_type ch) const noexcept { + string_literal result {}; + for (auto i = 0u; i != N; i++) + result._data[i] = _data[i]; + + for (auto i = N; i != N + count; i++) + result._data[i] = ch; + + return result; + } + + template + constexpr auto append(string_literal str) const noexcept { + return *this + str; + } + + template + constexpr auto append(const value_type (&literal)[N2]) const noexcept { + return *this + literal; + } + + template + constexpr auto substr() const noexcept { + static_assert(pos <= N, "pos must be less than or equal to N"); + constexpr size_type result_size = std::min(count - pos, N - pos); + + string_literal result {}; + for (size_type i = 0u, i2 = pos; i != result_size; i++, i2++) + result._data[i] = _data[i2]; + return result; + } + + constexpr auto substr() const noexcept { + return substr<>(); + } - using char_type = CharT; + constexpr std::string_view substr(size_type pos, size_type count = npos) const noexcept { + return as_string_view().substr(pos, count); + } - LEXY_CONSTEVAL string_literal(const CharT* str) : data {} { - for (auto i = 0u; i != N; ++i) - data[i] = str[i]; + constexpr size_type find(std::string_view str, size_type pos = 0) const noexcept { + return as_string_view().find(str, pos); } - LEXY_CONSTEVAL string_literal(CharT c) : data {} { - data[0] = c; + + template + constexpr size_type find(const value_type (&literal)[N2], size_type pos = 0) const noexcept { + return as_string_view().find(literal, pos, N2 - 2); } - LEXY_CONSTEVAL string_literal(const auto&... input) - requires(sizeof...(input) > 1) - { - _copy(_to_string(input)...); + constexpr size_type rfind(std::string_view str, size_type pos = 0) const noexcept { + return as_string_view().rfind(str, pos); } - template - LEXY_CONSTEVAL void _copy(const string_literal(&... input)) { - auto pos = data; - ((pos = std::copy_n(input.data, Ni - 1, pos)), ...); - *pos = 0; + template + constexpr size_type rfind(const value_type (&literal)[N2], size_type pos = 0) const noexcept { + return as_string_view().find(literal, pos, N2 - 2); } - template typename container, typename... T> - LEXY_CONSTEVAL string_literal(const container& input) { - std::apply([this](const auto&... s) constexpr { _copy(_to_string(s)...); }, input); + constexpr int compare(std::string_view str) const noexcept { + return as_string_view().compare(str); } - LEXY_CONSTEVAL auto operator+(const auto& rhs) const { - return _concat(*this, rhs); + template + constexpr int compare(const value_type (&literal)[N2]) const noexcept { + return as_string_view().compare(0, N, literal, N2 - 2); } - friend LEXY_CONSTEVAL auto operator+(const auto& lhs, string_literal rhs) { - return _concat(lhs, rhs); + constexpr operator std::basic_string_view() const& { return as_string_view(); } + constexpr operator std::basic_string_view() const&& = delete; + + constexpr std::basic_string_view as_string_view() const& { return std::basic_string_view(_data, size() - 1); } + constexpr std::basic_string_view as_string_view() const&& = delete; + + constexpr operator const value_type*() const& { return c_str(); } + constexpr operator const value_type*() const&& = delete; + + constexpr const value_type* c_str() const& { return _data; } + constexpr const value_type* c_str() const&& = delete; + + constexpr const value_type* data() const& { return _data; } + constexpr const value_type* data() const&& = delete; + + template + constexpr auto operator+(const string_literal& other) const noexcept { + string_literal result {}; + for (size_type i = 0u; i != N; i++) + result._data[i] = _data[i]; + + for (size_type i = N - 1, i2 = 0; i2 != N2; i++, i2++) + result._data[i] = other._data[i2]; + return result; } - LEXY_CONSTEVAL operator const char*() const { return data; } + template + constexpr auto operator+(const value_type (&rhs)[N2]) const noexcept { + return *this + _to_string(rhs); + } - static LEXY_CONSTEVAL auto size() { - return N; + template + friend constexpr auto operator+(const value_type (&lhs)[N2], string_literal rhs) noexcept { + return _to_string(lhs) + rhs; } }; - template + template string_literal(const CharT (&)[N]) -> string_literal; - template - string_literal(CharT) -> string_literal<1, CharT>; - string_literal(const auto&... input) - -> string_literal<((sizeof(input.data) - 1) + ... + 1), char>; + template + string_literal(CharT) -> string_literal<1, CharT>; template typename T, string_literal Str, std::size_t... Idx> auto _to_type_string(lexy::_detail::index_sequence) { - return T {}; + return T {}; } template typename T, string_literal Str> - using to_type_string = decltype(_to_type_string(lexy::_detail::make_index_sequence {})); + using to_type_string = decltype(ovdl::detail::_to_type_string(lexy::_detail::make_index_sequence {})); } namespace ovdl::dsl { diff --git a/src/openvic-dataloader/detail/dsl.hpp b/src/openvic-dataloader/detail/dsl.hpp index bd78b95..49ec79c 100644 --- a/src/openvic-dataloader/detail/dsl.hpp +++ b/src/openvic-dataloader/detail/dsl.hpp @@ -1,10 +1,15 @@ #pragma once +#include #include #include #include +#include #include +#include + +#include "detail/StringLiteral.hpp" namespace ovdl::dsl { template @@ -13,10 +18,20 @@ namespace ovdl::dsl { } template - constexpr auto sink(Sink&& sink) { + constexpr auto sink(Sink sink) { return lexy::bind_sink(sink, lexy::parse_state); } + template + constexpr auto collect(Callback callback) { + return sink(lexy::collect(callback)); + } + + template + constexpr auto collect(Callback callback) { + return sink(lexy::collect(callback)); + } + template constexpr auto construct = callback( [](StateType& state, ovdl::NodeLocation loc, auto&& arg) { @@ -25,8 +40,29 @@ namespace ovdl::dsl { else return state.ast().template create(loc, DRYAD_FWD(arg)); }, - [](StateType& state, ovdl::NodeLocation loc, auto&& arg, auto&&... args) { - return state.ast().template create(loc, DRYAD_FWD(arg), DRYAD_FWD(args)...); + [](StateType& state, ovdl::NodeLocation loc, auto&&... args) { + return state.ast().template create(loc, DRYAD_FWD(args)...); + }); + + template + constexpr auto construct_list = callback( + [](StateType& state, const char* begin, ListType&& arg, const char* end) { + return state.ast().template create(NodeLocation::make_from(begin, end), DRYAD_FWD(arg)); + }, + [](StateType& state, const char* begin, lexy::nullopt, const char* end) { + return state.ast().template create(NodeLocation::make_from(begin, end)); + }, + [](StateType& state, const char* begin, const char* end) { + return state.ast().template create(NodeLocation::make_from(begin, end)); + }); + + template + constexpr auto construct_list = callback( + [](StateType& state, const char* begin, ListType&& arg, const char* end) { + return state.ast().template create(NodeLocation::make_from(begin, end), DRYAD_FWD(arg)); + }, + [](StateType& state, const char* begin, lexy::nullopt, const char* end) { + return state.ast().template create(NodeLocation::make_from(begin, end)); }); template @@ -39,4 +75,74 @@ namespace ovdl::dsl { return ::lexy::dsl::lit_c / make_range(); } } + + template + constexpr auto position_brackets = lexy::dsl::brackets(lexy::dsl::position(lexy::dsl::lit_c), lexy::dsl::position(lexy::dsl::lit_c)); + + constexpr auto round_bracketed = position_brackets<'(', ')'>; + constexpr auto square_bracketed = position_brackets<'[', ']'>; + constexpr auto curly_bracketed = position_brackets<'{', '}'>; + constexpr auto angle_bracketed = position_brackets<'<', '>'>; + + template + constexpr auto p = lexy::dsl::position(lexy::dsl::p); + + template + static constexpr auto default_kw_value = dsl::callback( + [](ParseType& state, NodeLocation loc) { + return state.ast().template create(loc, state.ast().intern_cstr(Keyword.data(), Keyword.size())); + }); + + template< + IsParseState ParseType, + typename Identifier, + typename RuleValue, + ovdl::detail::string_literal Keyword, + auto Production, + auto Value> + struct keyword_rule { + struct rule_t { + static constexpr auto keyword = ovdl::dsl::keyword(lexy::dsl::inline_); + static constexpr auto rule = lexy::dsl::position(keyword) >> lexy::dsl::equal_sign; + static constexpr auto value = Value; + }; + static constexpr auto rule = dsl::p >> Production; + static constexpr auto value = construct; + }; + + template< + IsParseState ParseType, + typename Identifier, + typename RuleValue, + ovdl::detail::string_literal Keyword, + auto Production, + auto Value> + struct fkeyword_rule : keyword_rule { + using base_type = keyword_rule; + struct context_t; + struct rule_t : base_type::rule_t { + static constexpr auto flag = lexy::dsl::context_flag; + struct too_many_error { + static constexpr auto name = "expected event " + Keyword + " to only be found once"; + }; + static constexpr auto must = lexy::dsl::must(rule_t::flag.is_reset()) + . +// See https://stackoverflow.com/questions/77144003/use-of-template-keyword-before-dependent-template-name +// THANKS FOR NOTHING MICROSOFT, CAN'T EVEN GET THE STANDARD RIGHT +#if !(defined(_MSC_VERSION) && !defined(__clang__)) + template +#endif + error; + }; + static constexpr auto make_flag = rule_t::flag.create(); + + static constexpr auto rule = dsl::p >> (rule_t::must >> rule_t::flag.set()) >> Production; + static constexpr auto value = construct; + }; + + template + struct rule_helper { + static constexpr auto flags = (Args::make_flag + ...); + static constexpr auto p = (lexy::dsl::p | ...); + }; } \ No newline at end of file diff --git a/src/openvic-dataloader/v2script/AbstractSyntaxTree.cpp b/src/openvic-dataloader/v2script/AbstractSyntaxTree.cpp index 45150cb..869ad4e 100644 --- a/src/openvic-dataloader/v2script/AbstractSyntaxTree.cpp +++ b/src/openvic-dataloader/v2script/AbstractSyntaxTree.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -12,281 +13,125 @@ #include #include +#include +#include + using namespace ovdl::v2script::ast; -static void _handle_string_characters(std::string& string, bool allow_newline) { - size_t position = 0; - for (auto& c : string) { - switch (c) { - case '\r': - case '\n': - if (allow_newline) goto END_LOOP; - c = ' '; - break; - default: break; +// static void _handle_string_characters(std::string& string, bool allow_newline) { +// size_t position = 0; +// for (auto& c : string) { +// switch (c) { +// case '\r': +// case '\n': +// if (allow_newline) goto END_LOOP; +// c = ' '; +// break; +// default: break; +// } +// END_LOOP: +// position++; +// } +// } + +std::string AbstractSyntaxTree::make_list_visualizer() const { + const int INDENT_SIZE = 2; + + std::string result; + unsigned int level = 0; + + for (auto [event, node] : dryad::traverse(_tree)) { + if (event == dryad::traverse_event::exit) { + --level; + continue; } - END_LOOP: - position++; - } -} - -void ovdl::v2script::ast::copy_into_node_ptr_vector(const std::vector& source, std::vector& dest) { - dest.clear(); - dest.reserve(source.size()); - for (auto&& p : source) { - dest.push_back(NodeUPtr { p }); - } -} - -AbstractStringNode::AbstractStringNode() : Node({}) {} -AbstractStringNode::AbstractStringNode(NodeLocation location, std::string&& name, bool allow_newline) : Node(location), - _name(std::move(name)) { - _handle_string_characters(_name, allow_newline); -} -AbstractStringNode::AbstractStringNode(NodeLocation location) : Node(location) {} -AbstractStringNode::AbstractStringNode(std::string&& name, bool allow_newline) : AbstractStringNode({}, std::move(name), allow_newline) {} - -std::ostream& AbstractStringNode::print(std::ostream& stream, size_t indent) const { - return stream << _name; -} - -#define OVDL_AST_STRING_NODE_DEF(NAME, ...) \ - NAME::NAME() : AbstractStringNode() {} \ - NAME::NAME(std::string&& name, bool allow_newline) : AbstractStringNode(std::move(name), allow_newline) {} \ - NAME::NAME(lexy::nullopt) : AbstractStringNode() {} \ - NAME::NAME(NodeLocation location) : AbstractStringNode(location) {} \ - NAME::NAME(NodeLocation location, std::string&& name, bool allow_newline) : AbstractStringNode(location, std::move(name), allow_newline) {} \ - NAME::NAME(NodeLocation location, lexy::nullopt) : AbstractStringNode(location, {}, true) {} \ - std::ostream& NAME::print(std::ostream& stream, size_t indent) const __VA_ARGS__ - -OVDL_AST_STRING_NODE_DEF(IdentifierNode, { - return stream << _name; -}); - -OVDL_AST_STRING_NODE_DEF(StringNode, { - return stream << '"' << _name << '"'; -}); - -OVDL_AST_STRING_NODE_DEF(FactorNode, { - return stream << "factor = " << _name; -}); - -OVDL_AST_STRING_NODE_DEF(MonthNode, { - return stream << "months = " << _name; -}); - -OVDL_AST_STRING_NODE_DEF(NameNode, { - return stream << "name = " << _name; -}); - -OVDL_AST_STRING_NODE_DEF(FireOnlyNode, { - return stream << "fire_only_once = " << _name; -}); - -OVDL_AST_STRING_NODE_DEF(IdNode, { - return stream << "id = " << _name; -}); - -OVDL_AST_STRING_NODE_DEF(TitleNode, { - return stream << "title = " << _name; -}); - -OVDL_AST_STRING_NODE_DEF(DescNode, { - return stream << "desc = " << _name; -}); - -OVDL_AST_STRING_NODE_DEF(PictureNode, { - return stream << "picture = " << _name; -}); - -OVDL_AST_STRING_NODE_DEF(IsTriggeredNode, { - return stream << "is_triggered_only = " << _name; -}); - -#undef OVDL_AST_STRING_NODE_DEF - -AssignNode::AssignNode(NodeLocation location, NodeCPtr name, NodePtr init) - : Node(location), - _initializer(std::move(init)) { - if (name->is_type()) { - _name = cast_node_cptr(name)._name; - } -} - -std::ostream& Node::print_ptr(std::ostream& stream, NodeCPtr node, size_t indent) { - return node != nullptr ? node->print(stream, indent) : stream << ""; -} - -static std::ostream& print_newline_indent(std::ostream& stream, size_t indent) { - return stream << "\n" - << std::setw(indent) << std::setfill('\t') << ""; -} - -/* Starts with a newline and ends at the end of a line, and so - * should be followed by a call to print_newline_indent. - */ -static std::ostream& print_nodeuptr_vector(const std::vector& nodes, - std::ostream& stream, size_t indent) { - for (NodeUPtr const& node : nodes) { - print_newline_indent(stream, indent); - Node::print_ptr(stream, node.get(), indent); - } - return stream; -} - -AbstractListNode::AbstractListNode(NodeLocation location, const std::vector& statements) : Node(location) { - copy_into_node_ptr_vector(statements, _statements); -} -AbstractListNode::AbstractListNode(const std::vector& statements) : AbstractListNode({}, statements) {} -std::ostream& AbstractListNode::print(std::ostream& stream, size_t indent) const { - stream << '{'; - if (!_statements.empty()) { - print_nodeuptr_vector(_statements, stream, indent + 1); - print_newline_indent(stream, indent); - } - return stream << "}"; -} - -#define OVDL_AST_LIST_NODE_DEF(NAME, ...) \ - NAME::NAME(const std::vector& statements) : AbstractListNode(statements) {} \ - NAME::NAME(lexy::nullopt) : AbstractListNode() {} \ - NAME::NAME(NodeLocation location, const std::vector& statements) : AbstractListNode(location, statements) {} \ - NAME::NAME(NodeLocation location, lexy::nullopt) : AbstractListNode(location, {}) {} \ - std::ostream& NAME::print(std::ostream& stream, size_t indent) const __VA_ARGS__ - -OVDL_AST_LIST_NODE_DEF(FileNode, { - print_nodeuptr_vector(_statements, stream, indent); - return print_newline_indent(stream, indent); -}); - -OVDL_AST_LIST_NODE_DEF(ListNode, { - stream << '{'; - if (!_statements.empty()) { - print_nodeuptr_vector(_statements, stream, indent + 1); - print_newline_indent(stream, indent); - } - return stream << "}"; -}); - -OVDL_AST_LIST_NODE_DEF(ModifierNode, { - stream << "modifier = {"; - if (!_statements.empty()) { - print_nodeuptr_vector(_statements, stream, indent + 1); - print_newline_indent(stream, indent); - } - return stream << '}'; -}); - -OVDL_AST_LIST_NODE_DEF(MtthNode, { - stream << "mean_time_to_happen = {"; - if (!_statements.empty()) { - print_nodeuptr_vector(_statements, stream, indent + 1); - print_newline_indent(stream, indent); - } - return stream << '}'; -}); - -OVDL_AST_LIST_NODE_DEF(EventOptionNode, { - stream << "option = {"; - if (!_statements.empty()) { - print_nodeuptr_vector(_statements, stream, indent + 1); - print_newline_indent(stream, indent); - } - return stream << '}'; -}); - -OVDL_AST_LIST_NODE_DEF(BehaviorListNode, { - stream << "ai_chance = {"; // may be ai_chance or ai_will_do - if (!_statements.empty()) { - print_nodeuptr_vector(_statements, stream, indent + 1); - print_newline_indent(stream, indent); - } - return stream << '}'; -}); - -OVDL_AST_LIST_NODE_DEF(DecisionListNode, { - stream << "political_decisions = {"; - if (!_statements.empty()) { - print_nodeuptr_vector(_statements, stream, indent + 1); - print_newline_indent(stream, indent); - } - return stream << '}'; -}); - -#undef OVDL_AST_LIST_NODE_DEF - -EventNode::EventNode(NodeLocation location, Type type, const std::vector& statements) : AbstractListNode(location), - _type(type) { - copy_into_node_ptr_vector(statements, _statements); -} -EventNode::EventNode(Type type, const std::vector& statements) : EventNode({}, type, statements) {} -std::ostream& EventNode::print(std::ostream& stream, size_t indent) const { - switch (_type) { - case Type::Country: stream << "country_event = "; break; - case Type::Province: stream << "province_event = "; break; - } - stream << '{'; - if (!_statements.empty()) { - print_nodeuptr_vector(_statements, stream, indent + 1); - print_newline_indent(stream, indent); - } - return stream << '}'; -} - -DecisionNode::DecisionNode(NodeLocation location, NodePtr name, const std::vector& statements) : AbstractListNode(location), - _name(std::move(name)) { - copy_into_node_ptr_vector(statements, _statements); -} -DecisionNode::DecisionNode(NodePtr name, const std::vector& statements) : DecisionNode({}, name, statements) {} -std::ostream& DecisionNode::print(std::ostream& stream, size_t indent) const { - print_ptr(stream, _name.get(), indent) << " = {"; - if (!_statements.empty()) { - print_nodeuptr_vector(_statements, stream, indent + 1); - print_newline_indent(stream, indent); - } - return stream << '}'; -} - -ExecutionNode::ExecutionNode(NodeLocation location, Type type, NodePtr name, NodePtr init) : Node(location), - _type(type), - _name(std::move(name)), - _initializer(std::move(init)) { -} -ExecutionNode::ExecutionNode(Type type, NodePtr name, NodePtr init) : ExecutionNode({}, type, name, init) {} -std::ostream& ExecutionNode::print(std::ostream& stream, size_t indent) const { - print_ptr(stream, _name.get(), indent) << " = "; - if (_initializer) { - Node::print_ptr(stream, _initializer.get(), indent + 1); - } - return stream; -} - -ExecutionListNode::ExecutionListNode(NodeLocation location, ExecutionNode::Type type, const std::vector& statements) : AbstractListNode(location), - _type(type) { - copy_into_node_ptr_vector(statements, _statements); -} -ExecutionListNode::ExecutionListNode(ExecutionNode::Type type, const std::vector& statements) : ExecutionListNode({}, type, statements) {} -std::ostream& ExecutionListNode::print(std::ostream& stream, size_t indent) const { - // Only way to make a valid declared parsable file - stream << "{ "; - switch (_type) { - case ExecutionNode::Type::Effect: stream << "effect = {"; break; - case ExecutionNode::Type::Trigger: stream << "trigger = {"; break; - } - if (!_statements.empty()) { - print_nodeuptr_vector(_statements, stream, indent + 1); - print_newline_indent(stream, indent); - } - return stream << "}}"; -} - -Node::operator std::string() const { - std::stringstream ss; - ss << *this; - return ss.str(); -} -std::ostream& AssignNode::print(std::ostream& stream, size_t indent) const { - stream << _name << " = "; - return Node::print_ptr(stream, _initializer.get(), indent); + result.append(INDENT_SIZE * level, ' '); + result.append(fmt::format("- {}: ", get_kind_name(node->kind()))); + + dryad::visit_node( + node, + [&](const FlatValue* value) { + result.append(value->value()); + }, + [&](const ListValue* value) { + }, + [&](const NullValue* value) { + }, + [&](const EventStatement* statement) { + result.append(statement->is_province_event() ? "province_event" : "country_event"); + }, + [&](const AssignStatement* statement) { + }, + [&](const FileTree* tree) { + }); + + result.append(1, '\n'); + + if (event == dryad::traverse_event::enter) + ++level; + } + + return result; +} + +std::string AbstractSyntaxTree::make_native_visualizer() const { + constexpr int INDENT_SIZE = 2; + + std::string result; + unsigned int level = 0; + + dryad::visit_tree( + _tree, + [&](const IdentifierValue* value) { + result.append(value->value()); + }, + [&](const StringValue* value) { + result.append(1, '"').append(value->value()).append(1, '"'); + }, + [&](dryad::child_visitor visitor, const ValueStatement* statement) { + visitor(statement->value()); + }, + [&](dryad::child_visitor visitor, const AssignStatement* statement) { + visitor(statement->left()); + if (statement->right()->kind() != NodeKind::NullValue) { + result.append(" = "); + visitor(statement->right()); + } + }, + [&](dryad::child_visitor visitor, const ListValue* value) { + result.append(1, '{'); + level++; + for (const auto& statement : value->statements()) { + result + .append(1, '\n') + .append(INDENT_SIZE * level, ' '); + visitor(statement); + } + level--; + result + .append(1, '\n') + .append(INDENT_SIZE * level, ' ') + .append(1, '}'); + }, + [&](dryad::child_visitor visitor, const EventStatement* statement) { + result.append(statement->is_province_event() ? "province_event" : "country_event"); + if (statement->right()->kind() != NodeKind::NullValue) { + result.append(" = "); + visitor(statement->right()); + } + }, + [&](dryad::child_visitor visitor, const FileTree* value) { + auto statements = value->statements(); + visitor(*statements.begin()); + + for (const auto& statement : statements | std::views::drop(1)) { + result + .append(1, '\n') + .append(INDENT_SIZE * level, ' '); + visitor(statement); + } + }); + + return result; } \ No newline at end of file diff --git a/src/openvic-dataloader/v2script/AiBehaviorGrammar.hpp b/src/openvic-dataloader/v2script/AiBehaviorGrammar.hpp index 012820f..f3d6ad2 100644 --- a/src/openvic-dataloader/v2script/AiBehaviorGrammar.hpp +++ b/src/openvic-dataloader/v2script/AiBehaviorGrammar.hpp @@ -2,33 +2,23 @@ #include +#include #include #include "ModifierGrammar.hpp" #include "SimpleGrammar.hpp" -#include "TriggerGrammar.hpp" +#include "detail/dsl.hpp" namespace ovdl::v2script::grammar { struct AiBehaviorList { static constexpr auto rule = lexy::dsl::list(lexy::dsl::p | lexy::dsl::p); - static constexpr auto value = - lexy::as_list> >> - lexy::callback( - [](auto&& list) { - return ast::make_node_ptr(LEXY_MOV(list)); - }); + static constexpr auto value = lexy::as_list; }; struct AiBehaviorBlock { - static constexpr auto rule = lexy::dsl::curly_bracketed.opt(lexy::dsl::p); + static constexpr auto rule = dsl::curly_bracketed.opt(lexy::dsl::p); - static constexpr auto value = lexy::callback( - [](auto&& list) { - return LEXY_MOV(list); - }, - [](lexy::nullopt = {}) { - return lexy::nullopt {}; - }); + static constexpr auto value = construct_list; }; } \ No newline at end of file diff --git a/src/openvic-dataloader/v2script/DecisionGrammar.hpp b/src/openvic-dataloader/v2script/DecisionGrammar.hpp index a1c1e3e..7c59ff2 100644 --- a/src/openvic-dataloader/v2script/DecisionGrammar.hpp +++ b/src/openvic-dataloader/v2script/DecisionGrammar.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -8,105 +9,52 @@ #include #include +#include #include #include +#include #include +#include +#include + +#include "openvic-dataloader/NodeLocation.hpp" #include "AiBehaviorGrammar.hpp" #include "EffectGrammar.hpp" #include "SimpleGrammar.hpp" #include "TriggerGrammar.hpp" +#include "detail/StringLiteral.hpp" +#include "detail/dsl.hpp" // Decision Grammar Definitions // namespace ovdl::v2script::grammar { - ////////////////// - // Macros - ////////////////// -// Produces _rule and _p -#define OVDL_GRAMMAR_KEYWORD_DEFINE(KW_NAME) \ - struct KW_NAME##_rule { \ - static constexpr auto keyword = LEXY_KEYWORD(#KW_NAME, lexy::dsl::inline_>); \ - static constexpr auto rule = keyword >> lexy::dsl::equal_sign; \ - static constexpr auto value = lexy::noop; \ - }; \ - static constexpr auto KW_NAME##_p = lexy::dsl::p - -// Produces _rule and _p and _rule::flag and _rule::too_many_error -#define OVDL_GRAMMAR_KEYWORD_FLAG_DEFINE(KW_NAME) \ - struct KW_NAME##_rule { \ - static constexpr auto keyword = LEXY_KEYWORD(#KW_NAME, lexy::dsl::inline_>); \ - static constexpr auto rule = keyword >> lexy::dsl::equal_sign; \ - static constexpr auto value = lexy::noop; \ - static constexpr auto flag = lexy::dsl::context_flag; \ - struct too_many_error { \ - static constexpr auto name = "expected left side " #KW_NAME " to be found once"; \ - }; \ - }; \ - static constexpr auto KW_NAME##_p = lexy::dsl::p >> (lexy::dsl::must(KW_NAME##_rule::flag.is_reset()).error + KW_NAME##_rule::flag.set()) - ////////////////// - // Macros - ////////////////// struct DecisionStatement { - template - struct _StringStatement { - static constexpr auto rule = Production >> (lexy::dsl::p> | lexy::dsl::p>); - static constexpr auto value = lexy::forward; + using potential = fkeyword_rule<"potential", lexy::dsl::p>; + using allow = fkeyword_rule<"allow", lexy::dsl::p>; + using effect = fkeyword_rule<"effect", lexy::dsl::p>; + using ai_will_do = fkeyword_rule<"ai_will_do", lexy::dsl::p>; + + using helper = dsl::rule_helper; + + struct List { + static constexpr auto rule = dsl::curly_bracketed.opt_list(helper::p | lexy::dsl::p>); + + static constexpr auto value = lexy::as_list >> construct_list; }; - template - static constexpr auto StringStatement = lexy::dsl::p<_StringStatement>; - - OVDL_GRAMMAR_KEYWORD_FLAG_DEFINE(potential); - OVDL_GRAMMAR_KEYWORD_FLAG_DEFINE(allow); - OVDL_GRAMMAR_KEYWORD_FLAG_DEFINE(effect); - OVDL_GRAMMAR_KEYWORD_FLAG_DEFINE(ai_will_do); - - static constexpr auto rule = [] { - constexpr auto create_flags = - potential_rule::flag.create() + - allow_rule::flag.create() + - effect_rule::flag.create() + - ai_will_do_rule::flag.create(); - - constexpr auto potential_statement = potential_p >> lexy::dsl::p; - constexpr auto allow_statement = allow_p >> lexy::dsl::p; - constexpr auto effect_statement = effect_p >> lexy::dsl::p; - constexpr auto ai_will_do_statement = ai_will_do_p >> lexy::dsl::p; - - return lexy::dsl::p> >> - (create_flags + lexy::dsl::equal_sign + - lexy::dsl::curly_bracketed.list( - potential_statement | - allow_statement | - effect_statement | - ai_will_do_statement | - lexy::dsl::p>)); - }(); - - static constexpr auto value = - lexy::as_list> >> - lexy::callback( - [](auto&& name, auto&& list) { - return ast::make_node_ptr(LEXY_MOV(name), LEXY_MOV(list)); - }, - [](auto&& name, lexy::nullopt = {}) { - return ast::make_node_ptr(LEXY_MOV(name)); - }); + + static constexpr auto rule = + dsl::p> >> + (helper::flags + lexy::dsl::equal_sign + lexy::dsl::p); + + static constexpr auto value = construct; }; struct DecisionList { static constexpr auto rule = - LEXY_KEYWORD("political_decisions", lexy::dsl::inline_>) >> - (lexy::dsl::equal_sign + lexy::dsl::curly_bracketed.opt_list(lexy::dsl::p)); - - static constexpr auto value = - lexy::as_list> >> - lexy::callback( - [](auto&& list) { - return ast::make_node_ptr(LEXY_MOV(list)); - }, - [](lexy::nullopt = {}) { - return lexy::nullopt {}; - }); + ovdl::dsl::keyword<"political_decisions">(lexy::dsl::inline_>) >> + (lexy::dsl::equal_sign >> lexy::dsl::curly_bracketed.opt_list(lexy::dsl::p)); + + static constexpr auto value = lexy::as_list; }; struct DecisionFile { @@ -114,15 +62,8 @@ namespace ovdl::v2script::grammar { static constexpr auto whitespace = whitespace_specifier | comment_specifier; static constexpr auto rule = - lexy::dsl::terminator(lexy::dsl::eof).list( // - lexy::dsl::p | // - lexy::dsl::p>); + lexy::dsl::position + lexy::dsl::terminator(lexy::dsl::eof).opt_list(lexy::dsl::p); - static constexpr auto value = lexy::as_list> >> lexy::new_; + static constexpr auto value = lexy::concat >> construct; }; - -#undef OVDL_GRAMMAR_KEYWORD_DEFINE -#undef OVDL_GRAMMAR_KEYWORD_FLAG_DEFINE -#undef OVDL_GRAMMAR_KEYWORD_STATEMENT -#undef OVDL_GRAMMAR_KEYWORD_FLAG_STATEMENT } \ No newline at end of file diff --git a/src/openvic-dataloader/v2script/EffectGrammar.hpp b/src/openvic-dataloader/v2script/EffectGrammar.hpp index 1b85382..10f8348 100644 --- a/src/openvic-dataloader/v2script/EffectGrammar.hpp +++ b/src/openvic-dataloader/v2script/EffectGrammar.hpp @@ -6,37 +6,24 @@ #include #include "SimpleGrammar.hpp" +#include "detail/dsl.hpp" namespace ovdl::v2script::grammar { struct EffectStatement { - static constexpr auto rule = lexy::dsl::inline_>; + static constexpr auto rule = lexy::dsl::p>; - static constexpr auto value = lexy::callback( - [](auto name, auto&& initalizer) { - return ast::make_node_ptr(ast::ExecutionNode::Type::Effect, LEXY_MOV(name), LEXY_MOV(initalizer)); - }); + static constexpr auto value = lexy::forward; }; struct EffectList { - static constexpr auto rule = lexy::dsl::list(lexy::dsl::p>); - - static constexpr auto value = - lexy::as_list> >> - lexy::callback( - [](auto&& list) { - return ast::make_node_ptr(ast::ExecutionNode::Type::Effect, LEXY_MOV(list)); - }); + static constexpr auto rule = lexy::dsl::list(lexy::dsl::p); + + static constexpr auto value = lexy::as_list; }; struct EffectBlock { - static constexpr auto rule = lexy::dsl::curly_bracketed.opt(lexy::dsl::p); - - static constexpr auto value = lexy::callback( - [](auto&& list) { - return LEXY_MOV(list); - }, - [](lexy::nullopt = {}) { - return lexy::nullopt {}; - }); + static constexpr auto rule = dsl::curly_bracketed.opt(lexy::dsl::p); + + static constexpr auto value = construct_list; }; } \ No newline at end of file diff --git a/src/openvic-dataloader/v2script/EventGrammar.hpp b/src/openvic-dataloader/v2script/EventGrammar.hpp index e6e4c02..935ddd8 100644 --- a/src/openvic-dataloader/v2script/EventGrammar.hpp +++ b/src/openvic-dataloader/v2script/EventGrammar.hpp @@ -1,169 +1,120 @@ #pragma once +#include +#include +#include +#include +#include +#include +#include #include #include +#include #include #include #include #include +#include + +#include "openvic-dataloader/NodeLocation.hpp" #include "AiBehaviorGrammar.hpp" #include "EffectGrammar.hpp" #include "ModifierGrammar.hpp" #include "SimpleGrammar.hpp" #include "TriggerGrammar.hpp" +#include "detail/StringLiteral.hpp" +#include "detail/dsl.hpp" // Event Grammar Definitions // namespace ovdl::v2script::grammar { - ////////////////// - // Macros - ////////////////// -// Produces _rule and _p -#define OVDL_GRAMMAR_KEYWORD_DEFINE(KW_NAME) \ - struct KW_NAME##_rule { \ - static constexpr auto keyword = LEXY_KEYWORD(#KW_NAME, lexy::dsl::inline_>); \ - static constexpr auto rule = keyword >> lexy::dsl::equal_sign; \ - static constexpr auto value = lexy::noop; \ - }; \ - static constexpr auto KW_NAME##_p = lexy::dsl::p - -// Produces _rule and _p and _rule::flag and _rule::too_many_error -#define OVDL_GRAMMAR_KEYWORD_FLAG_DEFINE(KW_NAME) \ - struct KW_NAME##_rule { \ - static constexpr auto keyword = LEXY_KEYWORD(#KW_NAME, lexy::dsl::inline_>); \ - static constexpr auto rule = keyword >> lexy::dsl::equal_sign; \ - static constexpr auto value = lexy::noop; \ - static constexpr auto flag = lexy::dsl::context_flag; \ - struct too_many_error { \ - static constexpr auto name = "expected left side " #KW_NAME " to be found once"; \ - }; \ - }; \ - static constexpr auto KW_NAME##_p = lexy::dsl::p >> (lexy::dsl::must(KW_NAME##_rule::flag.is_reset()).error + KW_NAME##_rule::flag.set()) - ////////////////// - // Macros - ////////////////// - static constexpr auto event_symbols = lexy::symbol_table // - .map(ast::EventNode::Type::Country) - .map(ast::EventNode::Type::Province); + static constexpr auto event_symbols = lexy::symbol_table // + .map(false) + .map(true); struct EventMtthStatement { - OVDL_GRAMMAR_KEYWORD_DEFINE(months); - struct MonthValue { - static constexpr auto rule = lexy::dsl::inline_>; - static constexpr auto value = lexy::as_string | lexy::new_; + static constexpr auto rule = lexy::dsl::p>; + static constexpr auto value = dsl::callback( + [](ast::ParseState& state, ast::IdentifierValue* value) { + bool is_number = true; + for (auto* current = value->value(); *current; current++) { + is_number = is_number && std::isdigit(*current); + if (!is_number) break; + } + if (!is_number) { + state.logger().warning("month is not an integer") // + .primary(state.ast().location_of(value), "here") + .finish(); + } + return value; + }); }; - static constexpr auto rule = lexy::dsl::list( - (months_p >> lexy::dsl::p) | - lexy::dsl::p); + using months = keyword_rule<"months", lexy::dsl::p>; - static constexpr auto value = - lexy::as_list> >> - lexy::callback( - [](auto&& list) { - return ast::make_node_ptr(LEXY_MOV(list)); - }); - }; + static constexpr auto rule = dsl::curly_bracketed(lexy::dsl::p | lexy::dsl::p); - template - struct _StringStatement { - static constexpr auto rule = Production >> (lexy::dsl::p> | lexy::dsl::p>); - static constexpr auto value = - lexy::callback( - [](auto&& value) { - auto result = ast::make_node_ptr(std::move(static_cast(value)->_name)); - delete value; - return result; - }); + static constexpr auto value = lexy::as_list >> construct_list; }; - template - static constexpr auto StringStatement = lexy::dsl::p<_StringStatement>; + + static constexpr auto str_or_id = lexy::dsl::p::ValueExpression>; struct EventOptionList { - OVDL_GRAMMAR_KEYWORD_FLAG_DEFINE(name); - OVDL_GRAMMAR_KEYWORD_FLAG_DEFINE(ai_chance); + using name = fkeyword_rule<"name", str_or_id>; + using ai_chance = fkeyword_rule<"ai_chance", lexy::dsl::p>; static constexpr auto rule = [] { - constexpr auto create_flags = name_rule::flag.create() + ai_chance_rule::flag.create(); - - constexpr auto name_statement = StringStatement; - constexpr auto ai_chance_statement = ai_chance_p >> lexy::dsl::curly_bracketed(lexy::dsl::p); + using helper = dsl::rule_helper; - return create_flags + lexy::dsl::list(name_statement | ai_chance_statement | lexy::dsl::p); + return dsl::curly_bracketed(helper::flags + lexy::dsl::list(helper::p | lexy::dsl::p)); }(); - static constexpr auto value = - lexy::as_list> >> - lexy::callback( - [](auto&& list) { - return ast::make_node_ptr(LEXY_MOV(list)); - }); + static constexpr auto value = lexy::as_list >> construct_list; }; struct EventStatement { - OVDL_GRAMMAR_KEYWORD_FLAG_DEFINE(id); - OVDL_GRAMMAR_KEYWORD_FLAG_DEFINE(title); - OVDL_GRAMMAR_KEYWORD_FLAG_DEFINE(desc); - OVDL_GRAMMAR_KEYWORD_FLAG_DEFINE(picture); - OVDL_GRAMMAR_KEYWORD_FLAG_DEFINE(is_triggered_only); - OVDL_GRAMMAR_KEYWORD_FLAG_DEFINE(fire_only_once); - OVDL_GRAMMAR_KEYWORD_FLAG_DEFINE(immediate); - OVDL_GRAMMAR_KEYWORD_FLAG_DEFINE(mean_time_to_happen); - OVDL_GRAMMAR_KEYWORD_DEFINE(trigger); - OVDL_GRAMMAR_KEYWORD_DEFINE(option); + using id = fkeyword_rule<"id", str_or_id>; + using title = fkeyword_rule<"title", str_or_id>; + using desc = fkeyword_rule<"desc", str_or_id>; + using picture = fkeyword_rule<"picture", str_or_id>; + using is_triggered_only = fkeyword_rule<"is_triggered_only", str_or_id>; + using fire_only_once = fkeyword_rule<"fire_only_once", str_or_id>; + using immediate = fkeyword_rule<"immediate", lexy::dsl::p>; + using mean_time_to_happen = fkeyword_rule<"mean_time_to_happen", lexy::dsl::p>; + using trigger = keyword_rule<"trigger", lexy::dsl::p>; + using option = keyword_rule<"option", lexy::dsl::p>; + + struct EventList { + static constexpr auto rule = [] { + using helper = dsl::rule_helper; + + return helper::flags + + dsl::curly_bracketed.opt_list( + helper::p | lexy::dsl::p | lexy::dsl::p