aboutsummaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
author Spartan322 <Megacake1234@gmail.com>2023-07-28 06:52:00 +0200
committer Spartan322 <Megacake1234@gmail.com>2023-08-17 09:04:56 +0200
commit90f15b582788a9aab0dfe6c81fc4cbbe1d4d3308 (patch)
treedb58100ed696c992addee1a9113b5415f55615ad /include
parente941573f47fb867ff75c8a2cf78302b754ffbeee (diff)
Rework Grammar and Parser
Properly construct headless binary with basic validation and print functionality Add Error and Warning structs to Parser Add FileNode pointer getter to Parser Change all `char8_t*` and `const char8_t` to `const char*` in Parser Add Parser move operators and Parser deconstructor Add BufferHandler PIMPL object to Parser Add UTF-8 file Warning Add proper Grammar value retrieval Simplify AST node resolution for Grammar Add AbstractSyntaxTree for v2script data parser: Has compile-time embedded type information accessible at compile-time and runtime Optionally compiled AST print functionality Add detail/TypeName.hpp Add detail/SelfType.hpp Add detail/DetectUtf8.hpp Add detail/Errors.hpp Add detail/Warnings.hpp Add `OPENVIC_DATALOADER_PRINT_NODES` for headless construction Fix wrong environment reference for headless construction in SConstruct
Diffstat (limited to 'include')
-rw-r--r--include/openvic-dataloader/detail/SelfType.hpp24
-rw-r--r--include/openvic-dataloader/detail/TypeName.hpp52
-rw-r--r--include/openvic-dataloader/v2script/AbstractSyntaxTree.hpp174
-rw-r--r--include/openvic-dataloader/v2script/Parser.hpp74
4 files changed, 313 insertions, 11 deletions
diff --git a/include/openvic-dataloader/detail/SelfType.hpp b/include/openvic-dataloader/detail/SelfType.hpp
new file mode 100644
index 0000000..5366aef
--- /dev/null
+++ b/include/openvic-dataloader/detail/SelfType.hpp
@@ -0,0 +1,24 @@
+#pragma once
+
+#include <type_traits>
+
+namespace ovdl::detail {
+#pragma GCC diagnostic push
+#pragma clang diagnostic ignored "-Wunknown-warning-option"
+#pragma GCC diagnostic ignored "-Wnon-template-friend"
+ template<typename T>
+ struct Reader {
+ friend auto adl_GetSelfType(Reader<T>);
+ };
+
+ template<typename T, typename U>
+ struct Writer {
+ friend auto adl_GetSelfType(Reader<T>) { return U {}; }
+ };
+#pragma GCC diagnostic pop
+
+ inline void adl_GetSelfType() {}
+
+ template<typename T>
+ using Read = std::remove_pointer_t<decltype(adl_GetSelfType(Reader<T> {}))>;
+}
diff --git a/include/openvic-dataloader/detail/TypeName.hpp b/include/openvic-dataloader/detail/TypeName.hpp
new file mode 100644
index 0000000..e9f27d3
--- /dev/null
+++ b/include/openvic-dataloader/detail/TypeName.hpp
@@ -0,0 +1,52 @@
+#pragma once
+
+#include <array>
+#include <cstddef>
+#include <string_view>
+#include <utility>
+
+namespace ovdl::detail {
+
+ template<std::size_t... Idxs>
+ constexpr auto substring_as_array(std::string_view str, std::index_sequence<Idxs...>) {
+ return std::array { str[Idxs]..., '\n' };
+ }
+
+ template<typename T>
+ constexpr auto type_name_array() {
+#if defined(__clang__)
+ constexpr auto prefix = std::string_view { "[T = " };
+ constexpr auto suffix = std::string_view { "]" };
+ constexpr auto function = std::string_view { __PRETTY_FUNCTION__ };
+#elif defined(__GNUC__)
+ constexpr auto prefix = std::string_view { "with T = " };
+ constexpr auto suffix = std::string_view { "]" };
+ constexpr auto function = std::string_view { __PRETTY_FUNCTION__ };
+#elif defined(_MSC_VER)
+ constexpr auto prefix = std::string_view { "type_name_array<" };
+ constexpr auto suffix = std::string_view { ">(void)" };
+ constexpr auto function = std::string_view { __FUNCSIG__ };
+#else
+#error Unsupported compiler
+#endif
+
+ constexpr auto start = function.find(prefix) + prefix.size();
+ constexpr auto end = function.rfind(suffix);
+
+ static_assert(start < end);
+
+ constexpr auto name = function.substr(start, (end - start));
+ return substring_as_array(name, std::make_index_sequence<name.size()> {});
+ }
+
+ template<typename T>
+ struct type_name_holder {
+ static inline constexpr auto value = type_name_array<T>();
+ };
+
+ template<typename T>
+ constexpr auto type_name() -> std::string_view {
+ constexpr auto& value = type_name_holder<T>::value;
+ return std::string_view { value.data(), value.size() };
+ }
+} \ No newline at end of file
diff --git a/include/openvic-dataloader/v2script/AbstractSyntaxTree.hpp b/include/openvic-dataloader/v2script/AbstractSyntaxTree.hpp
new file mode 100644
index 0000000..80485b7
--- /dev/null
+++ b/include/openvic-dataloader/v2script/AbstractSyntaxTree.hpp
@@ -0,0 +1,174 @@
+#pragma once
+
+#include <memory>
+#include <string>
+#include <string_view>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+#include <openvic-dataloader/detail/SelfType.hpp>
+#include <openvic-dataloader/detail/TypeName.hpp>
+
+#ifdef OPENVIC_DATALOADER_PRINT_NODES
+#include <iostream>
+
+#define OVDL_PRINT_FUNC_DECL virtual void print(std::ostream& stream) const = 0
+#define OVDL_PRINT_FUNC_DEF(...) \
+ void print(std::ostream& stream) const override __VA_ARGS__
+#else
+#define OVDL_PRINT_FUNC_DECL
+#define OVDL_PRINT_FUNC_DEF(...)
+#endif
+
+// defines get_type_static and get_type for string type naming
+#define OVDL_RT_TYPE_DEF \
+ static constexpr std::string_view get_type_static() { return ::ovdl::detail::type_name<type>(); } \
+ constexpr std::string_view get_type() const override { return ::ovdl::detail::type_name<std::decay_t<decltype(*this)>>(); }
+
+// 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>;
+
+namespace ovdl::v2script::ast {
+ struct Node {
+ Node(const Node&) = delete;
+ Node& operator=(const Node&) = delete;
+ Node() = default;
+ Node(Node&&) = default;
+ Node& operator=(Node&&) = default;
+ virtual ~Node() = default;
+
+ OVDL_PRINT_FUNC_DECL;
+
+ static constexpr std::string_view get_type_static() { return detail::type_name<Node>(); }
+ constexpr virtual std::string_view get_type() const = 0;
+
+ template<typename T>
+ constexpr bool is_type() const {
+ return get_type().compare(detail::type_name<T>()) == 0;
+ }
+ };
+
+ using NodePtr = Node*;
+ using NodeUPtr = std::unique_ptr<Node>;
+
+ template<class T, class... Args>
+ NodePtr make_node_ptr(Args&&... args) {
+ if constexpr (std::is_pointer_v<NodePtr>) {
+ return new T(std::forward<Args>(args)...);
+ } else {
+ return NodePtr(new T(std::forward<Args>(args)...));
+ }
+ }
+
+ template<typename To, typename From>
+ To& cast_node_ptr(const From& from) {
+ if constexpr (std::is_pointer_v<NodePtr>) {
+ return *static_cast<To*>(from);
+ } else {
+ return *static_cast<To*>(from.get());
+ }
+ }
+
+ constexpr std::vector<NodeUPtr> make_node_ptr_vector(const std::vector<NodePtr>& ptrs) {
+ std::vector<NodeUPtr> result;
+ result.reserve(ptrs.size());
+ for (auto&& p : ptrs) {
+ result.push_back(NodeUPtr(p));
+ }
+ return result;
+ }
+
+ struct IdentifierNode final : public Node {
+ std::string _name;
+ explicit IdentifierNode(std::string name)
+ : _name(std::move(name)) {
+ }
+
+ OVDL_TYPE_DEFINE_SELF;
+ OVDL_RT_TYPE_DEF;
+
+ OVDL_PRINT_FUNC_DEF({
+ stream << _name.c_str();
+ })
+ };
+
+ struct StringNode final : public Node {
+ std::string _name;
+ explicit StringNode(std::string name)
+ : _name(std::move(name)) {
+ }
+
+ OVDL_TYPE_DEFINE_SELF;
+ OVDL_RT_TYPE_DEF;
+
+ OVDL_PRINT_FUNC_DEF({
+ stream << '"' << _name.c_str() << '"';
+ })
+ };
+
+ struct AssignNode final : public Node {
+ std::string _name;
+ NodeUPtr _initializer;
+ explicit AssignNode(NodePtr name, NodePtr init)
+ : _initializer(std::move(init)) {
+ if (name->is_type<IdentifierNode>()) {
+ _name = cast_node_ptr<IdentifierNode>(name)._name;
+ }
+ }
+
+ OVDL_TYPE_DEFINE_SELF;
+ OVDL_RT_TYPE_DEF;
+
+ OVDL_PRINT_FUNC_DEF({
+ stream << _name.c_str() << " = ";
+ _initializer->print(stream);
+ })
+ };
+
+ struct ListNode final : public Node {
+ std::vector<NodeUPtr> _statements;
+ explicit ListNode(std::vector<NodePtr> statements = std::vector<NodePtr> {})
+ : _statements(make_node_ptr_vector(statements)) {
+ }
+
+ OVDL_TYPE_DEFINE_SELF;
+ OVDL_RT_TYPE_DEF;
+
+ OVDL_PRINT_FUNC_DEF({
+ stream << '{';
+ for (int i = 0; i < _statements.size(); i++) {
+ auto& statement = _statements[i];
+ statement->print(stream);
+ if (i + 1 != _statements.size())
+ stream << ' ';
+ }
+ stream << '}';
+ })
+ };
+
+ struct FileNode final : public Node {
+ std::vector<NodeUPtr> _statements;
+ FileNode() {}
+ explicit FileNode(std::vector<NodePtr> statements)
+ : _statements(make_node_ptr_vector(statements)) {
+ }
+
+ OVDL_TYPE_DEFINE_SELF;
+ OVDL_RT_TYPE_DEF;
+
+ OVDL_PRINT_FUNC_DEF({
+ for (auto& statement : _statements) {
+ statement->print(stream);
+ stream << "\n===========\n";
+ }
+ })
+ };
+}
+
+#undef OVDL_PRINT_FUNC_DECL
+#undef OVDL_PRINT_FUNC_DEF
+#undef OVDL_TYPE_DEFINE_SELF \ No newline at end of file
diff --git a/include/openvic-dataloader/v2script/Parser.hpp b/include/openvic-dataloader/v2script/Parser.hpp
index 53aab90..dbbec73 100644
--- a/include/openvic-dataloader/v2script/Parser.hpp
+++ b/include/openvic-dataloader/v2script/Parser.hpp
@@ -1,27 +1,79 @@
#pragma once
#include <cstddef>
-#include <cstdio>
+#include <functional>
+#include <memory>
+#include <optional>
#include <ostream>
+#include <string>
+#include <vector>
+
+#include <openvic-dataloader/v2script/AbstractSyntaxTree.hpp>
namespace ovdl::v2script {
+
+ using FileNode = ast::FileNode;
+
class Parser {
public:
- static Parser from_buffer(char8_t* data, std::size_t size);
- static Parser from_buffer(char8_t* start, char8_t* end);
- static Parser from_file(const char8_t* path);
+ struct Error {
+ const enum class Type : unsigned char {
+ Recoverable,
+ Fatal
+ } type;
+ const std::string message;
+ const int error_value;
+ };
+
+ struct Warning {
+ const std::string message;
+ const int warning_value;
+ };
+
+ Parser();
+
+ static Parser from_buffer(const char* data, std::size_t size);
+ static Parser from_buffer(const char* start, const char* end);
+ static Parser from_file(const char* path);
+
+ Parser& load_from_buffer(const char* data, std::size_t size);
+ Parser& load_from_buffer(const char* start, const char* end);
+ Parser& load_from_file(const char* path);
+ void set_error_log_to_null();
void set_error_log_to_stderr();
- void set_error_log_path(const char8_t* path);
- void set_error_log_to(std::basic_ostream<char8_t> stream);
- void set_error_log_to(std::FILE* file);
+ void set_error_log_to_stdout();
+ void set_error_log_to(std::basic_ostream<char>& stream);
- bool parse();
+ bool simple_parse();
- bool has_error();
- bool has_warning();
+ bool has_error() const;
+ bool has_fatal_error() const;
+ bool has_warning() const;
+
+ const std::vector<Error>& get_errors() const;
+ const std::vector<Warning>& get_warnings() const;
+
+ const FileNode* get_file_node() const;
+
+ Parser(Parser&&);
+ Parser& operator=(Parser&&);
+
+ ~Parser();
private:
- Parser();
+ std::vector<Error> _errors;
+ std::vector<Warning> _warnings;
+
+ class BufferHandler;
+ friend class BufferHandler;
+ std::unique_ptr<BufferHandler> _buffer_handler;
+ std::unique_ptr<FileNode> _file_node;
+ std::reference_wrapper<std::ostream> _error_stream;
+ const char* _file_path;
+ bool _has_fatal_error = false;
+
+ template<typename... Args>
+ inline void _run_load_func(std::optional<Error> (BufferHandler::*func)(Args...), Args... args);
};
} \ No newline at end of file