183 lines
8.0 KiB
C++
183 lines
8.0 KiB
C++
#ifndef YERBACON_PARSECOMPONENTS_HPP
|
|
#define YERBACON_PARSECOMPONENTS_HPP
|
|
|
|
#include <iostream>
|
|
#include <memory>
|
|
#include <utility>
|
|
#include <vector>
|
|
#include <typeinfo>
|
|
#include <memory>
|
|
#include <optional>
|
|
#include <algorithm>
|
|
#include "ReservedIdentifiers.hpp"
|
|
using namespace std;
|
|
|
|
#include "../lex.hpp"
|
|
|
|
#include <concepts>
|
|
#define IS(X) template<derived_from<X> T = X>
|
|
struct ParseComponent {
|
|
[[nodiscard]] inline const type_info& getId() const { return typeid(*this); }
|
|
virtual ~ParseComponent() = default;
|
|
};
|
|
template<bool disallow_reserved>
|
|
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<ParseComponent> component_ptr;
|
|
|
|
#define IS_PARSECOMPONENT IS(ParseComponent)
|
|
#define IS_IDENTIFIER enable_if_t<is_base_of_v<NamedIdentifier<false>, T> or is_base_of_v<NamedIdentifier<true>, T>, T>
|
|
class ParseTree: public virtual ParseComponent {
|
|
mutable vector<component_ptr> 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<T>) {
|
|
subComponents.emplace_back(new T(component));
|
|
} else {
|
|
static_assert(is_move_constructible_v<T>, "T is not copy-constructible or move-constructible");
|
|
subComponents.emplace_back(new T(move(const_cast<T&>(component))));
|
|
}
|
|
};
|
|
IS_PARSECOMPONENT
|
|
void addAllComponents(
|
|
const initializer_list<T>& components
|
|
) const {
|
|
subComponents.reserve(subComponents.size() + components.size());
|
|
for (const T& current: components) addComponent<T>(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<T*> findById() const {
|
|
vector<T*> filteredComponents;
|
|
for_each(cbegin(), cend(), [&filteredComponents](const component_ptr& it) {
|
|
if (it->getId() == typeid(T)) {
|
|
filteredComponents.push_back(dynamic_cast<T*>(to_address(it)));
|
|
}
|
|
});
|
|
return filteredComponents;
|
|
}
|
|
template<typename T>
|
|
optional<reference_wrapper<IS_IDENTIFIER>> findReferenceByName(const string& name) const {
|
|
const vector<T*> identifiers = findById<T>();
|
|
for (T* identifier: identifiers) {
|
|
if (identifier->getId() == typeid(T) && identifier->name == name) {
|
|
return make_optional(ref(static_cast<T&>(*identifier)));
|
|
}
|
|
}
|
|
return optional<reference_wrapper<T>>();
|
|
};
|
|
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<typename T>
|
|
inline auto operator[](const string& key) const { return findReferenceByName<IS_IDENTIFIER>(key); }
|
|
IS_PARSECOMPONENT inline void add(const T& component) { addComponent<T>(component); }
|
|
IS_PARSECOMPONENT inline void addAll(const initializer_list<T>& components) { addAllComponents<T>(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<T>& 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<true> {
|
|
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<false> {
|
|
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<tok::type> 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<ParseComponent> 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<const Branch*>(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<true>, ParseTree {
|
|
ParseTree parameters;
|
|
using NamedIdentifier::NamedIdentifier;
|
|
};
|
|
struct Class: NamedIdentifier<true>, ParseTree {
|
|
using NamedIdentifier::NamedIdentifier;
|
|
};
|
|
}
|
|
|
|
ParseTree& ParseTree::operator<<(const string& text) {
|
|
return *this << StandardComponents::types::String(text);
|
|
}
|
|
|
|
#endif //YERBACON_PARSECOMPONENTS_HPP
|