2023-07-18 16:45:35 +03:00
|
|
|
#pragma once
|
|
|
|
|
|
2023-08-12 14:36:00 +03:00
|
|
|
#include "utils.hpp"
|
2024-03-11 00:33:53 +03:00
|
|
|
|
2023-07-18 16:45:35 +03:00
|
|
|
#include <optional>
|
2024-03-11 00:33:53 +03:00
|
|
|
#include <ranges>
|
2023-07-18 16:45:35 +03:00
|
|
|
#include <string>
|
|
|
|
|
#include <utility>
|
|
|
|
|
#include <variant>
|
2024-03-11 00:33:53 +03:00
|
|
|
#include <vector>
|
2023-07-18 16:45:35 +03:00
|
|
|
|
|
|
|
|
namespace nodes {
|
|
|
|
|
|
2023-07-23 19:40:27 +03:00
|
|
|
enum class Modifier {
|
2023-07-31 22:07:32 +03:00
|
|
|
IN, // <- x
|
|
|
|
|
REF, // <> x
|
2023-08-13 12:47:32 +03:00
|
|
|
CONST, // -- x (or x sometimes)
|
2023-07-31 22:07:32 +03:00
|
|
|
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
|
2023-08-12 14:36:00 +03:00
|
|
|
REF_OR_CONST_OR_OUT, // <>|--|-> x
|
|
|
|
|
//
|
|
|
|
|
IN_OR_REF_OR_CONST_OR_OUT, // <-|<>|--|-> x
|
|
|
|
|
//
|
|
|
|
|
OPTIONAL, // x?
|
|
|
|
|
RESULT, // x!
|
2023-07-31 22:07:32 +03:00
|
|
|
//
|
2023-07-23 19:40:27 +03:00
|
|
|
NONE,
|
|
|
|
|
};
|
2023-07-20 14:38:44 +03:00
|
|
|
|
2023-08-12 14:36:00 +03:00
|
|
|
namespace utils {
|
|
|
|
|
|
2023-08-13 12:47:32 +03:00
|
|
|
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
|
2023-08-12 14:36:00 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace utils
|
|
|
|
|
|
2023-07-18 16:45:35 +03:00
|
|
|
class Node {
|
|
|
|
|
public:
|
2023-08-12 14:36:00 +03:00
|
|
|
Node() : undefined_(true) {}
|
|
|
|
|
|
2023-07-18 16:45:35 +03:00
|
|
|
Node(std::pair<size_t, size_t> start_position,
|
|
|
|
|
std::pair<size_t, size_t> end_position)
|
2023-08-12 14:36:00 +03:00
|
|
|
: undefined_(false), start_position_(start_position),
|
|
|
|
|
end_position_(end_position) {}
|
2023-07-18 16:45:35 +03:00
|
|
|
|
2023-07-28 17:58:45 +03:00
|
|
|
std::pair<size_t, size_t> get_start_position() const {
|
2023-08-12 14:36:00 +03:00
|
|
|
if (undefined_) {
|
|
|
|
|
error_handling::handle_general_error(
|
|
|
|
|
"Get start position from undefined node");
|
|
|
|
|
}
|
2023-07-28 17:58:45 +03:00
|
|
|
return start_position_;
|
|
|
|
|
}
|
2023-07-18 16:45:35 +03:00
|
|
|
|
2023-08-12 14:36:00 +03:00
|
|
|
std::pair<size_t, size_t> get_end_position() const {
|
|
|
|
|
if (undefined_) {
|
|
|
|
|
error_handling::handle_general_error(
|
|
|
|
|
"Get end position from undefined node");
|
|
|
|
|
}
|
|
|
|
|
return end_position_;
|
|
|
|
|
}
|
2023-07-18 16:45:35 +03:00
|
|
|
|
|
|
|
|
protected:
|
2023-08-12 14:36:00 +03:00
|
|
|
bool undefined_ = false;
|
|
|
|
|
|
|
|
|
|
std::pair<size_t, size_t> start_position_ = {0, 0};
|
|
|
|
|
std::pair<size_t, size_t> end_position_ = {0, 0};
|
2023-07-18 16:45:35 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct unit {};
|
|
|
|
|
struct null {};
|
|
|
|
|
|
2023-08-12 15:55:33 +03:00
|
|
|
struct unicode_string {
|
|
|
|
|
std::string str;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct unicode {
|
|
|
|
|
std::string ch;
|
|
|
|
|
};
|
|
|
|
|
|
2023-07-18 16:45:35 +03:00
|
|
|
class Literal : public Node {
|
|
|
|
|
public:
|
|
|
|
|
template <typename T>
|
|
|
|
|
Literal(Node node, T &&value) : Node(node), value_(std::forward<T>(value)) {}
|
|
|
|
|
|
|
|
|
|
template <typename T> std::optional<T *> get() {
|
|
|
|
|
if (std::holds_alternative<T>(value_)) {
|
|
|
|
|
return &std::get<T>(value_);
|
|
|
|
|
}
|
|
|
|
|
return std::nullopt;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename T> std::optional<const T *> get() const {
|
|
|
|
|
if (std::holds_alternative<T>(value_)) {
|
|
|
|
|
return &std::get<T>(value_);
|
|
|
|
|
}
|
|
|
|
|
return std::nullopt;
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-25 21:33:57 +03:00
|
|
|
auto get_any() { return &value_; }
|
2023-07-24 18:47:57 +03:00
|
|
|
|
2023-07-25 21:33:57 +03:00
|
|
|
auto get_any() const { return &value_; }
|
2023-07-24 18:47:57 +03:00
|
|
|
|
2023-07-18 16:45:35 +03:00
|
|
|
private:
|
2023-08-12 15:55:33 +03:00
|
|
|
std::variant<float, double, int32_t, int64_t, size_t, std::string,
|
|
|
|
|
unicode_string, char, unicode, bool, unit, null>
|
|
|
|
|
value_;
|
2023-07-18 16:45:35 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class Identifier : public Node {
|
|
|
|
|
public:
|
2024-03-11 00:33:53 +03:00
|
|
|
static constexpr char NAME_DELIMITER = '.';
|
|
|
|
|
|
2023-07-18 16:45:35 +03:00
|
|
|
enum IdentifierType {
|
|
|
|
|
SIMPLE_NAME,
|
|
|
|
|
SIMPLE_TYPE,
|
|
|
|
|
TYPECLASS,
|
|
|
|
|
ARGUMENT_NAME,
|
|
|
|
|
ARGUMENT_TYPE,
|
|
|
|
|
// ANNOTATION, used as std::string
|
|
|
|
|
OPERATOR,
|
|
|
|
|
PLACEHOLDER,
|
2023-08-14 21:30:06 +03:00
|
|
|
//
|
|
|
|
|
GENERIC_TYPE,
|
2023-07-18 16:45:35 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
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) {}
|
|
|
|
|
|
2023-07-25 21:33:57 +03:00
|
|
|
IdentifierType get_type() const { return type_; }
|
2023-07-18 16:45:35 +03:00
|
|
|
|
2023-07-31 22:07:32 +03:00
|
|
|
//
|
|
|
|
|
|
2023-07-18 16:45:35 +03:00
|
|
|
std::string *get() { return &value_; }
|
|
|
|
|
|
|
|
|
|
const std::string *get() const { return &value_; }
|
|
|
|
|
|
2023-07-31 22:07:32 +03:00
|
|
|
//
|
|
|
|
|
|
2024-03-11 00:33:53 +03:00
|
|
|
void append_before(const std::string &name) {
|
|
|
|
|
value_ = name + NAME_DELIMITER + value_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void append_before(
|
|
|
|
|
const Identifier &identifier,
|
|
|
|
|
std::source_location location = std::source_location::current()) {
|
|
|
|
|
error_handling::expect(identifier.type_ == type_,
|
|
|
|
|
"different Identifier types on append_before",
|
|
|
|
|
location);
|
|
|
|
|
value_ = *identifier.get() + NAME_DELIMITER + value_;
|
|
|
|
|
}
|
2023-07-31 22:07:32 +03:00
|
|
|
|
|
|
|
|
void append_after(const std::string &name) {
|
2024-03-11 00:33:53 +03:00
|
|
|
value_ += NAME_DELIMITER + name;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void append_after(
|
|
|
|
|
const Identifier &identifier,
|
|
|
|
|
std::source_location location = std::source_location::current()) {
|
|
|
|
|
error_handling::expect(identifier.type_ == type_,
|
|
|
|
|
"different Identifier types on append_after",
|
|
|
|
|
location);
|
|
|
|
|
value_ += NAME_DELIMITER + *identifier.get();
|
|
|
|
|
}
|
|
|
|
|
|
2024-04-06 14:04:15 +03:00
|
|
|
std::vector<Identifier> get_fragments() const {
|
2024-03-11 00:33:53 +03:00
|
|
|
std::vector<Identifier> fragments;
|
|
|
|
|
for (auto &&fragment_name :
|
|
|
|
|
std::ranges::views::split(value_, NAME_DELIMITER)) {
|
|
|
|
|
fragments.emplace_back(
|
|
|
|
|
*this, type_,
|
|
|
|
|
std::string(fragment_name.begin(), fragment_name.end()));
|
|
|
|
|
}
|
|
|
|
|
return fragments;
|
2024-02-23 16:20:02 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::pair<Identifier, Identifier> split_first() {
|
2024-03-11 00:33:53 +03:00
|
|
|
const auto pos = value_.find(NAME_DELIMITER);
|
2024-02-23 16:20:02 +03:00
|
|
|
if (pos == std::string::npos) {
|
|
|
|
|
return {Identifier(*this, type_, ""), *this};
|
|
|
|
|
}
|
2024-03-11 00:33:53 +03:00
|
|
|
return {
|
|
|
|
|
Identifier(*this, type_, value_.substr(0, pos)),
|
|
|
|
|
Identifier(*this, type_, value_.substr(pos + 1))}; // '.' is leaved out
|
2023-07-31 22:07:32 +03:00
|
|
|
}
|
|
|
|
|
|
2023-08-02 13:10:16 +03:00
|
|
|
//
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-12 14:36:00 +03:00
|
|
|
bool operator<(const Identifier &other_identifier) const {
|
|
|
|
|
return type_ < other_identifier.type_ || (type_ == other_identifier.type_ &&
|
|
|
|
|
value_ < other_identifier.value_);
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-18 16:45:35 +03:00
|
|
|
private:
|
|
|
|
|
IdentifierType type_;
|
|
|
|
|
std::string value_;
|
|
|
|
|
};
|
|
|
|
|
|
2023-07-31 22:07:32 +03:00
|
|
|
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_;
|
|
|
|
|
};
|
|
|
|
|
|
2023-07-25 21:33:57 +03:00
|
|
|
class EmptyLines : public Node {
|
|
|
|
|
public:
|
2023-07-31 22:07:32 +03:00
|
|
|
EmptyLines(Node node, size_t line_count)
|
|
|
|
|
: Node(node), line_count_(line_count) {}
|
2023-07-25 21:33:57 +03:00
|
|
|
|
2023-07-31 22:07:32 +03:00
|
|
|
size_t line_count() const { return line_count_; }
|
2023-07-25 21:33:57 +03:00
|
|
|
|
|
|
|
|
private:
|
2023-07-31 22:07:32 +03:00
|
|
|
size_t line_count_;
|
2023-07-25 21:33:57 +03:00
|
|
|
};
|
|
|
|
|
|
2023-07-18 16:45:35 +03:00
|
|
|
} // namespace nodes
|