optional arguments, fixes

This commit is contained in:
ProgramSnail 2023-07-07 17:59:32 +03:00
parent 8647918f37
commit a208e2f42d
3 changed files with 90 additions and 24 deletions

View file

@ -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);
}
}
}

View file

@ -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<std::unique_ptr<TypeExpression>>(function_declaration->type->types[j].second->type) ||
!std::get<std::unique_ptr<TypeExpression>>(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<std::unique_ptr<TypeExpression>>(function_declaration->type->types[j].second->type) ||
!std::get<std::unique_ptr<TypeExpression>>(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);
}
}
}
}