lang/include/nodes/basic_nodes.hpp

354 lines
10 KiB
C++
Raw Normal View History

2023-07-18 16:45:35 +03:00
#pragma once
#include "utils.hpp"
2023-07-18 16:45:35 +03:00
#include <optional>
#include <ranges>
2023-07-18 16:45:35 +03:00
#include <string>
#include <utility>
#include <variant>
#include <vector>
2023-07-18 16:45:35 +03:00
namespace nodes {
2023-07-23 19:40:27 +03:00
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!
//
2023-07-23 19:40:27 +03:00
NONE,
};
2023-07-20 14:38:44 +03:00
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
2023-07-18 16:45:35 +03:00
class Node {
public:
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)
: undefined_(false), start_position_(start_position),
end_position_(end_position) {}
2023-07-18 16:45:35 +03:00
std::pair<size_t, size_t> get_start_position() const {
if (undefined_) {
error_handling::handle_general_error(
"Get start position from undefined node");
}
return start_position_;
}
2023-07-18 16:45:35 +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:
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-25 21:33:57 +03:00
auto get_any() const { return &value_; }
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:
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,
//
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-18 16:45:35 +03:00
std::string *get() { return &value_; }
const std::string *get() const { return &value_; }
//
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_;
}
void append_after(const std::string &name) {
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 {
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;
}
std::pair<Identifier, Identifier> split_first() {
const auto pos = value_.find(NAME_DELIMITER);
if (pos == std::string::npos) {
return {Identifier(*this, type_, ""), *this};
}
return {
Identifier(*this, type_, value_.substr(0, pos)),
Identifier(*this, type_, value_.substr(pos + 1))}; // '.' is leaved out
}
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);
}
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_;
};
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:
EmptyLines(Node node, size_t line_count)
: Node(node), line_count_(line_count) {}
2023-07-25 21:33:57 +03:00
size_t line_count() const { return line_count_; }
2023-07-25 21:33:57 +03:00
private:
size_t line_count_;
2023-07-25 21:33:57 +03:00
};
2023-07-18 16:45:35 +03:00
} // namespace nodes