#pragma once #include #include #include #include #include #include // for clangd #include "error_handling.hpp" #include "typeclass_graph.hpp" #include "utils.hpp" namespace info::type { // TODO: move in constructors class TypeManager; class AbstractType { // latter will be found in context public: AbstractType(utils::AbstractTypeModifier modifier, utils::IdType graph_id, info::TypeclassGraph& typeclass_graph) : modifier_(modifier), graph_id_(graph_id), typeclass_graph_(typeclass_graph) {} std::optional InContext(const std::unordered_map& context); bool Same(const AbstractType& type) const; bool operator<(const AbstractType& type) const; bool operator>(const AbstractType& type) const; std::optional GetFieldType(const std::string& name, const std::unordered_set& type_namespaces) const; utils::IdType GetGraphId() { return graph_id_; } bool HasTypeclass(utils::IdType graph_id) { // TODO: cache dependencies set return graph_id == graph_id_ || typeclass_graph_.GetDependenciesSet(graph_id_).count(graph_id) != 0; } std::string ToString() { return "Abstract " + std::to_string(graph_id_); } private: utils::AbstractTypeModifier modifier_; utils::IdType graph_id_; info::TypeclassGraph& typeclass_graph_; }; class DefinedType { public: DefinedType() = default; DefinedType(utils::IdType type_id, utils::IdType type, utils::ClassModifier class_modifier, TypeManager* type_manager) : type_id_(type_id), type_(type), class_modifier_(class_modifier), type_manager_(type_manager) {} std::optional InContext(const std::unordered_map& context); bool Same(const DefinedType& type) const; bool operator<(const DefinedType& type) const; bool operator>(const DefinedType& type) const; std::optional GetFieldType(const std::string& name, const std::unordered_set& type_namespaces) const; utils::IdType GetTypeId() const { return type_id_; } utils::IdType GetType() const { return type_; } utils::ClassModifier GetClassModifier() const { return class_modifier_; } std::string ToString() { return "Defined"; } private: utils::IdType type_id_; // in defined types utils::IdType type_; // in types manager, created using context types (if specific type) utils::ClassModifier class_modifier_; TypeManager* type_manager_ = nullptr; }; const size_t InternalTypesCount = 6; enum class InternalType { Float = 0, Int = 1, String = 2, Char = 3, Bool = 4, Unit = 5, }; inline std::optional ToInternalType(const std::string& type) { if (type.empty()) { return std::nullopt; } switch (type[0]) { case 'F': if (type == "Float") { return InternalType::Float; } break; case 'I': if (type == "Int") { return InternalType::Int; } break; case 'S': if (type == "String") { return InternalType::String; } break; case 'C': if (type == "Char") { return InternalType::Char; } break; case 'B': if (type == "Bool") { return InternalType::Bool; } break; case 'U': if (type == "Unit") { return InternalType::Unit; } break; default: break; } return std::nullopt; } inline std::string ToString(InternalType type) { std::string result; switch (type) { case InternalType::Float: result = "Float"; break; case InternalType::Int: result = "Int"; break; case InternalType::String: result = "String"; break; case InternalType::Char: result = "Char"; break; case InternalType::Bool: result = "Bool"; break; case InternalType::Unit: result = "Unit"; break; } return result; } class TupleType { public: TupleType() = default; TupleType(const std::optional& name, const std::vector, utils::IdType>>& fields, TypeManager* type_manager) : name_(name), fields_(fields), type_manager_(type_manager) {} std::optional InContext(const std::unordered_map& context); bool Same(const TupleType& type) const; bool operator<(const TupleType& type) const; bool operator>(const TupleType& type) const; std::optional GetFieldType(const std::string& name, const std::unordered_set& type_namespaces) const; const std::vector, utils::IdType>>& GetFields() const { return fields_; } std::string ToString(); private: std::optional name_; std::vector, utils::IdType>> fields_; TypeManager* type_manager_ = nullptr; }; class VariantType { public: VariantType() = default; VariantType(const std::optional& name, const std::vector& constructors, std::optional current_constructor) : name_(name), constructors_(constructors), current_constructor_(current_constructor) {} std::optional InContext(const std::unordered_map& context); bool Same(const VariantType& type) const; bool operator<(const VariantType& type) const; bool operator>(const VariantType& type) const; std::optional GetFieldType(const std::string& name, const std::unordered_set& type_namespaces) const; const std::vector& GetConstructors() const { return constructors_; } void SetCurrentConstructor(size_t constructor) { current_constructor_ = constructor; } std::string ToString(); private: std::optional name_; std::vector constructors_; std::optional current_constructor_; }; class OptionalType { public: OptionalType() = default; OptionalType(utils::IdType type, TypeManager* type_manager) : type_(type), type_manager_(type_manager) {} std::optional InContext(const std::unordered_map& context); bool Same(const OptionalType& type) const; bool operator<(const OptionalType& type) const; bool operator>(const OptionalType& type) const; std::optional GetFieldType(const std::string& name, const std::unordered_set& type_namespaces) const; std::string ToString(); private: utils::IdType type_; TypeManager* type_manager_ = nullptr; }; class ReferenceToType { public: ReferenceToType() = default; ReferenceToType(const std::vector& references, utils::IdType type, TypeManager* type_manager) : references_(references), type_(type), type_manager_(type_manager) {} std::optional InContext(const std::unordered_map& context); bool Same(const ReferenceToType& type) const; bool operator<(const ReferenceToType& type) const; bool operator>(const ReferenceToType& type) const; std::optional GetFieldType(const std::string& name, const std::unordered_set& type_namespaces) const; std::string ToString(); private: std::vector references_; utils::IdType type_; TypeManager* type_manager_ = nullptr; }; ///////////////////////////// class FunctionType { public: FunctionType() = default; FunctionType(const std::vector& argument_types, utils::IdType return_type, TypeManager* type_manager) : argument_types_(argument_types), return_type_(return_type), type_manager_(type_manager) {} std::optional InContext(const std::unordered_map& context); bool Same(const FunctionType& type) const; bool operator<(const FunctionType& type) const; bool operator>(const FunctionType& type) const; std::optional GetFieldType(const std::string& name, const std::unordered_set& type_namespaces) const; std::string ToString(); private: std::vector argument_types_; utils::IdType return_type_; TypeManager* type_manager_ = nullptr; }; class ArrayType { public: ArrayType() = default; ArrayType(size_t size, utils::IdType elements_type, TypeManager* type_manager) : size_(size), elements_type_(elements_type), type_manager_(type_manager) {} std::optional InContext(const std::unordered_map& context); bool Same(const ArrayType& type) const; bool operator<(const ArrayType& type) const; bool operator>(const ArrayType& type) const; std::optional GetFieldType(const std::string& name, const std::unordered_set& type_namespaces) const; utils::IdType GetElementsType() { return elements_type_; } std::string ToString(); private: size_t size_; // = 0 for dynamic utils::IdType elements_type_; TypeManager* type_manager_ = nullptr; }; class Type { public: template explicit Type(const T& type) : type_(type) {} std::optional InContext(const std::unordered_map& context); bool Same(const Type& type) const; bool operator<(const Type& type) const; // TODO: rule exceptions bool operator>(const Type& type) const; std::optional GetFieldType(const std::string& name, const std::unordered_set& type_namespaces) const; std::string GetTypeName() const; std::variant& GetType() { return type_; } std::string ToString(); private: std::variant type_; }; class TypeManager { public: template utils::IdType AddValue(const T& type, utils::ValueType value_type) { types_.push_back(std::pair {type, value_type}); return types_.size() - 1; } utils::IdType AddAnyValue(Type&& type, utils::ValueType value_type) { types_.push_back(std::pair {std::move(type), value_type}); return types_.size() - 1; } template std::optional GetValue(utils::IdType type_id) { if (!std::holds_alternative(types_.at(type_id).first.GetType())) { return std::nullopt; } return &std::get(types_.at(type_id).first.GetType()); } Type* GetAnyValue(utils::IdType type_id) { return &types_.at(type_id).first; } utils::ValueType GetValueType(utils::IdType type_id) { return types_.at(type_id).second; } bool EqualValues(utils::IdType first_type, utils::IdType second_type) { return GetAnyValue(first_type)->Same(*GetAnyValue(second_type)); } bool AddValueRequirement(utils::IdType type, utils::IdType requrement) { return *GetAnyValue(requrement) < *GetAnyValue(type); } private: std::vector> types_; }; } // namespace info::type