#pragma once #include "utils.hpp" #include #include #include #include namespace nodes { enum class Modifier { IN, // <- x REF, // <> x CONST, // -- x (or x sometimes) OUT, // -> x // IN_OR_REF, // <-|<> x IN_OR_CONST, // <-|-- x REF_OR_OUT, // <>|-> x CONST_OR_OUT, // --|-> x REF_OR_CONST, // <>|-- x IN_OR_OUT, // <-|-> x // IN_OR_REF_OR_OUT, // <-|<>|-> x IN_OR_CONST_OR_OUT, // <-|--|-> x IN_OR_REF_OR_CONST, // <-|<>|-- x REF_OR_CONST_OR_OUT, // <>|--|-> x // IN_OR_REF_OR_CONST_OR_OUT, // <-|<>|--|-> x // OPTIONAL, // x? RESULT, // x! // NONE, }; namespace utils { inline bool is_suffix_modifier(Modifier modifier) { return modifier == Modifier::OPTIONAL || modifier == Modifier::RESULT; } inline bool modifier_contains_IN(Modifier modifier) { return modifier == Modifier::IN || // modifier == Modifier::IN_OR_REF || // modifier == Modifier::IN_OR_CONST || // modifier == Modifier::IN_OR_OUT || // modifier == Modifier::IN_OR_REF_OR_OUT || // modifier == Modifier::IN_OR_CONST_OR_OUT || // modifier == Modifier::IN_OR_REF_OR_CONST || // modifier == Modifier::IN_OR_REF_OR_CONST_OR_OUT; // } inline bool modifier_contains_REF(Modifier modifier) { return modifier == Modifier::REF || // modifier == Modifier::IN_OR_REF || // modifier == Modifier::REF_OR_OUT || // modifier == Modifier::REF_OR_CONST || // modifier == Modifier::IN_OR_REF_OR_OUT || // modifier == Modifier::IN_OR_REF_OR_CONST || // modifier == Modifier::REF_OR_CONST_OR_OUT || // modifier == Modifier::IN_OR_REF_OR_CONST_OR_OUT; // } inline bool modifier_contains_CONST(Modifier modifier) { return modifier == Modifier::CONST || // modifier == Modifier::IN_OR_CONST || // modifier == Modifier::CONST_OR_OUT || // modifier == Modifier::REF_OR_CONST || // modifier == Modifier::IN_OR_CONST_OR_OUT || // modifier == Modifier::IN_OR_REF_OR_CONST || // modifier == Modifier::REF_OR_CONST_OR_OUT || // modifier == Modifier::IN_OR_REF_OR_CONST_OR_OUT; // } inline bool modifier_contains_OUT(Modifier modifier) { return modifier == Modifier::OUT || // modifier == Modifier::REF_OR_OUT || // modifier == Modifier::CONST_OR_OUT || // modifier == Modifier::IN_OR_OUT || // modifier == Modifier::IN_OR_REF_OR_OUT || // modifier == Modifier::IN_OR_CONST_OR_OUT || // modifier == Modifier::REF_OR_CONST_OR_OUT || // modifier == Modifier::IN_OR_REF_OR_CONST_OR_OUT; // } // possible casts: // <> => -> // <> => <- // <> => -- inline bool can_cast_modifier(Modifier from, Modifier to) { if (is_suffix_modifier(from) || is_suffix_modifier(to) || from == Modifier::NONE || to == Modifier::NONE) { return false; } switch (from) { case Modifier::IN: // // <- x return modifier_contains_IN(to); // case Modifier::REF: // // <> x return true; // case Modifier::CONST: // // -- x (or x sometimes) return modifier_contains_CONST(to); // case Modifier::OUT: // // -> x return modifier_contains_OUT(to); // // case Modifier::IN_OR_REF: // // <-|<> x return modifier_contains_IN(to); // case Modifier::IN_OR_CONST: // // <-|-- x return modifier_contains_IN(to) && // modifier_contains_CONST(to); // case Modifier::REF_OR_OUT: // // <>|-> x return modifier_contains_OUT(to); // case Modifier::CONST_OR_OUT: // // --|-> x return modifier_contains_CONST(to) && // modifier_contains_OUT(to); // case Modifier::REF_OR_CONST: // // <>|-- x return modifier_contains_CONST(to); // case Modifier::IN_OR_OUT: // // <-|-> x return modifier_contains_IN(to) && // modifier_contains_OUT(to); // // case Modifier::IN_OR_REF_OR_OUT: // // <-|<>|-> x return modifier_contains_IN(to) && // modifier_contains_OUT(to); // case Modifier::IN_OR_CONST_OR_OUT: // // <-|--|-> x return modifier_contains_IN(to) && // modifier_contains_CONST(to) && // modifier_contains_OUT(to); // case Modifier::IN_OR_REF_OR_CONST: // // <-|<>|-- x return modifier_contains_IN(to) && // modifier_contains_CONST(to); // case Modifier::REF_OR_CONST_OR_OUT: // // <>|--|-> x return modifier_contains_CONST(to) && // modifier_contains_OUT(to); // // case Modifier::IN_OR_REF_OR_CONST_OR_OUT: // // <-|<>|--|-> x return modifier_contains_IN(to) && // modifier_contains_CONST(to) && // modifier_contains_OUT(to); // default: break; } error_handling::handle_general_error("Unreachable"); exit(1); // unreachable } } // namespace utils class Node { public: Node() : undefined_(true) {} Node(std::pair start_position, std::pair end_position) : undefined_(false), start_position_(start_position), end_position_(end_position) {} std::pair get_start_position() const { if (undefined_) { error_handling::handle_general_error( "Get start position from undefined node"); } return start_position_; } std::pair get_end_position() const { if (undefined_) { error_handling::handle_general_error( "Get end position from undefined node"); } return end_position_; } protected: bool undefined_ = false; std::pair start_position_ = {0, 0}; std::pair end_position_ = {0, 0}; }; struct unit {}; struct null {}; struct unicode_string { std::string str; }; struct unicode { std::string ch; }; class Literal : public Node { public: template Literal(Node node, T &&value) : Node(node), value_(std::forward(value)) {} template std::optional get() { if (std::holds_alternative(value_)) { return &std::get(value_); } return std::nullopt; } template std::optional get() const { if (std::holds_alternative(value_)) { return &std::get(value_); } return std::nullopt; } auto get_any() { return &value_; } auto get_any() const { return &value_; } private: std::variant value_; }; class Identifier : public Node { public: enum IdentifierType { SIMPLE_NAME, SIMPLE_TYPE, TYPECLASS, ARGUMENT_NAME, ARGUMENT_TYPE, // ANNOTATION, used as std::string OPERATOR, PLACEHOLDER, // GENERIC_TYPE, }; Identifier(Node node, IdentifierType type, std::string &&value) : Node(node), type_(type), value_(std::move(value)) {} Identifier(Node node, IdentifierType type, const std::string &value) : Node(node), type_(type), value_(value) {} IdentifierType get_type() const { return type_; } // std::string *get() { return &value_; } const std::string *get() const { return &value_; } // void append_before(const std::string &name) { value_ = name + "." + value_; } void append_after(const std::string &name) { value_ += "."; value_ += name; } // bool operator==(const Identifier &other_identifier) const { return type_ == other_identifier.type_ && value_ == other_identifier.value_; } bool operator!=(const Identifier &other_identifier) const { return !(*this == other_identifier); } bool operator<(const Identifier &other_identifier) const { return type_ < other_identifier.type_ || (type_ == other_identifier.type_ && value_ < other_identifier.value_); } private: IdentifierType type_; std::string value_; }; class Extra : public Node { public: Extra(Node node, std::string &&content) : Node(node), content_(std::move(content)) {} Extra(Node node, const std::string &content) : Node(node), content_(content) {} std::string *content() { return &content_; } const std::string *content() const { return &content_; } private: std::string content_; }; class EmptyLines : public Node { public: EmptyLines(Node node, size_t line_count) : Node(node), line_count_(line_count) {} size_t line_count() const { return line_count_; } private: size_t line_count_; }; } // namespace nodes