diff options
author | Spartan322 <Megacake1234@gmail.com> | 2023-09-03 05:56:26 +0200 |
---|---|---|
committer | Spartan322 <Megacake1234@gmail.com> | 2023-09-05 21:29:31 +0200 |
commit | 1d2c5ce39d12adcb584d586952a59e15f2495f67 (patch) | |
tree | f7569029f45ec019b0387e63aa7b94d1da7cc03a /include | |
parent | 238ab9dfaa8ec7a48142154d227605ae367d53d1 (diff) |
Add Node Line/Column Generator
Fix Errors.hpp dependency on v2script/Parser.hpp
Add node location print to headless/main.cpp
Add Node::line_col << operator
Add Node::cast_to
WARNING: Takes advantage of non-standard behavior in unordered_multimap
THIS IS A HACK FOR NOW
Only GCC unordered_multimap::equal_range sees elements backwards
Prefer moving off of unordered_multimap to something like EASTL hash_multimap
Diffstat (limited to 'include')
4 files changed, 224 insertions, 27 deletions
diff --git a/include/openvic-dataloader/detail/PointerHash.hpp b/include/openvic-dataloader/detail/PointerHash.hpp new file mode 100644 index 0000000..c0d28bc --- /dev/null +++ b/include/openvic-dataloader/detail/PointerHash.hpp @@ -0,0 +1,23 @@ +#pragma once + +#include <cstdint> + +namespace ovdl::detail { + /* hash any pointer */ + template<typename T> + struct PointerHash { + using type = T; + using ptr_type = T*; + using const_type = const T; + using const_ptr_type = const T*; + using const_ptr_const_type = const const_ptr_type; + constexpr std::size_t operator()(const_ptr_const_type pointer) const { + auto addr = reinterpret_cast<uintptr_t>(pointer); +#if SIZE_MAX < UINTPTR_MAX + /* size_t is not large enough to hold the pointer’s memory address */ + addr %= SIZE_MAX; /* truncate the address so it is small enough to fit in a size_t */ +#endif + return addr; + } + }; +}
\ No newline at end of file diff --git a/include/openvic-dataloader/v2script/AbstractSyntaxTree.hpp b/include/openvic-dataloader/v2script/AbstractSyntaxTree.hpp index 7b382fd..8e39bd9 100644 --- a/include/openvic-dataloader/v2script/AbstractSyntaxTree.hpp +++ b/include/openvic-dataloader/v2script/AbstractSyntaxTree.hpp @@ -1,18 +1,24 @@ #pragma once +#include <cstddef> +#include <cstdint> #include <iostream> #include <memory> -#include <optional> #include <string> #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> -#define OVDL_PRINT_FUNC_DEF std::ostream& print(std::ostream& stream, size_t indent) const override +namespace ovdl::v2script { + class Parser; +} + +#define OVDL_PRINT_FUNC_DEF std::ostream& print(std::ostream& stream, std::size_t indent) const override // defines get_type_static and get_type for string type naming #define OVDL_RT_TYPE_DEF \ @@ -32,31 +38,86 @@ namespace ovdl::v2script::ast { using NodeCPtr = const Node*; using NodeUPtr = std::unique_ptr<Node>; + struct NodeLocation { + const char* _begin = nullptr; + const char* _end = nullptr; + + NodeLocation() = default; + NodeLocation(const char* pos) : _begin(pos), + _end(pos) {} + NodeLocation(const char* begin, const char* end) : _begin(begin), + _end(end) {} + + NodeLocation(const NodeLocation&) = default; + NodeLocation& operator=(const NodeLocation&) = default; + + NodeLocation(NodeLocation&&) = default; + NodeLocation& operator=(NodeLocation&&) = default; + + const char* begin() const { return _begin; } + const char* end() const { return _end; } + + static inline NodeLocation make_from(const char* begin, const char* end) { + end++; + if (begin >= end) return NodeLocation(begin); + return NodeLocation(begin, end); + } + }; + struct Node { Node(const Node&) = delete; Node& operator=(const Node&) = delete; - Node() = default; + Node(NodeLocation location) : _location(location) {} Node(Node&&) = default; Node& operator=(Node&&) = default; virtual ~Node() = default; - virtual std::ostream& print(std::ostream& stream, size_t indent) const = 0; - static std::ostream& print_ptr(std::ostream& stream, NodeCPtr node, size_t indent); + 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; static constexpr std::string_view get_type_static() { return detail::type_name<Node>(); } constexpr virtual std::string_view get_type() const = 0; + 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(); } + template<typename T> constexpr bool is_type() const { return get_type().compare(detail::type_name<T>()) == 0; } template<typename T> - constexpr std::optional<T&> cast_to() { - if (is_type<T>()) return static_cast<T>(*this); - return std::nullopt; + constexpr bool is_derived_from() const { + return is_type<T>() || get_base_type().compare(detail::type_name<T>()) == 0; } + + template<typename T> + constexpr T* cast_to() { + if (is_derived_from<T>() || is_type<Node>()) return (static_cast<T*>(this)); + return nullptr; + } + + 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; + } + + const NodeLocation location() const { return _location; } + + struct line_col { + uint32_t line; + uint32_t column; + }; + + 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; + + private: + NodeLocation _location; }; inline std::ostream& operator<<(std::ostream& stream, Node const& node) { @@ -65,6 +126,9 @@ namespace ovdl::v2script::ast { 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 << ')'; + } template<class T, class... Args> NodePtr make_node_ptr(Args&&... args) { @@ -97,18 +161,22 @@ namespace ovdl::v2script::ast { struct AbstractStringNode : public Node { std::string _name; - explicit AbstractStringNode(std::string&& name); + AbstractStringNode(std::string&& name); + AbstractStringNode(NodeLocation location, std::string&& name); 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)>>(); } }; -#define OVDL_AST_STRING_NODE(NAME) \ - struct NAME final : public AbstractStringNode { \ - explicit NAME(std::string&& name); \ - OVDL_TYPE_DEFINE_SELF; \ - OVDL_RT_TYPE_DEF; \ - OVDL_PRINT_FUNC_DEF; \ +#define OVDL_AST_STRING_NODE(NAME) \ + struct NAME final : public AbstractStringNode { \ + NAME(std::string&& name); \ + NAME(NodeLocation location, std::string&& name); \ + OVDL_TYPE_DEFINE_SELF; \ + OVDL_RT_TYPE_DEF; \ + OVDL_PRINT_FUNC_DEF; \ } // Value Expression Nodes @@ -131,7 +199,7 @@ namespace ovdl::v2script::ast { struct AssignNode final : public Node { std::string _name; NodeUPtr _initializer; - explicit AssignNode(NodeCPtr name, NodePtr init); + AssignNode(NodeLocation location, NodeCPtr name, NodePtr init); OVDL_TYPE_DEFINE_SELF; OVDL_RT_TYPE_DEF; OVDL_PRINT_FUNC_DEF; @@ -140,17 +208,21 @@ namespace ovdl::v2script::ast { 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)>>(); } }; -#define OVDL_AST_LIST_NODE(NAME) \ - struct NAME final : public AbstractListNode { \ - explicit NAME(const std::vector<NodePtr>& statements = std::vector<NodePtr> {}); \ - OVDL_TYPE_DEFINE_SELF; \ - OVDL_RT_TYPE_DEF; \ - OVDL_PRINT_FUNC_DEF; \ +#define OVDL_AST_LIST_NODE(NAME) \ + struct NAME final : public AbstractListNode { \ + NAME(const std::vector<NodePtr>& statements = std::vector<NodePtr> {}); \ + NAME(NodeLocation location, const std::vector<NodePtr>& statements = std::vector<NodePtr> {}); \ + OVDL_TYPE_DEFINE_SELF; \ + OVDL_RT_TYPE_DEF; \ + OVDL_PRINT_FUNC_DEF; \ } OVDL_AST_LIST_NODE(FileNode); @@ -170,7 +242,8 @@ namespace ovdl::v2script::ast { Province } _type; std::vector<NodeUPtr> _statements; - explicit EventNode(Type type, const std::vector<NodePtr>& statements = {}); + EventNode(Type type, const std::vector<NodePtr>& statements = {}); + EventNode(NodeLocation location, Type type, const std::vector<NodePtr>& statements = {}); OVDL_TYPE_DEFINE_SELF; OVDL_RT_TYPE_DEF; OVDL_PRINT_FUNC_DEF; @@ -179,7 +252,8 @@ namespace ovdl::v2script::ast { struct DecisionNode final : public Node { NodeUPtr _name; std::vector<NodeUPtr> _statements; - explicit DecisionNode(NodePtr name, const std::vector<NodePtr>& statements = {}); + DecisionNode(NodePtr name, const std::vector<NodePtr>& statements = {}); + DecisionNode(NodeLocation location, NodePtr name, const std::vector<NodePtr>& statements = {}); OVDL_TYPE_DEFINE_SELF; OVDL_RT_TYPE_DEF; OVDL_PRINT_FUNC_DEF; @@ -188,7 +262,8 @@ namespace ovdl::v2script::ast { struct EventMtthModifierNode final : public Node { NodeUPtr _factor_value; std::vector<NodeUPtr> _statements; - EventMtthModifierNode() {} + EventMtthModifierNode() : Node({}) {} + EventMtthModifierNode(NodeLocation location) : Node(location) {} OVDL_TYPE_DEFINE_SELF; OVDL_RT_TYPE_DEF; OVDL_PRINT_FUNC_DEF; @@ -202,7 +277,8 @@ namespace ovdl::v2script::ast { } _type; NodeUPtr _name; NodeUPtr _initializer; - explicit ExecutionNode(Type type, NodePtr name, NodePtr init); + 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; @@ -211,7 +287,8 @@ namespace ovdl::v2script::ast { struct ExecutionListNode final : public Node { ExecutionNode::Type _type; std::vector<NodeUPtr> _statements; - explicit ExecutionListNode(ExecutionNode::Type type, const std::vector<NodePtr>& statements); + ExecutionListNode(ExecutionNode::Type type, const std::vector<NodePtr>& statements); + ExecutionListNode(NodeLocation location, ExecutionNode::Type type, const std::vector<NodePtr>& statements); OVDL_TYPE_DEFINE_SELF; OVDL_RT_TYPE_DEF; OVDL_PRINT_FUNC_DEF; diff --git a/include/openvic-dataloader/v2script/NodeLocationMap.hpp b/include/openvic-dataloader/v2script/NodeLocationMap.hpp new file mode 100644 index 0000000..aa88d62 --- /dev/null +++ b/include/openvic-dataloader/v2script/NodeLocationMap.hpp @@ -0,0 +1,91 @@ +#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 1c524b2..fb9022a 100644 --- a/include/openvic-dataloader/v2script/Parser.hpp +++ b/include/openvic-dataloader/v2script/Parser.hpp @@ -43,12 +43,18 @@ namespace ovdl::v2script { const FileNode* get_file_node() const; + void generate_node_location_map(); + + 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; + Parser(Parser&&); Parser& operator=(Parser&&); ~Parser(); private: + friend class ::ovdl::v2script::ast::Node; class BufferHandler; std::unique_ptr<BufferHandler> _buffer_handler; std::unique_ptr<FileNode> _file_node; |