diff --git a/deps/tree-sitter-lang b/deps/tree-sitter-lang index 1c19b47..a75ea80 160000 --- a/deps/tree-sitter-lang +++ b/deps/tree-sitter-lang @@ -1 +1 @@ -Subproject commit 1c19b471990acb91cc0ccc9426d988debab8cb27 +Subproject commit a75ea8012d6b104fb26efcd17e5ebc02ab49f7af diff --git a/include/statement_nodes.hpp b/include/statement_nodes.hpp index c86929d..7a1c661 100644 --- a/include/statement_nodes.hpp +++ b/include/statement_nodes.hpp @@ -256,6 +256,10 @@ public: return are_annotations_same_to_names_; } + // + + bool combine(FunctionDefinition &&other_function_definition); + private: SymbolDocs docs_; std::vector constraints_; @@ -326,6 +330,10 @@ public: return &methods_.at(id); } + // + + bool combine(TypeDefinition &&other_type_definition); + private: SymbolDocs docs_; bool is_on_heap_; @@ -378,6 +386,10 @@ public: return &methods_.at(id); } + // + + bool combine(TypeclassDefinition &&other_typeclass_definition); + private: SymbolDocs docs_; Identifier name_; diff --git a/src/statement_nodes.cpp b/src/statement_nodes.cpp new file mode 100644 index 0000000..ca028a9 --- /dev/null +++ b/src/statement_nodes.cpp @@ -0,0 +1,256 @@ +#include "statement_nodes.hpp" + +namespace nodes { + +// TODO: return error type instead of bool ?? +bool FunctionDefinition::combine( + FunctionDefinition &&other_function_definition) { + // should be same in all definitions of one function + if (*name_.get() != *other_function_definition.name_.get()) { + return false; + } + if (modifier_ != other_function_definition.modifier_) { + return false; + } + if (are_annotations_same_to_names_ != + other_function_definition.are_annotations_same_to_names_) { + return false; + } + + // only one definition should have constraints + if (!constraints_.empty() && + !other_function_definition.constraints_.empty()) { + return false; + } + + // only one definition should have expression + if (expression_.has_value() && + other_function_definition.expression_.has_value()) { + return false; + } + + // only one definition should have documentation + if (docs_.get_description().has_value() && + other_function_definition.docs_.get_description().has_value()) { + return false; + } + if (docs_.get_annotations_info_size() > 0 && + other_function_definition.docs_.get_annotations_info_size() > 0) { + return false; + } + + // TODO: think about required checks + // check, that function definitions have same named arguments count + for (size_t i = 0; i < std::max(arguments_.size(), + other_function_definition.arguments_.size()); + ++i) { + if (i < arguments_.size() && + i < other_function_definition.arguments_.size()) { + + // check that all argument annotations are the same + if ((!arguments_[i].get_annotation().has_value() && + !other_function_definition.arguments_[i] + .get_annotation() + .has_value()) || + (arguments_[i].get_annotation().has_value() && + other_function_definition.arguments_[i] + .get_annotation() + .has_value() && + *arguments_[i].get_annotation().value() != + *other_function_definition.arguments_[i] + .get_annotation() + .value())) { + return false; + } + + // check that all argument names are the same + if ((!arguments_[i].get_name().has_value() && + !other_function_definition.arguments_[i].get_name().has_value()) || + (arguments_[i].get_name().has_value() && + other_function_definition.arguments_[i].get_name().has_value() && + *arguments_[i].get_name().value()->get() != + *other_function_definition.arguments_[i] + .get_name() + .value() + ->get())) { + return false; + } + + // check that types are are in zero or one set of arguments (TODO: can be + // same and in two sets ??) + if (arguments_[i].get_type().has_value() && + other_function_definition.arguments_[i].get_type().has_value()) { + return false; + } + + // argument modifiers should be same + if (arguments_[i].get_before_modifier() != + other_function_definition.arguments_[i].get_before_modifier() || + arguments_[i].get_after_modifier() != + other_function_definition.arguments_[i].get_after_modifier()) { + return false; + } + + // TODO: other checks (annotations, ...) + + } else if (i < arguments_.size()) { + // last arguments shouldn't be annotated (because they are not annotated + // in other function definition statement) + if (arguments_[i].get_annotation().has_value()) { + return false; + } + + // last arguments can only be unnamed arguments (returned values) + if (arguments_[i].get_name().has_value()) { + return false; + } + } else { // i < other_function_definition.size() + // last arguments shouldn't be annotated (because they are not annotated + // in other function definition statement) + if (other_function_definition.arguments_[i] + .get_annotation() + .has_value()) { + return false; + } + + // last arguments can only be unnamed arguments (returned values) + if (other_function_definition.arguments_[i].get_name().has_value()) { + return false; + } + } + } + + // combine docs + // all docs should be in one definition + if (other_function_definition.docs_.get_description().has_value() || + other_function_definition.docs_.get_annotations_info_size() > 0) { + if (docs_.get_annotations_info_size() > 0 || + docs_.get_description().has_value()) { + return false; + } + + docs_ = std::move(other_function_definition.docs_); + } + + if (!other_function_definition.constraints_.empty()) { + constraints_ = std::move(other_function_definition.constraints_); + } + + if (other_function_definition.expression_.has_value()) { + expression_ = other_function_definition.expression_; + } + + // TODO: arguments: check and merge + + return true; +} + +bool TypeDefinition::combine(TypeDefinition &&other_type_definition) { + // should be same in all definitions of one type + if (*name_.get() != *other_type_definition.name_.get()) { + return false; + } + if (is_on_heap_ != other_type_definition.is_on_heap_) { + return false; + } + + // only one definition should have documentation + if (docs_.get_description().has_value() && + other_type_definition.docs_.get_description().has_value()) { + return false; + } + if (docs_.get_annotations_info_size() > 0 && + other_type_definition.docs_.get_annotations_info_size() > 0) { + return false; + } + + // only one definition should define type and arguments (they should be + // defined in one place) + if ((other_type_definition.type_.has_value() || + !other_type_definition.arguments_.empty()) && + (type_.has_value() || !arguments_.empty())) { + return false; + } + + // combine docs + // all docs should be in one definition + if (other_type_definition.docs_.get_description().has_value() || + other_type_definition.docs_.get_annotations_info_size() > 0) { + if (docs_.get_annotations_info_size() > 0 || + docs_.get_description().has_value()) { + return false; + } + + docs_ = std::move(other_type_definition.docs_); + } + + if (!other_type_definition.arguments_.empty()) { + arguments_ = std::move(other_type_definition.arguments_); + } + + if (other_type_definition.type_.has_value()) { + type_ = std::move(other_type_definition.type_); + } + + methods_.reserve(methods_.size() + other_type_definition.methods_.size()); + + for (size_t i = 0; i < other_type_definition.methods_.size(); ++i) { + methods_.push_back(std::move(other_type_definition.methods_[i])); + } + + // TODO: combine methods ?? + + return true; +} + +bool TypeclassDefinition::combine( + TypeclassDefinition &&other_typeclass_definition) { + // should be same in all definitions of one typeclass + if (*name_.get() != *other_typeclass_definition.name_.get()) { + return false; + } + + // only one definition should have documentation + if (docs_.get_description().has_value() && + other_typeclass_definition.docs_.get_description().has_value()) { + return false; + } + if (docs_.get_annotations_info_size() > 0 && + other_typeclass_definition.docs_.get_annotations_info_size() > 0) { + return false; + } + + // only one definition should define base typeclasses + if (!base_typeclasses_.empty() && + !other_typeclass_definition.base_typeclasses_.empty()) { + return false; + } + + // combine docs + // all docs should be in one definition + if (other_typeclass_definition.docs_.get_description().has_value() || + other_typeclass_definition.docs_.get_annotations_info_size() > 0) { + if (docs_.get_annotations_info_size() > 0 || + docs_.get_description().has_value()) { + return false; + } + + docs_ = std::move(other_typeclass_definition.docs_); + } + + if (!other_typeclass_definition.base_typeclasses_.empty()) { + base_typeclasses_ = std::move(other_typeclass_definition.base_typeclasses_); + } + + methods_.reserve(methods_.size() + + other_typeclass_definition.methods_.size()); + for (size_t i = 0; i < other_typeclass_definition.methods_.size(); ++i) { + methods_.push_back(std::move(other_typeclass_definition.methods_[i])); + } + + // TODO: combine methods ?? + + return true; +} + +} // namespace nodes