aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/openvic-dataloader/detail/PointerHash.hpp23
-rw-r--r--include/openvic-dataloader/v2script/AbstractSyntaxTree.hpp131
-rw-r--r--include/openvic-dataloader/v2script/NodeLocationMap.hpp91
-rw-r--r--include/openvic-dataloader/v2script/Parser.hpp6
-rw-r--r--src/headless/main.cpp15
-rw-r--r--src/openvic-dataloader/detail/BasicBufferHandler.hpp4
-rw-r--r--src/openvic-dataloader/detail/Errors.hpp2
-rw-r--r--src/openvic-dataloader/v2script/AbstractSyntaxTree.cpp48
-rw-r--r--src/openvic-dataloader/v2script/ModifierGrammar.hpp2
-rw-r--r--src/openvic-dataloader/v2script/Parser.cpp63
-rw-r--r--src/openvic-dataloader/v2script/SimpleGrammar.hpp56
-rw-r--r--src/openvic-dataloader/v2script/TriggerGrammar.hpp2
12 files changed, 380 insertions, 63 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;
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<ovdl::v2script::ast::AssignNode>(); 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<ovdl::v2script::ast::AbstractListNode>(); 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<Encoding, MemoryResource> _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 <openvic-dataloader/ParseError.hpp>
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 <concepts>
#include <iomanip>
#include <sstream>
#include <string>
@@ -8,6 +9,8 @@
#include <openvic-dataloader/v2script/AbstractSyntaxTree.hpp>
+#include <lexy/input_location.hpp>
+
using namespace ovdl::v2script::ast;
void ovdl::v2script::ast::copy_into_node_ptr_vector(const std::vector<NodePtr>& source, std::vector<NodeUPtr>& dest) {
@@ -18,13 +21,17 @@ void ovdl::v2script::ast::copy_into_node_ptr_vector(const std::vector<NodePtr>&
}
}
-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<IdentifierNode>()) {
_name = cast_node_cptr<IdentifierNode>(name)._name;
}
@@ -101,9 +109,10 @@ static std::ostream& print_nodeuptr_vector(const std::vector<NodeUPtr>& nodes,
return stream;
}
-AbstractListNode::AbstractListNode(const std::vector<NodePtr>& statements) {
+AbstractListNode::AbstractListNode(NodeLocation location, const std::vector<NodePtr>& statements) : Node(location) {
copy_into_node_ptr_vector(statements, _statements);
}
+AbstractListNode::AbstractListNode(const std::vector<NodePtr>& 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<NodePtr>& statements) : AbstractListNode(statements) {} \
+#define OVDL_AST_LIST_NODE_DEF(NAME, ...) \
+ NAME::NAME(const std::vector<NodePtr>& statements) : AbstractListNode(statements) {} \
+ NAME::NAME(NodeLocation location, const std::vector<NodePtr>& 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<NodePtr>& statements) : _type(type) {
+EventNode::EventNode(NodeLocation location, Type type, const std::vector<NodePtr>& statements) : Node(location),
+ _type(type) {
copy_into_node_ptr_vector(statements, _statements);
}
+EventNode::EventNode(Type type, const std::vector<NodePtr>& 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<NodePtr>& statements) : _name(std::move(name)) {
+DecisionNode::DecisionNode(NodeLocation location, NodePtr name, const std::vector<NodePtr>& statements) : Node(location),
+ _name(std::move(name)) {
copy_into_node_ptr_vector(statements, _statements);
}
+DecisionNode::DecisionNode(NodePtr name, const std::vector<NodePtr>& 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<NodePtr>& statements) : _type(type) {
+ExecutionListNode::ExecutionListNode(NodeLocation location, ExecutionNode::Type type, const std::vector<NodePtr>& statements) : Node(location),
+ _type(type) {
copy_into_node_ptr_vector(statements, _statements);
}
+ExecutionListNode::ExecutionListNode(ExecutionNode::Type type, const std::vector<NodePtr>& 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<std::vector<ast::NodePtr>> >>
lexy::callback<ast::NodePtr>(
[](auto&& list) {
- return make_node_ptr<ast::ModifierNode>(LEXY_MOV(list));
+ return ast::make_node_ptr<ast::ModifierNode>(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 <openvic-dataloader/ParseWarning.hpp>
#include <openvic-dataloader/detail/Concepts.hpp>
#include <openvic-dataloader/v2script/AbstractSyntaxTree.hpp>
+#include <openvic-dataloader/v2script/NodeLocationMap.hpp>
#include <lexy/action/parse.hpp>
#include <lexy/encoding.hpp>
@@ -57,8 +58,14 @@ public:
return _root;
}
+ ast::NodeLocationMap<decltype(_buffer)>& get_location_map() {
+ return _location_map;
+ }
+
private:
+ friend class ::ovdl::v2script::ast::Node;
std::unique_ptr<ast::Node> _root;
+ ast::NodeLocationMap<decltype(_buffer)> _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<std::string> | lexy::new_<ast::IdentifierNode, ast::NodePtr>;
+ static constexpr auto value = lexy::callback<ast::NodePtr>(
+ [](auto lexeme) {
+ std::string str(lexeme.data(), lexeme.size());
+ return ast::make_node_ptr<ast::IdentifierNode>(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<escaped_symbols>();
- 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<std::string> >> lexy::new_<ast::StringNode, ast::NodePtr>;
+ static constexpr auto value =
+ lexy::as_string<std::string> >>
+ lexy::callback<ast::NodePtr>(
+ [](const char* begin, auto&& str, const char* end) {
+ return ast::make_node_ptr<ast::StringNode>(ast::NodeLocation::make_from(begin, end), LEXY_MOV(str));
+ });
};
struct SimpleAssignmentStatement {
static constexpr auto rule =
- lexy::dsl::p<Identifier> >>
+ lexy::dsl::position(lexy::dsl::p<Identifier>) >>
lexy::dsl::equal_sign +
(lexy::dsl::p<Identifier> | lexy::dsl::p<StringExpression> | lexy::dsl::recurse_branch<StatementListBlock>);
static constexpr auto value = lexy::callback<ast::NodePtr>(
- [](auto name, auto&& initalizer) {
- return make_node_ptr<ast::AssignNode>(LEXY_MOV(name), LEXY_MOV(initalizer));
+ [](const char* pos, auto name, auto&& initalizer) {
+ return ast::make_node_ptr<ast::AssignNode>(pos, LEXY_MOV(name), LEXY_MOV(initalizer));
});
};
struct AssignmentStatement {
static constexpr auto rule =
- lexy::dsl::p<Identifier> >>
+ lexy::dsl::position(lexy::dsl::p<Identifier>) >>
(lexy::dsl::equal_sign >>
(lexy::dsl::p<Identifier> | lexy::dsl::p<StringExpression> | lexy::dsl::recurse_branch<StatementListBlock>) |
lexy::dsl::else_ >> lexy::dsl::return_) |
lexy::dsl::p<StringExpression>;
static constexpr auto value = lexy::callback<ast::NodePtr>(
+ [](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<ast::AssignNode>(LEXY_MOV(name), LEXY_MOV(initalizer));
+ [](const char* pos, auto name, auto&& initalizer) {
+ return ast::make_node_ptr<ast::AssignNode>(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<AssignmentStatement>)) + lexy::dsl::opt(lexy::dsl::semicolon));
+ lexy::dsl::position(lexy::dsl::curly_bracketed.open()) >>
+ lexy::dsl::opt(lexy::dsl::list(lexy::dsl::p<AssignmentStatement>)) +
+ lexy::dsl::opt(lexy::dsl::semicolon) >>
+ lexy::dsl::position(lexy::dsl::curly_bracketed.close());
static constexpr auto value =
lexy::as_list<std::vector<ast::NodePtr>> >>
lexy::callback<ast::NodePtr>(
- [](lexy::nullopt = {}, lexy::nullopt = {}) {
- return ast::make_node_ptr<ast::ListNode>();
+ [](const char* begin, lexy::nullopt, const char* end) {
+ return ast::make_node_ptr<ast::ListNode>(ast::NodeLocation::make_from(begin, end));
+ },
+ [](const char* begin, auto&& list, const char* end) {
+ return ast::make_node_ptr<ast::ListNode>(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::ListNode>(ast::NodeLocation::make_from(begin, end));
},
- [](auto&& list, lexy::nullopt = {}) {
- return make_node_ptr<ast::ListNode>(LEXY_MOV(list));
+ [](const char* begin, auto&& list, lexy::nullopt, const char* end) {
+ return ast::make_node_ptr<ast::ListNode>(ast::NodeLocation::make_from(begin, end), LEXY_MOV(list));
},
- [](auto& list) {
- return make_node_ptr<ast::ListNode>(list);
+ [](const char* begin, auto& list, const char* end) {
+ return ast::make_node_ptr<ast::ListNode>(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<AssignmentStatement>);
+ static constexpr auto rule = lexy::dsl::position + lexy::dsl::terminator(lexy::dsl::eof).list(lexy::dsl::p<AssignmentStatement>);
static constexpr auto value = lexy::as_list<std::vector<ast::NodePtr>> >> lexy::new_<ast::FileNode, ast::NodePtr>;
};
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<ast::NodePtr>(
[](auto name, auto&& initalizer) {
- return ast::make_node_ptr<ast::ExecutionNode>(ast::ExecutionNode::Type::Trigger, LEXY_MOV(name), LEXY_MOV(initalizer));
+ return ast::make_node_ptr<ast::ExecutionNode>({}, ast::ExecutionNode::Type::Trigger, LEXY_MOV(name), LEXY_MOV(initalizer));
});
};