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); size_t index_shift = (node->is_method_of_first_argument_ ? 1 : 0);
// handle arguments // handle arguments
for (size_t i = index_shift; i < node->arguments.size(); ++i) { bool all_arguments = function_declaration->type->types.size() <= node->arguments.size() + 1 - index_shift;
Visitor::Visit(node->arguments[i].second);
// function arguments can't be changed inside function {
current_value_ = context_manager_.ToModifiedValue(current_value_, utils::ValueType::Const); size_t i = index_shift; // function call argument id
if (!context_manager_.DefineVariable(function_definition->definition->arguments[i - index_shift], size_t j = 0; // actual argument id
current_value_)) { for (; j + 1 < function_declaration->type->types.size(); ++j) { // last type in function declaration is return type
error_handling::HandleRuntimeError("Variable redefinition (function argument)", node->base); 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 // check & collect parmeters
if (function_declaration->parameters.size() != node->parameters.size()) { 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); 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) { for (size_t i = 0; i < node->parameters.size(); ++i) {
Visit(node->parameters[i].get()); 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); size_t index_shift = (node->is_method_of_first_argument_ ? 1 : 0);
// check arguments // 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); error_handling::HandleTypecheckError("Mismatched argument count in function call expression", node->base);
} }
for (size_t i = index_shift; i < node->arguments.size(); ++i) { bool all_arguments = function_declaration->type->types.size() <= node->arguments.size() + 1 - index_shift;
Visit(function_declaration->type->types[i - index_shift].second.get());
utils::IdType argument_type = TypeInContext(current_type_, context);
if (node->arguments[i].first.has_value()) { {
if (!function_declaration->type->types[i - index_shift].first.has_value()) { size_t i = index_shift; // function call argument id
error_handling::HandleTypecheckError("Declared argument has no annotation (argument " + std::to_string(i - index_shift + 1) + ")", node->base); size_t j = 0; // actual argument id
} else if (node->arguments[i].first.value() != function_declaration->type->types[i - index_shift].first.value()) { for (; i < node->arguments.size() && j + 1 < function_declaration->type->types.size(); ++j) { // last type in function declaration is return type
error_handling::HandleTypecheckError("Wrong argument annotation (argument " + std::to_string(i - index_shift + 1) + ")", node->base); 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 (i < node->arguments.size()) {
if (!context_manager_.AddValueRequirement(current_type_, argument_type)) { error_handling::HandleTypecheckError("More arguments then needed in function call expression", node->base);
error_handling::HandleTypecheckError("Wrong argument type (argument " + std::to_string(i - index_shift + 1) + ")", 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);
}
}
} }
} }

View file

@ -213,9 +213,15 @@ def ( -- ) : begin end = {
decl scan-int : -> \int decl scan-int : -> \int
def scan-int = \int..read: (\io..scan:) 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:) 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 decl scan-anything 'a[#read] : -> 'a
def scan-anything = 'a..read: (\io..scan:) def scan-anything = 'a..read: (\io..scan:)
@ -272,7 +278,7 @@ exec main {
; print-anything:[int] n ; print-anything:[int] n
; print-int: ::x 123 ; print-int-with-comment: ::i 123
var & a & b & c = scan-three-t: var & a & b & c = scan-three-t:
; \io..print: b ; \io..print: b