#include "statement_nodes.hpp" #include "error_handling.hpp" #include "utils.hpp" #include namespace nodes { // TODO: function overloading, etc. ?? bool FunctionDefinition::is_same_to( const FunctionDefinition &other_function_definition) const { if (*name_.get() != *other_function_definition.name_.get()) { return false; } return true; } // TODO: function overloading, etc. ?? CombineResult FunctionDefinition::combine(FunctionDefinition &&other_function_definition) { // should be same in all definitions of one function if (*name_.get() != *other_function_definition.name_.get()) { return CombineResult::DIFFERENT_NAME_ERROR; } if (return_modifier_ != other_function_definition.return_modifier_) { return CombineResult::DIFFERNENT_MODIFIER_ERROR; } if (is_method_ != other_function_definition.is_method_) { return CombineResult::DIFFERNENT_MODIFIER_ERROR; // other error type ?? } if (are_annotations_same_to_names_ != other_function_definition.are_annotations_same_to_names_) { return CombineResult::ARGUMENTS_ERROR; } // only one definition should have constraints if (!constraints_.empty() && !other_function_definition.constraints_.empty()) { return CombineResult::MORE_THEN_ONE_CONSTRAINTS_ERROR; } // only one definition should have expression if (expression_.has_value() && other_function_definition.expression_.has_value()) { return CombineResult::MORE_THEN_ONE_DEFINITION_BODY_ERROR; } // only one definition should have documentation if (docs_.get_description().has_value() && other_function_definition.docs_.get_description().has_value()) { return CombineResult::MORE_THEN_ONE_DOCS_ERROR; } if (docs_.get_annotations_info_size() > 0 && other_function_definition.docs_.get_annotations_info_size() > 0) { return CombineResult::MORE_THEN_ONE_DOCS_ERROR; } // 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 CombineResult::ARGUMENTS_ERROR; } // 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 CombineResult::ARGUMENTS_ERROR; } // 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 CombineResult::ARGUMENTS_ERROR; } // 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 CombineResult::ARGUMENTS_ERROR; } } 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 CombineResult::ARGUMENTS_ERROR; } // last arguments can only be unnamed arguments (returned values) if (arguments_[i].get_name().has_value()) { return CombineResult::ARGUMENTS_ERROR; } } 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 CombineResult::ARGUMENTS_ERROR; } // last arguments can only be unnamed arguments (returned values) if (other_function_definition.arguments_[i].get_name().has_value()) { return CombineResult::ARGUMENTS_ERROR; } } } // 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 CombineResult::MORE_THEN_ONE_DOCS_ERROR; } 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_; } for (size_t i = 0; i < other_function_definition.arguments_.size(); ++i) { if (i < arguments_.size()) { if (other_function_definition.arguments_[i].get_type().has_value()) { if (arguments_[i].update_type_from( other_function_definition.arguments_[i])) { error_handling::handle_internal_error( "Function arguments are not properly checked before merging " "during combination", *this); } } } else { arguments_.push_back(std::move(other_function_definition.arguments_[i])); } } return CombineResult::OK; } bool TypeDefinition::is_same_to( const TypeDefinition &other_type_definition) const { if (*name_.get() != *other_type_definition.name_.get()) { return false; } return true; } CombineResult TypeDefinition::combine(TypeDefinition &&other_type_definition) { // should be same in all definitions of one type if (*name_.get() != *other_type_definition.name_.get()) { return CombineResult::DIFFERENT_NAME_ERROR; } if (is_on_heap_ != other_type_definition.is_on_heap_) { return CombineResult::DIFFERNENT_MODIFIER_ERROR; } // only one definition should have documentation if (docs_.get_description().has_value() && other_type_definition.docs_.get_description().has_value()) { return CombineResult::MORE_THEN_ONE_DOCS_ERROR; } if (docs_.get_annotations_info_size() > 0 && other_type_definition.docs_.get_annotations_info_size() > 0) { return CombineResult::MORE_THEN_ONE_DOCS_ERROR; } // 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 CombineResult::ARGUMENTS_ERROR; } // 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 CombineResult::MORE_THEN_ONE_DOCS_ERROR; } 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_); } return CombineResult::OK; } bool Statement::is_same_to(const Statement &other_statement) const { if (expression_.index() != other_statement.expression_.index()) { return false; } switch (expression_.index()) { case 0: // Import return false; case 1: // TypeDefinition return std::get(expression_) .is_same_to( std::move(std::get(other_statement.expression_))); case 2: // FunctionDefinition return std::get(expression_) .is_same_to(std::move( std::get(other_statement.expression_))); case 3: // EmptyLines return false; default: break; } error_handling::handle_general_error("Unreachable"); exit(1); } CombineResult Statement::combine(Statement &&other_statement) { if (expression_.index() != other_statement.expression_.index()) { return CombineResult::DIFFERENT_STATEMENT_TYPES; } switch (expression_.index()) { case 0: // Import return CombineResult::STATEMENTS_CANT_BE_COMBINED_ERROR; case 1: // TypeDefinition return std::get(expression_) .combine( std::move(std::get(other_statement.expression_))); case 2: // FunctionDefinition return std::get(expression_) .combine(std::move( std::get(other_statement.expression_))); case 3: // EmptyLines return CombineResult::STATEMENTS_CANT_BE_COMBINED_ERROR; default: break; } error_handling::handle_general_error("Unreachable"); exit(1); } } // namespace nodes