#ifndef YERBACON_PARSECOMPONENTS_HPP #define YERBACON_PARSECOMPONENTS_HPP #include #include #include #include #include #include #include #include #include "ReservedIdentifiers.hpp" 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; }; template struct NamedIdentifier: virtual ParseComponent { struct identifier_reserved_exception: exception {}; const string name; explicit NamedIdentifier(const string_view nameText): name(nameText) { if (disallow_reserved and reserved(name)) { throw identifier_reserved_exception(); } } NamedIdentifier() = delete; }; typedef unique_ptr component_ptr; #define IS_PARSECOMPONENT IS(ParseComponent) #define IS_IDENTIFIER enable_if_t, T> or is_base_of_v, T>, T> 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(subComponents.size() + components.size()); for (const T& current: components) addComponent(current); } public: inline size_t size() const { return subComponents.size(); } inline bool empty() const { return size() == 0; } inline iterator begin() noexcept { return subComponents.begin(); } inline constant_iterator begin() const noexcept { return cbegin(); } inline constant_iterator cbegin() const noexcept { return subComponents.cbegin(); } inline iterator end() noexcept { return subComponents.end(); } inline constant_iterator end() const noexcept { return cend(); } 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(to_address(it))); } }); return filteredComponents; } template 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); } template 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& operator<<(const string&); 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 Integer: ParseComponent { typedef uint_fast8_t precision_type; const long double value; const precision_type precision; Integer(const long double& value, const precision_type& precision): value(value), precision(precision) {} }; struct String: ParseComponent { const string content; explicit String(string content_string): content(move(content_string)) {} }; } struct Call: ParseTree, Reference { using Reference::Reference; }; struct Operator: ParseComponent { // TODO Parse operators in Parser.hpp tok::type operator_type; Operator(const convertible_to auto& operator_token): operator_type() { using enum tok::type; static_assert((operator_token == PLUS or operator_token == HYPHEN or operator_token == ASTERISK or operator_token == DIVIDE or operator_token == LCOMP or operator_token == RCOMP)); operator_type = operator_token; } }; struct Condition: ParseTree { Condition(const ParseTree left, const ParseTree right, const Operator& operator_token) { *this << left << operator_token << right; } explicit Condition(const derived_from auto condition) { *this << condition; } struct Statement; protected: Condition() = default; }; struct Condition::Statement: ParseTree { struct Branch; Condition condition; ParseTree else_branches; bool is_last_branch_conditional() const; Statement(Condition _condition): ParseTree(), condition(move(_condition)), else_branches() {} protected: Statement(): condition(), else_branches() {} }; struct Condition::Statement::Branch: Condition::Statement { inline bool is_conditional() const { return not condition.empty(); }; using Condition::Statement::Statement; Branch(): Condition::Statement() {}; private: using Condition::Statement::is_last_branch_conditional; }; bool Condition::Statement::is_last_branch_conditional() const { const auto* last = (not else_branches.empty()) ? dynamic_cast(else_branches[else_branches.size() - 1].get()) : nullptr; return (last == nullptr and (not this->condition.empty())) or (last != nullptr and not last->condition.empty()); } struct Function: NamedIdentifier, ParseTree { ParseTree parameters; using NamedIdentifier::NamedIdentifier; }; struct Class: NamedIdentifier, ParseTree { using NamedIdentifier::NamedIdentifier; }; } ParseTree& ParseTree::operator<<(const string& text) { return *this << StandardComponents::types::String(text); } #endif //YERBACON_PARSECOMPONENTS_HPP