combine functions fixes

This commit is contained in:
ProgramSnail 2023-08-02 13:10:16 +03:00
parent 5e70f0015f
commit 4714a05467
5 changed files with 117 additions and 44 deletions

View file

@ -115,6 +115,16 @@ public:
value_ += name;
}
//
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);
}
private:
IdentifierType type_;
std::string value_;

View file

@ -17,6 +17,7 @@ enum class CombineResult {
MORE_THEN_ONE_DOCS_ERROR,
MORE_THEN_ONE_CONSTRAINTS_ERROR,
MORE_THEN_ONE_DEFINITION_BODY_ERROR,
TYPECLASSES_ERROR,
ARGUMENTS_ERROR,
DIFFERENT_STATEMENT_TYPES,
STATEMENTS_CANT_BE_COMBINED_ERROR,

View file

@ -56,10 +56,14 @@ public:
: Node(node), name_(identifier), parameters_(std::move(parameters)),
is_on_heap_(is_on_heap), modifier_(modifier) {}
//
Identifier *get_name() { return &name_; }
const Identifier *get_name() const { return &name_; }
//
size_t get_parametrs_size() const { return parameters_.size(); }
Type *get_parameter(size_t id) { return parameters_.at(id).get(); }
@ -68,10 +72,34 @@ public:
return parameters_.at(id).get();
}
//
bool is_on_heap() const { return is_on_heap_; }
Modifier get_modifier() const { return modifier_; }
//
bool operator==(const Type &other_type) const {
if (name_ != other_type.name_ || is_on_heap_ != other_type.is_on_heap_ ||
modifier_ != other_type.modifier_ ||
parameters_.size() != other_type.parameters_.size()) {
return false;
}
for (size_t i = 0; i < parameters_.size(); ++i) {
if (*parameters_[i].get() != *other_type.parameters_[i].get()) {
return false;
}
}
return true;
}
bool operator!=(const Type &other_type) const {
return !(*this == other_type);
}
private:
Identifier name_;
std::vector<TypeProxy> parameters_;

View file

@ -166,8 +166,8 @@ parser::ParseTree::Node collect_symbol_doc_nodes(
return current_node;
}
// definition_info? annotation_info* '^'? simple_type (argument_type* '='
// variant_type)? ('{' function_definition* '}' | ';')
// definition_info? annotation_info* '^'? (simple_type | typeclass)
// (argument_type* '=' variant_type)? ';'
nodes::TypeDefinition build_type_definition(parser::ParseTree::Node parser_node,
nodes::TypeStorage &type_storage) {
bool is_on_heap = parser_node.nth_child(0).get_value() == "^";
@ -262,7 +262,7 @@ nodes::TypeDefinition build_type_definition(parser::ParseTree::Node parser_node,
std::move(type));
}
// definition_info? annotation_info* (constraint ';')* _var_let_? (simple_name
// definition_info? annotation_info* (constraint ';')* '.'? (simple_name
// | '(' operator ')') (annotation? _reference_? argument_name '?'?)* (:
// (annotation? _reference_ type)+)?
// ('=' (block | expression ';') | ';')
@ -410,6 +410,13 @@ nodes::FunctionDefinition build_function_definition(
"Less types then arguments in function definition", parser_node);
}
if (current_type_id == 0 && !expression_node.has_value()) {
error_handling::handle_parsing_error(
"Can't declare function without types (types or function body should "
"be added)",
parser_node);
}
// automatic annotations
bool are_annotations_same_to_names =
(!at_least_one_argument_annotation_found && current_type_id == 0);

View file

@ -6,29 +6,34 @@
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()) {
if (name_ != other_function_definition.name_) {
return false;
}
return true;
}
// TODO: function overloading, etc. ??
// TODO
// possible configurations:
// name 'arg1 'arg2 'arg3 : Type1 Type2 Type3 -> Type4; // function declaration
// name 'arg1 'arg2 'arg3 : Type1 Type2 Type3 -> Type4 = ... // function
// definition (with types)
// name 'arg1 'arg2 -> 'arg3 = ... // function definition (without types)
CombineResult
FunctionDefinition::combine(FunctionDefinition &&other_function_definition) {
// should be same in all definitions of one function
if (*name_.get() != *other_function_definition.name_.get()) {
// names should be the same
if (name_ != other_function_definition.name_) {
return CombineResult::DIFFERENT_NAME_ERROR;
}
// modifiers should be the same
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;
@ -40,7 +45,7 @@ FunctionDefinition::combine(FunctionDefinition &&other_function_definition) {
return CombineResult::MORE_THEN_ONE_CONSTRAINTS_ERROR;
}
// only one definition should have expression
// only one definition should have expression (body)
if (expression_.has_value() &&
other_function_definition.expression_.has_value()) {
return CombineResult::MORE_THEN_ONE_DEFINITION_BODY_ERROR;
@ -56,15 +61,14 @@ FunctionDefinition::combine(FunctionDefinition &&other_function_definition) {
return CombineResult::MORE_THEN_ONE_DOCS_ERROR;
}
// TODO: think about required checks
// check, that function definitions have same named arguments count
// check, that function definitions have same named arguments
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
// annotations should be the same
if ((!arguments_[i].get_annotation().has_value() &&
!other_function_definition.arguments_[i]
.get_annotation()
@ -80,27 +84,25 @@ FunctionDefinition::combine(FunctionDefinition &&other_function_definition) {
return CombineResult::ARGUMENTS_ERROR;
}
// check that all argument names are the same
// argument names should be 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())) {
arguments_[i].get_name().value() !=
other_function_definition.arguments_[i].get_name().value())) {
return CombineResult::ARGUMENTS_ERROR;
}
// check that types are are in zero or one set of arguments (TODO: can be
// same and in two sets ??)
// types should be the same (if present in both definitions)
if (arguments_[i].get_type().has_value() &&
other_function_definition.arguments_[i].get_type().has_value()) {
other_function_definition.arguments_[i].get_type().has_value() &&
*arguments_[i].get_type().value() !=
*other_function_definition.arguments_[i].get_type().value()) {
return CombineResult::ARGUMENTS_ERROR;
}
// argument modifiers should be same
// argument modifiers should be the same
if (arguments_[i].get_before_modifier() !=
other_function_definition.arguments_[i].get_before_modifier() ||
arguments_[i].get_after_modifier() !=
@ -108,26 +110,24 @@ FunctionDefinition::combine(FunctionDefinition &&other_function_definition) {
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)
// annotations should be the same
if (arguments_[i].get_annotation().has_value()) {
return CombineResult::ARGUMENTS_ERROR;
}
// last arguments can only be unnamed arguments (returned values)
// names should be the same
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)
// annotations should be the same
if (other_function_definition.arguments_[i]
.get_annotation()
.has_value()) {
return CombineResult::ARGUMENTS_ERROR;
}
// last arguments can only be unnamed arguments (returned values)
// names should be the same
if (other_function_definition.arguments_[i].get_name().has_value()) {
return CombineResult::ARGUMENTS_ERROR;
}
@ -175,21 +175,47 @@ FunctionDefinition::combine(FunctionDefinition &&other_function_definition) {
bool TypeDefinition::is_same_to(
const TypeDefinition &other_type_definition) const {
if (*name_.get() != *other_type_definition.name_.get()) {
if (name_ != other_type_definition.name_) {
return false;
}
return true;
}
// possible configurations:
// Type[...] 'A 'B 'C; // declare type / define typeclass (statement without
// args in this case)
// Type[...] 'A 'B 'C = ... // define type
CombineResult TypeDefinition::combine(TypeDefinition &&other_type_definition) {
// should be same in all definitions of one type
if (*name_.get() != *other_type_definition.name_.get()) {
// name should be same
if (name_ != other_type_definition.name_) {
return CombineResult::DIFFERENT_NAME_ERROR;
}
// modifier should be the same
if (is_on_heap_ != other_type_definition.is_on_heap_) {
return CombineResult::DIFFERNENT_MODIFIER_ERROR;
}
// typeclasses should be the same
if (typeclasses_.size() != other_type_definition.typeclasses_.size()) {
return CombineResult::ARGUMENTS_ERROR;
}
for (size_t i = 0; i < typeclasses_.size(); ++i) {
if (typeclasses_[i] != other_type_definition.typeclasses_[i]) {
return CombineResult::ARGUMENTS_ERROR;
}
}
// arguments should be the same
if (arguments_.size() != other_type_definition.arguments_.size()) {
return CombineResult::ARGUMENTS_ERROR;
}
for (size_t i = 0; i < arguments_.size(); ++i) {
if (arguments_[i] != other_type_definition.arguments_[i]) {
return CombineResult::ARGUMENTS_ERROR;
}
}
// only one definition should have documentation
if (docs_.get_description().has_value() &&
other_type_definition.docs_.get_description().has_value()) {
@ -200,12 +226,9 @@ CombineResult TypeDefinition::combine(TypeDefinition &&other_type_definition) {
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;
// only one type should define type / body
if (type_.has_value() && other_type_definition.type_.has_value()) {
return CombineResult::MORE_THEN_ONE_DEFINITION_BODY_ERROR;
}
// combine docs
@ -220,10 +243,6 @@ CombineResult TypeDefinition::combine(TypeDefinition &&other_type_definition) {
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_);
}
@ -247,9 +266,13 @@ bool Statement::is_same_to(const Statement &other_statement) const {
return std::get<FunctionDefinition>(expression_)
.is_same_to(std::move(
std::get<FunctionDefinition>(other_statement.expression_)));
case 3: // EmptyLines
case 3: // Extra
return false;
case 4: // EmptyLines
return false;
default:
error_handling::handle_general_error(
"Unexpected statement type in is_same_to");
break;
}
@ -273,9 +296,13 @@ CombineResult Statement::combine(Statement &&other_statement) {
return std::get<FunctionDefinition>(expression_)
.combine(std::move(
std::get<FunctionDefinition>(other_statement.expression_)));
case 3: // EmptyLines
case 3: // Extra
return CombineResult::STATEMENTS_CANT_BE_COMBINED_ERROR;
case 4: // EmptyLines
return CombineResult::STATEMENTS_CANT_BE_COMBINED_ERROR;
default:
error_handling::handle_general_error(
"Unexpected statement type in combine");
break;
}