diff --git a/src/execute_visitor.cpp b/src/execute_visitor.cpp index 1b0e278..ff2a219 100644 --- a/src/execute_visitor.cpp +++ b/src/execute_visitor.cpp @@ -603,14 +603,32 @@ void ExecuteVisitor::Visit(FunctionCallExpression* node) { size_t index_shift = (node->is_method_of_first_argument_ ? 1 : 0); // handle arguments - for (size_t i = index_shift; i < node->arguments.size(); ++i) { - Visitor::Visit(node->arguments[i].second); + bool all_arguments = function_declaration->type->types.size() <= node->arguments.size() + 1 - index_shift; - // function arguments can't be changed inside function - current_value_ = context_manager_.ToModifiedValue(current_value_, utils::ValueType::Const); - if (!context_manager_.DefineVariable(function_definition->definition->arguments[i - index_shift], - current_value_)) { - error_handling::HandleRuntimeError("Variable redefinition (function argument)", node->base); + { + size_t i = index_shift; // function call argument id + size_t j = 0; // actual argument id + for (; j + 1 < function_declaration->type->types.size(); ++j) { // last type in function declaration is return type + if (!all_arguments && i < node->arguments.size() && !node->arguments[i].first.has_value()) { + error_handling::HandleRuntimeError("Function call argument has no annotation (in function with part of arguments)", node->base); + } + + if (i < node->arguments.size() && (all_arguments || (function_declaration->type->types[j].first.has_value() && function_declaration->type->types[j].first.value() == node->arguments[i].first.value()))) { + Visitor::Visit(node->arguments[i].second); + ++i; + + // function arguments can't be changed inside function + current_value_ = context_manager_.ToModifiedValue(current_value_, utils::ValueType::Const); + } else { + current_value_ = context_manager_.AddValue(info::value::OptionalValue(std::nullopt, + context_manager_.GetValueManager()), + utils::ValueType::Const); + } + + if (!context_manager_.DefineVariable(function_definition->definition->arguments[j], + current_value_)) { + error_handling::HandleRuntimeError("Variable redefinition (function argument)", node->base); + } } } diff --git a/src/type_check_visitor.cpp b/src/type_check_visitor.cpp index 66faced..6b676d9 100644 --- a/src/type_check_visitor.cpp +++ b/src/type_check_visitor.cpp @@ -794,10 +794,11 @@ void TypeCheckVisitor::Visit(FunctionCallExpression* node) { // check & collect parmeters if (function_declaration->parameters.size() != node->parameters.size()) { - if (node->parameters.size() != 0) { + // if (node->parameters.size() != 0) { error_handling::HandleTypecheckError("Mismatched parameter count in function call expression", node->base); - } - deduce_parameters = true; + // } + // deduce_parameters = true; + // TODO: paramters deduction } for (size_t i = 0; i < node->parameters.size(); ++i) { Visit(node->parameters[i].get()); @@ -823,25 +824,66 @@ void TypeCheckVisitor::Visit(FunctionCallExpression* node) { size_t index_shift = (node->is_method_of_first_argument_ ? 1 : 0); // check arguments - if (function_declaration->type->types.size() != node->arguments.size() + 1 - index_shift) { + if (function_declaration->type->types.size() < node->arguments.size() + 1 - index_shift) { error_handling::HandleTypecheckError("Mismatched argument count in function call expression", node->base); } - for (size_t i = index_shift; i < node->arguments.size(); ++i) { - Visit(function_declaration->type->types[i - index_shift].second.get()); - utils::IdType argument_type = TypeInContext(current_type_, context); + bool all_arguments = function_declaration->type->types.size() <= node->arguments.size() + 1 - index_shift; - if (node->arguments[i].first.has_value()) { - if (!function_declaration->type->types[i - index_shift].first.has_value()) { - error_handling::HandleTypecheckError("Declared argument has no annotation (argument " + std::to_string(i - index_shift + 1) + ")", node->base); - } else if (node->arguments[i].first.value() != function_declaration->type->types[i - index_shift].first.value()) { - error_handling::HandleTypecheckError("Wrong argument annotation (argument " + std::to_string(i - index_shift + 1) + ")", node->base); + { + size_t i = index_shift; // function call argument id + size_t j = 0; // actual argument id + for (; i < node->arguments.size() && j + 1 < function_declaration->type->types.size(); ++j) { // last type in function declaration is return type + if (!all_arguments) { + if (!node->arguments[i].first.has_value()) { // function calls with part of arguments should have annotations for all arguments + error_handling::HandleTypecheckError("Not all arguments annotated in function call expression with part of arguments (argument " + std::to_string(j + 1) + ")", node->base); + } + + if (!function_declaration->type->types[j].first.has_value() || function_declaration->type->types[j].first.value() != node->arguments[i].first.value()) { + if (!function_declaration->type->types[j].second->references.empty() || + !std::holds_alternative>(function_declaration->type->types[j].second->type) || + !std::get>(function_declaration->type->types[j].second->type)->is_optional + ) { + // TODO: make separated OptionalType ?? + error_handling::HandleTypecheckError("All missed arguments should be optionals in function call expression with part of arguments (argument " + std::to_string(j + 1) + ")", node->base); + } + continue; + } } + + Visit(function_declaration->type->types[j].second.get()); + utils::IdType argument_type = TypeInContext(current_type_, context); + + if (node->arguments[i].first.has_value()) { + if (!function_declaration->type->types[j].first.has_value()) { + error_handling::HandleTypecheckError("Declared argument has no annotation (argument " + std::to_string(j + 1) + ")", node->base); + } else if (node->arguments[i].first.value() != function_declaration->type->types[j].first.value()) { + error_handling::HandleTypecheckError("Wrong argument annotation (argument " + std::to_string(j + 1) + ")", node->base); + } + } + + Visitor::Visit(node->arguments[i].second); + if (!context_manager_.AddValueRequirement(current_type_, argument_type)) { + error_handling::HandleTypecheckError("Wrong argument type (argument " + std::to_string(j + 1) + ")", node->base); + } + + ++i; } - Visitor::Visit(node->arguments[i].second); - if (!context_manager_.AddValueRequirement(current_type_, argument_type)) { - error_handling::HandleTypecheckError("Wrong argument type (argument " + std::to_string(i - index_shift + 1) + ")", node->base); + if (i < node->arguments.size()) { + error_handling::HandleTypecheckError("More arguments then needed in function call expression", node->base); + } + + if (j + 1 < function_declaration->type->types.size()) { // last type is return type + for (; j + 1 < function_declaration->type->types.size(); ++j) { + if (!function_declaration->type->types[j].second->references.empty() || + !std::holds_alternative>(function_declaration->type->types[j].second->type) || + !std::get>(function_declaration->type->types[j].second->type)->is_optional + ) { + // TODO: make separated OptionalType ?? + error_handling::HandleTypecheckError("All missed arguments should be optionals in function call expression with part of arguments (after last argument)", node->base); + } + } } } diff --git a/tests/test_code.lang b/tests/test_code.lang index 27d0eb8..e963ab7 100644 --- a/tests/test_code.lang +++ b/tests/test_code.lang @@ -213,9 +213,15 @@ def ( -- ) : begin end = { decl scan-int : -> \int def scan-int = \int..read: (\io..scan:) -decl print-int : ::x \int -> \unit +decl print-int : \int -> \unit def print-int : x = \io..print: (x..show:) +decl print-int-with-comment : ::i \int -> \string? -> \unit +def print-int-with-comment : i maybe-comment = { + ; \io..print: (i..show:) + var comment? = maybe-comment in \io..print: comment +} + decl scan-anything 'a[#read] : -> 'a def scan-anything = 'a..read: (\io..scan:) @@ -272,7 +278,7 @@ exec main { ; print-anything:[int] n - ; print-int: ::x 123 + ; print-int-with-comment: ::i 123 var & a & b & c = scan-three-t: ; \io..print: b