mirror of
https://codeberg.org/ProgramSnail/lang.git
synced 2025-12-05 22:48:43 +00:00
type node refactoring
This commit is contained in:
parent
361a267054
commit
662a846d2d
11 changed files with 564 additions and 415 deletions
|
|
@ -246,7 +246,7 @@ BuilderTask<nodes::TypeDefinition>::operator()(const ParserNode &parser_node,
|
|||
std::unordered_set<std::string> annotations;
|
||||
|
||||
if (type.has_value()) {
|
||||
type.value().get()->collect_annotations_recursively(
|
||||
type.value().get().CollectAnnotationsRecursively(
|
||||
std::insert_iterator<std::unordered_set<std::string>>(
|
||||
annotations, annotations.begin()));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ std::vector<nodes::Type> collect_parameters(parser::ParseTree::Node first_node,
|
|||
parameters.push_back(
|
||||
BuilderTask<nodes::Type>{executor}(current_node, {}));
|
||||
if (current_annotation.has_value()) {
|
||||
parameters.back().get()->set_annotation(current_annotation.value());
|
||||
parameters.back().get().annotation = current_annotation.value();
|
||||
}
|
||||
}
|
||||
current_node = current_node.next_named_sibling();
|
||||
|
|
@ -77,7 +77,7 @@ nodes::Type build_container_type(parser::ParseTree::Node parser_node,
|
|||
std::vector<nodes::Type> parameters =
|
||||
collect_parameters(parser_node.nth_named_child(0), executor);
|
||||
|
||||
return executor.state<Types>().add_container_of(std::move(parameters),
|
||||
return executor.state<Types>().AddContainerOf(std::move(parameters),
|
||||
container);
|
||||
}
|
||||
|
||||
|
|
@ -103,7 +103,7 @@ nodes::Type BuilderTask<nodes::Type, TypeTag<Tp::REFERENCE_TYPE>>::operator()(
|
|||
Log::Context logc(executor.log(), Log::Area::kParse);
|
||||
|
||||
nodes::Type type = Run<nodes::Type>(parser_node.nth_named_child(0));
|
||||
type.get()->set_modifier(RunOther<nodes::Modifier>(parser_node.nth_child(0)));
|
||||
type.get().modifier = RunOther<nodes::Modifier>(parser_node.nth_child(0));
|
||||
return type;
|
||||
}
|
||||
|
||||
|
|
@ -112,8 +112,8 @@ nodes::Type BuilderTask<nodes::Type, TypeTag<Tp::MODIFIED_TYPE>>::operator()(
|
|||
const ParserNode &parser_node, const Args &) {
|
||||
Log::Context logc(executor.log(), Log::Area::kParse);
|
||||
|
||||
std::vector<nodes::Type> parameters;
|
||||
parameters.push_back(Run<nodes::Type>(parser_node.nth_named_child(0)));
|
||||
std::vector<nodes::Type> params;
|
||||
params.push_back(Run<nodes::Type>(parser_node.nth_named_child(0)));
|
||||
|
||||
nodes::Modifier modifier = RunOther<nodes::Modifier>(
|
||||
parser_node.nth_child(parser_node.child_count() - 1));
|
||||
|
|
@ -133,10 +133,11 @@ nodes::Type BuilderTask<nodes::Type, TypeTag<Tp::MODIFIED_TYPE>>::operator()(
|
|||
break;
|
||||
}
|
||||
|
||||
return executor.state<Types>().add_type(
|
||||
nodes::TypeData(nodes::Identifier{.kind = nodes::Identifier::kSimpleType,
|
||||
return executor.state<Types>().AddType(nodes::TypeData{
|
||||
.name = nodes::Identifier{.kind = nodes::Identifier::kSimpleType,
|
||||
.value = identifier},
|
||||
std::move(parameters)));
|
||||
.params = std::move(params),
|
||||
});
|
||||
}
|
||||
|
||||
// type_identifier ('[' (annotation? type)+ ']')?
|
||||
|
|
@ -146,11 +147,13 @@ nodes::Type BuilderTask<nodes::Type, TypeTag<Tp::SIMPLE_TYPE>>::operator()(
|
|||
|
||||
auto name_node = parser_node.child_by_field_name("name");
|
||||
|
||||
std::vector<nodes::Type> parameters =
|
||||
std::vector<nodes::Type> params =
|
||||
collect_parameters(name_node.next_named_sibling(), executor);
|
||||
|
||||
return executor.state<Types>().add_type(nodes::TypeData(
|
||||
RunOther<nodes::Identifier>(name_node), std::move(parameters)));
|
||||
return executor.state<Types>().AddType(nodes::TypeData{
|
||||
.name = RunOther<nodes::Identifier>(name_node),
|
||||
.params = std::move(params),
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace builders
|
||||
|
|
|
|||
|
|
@ -55,8 +55,8 @@ struct FunctionDefinition {
|
|||
Argument(const std::optional<std::string> &annotation, Type type,
|
||||
Modifier before_modifier = Modifier::NONE)
|
||||
: annotation(annotation), type(type), before_modifier(before_modifier),
|
||||
after_modifier(
|
||||
builtin::types::get_modifier(type.get()->to_builtin())) {}
|
||||
after_modifier(builtin::types::get_modifier(type.get().ToBuiltin())) {
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
|
|
@ -109,7 +109,7 @@ struct FunctionDefinition {
|
|||
}
|
||||
|
||||
auto type_after_modifier =
|
||||
builtin::types::get_modifier(new_type.get()->to_builtin());
|
||||
builtin::types::get_modifier(new_type.get().ToBuiltin());
|
||||
|
||||
if (after_modifier != Modifier::NONE &&
|
||||
after_modifier != type_after_modifier) {
|
||||
|
|
|
|||
|
|
@ -23,13 +23,16 @@ class Type {
|
|||
friend TypeStorage;
|
||||
|
||||
public:
|
||||
TypeData *get();
|
||||
TypeData &get();
|
||||
|
||||
const TypeData *get() const;
|
||||
const TypeData &get() const;
|
||||
|
||||
bool operator==(const Type &other) const;
|
||||
std::strong_ordering operator<=>(const Type &other) const;
|
||||
|
||||
bool operator!=(const Type &) const = default;
|
||||
// TODO: FIXME: should be automatic
|
||||
bool operator==(const Type &other) const {
|
||||
return (*this <=> other) == std::strong_ordering::equal;
|
||||
}
|
||||
|
||||
private:
|
||||
Type(TypeStorage &type_storage, size_t id)
|
||||
|
|
@ -45,297 +48,193 @@ using Types = std::vector<Type>;
|
|||
|
||||
class TypeData {
|
||||
public:
|
||||
TypeData(Identifier &&identifier, Modifier modifier = nodes::Modifier::CONST,
|
||||
const std::optional<std::string> &annotation = std::nullopt)
|
||||
: name_(std::move(identifier)), modifier_(modifier),
|
||||
annotation_(annotation) {}
|
||||
|
||||
TypeData(const Identifier &identifier,
|
||||
Modifier modifier = nodes::Modifier::CONST,
|
||||
const std::optional<std::string> &annotation = std::nullopt)
|
||||
: name_(identifier), modifier_(modifier), annotation_(annotation) {}
|
||||
|
||||
TypeData(Identifier &&identifier, std::vector<Type> &¶meters,
|
||||
Modifier modifier = nodes::Modifier::CONST,
|
||||
const std::optional<std::string> &annotation = std::nullopt)
|
||||
: name_(std::move(identifier)), parameters_(std::move(parameters)),
|
||||
modifier_(modifier), annotation_(annotation) {}
|
||||
|
||||
TypeData(const Identifier &identifier, std::vector<Type> &¶meters,
|
||||
Modifier modifier = nodes::Modifier::CONST,
|
||||
const std::optional<std::string> &annotation = std::nullopt)
|
||||
: name_(identifier), parameters_(std::move(parameters)),
|
||||
modifier_(modifier), annotation_(annotation) {}
|
||||
|
||||
//
|
||||
|
||||
Identifier *get_name() { return &name_; }
|
||||
|
||||
const Identifier *get_name() const { return &name_; }
|
||||
|
||||
//
|
||||
|
||||
size_t parameters_size() const { return parameters_.size(); }
|
||||
|
||||
Type get_parameter_proxy(size_t id) const { return parameters_.at(id); }
|
||||
|
||||
TypeData *get_parameter(size_t id) { return get_parameter_proxy(id).get(); }
|
||||
|
||||
const TypeData *get_parameter(size_t id) const {
|
||||
return get_parameter_proxy(id).get();
|
||||
}
|
||||
|
||||
// TODO: cache with map ??
|
||||
std::optional<Type>
|
||||
get_parameter_proxy_by_name(const std::string &name) const {
|
||||
std::optional<Type> ParamByName(const std::string &name) const {
|
||||
const auto it = std::find_if(
|
||||
parameters_.begin(), parameters_.end(), [&name](const auto ¶meter) {
|
||||
return parameter.get()->has_annotation() &&
|
||||
*parameter.get()->get_annotation().value() == name;
|
||||
params.begin(), params.end(), [&name](const auto ¶meter) {
|
||||
return parameter.get().HasAnnotation() &&
|
||||
parameter.get().annotation.value() == name;
|
||||
});
|
||||
|
||||
if (it != parameters_.end()) {
|
||||
if (it != params.end()) {
|
||||
return *it;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<const TypeData *>
|
||||
get_parameter_by_name(const std::string &name) const {
|
||||
const auto proxy = get_parameter_proxy_by_name(name);
|
||||
return proxy.has_value() ? proxy.value().get()
|
||||
: std::optional<const TypeData *>{};
|
||||
}
|
||||
//
|
||||
|
||||
std::optional<TypeData *> get_parameter_by_name(const std::string &name) {
|
||||
auto proxy = get_parameter_proxy_by_name(name);
|
||||
return proxy.has_value() ? proxy.value().get()
|
||||
: std::optional<TypeData *>{};
|
||||
bool IsModifier(Modifier other_modifier) const {
|
||||
return modifier == other_modifier;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
Modifier get_modifier() const { return modifier_; }
|
||||
bool HasAnnotation() const { return annotation.has_value(); }
|
||||
|
||||
void set_modifier(Modifier modifier) { modifier_ = modifier; }
|
||||
|
||||
bool is_modifier(Modifier modifier) const { return modifier_ == modifier; }
|
||||
|
||||
//
|
||||
|
||||
bool has_annotation() const { return annotation_.has_value(); }
|
||||
|
||||
std::optional<std::string *> get_annotation() {
|
||||
if (annotation_.has_value()) {
|
||||
return &annotation_.value();
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<const std::string *> get_annotation() const {
|
||||
if (annotation_.has_value()) {
|
||||
return &annotation_.value();
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
bool is_no_annotation() const { return !annotation_.has_value(); }
|
||||
|
||||
bool is_annotation(const std::string &annotation) const {
|
||||
return annotation_.has_value() && annotation_.value() == annotation;
|
||||
}
|
||||
|
||||
void set_annotation(std::string &&annotation) {
|
||||
annotation_ = std::move(annotation);
|
||||
}
|
||||
|
||||
void set_annotation(const std::string &annotation) {
|
||||
annotation_ = annotation;
|
||||
bool IsAnnotation(const std::string &other_annotation) const {
|
||||
return annotation.has_value() and annotation.value() == other_annotation;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void collect_annotations_recursively(
|
||||
std::insert_iterator<T> insert_iterator) const {
|
||||
if (annotation_.has_value()) {
|
||||
insert_iterator = annotation_.value();
|
||||
void
|
||||
CollectAnnotationsRecursively(std::insert_iterator<T> insert_iterator) const {
|
||||
if (annotation.has_value()) {
|
||||
insert_iterator = annotation.value();
|
||||
}
|
||||
|
||||
for (auto ¶meter : parameters_) {
|
||||
parameter.get()->collect_annotations_recursively(insert_iterator);
|
||||
for (auto ¶meter : params) {
|
||||
parameter.get().CollectAnnotationsRecursively(insert_iterator);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
bool is_generic() { return name_.kind == Identifier::kGenericType; }
|
||||
bool IsGeneric() const { return name.kind == Identifier::kGenericType; }
|
||||
|
||||
//
|
||||
|
||||
bool operator==(const TypeData &other) const {
|
||||
if (name_ != other.name_ || modifier_ != other.modifier_ ||
|
||||
parameters_.size() != other.parameters_.size()) {
|
||||
return false;
|
||||
std::strong_ordering operator<=>(const TypeData &other) const {
|
||||
if (name != other.name) {
|
||||
return name.value <=> other.name.value;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < parameters_.size(); ++i) {
|
||||
if (parameters_[i] != other.parameters_[i]) {
|
||||
return false;
|
||||
if (modifier != other.modifier) {
|
||||
return modifier <=> other.modifier;
|
||||
}
|
||||
|
||||
if (params.size() != other.params.size()) {
|
||||
return params.size() <=> other.params.size();
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < params.size(); ++i) {
|
||||
if ((params[i].get() <=> other.params[i].get()) !=
|
||||
std::strong_ordering::equal) {
|
||||
return params[i].get() <=> other.params[i].get();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return std::strong_ordering::equal;
|
||||
}
|
||||
|
||||
bool operator!=(const TypeData &other) const { return !(*this == other); }
|
||||
|
||||
//
|
||||
|
||||
bool operator<(const TypeData &other) const {
|
||||
if (name_ != other.name_) {
|
||||
return name_.value < other.name_.value;
|
||||
}
|
||||
|
||||
if (modifier_ != other.modifier_) {
|
||||
return modifier_ < other.modifier_;
|
||||
}
|
||||
|
||||
if (parameters_.size() != other.parameters_.size()) {
|
||||
return parameters_.size() < other.parameters_.size();
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < parameters_.size(); ++i) {
|
||||
if (parameters_[i] != other.parameters_[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool operator>(const TypeData &other) const { return other < *this; }
|
||||
|
||||
bool operator<=(const TypeData &other) const { return !operator>(other); }
|
||||
|
||||
bool operator>=(const TypeData &other) const { return !operator<(other); }
|
||||
|
||||
// is parameters count check necessary ??
|
||||
builtin::Type to_builtin() const {
|
||||
auto builtin_type = builtin::types::to_type(name_.value);
|
||||
builtin::Type ToBuiltin() const {
|
||||
auto builtin_type = builtin::types::to_type(name.value);
|
||||
|
||||
auto builtin_type_parameters_count =
|
||||
builtin::types::get_parameters_count(builtin_type);
|
||||
|
||||
// for fixed parameter counts
|
||||
if (builtin_type_parameters_count.has_value() &&
|
||||
builtin_type_parameters_count.value() != parameters_.size()) {
|
||||
builtin_type_parameters_count.value() != params.size()) {
|
||||
return builtin::Type::NONE;
|
||||
}
|
||||
|
||||
return builtin_type;
|
||||
}
|
||||
|
||||
bool is_builtin(builtin::Type type) const { return to_builtin() == type; }
|
||||
bool IsBuiltin(builtin::Type type) const { return ToBuiltin() == type; }
|
||||
|
||||
private:
|
||||
Identifier name_;
|
||||
std::vector<Type> parameters_;
|
||||
Modifier modifier_ = Modifier::NONE;
|
||||
std::optional<std::string> annotation_;
|
||||
public:
|
||||
Identifier name;
|
||||
std::vector<Type> params = {};
|
||||
Modifier modifier = Modifier::NONE;
|
||||
std::optional<std::string> annotation = {};
|
||||
};
|
||||
|
||||
class TypeStorage {
|
||||
friend Type;
|
||||
|
||||
public:
|
||||
Type primitive(builtin::Type type);
|
||||
Type Primitive(builtin::Type type);
|
||||
|
||||
Type add_array_of(Type type);
|
||||
Type AddArrayOf(Type type);
|
||||
|
||||
Type add_error_of(Type type);
|
||||
Type AddErrorOf(Type type);
|
||||
|
||||
nodes::Type add_container_of(std::vector<Type> &¶meters,
|
||||
nodes::Type AddContainerOf(std::vector<Type> &¶meters,
|
||||
builtin::Type container);
|
||||
|
||||
nodes::Type add_modification_of(Type type, Modifier modifier);
|
||||
nodes::Type AddModificationOf(Type type, Modifier modifier);
|
||||
|
||||
Type add_type(const TypeData &type) {
|
||||
storage_.push_back(type);
|
||||
return Type(*this, storage_.size() - 1);
|
||||
}
|
||||
|
||||
Type add_type(TypeData &&type) {
|
||||
Type AddType(TypeData type) {
|
||||
storage_.push_back(std::move(type));
|
||||
return Type(*this, storage_.size() - 1);
|
||||
}
|
||||
|
||||
// -- deal with generic types (variable types in this case)
|
||||
|
||||
bool resolve_all_generic_types();
|
||||
|
||||
Type add_generic_type() {
|
||||
return add_type(TypeData(generate_generic_type_identifier()));
|
||||
Type AddGenericType() {
|
||||
return AddType(TypeData{.name = GenerateGenericTypeId()});
|
||||
}
|
||||
|
||||
bool resolve_generic_name(const std::string &name, const Type &actulal_type);
|
||||
|
||||
void clear_resolved_generic_names() { resolved_generic_names_.clear(); }
|
||||
|
||||
// -- deal with local types // not needed ??
|
||||
|
||||
bool add_local_type(const std::string &name);
|
||||
|
||||
bool add_local_type_requirement(const std::string &name,
|
||||
const Identifier &typeclass);
|
||||
|
||||
bool add_local_type_requirement(const std::string &name,
|
||||
Identifier &&typeclass);
|
||||
|
||||
std::optional<std::set<Identifier> *>
|
||||
get_local_type_requirements(const std::string &name);
|
||||
|
||||
std::optional<const std::set<Identifier> *>
|
||||
get_local_type_requirements(const std::string &name) const;
|
||||
|
||||
void clear_local_name_typeclasses() {
|
||||
local_name_ids_.clear();
|
||||
local_name_typeclasses_.clear();
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
enum class UnifyModePolicy { // TODO: proper modes for modifier
|
||||
Ignore, // all mode differences ignored
|
||||
ApplyStrongest, // unique > shared, modes changed
|
||||
CheckLeftIsSubmode, // only check is performed
|
||||
kIgnore, // all mode differences ignored
|
||||
kApplyStrongest, // unique > shared, modes changed
|
||||
kCheckLeftIsSubmode, // only check is performed
|
||||
};
|
||||
|
||||
// TODO: next iteration of type check
|
||||
bool unify(Type left_proxy, Type right_proxy, UnifyModePolicy policy);
|
||||
bool Unify(Type left, Type right, UnifyModePolicy policy);
|
||||
|
||||
bool resolve(Type generic,
|
||||
bool Resolve(Type generic,
|
||||
const TypeData &replacement /* TODO , Mode mode = {}*/);
|
||||
|
||||
// TODO: needed ??
|
||||
|
||||
// bool resolve_all_generic_types();
|
||||
|
||||
// bool resolve_generic_name(const std::string &name, const Type
|
||||
// &actulal_type);
|
||||
|
||||
// void clear_resolved_generic_names() { resolved_generic_names_.clear(); }
|
||||
|
||||
// -- deal with local types // not needed ??
|
||||
|
||||
// bool add_local_type(const std::string &name);
|
||||
|
||||
// bool add_local_type_requirement(const std::string &name,
|
||||
// const Identifier &typeclass);
|
||||
|
||||
// bool add_local_type_requirement(const std::string &name,
|
||||
// Identifier &&typeclass);
|
||||
|
||||
// std::optional<std::set<Identifier> *>
|
||||
// get_local_type_requirements(const std::string &name);
|
||||
|
||||
// std::optional<const std::set<Identifier> *>
|
||||
// get_local_type_requirements(const std::string &name) const;
|
||||
|
||||
// void clear_local_name_typeclasses() {
|
||||
// local_name_ids_.clear();
|
||||
// local_name_typeclasses_.clear();
|
||||
// }
|
||||
|
||||
private:
|
||||
TypeData *get_type(size_t id) { return &storage_.at(id); }
|
||||
TypeData &operator[](size_t id) { return storage_.at(id); }
|
||||
|
||||
const TypeData *get_type(size_t id) const { return &storage_.at(id); }
|
||||
const TypeData &operator[](size_t id) const { return storage_.at(id); }
|
||||
|
||||
Identifier generate_generic_type_identifier();
|
||||
Identifier GenerateGenericTypeId();
|
||||
|
||||
private:
|
||||
// check is builtin type instaniated
|
||||
std::unordered_map<builtin::Type, size_t> primitive_type_ids_;
|
||||
|
||||
// deal with generic types and generic names
|
||||
std::unordered_map<std::string, size_t> resolved_generic_names_;
|
||||
// std::unordered_map<std::string, size_t> resolved_generic_names_; // TODO:
|
||||
// needed ??
|
||||
size_t last_generic_type_id_ = 0;
|
||||
|
||||
// TODO: needed ??
|
||||
// deal with local types
|
||||
std::unordered_map<std::string, size_t> local_name_ids_;
|
||||
std::vector<std::set<Identifier>> local_name_typeclasses_;
|
||||
// std::unordered_map<std::string, size_t> local_name_ids_;
|
||||
// std::vector<std::set<Identifier>> local_name_typeclasses_;
|
||||
|
||||
// storage for all types
|
||||
std::vector<TypeData> storage_;
|
||||
std::vector<TypeData> storage_; // TODO: map ??
|
||||
};
|
||||
|
||||
} // namespace nodes
|
||||
|
|
|
|||
|
|
@ -4,69 +4,76 @@
|
|||
|
||||
namespace nodes {
|
||||
|
||||
TypeData *Type::get() { return type_storage_->get_type(id_); }
|
||||
TypeData &Type::get() { return (*type_storage_)[id_]; }
|
||||
|
||||
const TypeData *Type::get() const { return type_storage_->get_type(id_); }
|
||||
const TypeData &Type::get() const { return (*type_storage_)[id_]; }
|
||||
|
||||
bool Type::operator==(const Type &other) const {
|
||||
return *get() == *other.get();
|
||||
std::strong_ordering Type::operator<=>(const Type &other) const {
|
||||
return get() <=> other.get();
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
Type TypeStorage::primitive(builtin::Type type) {
|
||||
Type TypeStorage::Primitive(builtin::Type type) {
|
||||
auto iter = primitive_type_ids_.find(type);
|
||||
if (iter != primitive_type_ids_.end()) {
|
||||
return Type(*this, iter->second);
|
||||
} else {
|
||||
primitive_type_ids_[type] = storage_.size();
|
||||
return add_type(TypeData(Identifier{
|
||||
return AddType(TypeData{
|
||||
.name =
|
||||
Identifier{
|
||||
.kind = Identifier::kSimpleType,
|
||||
.value = builtin::types::to_string(type),
|
||||
}));
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Type TypeStorage::add_array_of(Type type) {
|
||||
Type TypeStorage::AddArrayOf(Type type) {
|
||||
if (type.type_storage_ != this) {
|
||||
error_handling::handle_general_error(
|
||||
"TypeStorage: Can't add array of type from another type "
|
||||
"storage");
|
||||
}
|
||||
|
||||
std::vector<nodes::Type> parameters;
|
||||
parameters.push_back(type);
|
||||
std::vector<nodes::Type> params;
|
||||
params.push_back(type);
|
||||
|
||||
return add_type(TypeData(
|
||||
return AddType(TypeData{
|
||||
.name =
|
||||
Identifier{
|
||||
.kind = Identifier::kSimpleType,
|
||||
.value = builtin::types::ARRAY_IDENTIFIER,
|
||||
},
|
||||
std::move(parameters)));
|
||||
.params = std::move(params),
|
||||
});
|
||||
}
|
||||
|
||||
Type TypeStorage::add_error_of(Type type) {
|
||||
Type TypeStorage::AddErrorOf(Type type) {
|
||||
if (type.type_storage_ != this) {
|
||||
error_handling::handle_general_error(
|
||||
"TypeStorage: Can't add error of type from another type "
|
||||
"storage");
|
||||
}
|
||||
|
||||
std::vector<nodes::Type> parameters;
|
||||
parameters.push_back(type);
|
||||
std::vector<nodes::Type> params;
|
||||
params.push_back(type);
|
||||
|
||||
return add_type(TypeData(
|
||||
return AddType(TypeData{
|
||||
.name =
|
||||
Identifier{
|
||||
.kind = Identifier::kSimpleType,
|
||||
.value = builtin::types::ERROR_IDENTIFIER,
|
||||
},
|
||||
std::move(parameters)));
|
||||
.params = std::move(params),
|
||||
});
|
||||
}
|
||||
|
||||
nodes::Type TypeStorage::add_container_of(std::vector<Type> &¶meters,
|
||||
nodes::Type TypeStorage::AddContainerOf(std::vector<Type> &¶ms,
|
||||
builtin::Type container) {
|
||||
for (auto ¶meter : parameters) {
|
||||
if (parameter.type_storage_ != this) {
|
||||
for (auto ¶m : params) {
|
||||
if (param.type_storage_ != this) {
|
||||
error_handling::handle_general_error(
|
||||
"TypeStorage: Can't add container with parameter of type from "
|
||||
"another type "
|
||||
|
|
@ -74,146 +81,148 @@ nodes::Type TypeStorage::add_container_of(std::vector<Type> &¶meters,
|
|||
}
|
||||
}
|
||||
|
||||
return add_type(nodes::TypeData(
|
||||
return AddType(nodes::TypeData{
|
||||
.name =
|
||||
nodes::Identifier{
|
||||
.kind = nodes::Identifier::kSimpleType,
|
||||
.value = builtin::types::to_string(container),
|
||||
},
|
||||
std::move(parameters)));
|
||||
.params = std::move(params),
|
||||
});
|
||||
}
|
||||
|
||||
nodes::Type TypeStorage::add_modification_of(Type type, Modifier modifier) {
|
||||
nodes::Type TypeStorage::AddModificationOf(Type type, Modifier modifier) {
|
||||
if (type.type_storage_ != this) {
|
||||
error_handling::handle_general_error(
|
||||
"TypeStorage: Can't add modification of type from another type "
|
||||
"storage");
|
||||
}
|
||||
|
||||
TypeData type_copy = *type.get();
|
||||
type_copy.set_modifier(modifier);
|
||||
TypeData type_copy = type.get();
|
||||
type_copy.modifier = modifier;
|
||||
|
||||
return add_type(std::move(type_copy));
|
||||
return AddType(std::move(type_copy));
|
||||
}
|
||||
|
||||
// -- deal with generic types (variable types in this case)
|
||||
|
||||
bool TypeStorage::resolve_all_generic_types() {
|
||||
bool are_all_resolved = true;
|
||||
// bool TypeStorage::ResolveAllGenericTypes() {
|
||||
// bool are_all_resolved = true;
|
||||
|
||||
bool new_types_resolved = true;
|
||||
// bool new_types_resolved = true;
|
||||
|
||||
while (new_types_resolved) {
|
||||
new_types_resolved = false;
|
||||
// while (new_types_resolved) {
|
||||
// new_types_resolved = false;
|
||||
|
||||
for (auto &type : storage_) {
|
||||
if (type.is_generic()) {
|
||||
auto iter = resolved_generic_names_.find(type.get_name()->value);
|
||||
// for (auto &type : storage_) {
|
||||
// if (type.is_generic()) {
|
||||
// auto iter = resolved_generic_names_.find(type.get_name()->value);
|
||||
|
||||
// because of undefined order some types can became resolved earlir
|
||||
// wirking correctly because each generic type has <= 1 successor, no
|
||||
// cyclic deps allowed (do check ??)
|
||||
if (iter != resolved_generic_names_.end()) {
|
||||
new_types_resolved = true;
|
||||
type = storage_[iter->second];
|
||||
} else {
|
||||
are_all_resolved = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// // because of undefined order some types can became resolved earlir
|
||||
// // wirking correctly because each generic type has <= 1 successor, no
|
||||
// // cyclic deps allowed (do check ??)
|
||||
// if (iter != resolved_generic_names_.end()) {
|
||||
// new_types_resolved = true;
|
||||
// type = storage_[iter->second];
|
||||
// } else {
|
||||
// are_all_resolved = false;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// this check is not required ??
|
||||
for (auto &type : storage_) {
|
||||
if (!type.is_generic()) {
|
||||
are_all_resolved = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// // this check is not required ??
|
||||
// for (auto &type : storage_) {
|
||||
// if (!type.is_generic()) {
|
||||
// are_all_resolved = false;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
|
||||
return are_all_resolved;
|
||||
}
|
||||
// return are_all_resolved;
|
||||
// }
|
||||
|
||||
bool TypeStorage::resolve_generic_name(const std::string &name,
|
||||
const Type &actulal_type) {
|
||||
if (actulal_type.type_storage_ != this) {
|
||||
error_handling::handle_general_error(
|
||||
"TypeStorage: Can't resolve generic type to type from another type "
|
||||
"storage");
|
||||
}
|
||||
// bool TypeStorage::ResolveGenericName(const std::string &name,
|
||||
// const Type &actulal_type) {
|
||||
// if (actulal_type.type_storage_ != this) {
|
||||
// error_handling::handle_general_error(
|
||||
// "TypeStorage: Can't resolve generic type to type from another type "
|
||||
// "storage");
|
||||
// }
|
||||
|
||||
if (resolved_generic_names_.count(name) != 0) {
|
||||
return false;
|
||||
}
|
||||
// if (resolved_generic_names_.count(name) != 0) {
|
||||
// return false;
|
||||
// }
|
||||
|
||||
resolved_generic_names_[name] = actulal_type.id_;
|
||||
// resolved_generic_names_[name] = actulal_type.id_;
|
||||
|
||||
return true;
|
||||
}
|
||||
// return true;
|
||||
// }
|
||||
|
||||
// -- deal with local types
|
||||
|
||||
bool TypeStorage::add_local_type(const std::string &name) {
|
||||
if (local_name_ids_.count(name) != 0) {
|
||||
return false;
|
||||
}
|
||||
// bool TypeStorage::AddLocalType(const std::string &name) {
|
||||
// if (local_name_ids_.count(name) != 0) {
|
||||
// return false;
|
||||
// }
|
||||
|
||||
local_name_ids_[name] = local_name_typeclasses_.size();
|
||||
local_name_typeclasses_.emplace_back();
|
||||
// local_name_ids_[name] = local_name_typeclasses_.size();
|
||||
// local_name_typeclasses_.emplace_back();
|
||||
|
||||
return true;
|
||||
}
|
||||
// return true;
|
||||
// }
|
||||
|
||||
bool TypeStorage::add_local_type_requirement(const std::string &name,
|
||||
const Identifier &typeclass) {
|
||||
auto iter = local_name_ids_.find(name);
|
||||
// bool TypeStorage::add_local_type_requirement(const std::string &name,
|
||||
// const Identifier &typeclass) {
|
||||
// auto iter = local_name_ids_.find(name);
|
||||
|
||||
if (iter == local_name_ids_.end()) {
|
||||
return false;
|
||||
}
|
||||
// if (iter == local_name_ids_.end()) {
|
||||
// return false;
|
||||
// }
|
||||
|
||||
local_name_typeclasses_[iter->second].insert(typeclass);
|
||||
// local_name_typeclasses_[iter->second].insert(typeclass);
|
||||
|
||||
return true;
|
||||
}
|
||||
// return true;
|
||||
// }
|
||||
|
||||
bool TypeStorage::add_local_type_requirement(const std::string &name,
|
||||
Identifier &&typeclass) {
|
||||
auto iter = local_name_ids_.find(name);
|
||||
// bool TypeStorage::add_local_type_requirement(const std::string &name,
|
||||
// Identifier &&typeclass) {
|
||||
// auto iter = local_name_ids_.find(name);
|
||||
|
||||
if (iter == local_name_ids_.end()) {
|
||||
return false;
|
||||
}
|
||||
// if (iter == local_name_ids_.end()) {
|
||||
// return false;
|
||||
// }
|
||||
|
||||
local_name_typeclasses_[iter->second].insert(std::move(typeclass));
|
||||
// local_name_typeclasses_[iter->second].insert(std::move(typeclass));
|
||||
|
||||
return true;
|
||||
}
|
||||
// return true;
|
||||
// }
|
||||
|
||||
std::optional<std::set<Identifier> *>
|
||||
TypeStorage::get_local_type_requirements(const std::string &name) {
|
||||
auto iter = local_name_ids_.find(name);
|
||||
// std::optional<std::set<Identifier> *>
|
||||
// TypeStorage::get_local_type_requirements(const std::string &name) {
|
||||
// auto iter = local_name_ids_.find(name);
|
||||
|
||||
if (iter == local_name_ids_.end()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
// if (iter == local_name_ids_.end()) {
|
||||
// return std::nullopt;
|
||||
// }
|
||||
|
||||
return &local_name_typeclasses_[iter->second];
|
||||
}
|
||||
// return &local_name_typeclasses_[iter->second];
|
||||
// }
|
||||
|
||||
std::optional<const std::set<Identifier> *>
|
||||
TypeStorage::get_local_type_requirements(const std::string &name) const {
|
||||
auto iter = local_name_ids_.find(name);
|
||||
// std::optional<const std::set<Identifier> *>
|
||||
// TypeStorage::get_local_type_requirements(const std::string &name) const {
|
||||
// auto iter = local_name_ids_.find(name);
|
||||
|
||||
if (iter == local_name_ids_.end()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
// if (iter == local_name_ids_.end()) {
|
||||
// return std::nullopt;
|
||||
// }
|
||||
|
||||
return &local_name_typeclasses_[iter->second];
|
||||
}
|
||||
// return &local_name_typeclasses_[iter->second];
|
||||
// }
|
||||
|
||||
// TODO
|
||||
|
||||
bool TypeStorage::unify(Type /*left_proxy*/, Type /*right_proxy*/,
|
||||
bool TypeStorage::Unify(Type /*left*/, Type /*right*/,
|
||||
UnifyModePolicy /*policy*/) {
|
||||
// Type &left = left_id.get();
|
||||
// Type &right = right_id.get();
|
||||
|
|
@ -275,12 +284,12 @@ bool TypeStorage::unify(Type /*left_proxy*/, Type /*right_proxy*/,
|
|||
throw std::exception();
|
||||
}
|
||||
|
||||
bool TypeStorage::resolve(
|
||||
bool TypeStorage::Resolve(
|
||||
Type generic, const TypeData &replacement /* TODO , Mode mode = {}*/) {
|
||||
error_handling::ensure(generic.get()->is_generic(), "Type should be generic");
|
||||
error_handling::ensure(generic.get()->is_generic(), "Type should be generic");
|
||||
error_handling::ensure(generic.get().IsGeneric(), "Type should be generic");
|
||||
error_handling::ensure(generic.get().IsGeneric(), "Type should be generic");
|
||||
for (auto &type : storage_) {
|
||||
if (type.is_generic() && type.get_name() == generic.get()->get_name()) {
|
||||
if (type.IsGeneric() && type.name == generic.get().name) {
|
||||
type = replacement;
|
||||
// type.mode = mode;
|
||||
}
|
||||
|
|
@ -291,7 +300,7 @@ bool TypeStorage::resolve(
|
|||
|
||||
//
|
||||
|
||||
Identifier TypeStorage::generate_generic_type_identifier() {
|
||||
Identifier TypeStorage::GenerateGenericTypeId() {
|
||||
Identifier identifier = Identifier{
|
||||
.kind = Identifier::kGenericType,
|
||||
.value = "G_" + std::to_string(last_generic_type_id_),
|
||||
|
|
|
|||
|
|
@ -7,27 +7,27 @@ namespace printers {
|
|||
|
||||
Result PrintTask<nodes::Type>::operator()(const nodes::Type &type,
|
||||
const Args &args) {
|
||||
return Run(*type.get(), args);
|
||||
return Run(type.get(), args);
|
||||
}
|
||||
// TODO: better printing format for builtin types
|
||||
Result PrintTask<nodes::TypeData>::operator()(const nodes::TypeData &type,
|
||||
const Args &) {
|
||||
if (type.has_annotation()) {
|
||||
Run(nodes::Annotation{.value = *type.get_annotation().value()});
|
||||
if (type.HasAnnotation()) {
|
||||
Run(nodes::Annotation{.value = type.annotation.value()});
|
||||
Space();
|
||||
}
|
||||
|
||||
if (type.get_modifier() != nodes::Modifier::CONST) {
|
||||
Run(type.get_modifier());
|
||||
if (type.modifier != nodes::Modifier::CONST) {
|
||||
Run(type.modifier);
|
||||
}
|
||||
|
||||
Run(*type.get_name());
|
||||
Run(type.name);
|
||||
|
||||
if (type.parameters_size() > 0) {
|
||||
if (type.params.size() > 0) {
|
||||
Print("[");
|
||||
for (size_t i = 0; i < type.parameters_size(); ++i) {
|
||||
Run(*type.get_parameter(i));
|
||||
if (i + 1 < type.parameters_size()) {
|
||||
for (size_t i = 0; i < type.params.size(); ++i) {
|
||||
Run(type.params.at(i));
|
||||
if (i + 1 < type.params.size()) {
|
||||
Space();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -189,13 +189,13 @@ public:
|
|||
|
||||
Args ExpectBuiltin(builtin::Type type, Executor &executor) const {
|
||||
Args copy(*this);
|
||||
copy.expected_types_ = {executor.state<Types>().primitive(type)};
|
||||
copy.expected_types_ = {executor.state<Types>().Primitive(type)};
|
||||
return copy;
|
||||
}
|
||||
|
||||
Args PassBuiltin(builtin::Type type, Executor &executor) const {
|
||||
Args copy(*this);
|
||||
copy.passed_type_ = executor.state<Types>().primitive(type);
|
||||
copy.passed_type_ = executor.state<Types>().Primitive(type);
|
||||
return copy;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,31 +8,31 @@ nodes::Type get_literal_type(const nodes::Literal &literal,
|
|||
|
||||
switch (literal.value.index()) {
|
||||
case 0: // float
|
||||
return executor.state<Types>().primitive(builtin::Type::FLOAT);
|
||||
return executor.state<Types>().Primitive(builtin::Type::FLOAT);
|
||||
case 1: // double
|
||||
return executor.state<Types>().primitive(builtin::Type::DOUBLE);
|
||||
return executor.state<Types>().Primitive(builtin::Type::DOUBLE);
|
||||
case 2: // int32_t
|
||||
return executor.state<Types>().primitive(builtin::Type::INT);
|
||||
return executor.state<Types>().Primitive(builtin::Type::INT);
|
||||
case 3: // int64_t
|
||||
return executor.state<Types>().primitive(builtin::Type::LONG);
|
||||
return executor.state<Types>().Primitive(builtin::Type::LONG);
|
||||
case 4: // size_t
|
||||
return executor.state<Types>().primitive(builtin::Type::INDEX);
|
||||
return executor.state<Types>().Primitive(builtin::Type::INDEX);
|
||||
case 5: // std::string
|
||||
return executor.state<Types>().add_array_of(
|
||||
executor.state<Types>().primitive(builtin::Type::CHAR));
|
||||
return executor.state<Types>().AddArrayOf(
|
||||
executor.state<Types>().Primitive(builtin::Type::CHAR));
|
||||
case 6: // unicode_string
|
||||
return executor.state<Types>().add_array_of(
|
||||
executor.state<Types>().primitive(builtin::Type::UNICODE));
|
||||
return executor.state<Types>().AddArrayOf(
|
||||
executor.state<Types>().Primitive(builtin::Type::UNICODE));
|
||||
case 7: // char
|
||||
return executor.state<Types>().primitive(builtin::Type::CHAR);
|
||||
return executor.state<Types>().Primitive(builtin::Type::CHAR);
|
||||
case 8: // unicode
|
||||
return executor.state<Types>().primitive(builtin::Type::UNICODE);
|
||||
return executor.state<Types>().Primitive(builtin::Type::UNICODE);
|
||||
case 9: // bool
|
||||
return executor.state<Types>().primitive(builtin::Type::BOOL);
|
||||
return executor.state<Types>().Primitive(builtin::Type::BOOL);
|
||||
case 10: // unit
|
||||
return executor.state<Types>().primitive(builtin::Type::UNIT);
|
||||
return executor.state<Types>().Primitive(builtin::Type::UNIT);
|
||||
case 11: // null
|
||||
return executor.state<Types>().primitive(builtin::Type::NULL_OPTION);
|
||||
return executor.state<Types>().Primitive(builtin::Type::NULL_OPTION);
|
||||
}
|
||||
|
||||
utils::Assert(true, "Unreachable");
|
||||
|
|
|
|||
|
|
@ -2,4 +2,245 @@
|
|||
|
||||
#include "expression_type_check.hpp"
|
||||
|
||||
namespace type_check {} // namespace type_check
|
||||
namespace type_check {
|
||||
|
||||
// <------ NOTE: CHECK ENDED THERE
|
||||
|
||||
// TODO: add constraints evaluation
|
||||
Result CheckTask<nodes::Constructor>::operator()(const nodes::Constructor &expr,
|
||||
const Args &args) {
|
||||
Log::Context logc(executor.log(), Log::Area::kTypeCheck);
|
||||
|
||||
const auto current_pos = PosOf(args.current_id);
|
||||
|
||||
// TODO: constraints ??
|
||||
|
||||
// TODO: use pass type
|
||||
const auto maybe_type_definition =
|
||||
FindTypeDefinition(expr.type.get().name.value, current_pos, executor);
|
||||
if (!maybe_type_definition.has_value()) {
|
||||
return Result::invalid();
|
||||
}
|
||||
const nodes::TypeDefinition *type_definition = maybe_type_definition.value();
|
||||
|
||||
if (!type_definition->type.has_value()) {
|
||||
TypeCheckError(
|
||||
"Type defenition for constructor type not found (declaration only)",
|
||||
current_pos);
|
||||
return Result::invalid();
|
||||
}
|
||||
|
||||
// TODO: deal with anniotations, recursive annotations
|
||||
|
||||
// TODO: check that is not typeclass ??
|
||||
|
||||
nodes::Type type = type_definition->type.value();
|
||||
|
||||
// TODO: work with different parametric types: tuple, variant, ...
|
||||
|
||||
if (expr.args.size() == 0) {
|
||||
TypeCheckError("Number of type constructor arguments should be > 0",
|
||||
current_pos);
|
||||
return Result::invalid();
|
||||
// TODO: try return correct type (constructor's type), when possible (not
|
||||
// generic)
|
||||
}
|
||||
|
||||
// TODO: work with generics (type_definition->args, ...)
|
||||
|
||||
const auto builtin_type = type.get().ToBuiltin();
|
||||
|
||||
{ // check args size, ets.
|
||||
switch (builtin_type) {
|
||||
case builtin::Type::TUPLE:
|
||||
if (expr.args.size() != type.get().params.size()) {
|
||||
TypeCheckError(
|
||||
"Number of type constructor arguments is different from expected "
|
||||
"(" +
|
||||
std::to_string(expr.args.size()) + " instead of " +
|
||||
std::to_string(type.get().params.size()) + ")",
|
||||
current_pos);
|
||||
return Result::invalid();
|
||||
// TODO: try return correct type (constructor's type), when possible
|
||||
// (not generic)
|
||||
}
|
||||
break;
|
||||
case builtin::Type::VARIANT:
|
||||
case builtin::Type::OPTIONAL:
|
||||
case builtin::Type::RESULT:
|
||||
case builtin::Type::ERROR:
|
||||
case builtin::Type::FUNCTION:
|
||||
case builtin::Type::NONE:
|
||||
if (expr.args.size() != 1) { // TODO: better to_string
|
||||
TypeCheckError(std::format("Number of type constructor arguments "
|
||||
"should be = 1 (builtin type {})",
|
||||
uint(builtin_type)),
|
||||
current_pos);
|
||||
return Result::invalid();
|
||||
// TODO: try return correct type (constructor's type), when possible
|
||||
// (not generic)
|
||||
}
|
||||
break;
|
||||
default: // array, basic types
|
||||
break;
|
||||
}
|
||||
|
||||
if (builtin::types::get_parameters_count(builtin_type).has_value() &&
|
||||
type.get().params.size() !=
|
||||
builtin::types::get_parameters_count(builtin_type).value()) {
|
||||
TypeCheckError("Wrong amount of parametars for builtin type",
|
||||
current_pos);
|
||||
|
||||
return Result::invalid();
|
||||
// TODO: try return correct type (constructor's type), when possible (not
|
||||
// generic)
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<size_t> chosen_variant_option; // for VARIANT
|
||||
|
||||
{ // check annotations
|
||||
const auto check_same_annotation =
|
||||
[&expr, this](size_t i,
|
||||
std::optional<const std::string_view> expected_annotation,
|
||||
bool log_errors) {
|
||||
bool is_same = true;
|
||||
|
||||
const auto annotation = expr.args.at(i).first;
|
||||
|
||||
if (annotation.has_value() != expected_annotation.has_value()) {
|
||||
if (log_errors) {
|
||||
TypeCheckError(
|
||||
"Wrong type constructor argument annotation: should be " +
|
||||
std::string{expected_annotation.has_value()
|
||||
? expected_annotation.value()
|
||||
: "[none]"},
|
||||
PosOf(expr.args.at(i).second));
|
||||
}
|
||||
is_same = false;
|
||||
}
|
||||
|
||||
if (annotation.has_value() &&
|
||||
annotation.value() != expected_annotation.value()) {
|
||||
if (log_errors) {
|
||||
TypeCheckError("Wrong function argument type annotation: " +
|
||||
annotation.value() + " instead of " +
|
||||
std::string{expected_annotation.value()},
|
||||
PosOf(expr.args.at(i).second));
|
||||
}
|
||||
|
||||
is_same = false;
|
||||
}
|
||||
|
||||
return is_same;
|
||||
};
|
||||
|
||||
const auto check_no_annotation = [&expr, this](size_t i, bool log_errors) {
|
||||
if (expr.args.at(i).first.has_value()) {
|
||||
if (log_errors) {
|
||||
TypeCheckError(
|
||||
"Type constructor argument annotation not expected there",
|
||||
PosOf(expr.args.at(i).second));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
switch (builtin_type) {
|
||||
case builtin::Type::TUPLE:
|
||||
for (size_t i = 0; i < expr.args.size(); ++i) {
|
||||
check_same_annotation(i, type.get().params.at(i).get().annotation,
|
||||
true /*log errors*/);
|
||||
}
|
||||
break;
|
||||
case builtin::Type::VARIANT:
|
||||
// more then one same annotation ??
|
||||
for (size_t i = 0; i < type.get().params.size(); ++i) {
|
||||
if (check_same_annotation(0, type.get().params.at(i).get().annotation,
|
||||
false /*do not log errors*/)) {
|
||||
chosen_variant_option = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!chosen_variant_option.has_value() &&
|
||||
!check_no_annotation(0, false /*do not log errors*/)) {
|
||||
TypeCheckError("Wrong type constructor argument annotation in "
|
||||
"constructor of variant type",
|
||||
PosOf(expr.args.front().second));
|
||||
}
|
||||
break;
|
||||
case builtin::Type::ERROR: // no anotations ??
|
||||
check_same_annotation(0, type.get().params.front().get().annotation,
|
||||
true /*log errors*/);
|
||||
break;
|
||||
case builtin::Type::OPTIONAL:
|
||||
case builtin::Type::RESULT:
|
||||
case builtin::Type::FUNCTION:
|
||||
case builtin::Type::NONE:
|
||||
check_no_annotation(0, true /*log errors*/);
|
||||
break;
|
||||
default: // array, basic types
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
{ // type check args
|
||||
switch (builtin_type) {
|
||||
case builtin::Type::TUPLE:
|
||||
for (size_t i = 0; i < expr.args.size(); ++i) {
|
||||
Run(expr.args.at(i).second,
|
||||
Args{expr.args.at(i).second}.Expect(type.get().params.at(i)));
|
||||
}
|
||||
break;
|
||||
case builtin::Type::VARIANT:
|
||||
if (chosen_variant_option.has_value()) {
|
||||
Run(expr.args.front().second,
|
||||
Args{expr.args.front().second}.Expect(
|
||||
type.get().params.at(chosen_variant_option.value())));
|
||||
} else { // TODO: error, if there is more then one possible variant in
|
||||
// answer
|
||||
nodes::Types possible_options = type.get().params;
|
||||
Run(expr.args.front().second,
|
||||
Args{expr.args.front().second}.Expect(possible_options));
|
||||
}
|
||||
break;
|
||||
case builtin::Type::OPTIONAL:
|
||||
// first parameter or NULL
|
||||
Run(expr.args.front().second,
|
||||
Args{expr.args.front().second}.Expect(
|
||||
{type.get().params.front(),
|
||||
state<Types>().Primitive(builtin::Type::NULL_OPTION)}));
|
||||
break;
|
||||
case builtin::Type::RESULT:
|
||||
// first parameter or ERROR[second parameter]
|
||||
Run(expr.args.front().second,
|
||||
Args{expr.args.front().second}.Expect(
|
||||
{type.get().params.front(),
|
||||
state<Types>().AddErrorOf(type.get().params.at(1))}));
|
||||
break;
|
||||
case builtin::Type::ERROR:
|
||||
// first parameter
|
||||
Run(expr.args.front().second,
|
||||
Args{expr.args.front().second}.Expect(type.get().params.front()));
|
||||
break;
|
||||
case builtin::Type::FUNCTION:
|
||||
case builtin::Type::NONE:
|
||||
// type itself
|
||||
Run(expr.args.front().second,
|
||||
Args{expr.args.front().second}.Expect(type));
|
||||
break;
|
||||
default: // array, basic types
|
||||
TypeCheckError("Type can't be constructed", current_pos);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: deduce generic parts in type
|
||||
return TypeCheckFromArgs(expr.type, args, current_pos);
|
||||
// TODO: add <- modifiier to type ??
|
||||
|
||||
} // IN PROGRESS
|
||||
|
||||
} // namespace type_check
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ Result CheckTask<nodes::Match>::operator()(const nodes::Match &expr,
|
|||
}
|
||||
|
||||
if (not expr_result.has_value()) {
|
||||
expr_result = Result{state<Types>().primitive(builtin::Type::UNIT)};
|
||||
expr_result = Result{state<Types>().Primitive(builtin::Type::UNIT)};
|
||||
}
|
||||
|
||||
return TypeCheckFromArgs(expr_result.value().Get(), args, current_pos);
|
||||
|
|
@ -179,7 +179,7 @@ Result CheckTask<nodes::Loop>::operator()(const nodes::Loop &expr,
|
|||
}
|
||||
|
||||
const auto range_elem_type =
|
||||
interval_result.value().Get().get()->get_parameter_proxy(0);
|
||||
interval_result.value().Get().get().params.at(0);
|
||||
|
||||
variable_result = Run(expr.variable.value(),
|
||||
Args{expr.variable.value()}.Expect(
|
||||
|
|
@ -192,7 +192,7 @@ Result CheckTask<nodes::Loop>::operator()(const nodes::Loop &expr,
|
|||
return Result::invalid();
|
||||
}
|
||||
|
||||
return TypeCheckFromArgs(state<Types>().add_array_of(expression_result.Get()),
|
||||
return TypeCheckFromArgs(state<Types>().AddArrayOf(expression_result.Get()),
|
||||
args, current_pos);
|
||||
}
|
||||
|
||||
|
|
@ -233,7 +233,7 @@ Result CheckTask<nodes::Container>::CheckArray(const nodes::Container &expr,
|
|||
}
|
||||
|
||||
return TypeCheckFromArgs(
|
||||
state<Types>().add_array_of(last_expr_result.value().Get()), args,
|
||||
state<Types>().AddArrayOf(last_expr_result.value().Get()), args,
|
||||
current_pos);
|
||||
}
|
||||
|
||||
|
|
@ -260,7 +260,7 @@ Result CheckTask<nodes::Container>::CheckBlock(const nodes::Container &expr,
|
|||
Result block_brought_type =
|
||||
context_exit_type.has_value()
|
||||
? Result(context_exit_type.value())
|
||||
: Result(state<Types>().primitive(builtin::Type::UNIT));
|
||||
: Result(state<Types>().Primitive(builtin::Type::UNIT));
|
||||
|
||||
return TypeCheckFromArgs(block_brought_type.Get(), args, current_pos);
|
||||
}
|
||||
|
|
@ -305,7 +305,7 @@ Result CheckTask<nodes::Return>::operator()(const nodes::Return &expr,
|
|||
break;
|
||||
}
|
||||
|
||||
return TypeCheckFromArgs(state<Types>().primitive(builtin::Type::UNIT), args,
|
||||
return TypeCheckFromArgs(state<Types>().Primitive(builtin::Type::UNIT), args,
|
||||
current_pos);
|
||||
}
|
||||
|
||||
|
|
@ -324,15 +324,14 @@ CheckTask<nodes::NameDefinition>::operator()(const nodes::NameDefinition &expr,
|
|||
|
||||
// assigned type shold be one of <-, <>, -- (can't be ->)
|
||||
const auto variable_type = args.passed().value();
|
||||
if (nodes::utils::modifier_contains_OUT(
|
||||
variable_type.get()->get_modifier())) {
|
||||
if (nodes::utils::modifier_contains_OUT(variable_type.get().modifier)) {
|
||||
// TODO: modifiers are nto fully implemented yet
|
||||
TypeCheckError("Variable can't be assigned from out (->) value",
|
||||
current_pos);
|
||||
}
|
||||
|
||||
// variable is accessible by reference by default
|
||||
state<Types>().add_modification_of(variable_type, nodes::Modifier::REF);
|
||||
state<Types>().AddModificationOf(variable_type, nodes::Modifier::REF);
|
||||
|
||||
// TODO: warning if name is same to package prefix, function prefix, etc. ??
|
||||
if (not state<State>().InsertVariable(expr.name.value, variable_type,
|
||||
|
|
@ -341,7 +340,7 @@ CheckTask<nodes::NameDefinition>::operator()(const nodes::NameDefinition &expr,
|
|||
}
|
||||
|
||||
// Return BOOL (as any := / =: expression) == true
|
||||
return TypeCheckFromArgs(state<Types>().primitive(builtin::Type::BOOL), args,
|
||||
return TypeCheckFromArgs(state<Types>().Primitive(builtin::Type::BOOL), args,
|
||||
current_pos);
|
||||
}
|
||||
|
||||
|
|
@ -370,8 +369,8 @@ Result CheckTask<nodes::Access>::CheckArrayAccess(const nodes::Access &expr,
|
|||
}
|
||||
|
||||
// NOTE: 0 - type of array
|
||||
return TypeCheckFromArgs(value_result.Get().get()->get_parameter_proxy(0),
|
||||
args, current_pos);
|
||||
return TypeCheckFromArgs(value_result.Get().get().params.front(), args,
|
||||
current_pos);
|
||||
}
|
||||
|
||||
Result CheckTask<nodes::Access>::CheckTupleAccess(const nodes::Access &expr,
|
||||
|
|
@ -395,8 +394,8 @@ Result CheckTask<nodes::Access>::CheckTupleAccess(const nodes::Access &expr,
|
|||
.get<size_t>() // Index type
|
||||
.value();
|
||||
|
||||
return TypeCheckFromArgs(value_result.Get().get()->get_parameter_proxy(index),
|
||||
args, current_pos);
|
||||
return TypeCheckFromArgs(value_result.Get().get().params.at(index), args,
|
||||
current_pos);
|
||||
}
|
||||
|
||||
Result CheckTask<nodes::Access>::operator()(const nodes::Access &expr,
|
||||
|
|
@ -418,7 +417,7 @@ Result CheckTask<nodes::LoopControl>::operator()(const nodes::LoopControl &expr,
|
|||
|
||||
//
|
||||
|
||||
return TypeCheckFromArgs(state<Types>().primitive(builtin::Type::UNIT), args,
|
||||
return TypeCheckFromArgs(state<Types>().Primitive(builtin::Type::UNIT), args,
|
||||
current_pos);
|
||||
}
|
||||
|
||||
|
|
@ -432,8 +431,8 @@ Result CheckTask<nodes::ModifierExpression>::operator()(
|
|||
// TODO: check expect for parametrized type without parameters
|
||||
auto given_args = nodes::utils::is_suffix_modifier(expr.modifier)
|
||||
? Args{expr.expr}.Expect({
|
||||
state<Types>().primitive(builtin::Type::OPTIONAL),
|
||||
state<Types>().primitive(builtin::Type::RESULT),
|
||||
state<Types>().Primitive(builtin::Type::OPTIONAL),
|
||||
state<Types>().Primitive(builtin::Type::RESULT),
|
||||
})
|
||||
: Args{expr.expr};
|
||||
|
||||
|
|
@ -444,14 +443,13 @@ Result CheckTask<nodes::ModifierExpression>::operator()(
|
|||
}
|
||||
|
||||
if (nodes::utils::is_suffix_modifier(expr.modifier)) { // optional, result
|
||||
switch (modified_result.Get().get()->to_builtin()) {
|
||||
switch (modified_result.Get().get().ToBuiltin()) {
|
||||
case builtin::Type::OPTIONAL: { // '?' - open optional / result in ->
|
||||
// (execute
|
||||
// or not execute pattern matching expression)
|
||||
// / (value / return)
|
||||
|
||||
const auto underlying_type =
|
||||
modified_result.Get().get()->get_parameter_proxy(0);
|
||||
const auto underlying_type = modified_result.Get().get().params.front();
|
||||
|
||||
// TODO: alternative for bring in future
|
||||
if (not state<State>().ReturnType(underlying_type)) {
|
||||
|
|
@ -463,8 +461,7 @@ Result CheckTask<nodes::ModifierExpression>::operator()(
|
|||
}
|
||||
case builtin::Type::RESULT: { // '!' - open optional / result -> value /
|
||||
// panic
|
||||
const auto underlying_type =
|
||||
modified_result.Get().get()->get_parameter_proxy(0);
|
||||
const auto underlying_type = modified_result.Get().get().params.front();
|
||||
|
||||
modified_result.Set(underlying_type);
|
||||
break;
|
||||
|
|
@ -477,8 +474,8 @@ Result CheckTask<nodes::ModifierExpression>::operator()(
|
|||
// NOTE: other modifiers applied instead of current one
|
||||
|
||||
// TODO: check that modification is possible (not all casts are possible)
|
||||
modified_result.Set(state<Types>().add_modification_of(
|
||||
modified_result.Get(), expr.modifier));
|
||||
modified_result.Set(
|
||||
state<Types>().AddModificationOf(modified_result.Get(), expr.modifier));
|
||||
}
|
||||
|
||||
return TypeCheckFromArgs(modified_result.Get(), args, current_pos);
|
||||
|
|
@ -510,7 +507,7 @@ Result CheckTask<nodes::Lambda>::operator()(const nodes::Lambda &expr,
|
|||
}
|
||||
|
||||
const auto expected_type = args.expected().front();
|
||||
if (!expected_type.get()->is_builtin(builtin::Type::FUNCTION)) {
|
||||
if (!expected_type.get().IsBuiltin(builtin::Type::FUNCTION)) {
|
||||
TypeCheckError("Type of lambda function should be function", current_pos);
|
||||
}
|
||||
|
||||
|
|
@ -539,7 +536,7 @@ Result CheckTask<nodes::Lambda>::operator()(const nodes::Lambda &expr,
|
|||
|
||||
for (size_t i = 0; i < expr.args.size(); ++i) {
|
||||
if (not state<State>().InsertVariable(expr.args.at(i).value,
|
||||
state<Types>().add_generic_type(),
|
||||
state<Types>().AddGenericType(),
|
||||
nodes::NameDefinition::Kind::LET)) {
|
||||
// TODO: choose LET / CONST
|
||||
TypeCheckError("Variable is already defined in this context",
|
||||
|
|
@ -580,7 +577,7 @@ Result CheckTask<nodes::Extra>::operator()(const nodes::Extra &, const Args &) {
|
|||
|
||||
//
|
||||
|
||||
return Result(state<Types>().primitive(builtin::Type::UNIT));
|
||||
return Result(state<Types>().Primitive(builtin::Type::UNIT));
|
||||
}
|
||||
|
||||
// NOTE: CHECKED
|
||||
|
|
@ -590,7 +587,7 @@ Result CheckTask<nodes::EmptyLines>::operator()(const nodes::EmptyLines &,
|
|||
|
||||
//
|
||||
|
||||
return Result(state<Types>().primitive(builtin::Type::UNIT));
|
||||
return Result(state<Types>().Primitive(builtin::Type::UNIT));
|
||||
}
|
||||
|
||||
} // namespace type_check
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ nodes::Type CheckSameToPassTypeInArgs(nodes::Type type, const Args &args,
|
|||
logc.Error<Log::kProc>({{message}} /* TODO: node */);
|
||||
}
|
||||
|
||||
return executor.state<Types>().primitive(builtin::Type::BOOL);
|
||||
return executor.state<Types>().Primitive(builtin::Type::BOOL);
|
||||
}
|
||||
|
||||
Result CheckTypeSameToExpected(nodes::Type type, const Args &args,
|
||||
|
|
@ -99,8 +99,8 @@ std::optional<nodes::Type> UnfoldUserDefinedType(nodes::Type type,
|
|||
bool handle_errors) {
|
||||
Log::Context logc(executor.log(), Log::Area::kTypeCheck);
|
||||
|
||||
const auto maybe_type_definition = FindTypeDefinition(
|
||||
type.get()->get_name()->value, pos, executor, handle_errors);
|
||||
const auto maybe_type_definition =
|
||||
FindTypeDefinition(type.get().name.value, pos, executor, handle_errors);
|
||||
|
||||
if (!maybe_type_definition.has_value()) {
|
||||
return std::nullopt;
|
||||
|
|
@ -110,13 +110,13 @@ std::optional<nodes::Type> UnfoldUserDefinedType(nodes::Type type,
|
|||
if (handle_errors) {
|
||||
logc.Error<Log::kProc>({{std::format(
|
||||
"Only type declaration found for type {} (type is not defined)",
|
||||
type.get()->get_name()->value)}} /* TODO: node*/);
|
||||
type.get().name.value)}} /* TODO: node*/);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// TODO: perform type args substitution
|
||||
logc.Require<Log::kProc>(type.get()->parameters_size() == 0,
|
||||
logc.Require<Log::kProc>(type.get().params.size() == 0,
|
||||
{{"Unfold of generic type is not supported (yet)"}});
|
||||
//
|
||||
return maybe_type_definition.value()->type.value();
|
||||
|
|
@ -127,10 +127,10 @@ FieldTypeByName(nodes::Type type, const std::string &field,
|
|||
const utils::Pos &pos, Executor &executor, bool handle_errors) {
|
||||
Log::Context logc(executor.log(), Log::Area::kTypeCheck);
|
||||
|
||||
switch (type.get()->to_builtin()) {
|
||||
switch (type.get().ToBuiltin()) {
|
||||
case builtin::Type::TUPLE: { // access field
|
||||
|
||||
const auto maybe_field = type.get()->get_parameter_proxy_by_name(field);
|
||||
const auto maybe_field = type.get().ParamByName(field);
|
||||
|
||||
if (not maybe_field.has_value() and handle_errors) {
|
||||
// TODO: pass unfolded type name to log it ??
|
||||
|
|
@ -159,7 +159,7 @@ FieldTypeByName(nodes::Type type, const std::string &field,
|
|||
logc.Error<Log::kProc>(
|
||||
{{std::format("Type {} has no accessible fields by definition",
|
||||
builtin::types::to_string(
|
||||
type.get()->to_builtin()))}} /* TODO: node */);
|
||||
type.get().ToBuiltin()))}} /* TODO: node */);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue