From 1d2c5ce39d12adcb584d586952a59e15f2495f67 Mon Sep 17 00:00:00 2001 From: Spartan322 Date: Sat, 2 Sep 2023 23:56:26 -0400 Subject: 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 --- include/openvic-dataloader/detail/PointerHash.hpp | 23 ++++ .../v2script/AbstractSyntaxTree.hpp | 131 ++++++++++++++++----- .../v2script/NodeLocationMap.hpp | 91 ++++++++++++++ include/openvic-dataloader/v2script/Parser.hpp | 6 + src/headless/main.cpp | 15 +++ .../detail/BasicBufferHandler.hpp | 4 + src/openvic-dataloader/detail/Errors.hpp | 2 +- .../v2script/AbstractSyntaxTree.cpp | 48 +++++--- .../v2script/ModifierGrammar.hpp | 2 +- src/openvic-dataloader/v2script/Parser.cpp | 63 ++++++++++ src/openvic-dataloader/v2script/SimpleGrammar.hpp | 56 ++++++--- src/openvic-dataloader/v2script/TriggerGrammar.hpp | 2 +- 12 files changed, 380 insertions(+), 63 deletions(-) create mode 100644 include/openvic-dataloader/detail/PointerHash.hpp create mode 100644 include/openvic-dataloader/v2script/NodeLocationMap.hpp 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 + +namespace ovdl::detail { + /* hash any pointer */ + template + 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(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 +#include #include #include -#include #include #include #include #include #include +#include #include #include -#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; + 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(); } constexpr virtual std::string_view get_type() const = 0; + 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(); } + template constexpr bool is_type() const { return get_type().compare(detail::type_name()) == 0; } template - constexpr std::optional cast_to() { - if (is_type()) return static_cast(*this); - return std::nullopt; + constexpr bool is_derived_from() const { + return is_type() || get_base_type().compare(detail::type_name()) == 0; } + + template + constexpr T* cast_to() { + if (is_derived_from() || is_type()) return (static_cast(this)); + return nullptr; + } + + template + constexpr const T* const cast_to() const { + if (is_derived_from() || is_type()) return (static_cast(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 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(); } + constexpr std::string_view get_base_type() const override { return ::ovdl::detail::type_name>(); } }; -#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 _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>(); } }; -#define OVDL_AST_LIST_NODE(NAME) \ - struct NAME final : public AbstractListNode { \ - explicit NAME(const std::vector& statements = std::vector {}); \ - 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& statements = std::vector {}); \ + NAME(NodeLocation location, const std::vector& statements = std::vector {}); \ + 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 _statements; - explicit EventNode(Type type, const std::vector& statements = {}); + EventNode(Type type, const std::vector& statements = {}); + EventNode(NodeLocation location, Type type, const std::vector& 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 _statements; - explicit DecisionNode(NodePtr name, const std::vector& statements = {}); + DecisionNode(NodePtr name, const std::vector& statements = {}); + DecisionNode(NodeLocation location, NodePtr name, const std::vector& 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 _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 _statements; - explicit ExecutionListNode(ExecutionNode::Type type, const std::vector& statements); + ExecutionListNode(ExecutionNode::Type type, const std::vector& statements); + ExecutionListNode(NodeLocation location, ExecutionNode::Type type, const std::vector& 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 + +#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 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 _buffer_handler; std::unique_ptr _file_node; diff --git a/src/headless/main.cpp b/src/headless/main.cpp index c3ca8c2..2075d9b 100644 --- a/src/headless/main.cpp +++ b/src/headless/main.cpp @@ -81,6 +81,21 @@ 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; + } + } + } + } std::cout << parser.get_file_node() << std::endl; return EXIT_SUCCESS; } diff --git a/src/openvic-dataloader/detail/BasicBufferHandler.hpp b/src/openvic-dataloader/detail/BasicBufferHandler.hpp index 5f4f82d..72b85d3 100644 --- a/src/openvic-dataloader/detail/BasicBufferHandler.hpp +++ b/src/openvic-dataloader/detail/BasicBufferHandler.hpp @@ -41,6 +41,10 @@ namespace ovdl::detail { return std::nullopt; } + const auto& get_buffer() const { + return _buffer; + } + protected: lexy::buffer _buffer; }; diff --git a/src/openvic-dataloader/detail/Errors.hpp b/src/openvic-dataloader/detail/Errors.hpp index f53bedc..bf7c831 100644 --- a/src/openvic-dataloader/detail/Errors.hpp +++ b/src/openvic-dataloader/detail/Errors.hpp @@ -1,6 +1,6 @@ #pragma once -#include "openvic-dataloader/v2script/Parser.hpp" +#include namespace ovdl::errors { inline const ParseError make_no_file_error(const char* file_path) { diff --git a/src/openvic-dataloader/v2script/AbstractSyntaxTree.cpp b/src/openvic-dataloader/v2script/AbstractSyntaxTree.cpp index f9fb716..8dc1800 100644 --- a/src/openvic-dataloader/v2script/AbstractSyntaxTree.cpp +++ b/src/openvic-dataloader/v2script/AbstractSyntaxTree.cpp @@ -1,3 +1,4 @@ +#include #include #include #include @@ -8,6 +9,8 @@ #include +#include + using namespace ovdl::v2script::ast; void ovdl::v2script::ast::copy_into_node_ptr_vector(const std::vector& source, std::vector& dest) { @@ -18,13 +21,17 @@ void ovdl::v2script::ast::copy_into_node_ptr_vector(const std::vector& } } -AbstractStringNode::AbstractStringNode(std::string&& name) : _name(std::move(name)) {} +AbstractStringNode::AbstractStringNode(NodeLocation location, std::string&& name) : Node(location), + _name(std::move(name)) {} +AbstractStringNode::AbstractStringNode(std::string&& name) : AbstractStringNode({}, std::move(name)) {} + std::ostream& AbstractStringNode::print(std::ostream& stream, size_t indent) const { return stream << _name; } -#define OVDL_AST_STRING_NODE_DEF(NAME, ...) \ - NAME::NAME(std::string&& name) : AbstractStringNode(std::move(name)) {} \ +#define OVDL_AST_STRING_NODE_DEF(NAME, ...) \ + NAME::NAME(std::string&& name) : AbstractStringNode(std::move(name)) {} \ + NAME::NAME(NodeLocation location, std::string&& name) : AbstractStringNode(location, std::move(name)) {} \ std::ostream& NAME::print(std::ostream& stream, size_t indent) const __VA_ARGS__ OVDL_AST_STRING_NODE_DEF(IdentifierNode, { @@ -73,8 +80,9 @@ OVDL_AST_STRING_NODE_DEF(IsTriggeredNode, { #undef OVDL_AST_STRING_NODE_DEF -AssignNode::AssignNode(NodeCPtr name, NodePtr init) - : _initializer(std::move(init)) { +AssignNode::AssignNode(NodeLocation location, NodeCPtr name, NodePtr init) + : Node(location), + _initializer(std::move(init)) { if (name->is_type()) { _name = cast_node_cptr(name)._name; } @@ -101,9 +109,10 @@ static std::ostream& print_nodeuptr_vector(const std::vector& nodes, return stream; } -AbstractListNode::AbstractListNode(const std::vector& statements) { +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()) { @@ -113,8 +122,9 @@ std::ostream& AbstractListNode::print(std::ostream& stream, size_t indent) const return stream << "}"; } -#define OVDL_AST_LIST_NODE_DEF(NAME, ...) \ - NAME::NAME(const std::vector& statements) : AbstractListNode(statements) {} \ +#define OVDL_AST_LIST_NODE_DEF(NAME, ...) \ + NAME::NAME(const std::vector& statements) : AbstractListNode(statements) {} \ + NAME::NAME(NodeLocation location, const std::vector& statements) : AbstractListNode(location, statements) {} \ std::ostream& NAME::print(std::ostream& stream, size_t indent) const __VA_ARGS__ OVDL_AST_LIST_NODE_DEF(FileNode, { @@ -178,9 +188,11 @@ OVDL_AST_LIST_NODE_DEF(DecisionListNode, { #undef OVDL_AST_LIST_NODE_DEF -EventNode::EventNode(Type type, const std::vector& statements) : _type(type) { +EventNode::EventNode(NodeLocation location, Type type, const std::vector& statements) : Node(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; @@ -194,9 +206,11 @@ std::ostream& EventNode::print(std::ostream& stream, size_t indent) const { return stream << '}'; } -DecisionNode::DecisionNode(NodePtr name, const std::vector& statements) : _name(std::move(name)) { +DecisionNode::DecisionNode(NodeLocation location, NodePtr name, const std::vector& statements) : Node(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()) { @@ -206,10 +220,12 @@ std::ostream& DecisionNode::print(std::ostream& stream, size_t indent) const { return stream << '}'; } -ExecutionNode::ExecutionNode(Type type, NodePtr name, NodePtr init) : _type(type), - _name(std::move(name)), - _initializer(std::move(init)) { +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) { @@ -218,9 +234,11 @@ std::ostream& ExecutionNode::print(std::ostream& stream, size_t indent) const { return stream; } -ExecutionListNode::ExecutionListNode(ExecutionNode::Type type, const std::vector& statements) : _type(type) { +ExecutionListNode::ExecutionListNode(NodeLocation location, ExecutionNode::Type type, const std::vector& statements) : Node(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 << "{ "; @@ -244,4 +262,4 @@ Node::operator std::string() const { std::ostream& AssignNode::print(std::ostream& stream, size_t indent) const { stream << _name << " = "; return Node::print_ptr(stream, _initializer.get(), indent); -} +} \ No newline at end of file diff --git a/src/openvic-dataloader/v2script/ModifierGrammar.hpp b/src/openvic-dataloader/v2script/ModifierGrammar.hpp index ad0704a..632cfd5 100644 --- a/src/openvic-dataloader/v2script/ModifierGrammar.hpp +++ b/src/openvic-dataloader/v2script/ModifierGrammar.hpp @@ -27,7 +27,7 @@ namespace ovdl::v2script::grammar { lexy::as_list> >> lexy::callback( [](auto&& list) { - return make_node_ptr(LEXY_MOV(list)); + return ast::make_node_ptr(LEXY_MOV(list)); }); }; } \ No newline at end of file diff --git a/src/openvic-dataloader/v2script/Parser.cpp b/src/openvic-dataloader/v2script/Parser.cpp index 07d6455..1258bca 100644 --- a/src/openvic-dataloader/v2script/Parser.cpp +++ b/src/openvic-dataloader/v2script/Parser.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -57,8 +58,14 @@ public: return _root; } + ast::NodeLocationMap& get_location_map() { + return _location_map; + } + private: + friend class ::ovdl::v2script::ast::Node; std::unique_ptr _root; + ast::NodeLocationMap _location_map; }; /// BufferHandler /// @@ -221,4 +228,60 @@ bool Parser::decision_parse() { const FileNode* Parser::get_file_node() const { return _file_node.get(); +} + +void Parser::generate_node_location_map() { + _buffer_handler->get_location_map().clear(); + _buffer_handler->get_location_map().generate_location_map(_buffer_handler->get_buffer(), get_file_node()); +} + +const ast::Node::line_col Parser::get_node_begin(const ast::NodeCPtr node) const { + if (!node) return { 0, 0 }; + return node->get_begin_line_col(*this); +} + +const ast::Node::line_col Parser::get_node_end(const ast::NodeCPtr node) const { + if (!node) return { 0, 0 }; + return node->get_end_line_col(*this); +} + +const ast::Node::line_col ast::Node::get_begin_line_col(const Parser& parser) const { + if (!parser._buffer_handler->is_valid() || parser._buffer_handler->_location_map.empty()) return {}; + line_col result; + auto [itr, range_end] = parser._buffer_handler->_location_map.equal_range(this); + if (itr != range_end) { + result.line = itr->second.line_nr(); + result.column = itr->second.column_nr(); + } + // Standard doesn't really guarantee the direction of the range's sequence, but only GCC goes backwards + // TODO: DON'T USE STANDARD UNORDERED_MULTIMAP +#if defined(__GNUC__) && !defined(__clang__) + itr++; + if (itr != range_end) { + result.line = itr->second.line_nr(); + result.column = itr->second.column_nr(); + } +#endif + return result; +} + +const ast::Node::line_col ast::Node::get_end_line_col(const Parser& parser) const { + if (!parser._buffer_handler->is_valid() || parser._buffer_handler->_location_map.empty()) return {}; + line_col result; + auto [itr, range_end] = parser._buffer_handler->_location_map.equal_range(this); + if (itr != range_end) { + result.line = itr->second.line_nr(); + result.column = itr->second.column_nr(); + } + // Standard doesn't really guarantee the direction of the range's sequence, but only GCC goes backwards + // TODO: DON'T USE STANDARD UNORDERED_MULTIMAP +#if defined(__GNUC__) && !defined(__clang__) + return result; +#endif + itr++; + if (itr != range_end) { + result.line = itr->second.line_nr(); + result.column = itr->second.column_nr(); + } + return result; } \ No newline at end of file diff --git a/src/openvic-dataloader/v2script/SimpleGrammar.hpp b/src/openvic-dataloader/v2script/SimpleGrammar.hpp index c91935e..3e9a96e 100644 --- a/src/openvic-dataloader/v2script/SimpleGrammar.hpp +++ b/src/openvic-dataloader/v2script/SimpleGrammar.hpp @@ -32,7 +32,11 @@ namespace ovdl::v2script::grammar { struct Identifier { static constexpr auto rule = lexy::dsl::identifier(data_char_class); - static constexpr auto value = lexy::as_string | lexy::new_; + static constexpr auto value = lexy::callback( + [](auto lexeme) { + std::string str(lexeme.data(), lexeme.size()); + return ast::make_node_ptr(ast::NodeLocation { lexeme.begin(), lexeme.end() }, LEXY_MOV(str)); + }); }; struct StringExpression { @@ -55,57 +59,73 @@ namespace ovdl::v2script::grammar { // or a Unicode code point of the form uXXXX. auto escape = lexy::dsl::backslash_escape // .symbol(); - return lexy::dsl::quoted(c, escape); + return lexy::dsl::delimited(lexy::dsl::position(lexy::dsl::lit_b<'"'>))(c, escape); }(); - static constexpr auto value = lexy::as_string >> lexy::new_; + static constexpr auto value = + lexy::as_string >> + lexy::callback( + [](const char* begin, auto&& str, const char* end) { + return ast::make_node_ptr(ast::NodeLocation::make_from(begin, end), LEXY_MOV(str)); + }); }; struct SimpleAssignmentStatement { static constexpr auto rule = - lexy::dsl::p >> + lexy::dsl::position(lexy::dsl::p) >> lexy::dsl::equal_sign + (lexy::dsl::p | lexy::dsl::p | lexy::dsl::recurse_branch); static constexpr auto value = lexy::callback( - [](auto name, auto&& initalizer) { - return make_node_ptr(LEXY_MOV(name), LEXY_MOV(initalizer)); + [](const char* pos, auto name, auto&& initalizer) { + return ast::make_node_ptr(pos, LEXY_MOV(name), LEXY_MOV(initalizer)); }); }; struct AssignmentStatement { static constexpr auto rule = - lexy::dsl::p >> + lexy::dsl::position(lexy::dsl::p) >> (lexy::dsl::equal_sign >> (lexy::dsl::p | lexy::dsl::p | lexy::dsl::recurse_branch) | lexy::dsl::else_ >> lexy::dsl::return_) | lexy::dsl::p; static constexpr auto value = lexy::callback( + [](const char* pos, auto name, lexy::nullopt = {}) { + return LEXY_MOV(name); + }, [](auto name, lexy::nullopt = {}) { return LEXY_MOV(name); }, - [](auto name, auto&& initalizer) { - return make_node_ptr(LEXY_MOV(name), LEXY_MOV(initalizer)); + [](const char* pos, auto name, auto&& initalizer) { + return ast::make_node_ptr(pos, LEXY_MOV(name), LEXY_MOV(initalizer)); }); }; struct StatementListBlock { static constexpr auto rule = - lexy::dsl::curly_bracketed( - lexy::dsl::opt(lexy::dsl::list(lexy::dsl::p)) + lexy::dsl::opt(lexy::dsl::semicolon)); + lexy::dsl::position(lexy::dsl::curly_bracketed.open()) >> + lexy::dsl::opt(lexy::dsl::list(lexy::dsl::p)) + + lexy::dsl::opt(lexy::dsl::semicolon) >> + lexy::dsl::position(lexy::dsl::curly_bracketed.close()); static constexpr auto value = lexy::as_list> >> lexy::callback( - [](lexy::nullopt = {}, lexy::nullopt = {}) { - return ast::make_node_ptr(); + [](const char* begin, lexy::nullopt, const char* end) { + return ast::make_node_ptr(ast::NodeLocation::make_from(begin, end)); + }, + [](const char* begin, auto&& list, const char* end) { + return ast::make_node_ptr(ast::NodeLocation::make_from(begin, end), LEXY_MOV(list)); + }, + [](const char* begin, lexy::nullopt, lexy::nullopt, const char* end) { + return ast::make_node_ptr(ast::NodeLocation::make_from(begin, end)); }, - [](auto&& list, lexy::nullopt = {}) { - return make_node_ptr(LEXY_MOV(list)); + [](const char* begin, auto&& list, lexy::nullopt, const char* end) { + return ast::make_node_ptr(ast::NodeLocation::make_from(begin, end), LEXY_MOV(list)); }, - [](auto& list) { - return make_node_ptr(list); + [](const char* begin, auto& list, const char* end) { + return ast::make_node_ptr(ast::NodeLocation::make_from(begin, end), list); }); }; @@ -113,7 +133,7 @@ namespace ovdl::v2script::grammar { // Allow arbitrary spaces between individual tokens. static constexpr auto whitespace = whitespace_specifier | comment_specifier; - static constexpr auto rule = lexy::dsl::terminator(lexy::dsl::eof).list(lexy::dsl::p); + static constexpr auto rule = lexy::dsl::position + lexy::dsl::terminator(lexy::dsl::eof).list(lexy::dsl::p); static constexpr auto value = lexy::as_list> >> lexy::new_; }; diff --git a/src/openvic-dataloader/v2script/TriggerGrammar.hpp b/src/openvic-dataloader/v2script/TriggerGrammar.hpp index 290fb70..6d964db 100644 --- a/src/openvic-dataloader/v2script/TriggerGrammar.hpp +++ b/src/openvic-dataloader/v2script/TriggerGrammar.hpp @@ -13,7 +13,7 @@ namespace ovdl::v2script::grammar { static constexpr auto value = lexy::callback( [](auto name, auto&& initalizer) { - return ast::make_node_ptr(ast::ExecutionNode::Type::Trigger, LEXY_MOV(name), LEXY_MOV(initalizer)); + return ast::make_node_ptr({}, ast::ExecutionNode::Type::Trigger, LEXY_MOV(name), LEXY_MOV(initalizer)); }); }; -- cgit v1.2.3-56-ga3b1