#ifndef YERBACON_PARSECOMPONENTS_HPP #define YERBACON_PARSECOMPONENTS_HPP #include #include #include #include #include #include #include #include using namespace std; #include "../lex.hpp" #include #define IS(X) template T = X> struct ParseComponent { [[nodiscard]] inline const type_info& getId() const { return typeid(*this); } virtual ~ParseComponent() = default; }; struct NamedIdentifier: virtual ParseComponent { const string name; explicit NamedIdentifier(string_view nameText): name(nameText) {} NamedIdentifier() = default; }; typedef unique_ptr component_ptr; #define IS_PARSECOMPONENT IS(ParseComponent) class ParseTree: public virtual ParseComponent { mutable vector subComponents; using array_type = decltype(subComponents); using iterator = array_type::iterator; using constant_iterator = array_type::const_iterator; protected: IS_PARSECOMPONENT void addComponent(const T& component) const { if constexpr(is_copy_constructible_v) { subComponents.emplace_back(new T(component)); } else { static_assert(is_move_constructible_v, "T is not copy-constructible or move-constructible"); subComponents.emplace_back(new T(move(const_cast(component)))); } }; IS_PARSECOMPONENT void addAllComponents( const initializer_list& components ) const { subComponents.reserve(components.size()); for (const T& current: components) addComponent(current); } public: inline size_t size() const { return subComponents.size(); } inline iterator begin() const noexcept { return subComponents.begin(); } inline constant_iterator cbegin() const noexcept { return subComponents.cbegin(); } inline iterator end() const noexcept { return subComponents.end(); } inline constant_iterator cend() const noexcept { return subComponents.cend(); } IS_PARSECOMPONENT vector findById() const { vector filteredComponents; for_each(cbegin(), cend(), [&filteredComponents](const component_ptr& it) { if (it->getId() == typeid(T)) { filteredComponents.push_back(dynamic_cast(it.get())); } }); return filteredComponents; } IS(NamedIdentifier) optional> findReferenceByName(const string& name) const { const vector identifiers = findById(); for (T* identifier: identifiers) { if (identifier->getId() == typeid(T) && identifier->name == name) { return make_optional(ref(static_cast(*identifier))); } } return optional>(); }; inline component_ptr& operator[](const unsigned int& index) const { return subComponents[index]; } inline component_ptr& at(const unsigned int& index) const { return subComponents.at(index); } IS(NamedIdentifier) inline auto operator[](const string& key) const { return findReferenceByName(key); } IS_PARSECOMPONENT inline void add(const T& component) { addComponent(component); } IS_PARSECOMPONENT inline void addAll(const initializer_list& components) { addAllComponents(components); } IS_PARSECOMPONENT inline ParseTree& operator<<(const T& component) { add(component); return *this; } ParseTree(): subComponents() {}; IS_PARSECOMPONENT inline explicit ParseTree(const T& element): ParseTree() { addComponent(element); } IS_PARSECOMPONENT inline ParseTree(const initializer_list& elements): ParseTree() { addAllComponents(elements); } ParseTree& operator=(ParseTree&& parseTree) noexcept { subComponents = move(parseTree.subComponents); return *this; } ParseTree(ParseTree&& parseTree) noexcept: subComponents(move(parseTree.subComponents)) {} ParseTree(const ParseTree& parseTree) = delete; }; #undef IS_PARSECOMPONENT namespace StandardComponents { struct Define: NamedIdentifier { const bool final; ParseTree content; explicit Define(const bool& isFinal, string_view nameText, ParseTree&& content): NamedIdentifier(nameText), final(isFinal), content(move(content)) {} explicit Define(string_view nameText, ParseTree&& content): Define(false, nameText, move(content)) {} Define(Define&& define) noexcept: Define(define.final, define.name, move(define.content)) {} }; struct Reference: NamedIdentifier { using NamedIdentifier::NamedIdentifier; }; namespace types { struct String: ParseComponent { const string content; explicit String(const char* string): content(string) {} }; } struct Call: ParseTree, Reference { using Reference::Reference; }; struct Function: NamedIdentifier, ParseTree { ParseTree parameters; using NamedIdentifier::NamedIdentifier; }; struct Class: NamedIdentifier { ParseTree body; using NamedIdentifier::NamedIdentifier; }; } #endif //YERBACON_PARSECOMPONENTS_HPP