From: Brendan Hansen Date: Fri, 15 Jan 2021 02:39:46 +0000 (-0600) Subject: working very of named arguments for function calls X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=8a6d4ad0af7bed4233d739b42ee121ad389ad27c;p=onyx.git working very of named arguments for function calls --- diff --git a/bin/onyx b/bin/onyx index bb4dec3c..a9abe2a7 100755 Binary files a/bin/onyx and b/bin/onyx differ diff --git a/include/onyxastnodes.h b/include/onyxastnodes.h index 825d2d96..3db35154 100644 --- a/include/onyxastnodes.h +++ b/include/onyxastnodes.h @@ -823,6 +823,12 @@ struct AstPackage { Package* package; }; +typedef struct Arguments Arguments; +struct Arguments { + bh_arr(AstNode *) values; + bh_arr(AstNamedValue *) named_values; +}; + extern AstNode empty_node; typedef enum EntityState { @@ -1006,7 +1012,7 @@ AstNode* make_symbol(bh_allocator a, OnyxToken* sym); typedef enum PolyProcLookupMethod { PPLM_By_Call, PPLM_By_Function_Type, - PPLM_By_Value_Array, + PPLM_By_Arguments, } PolyProcLookupMethod; AstFunction* polymorphic_proc_lookup(AstPolyProc* pp, PolyProcLookupMethod pp_lookup, ptr actual, OnyxFilePos pos); AstFunction* polymorphic_proc_solidify(AstPolyProc* pp, bh_arr(AstPolySolution) slns, OnyxFilePos pos); diff --git a/onyx.exe b/onyx.exe index 2307f964..2bb8a31e 100644 Binary files a/onyx.exe and b/onyx.exe differ diff --git a/src/onyxastnodes.c b/src/onyxastnodes.c index 17dc02b1..bb41ae4b 100644 --- a/src/onyxastnodes.c +++ b/src/onyxastnodes.c @@ -466,6 +466,10 @@ Type* resolve_expression_type(AstTyped* node) { } } + if (node->kind == Ast_Kind_Argument) { + node->type = resolve_expression_type(((AstArgument *) node)->value); + } + if (node->type == NULL) node->type = type_build_from_ast(semstate.allocator, node->type_node); diff --git a/src/onyxchecker.c b/src/onyxchecker.c index f9640cad..34405674 100644 --- a/src/onyxchecker.c +++ b/src/onyxchecker.c @@ -303,7 +303,11 @@ static AstTyped* match_overloaded_function(bh_arr(AstTyped *) arg_arr, bh_arr(As overload = (AstFunction *) *node; } else if ((*node)->kind == Ast_Kind_Polymorphic_Proc) { - overload = polymorphic_proc_build_only_header((AstPolyProc *) *node, PPLM_By_Value_Array, arg_arr); + Arguments args; + args.values = (bh_arr(AstNode*)) arg_arr; + args.named_values = named_values; + + overload = polymorphic_proc_build_only_header((AstPolyProc *) *node, PPLM_By_Arguments, &args); } if (overload == NULL) continue; @@ -312,8 +316,9 @@ static AstTyped* match_overloaded_function(bh_arr(AstTyped *) arg_arr, bh_arr(As if (named_values != NULL && bh_arr_length(named_values) > 0) { new_arg_arr = NULL; bh_arr_new(global_heap_allocator, new_arg_arr, bh_arr_length(arg_arr) + bh_arr_length(named_values)); - fori (i, 0, bh_arr_length(arg_arr)) - new_arg_arr[i] = arg_arr[i]; + fori (i, 0, bh_arr_length(arg_arr)) new_arg_arr[i] = arg_arr[i]; + fori (i, 0, bh_arr_length(named_values)) new_arg_arr[i + bh_arr_length(arg_arr)] = NULL; + bh_arr_set_length(new_arg_arr, bh_arr_length(arg_arr) + bh_arr_length(named_values)); b32 values_place_correctly = fill_in_arguments( (bh_arr(AstNode *)) new_arg_arr, @@ -352,7 +357,7 @@ static AstTyped* match_overloaded_function(bh_arr(AstTyped *) arg_arr, bh_arr(As return (AstTyped *) *node; no_match: - if (named_values != NULL) + if (named_values != NULL && bh_arr_length(named_values) > 0) bh_arr_free(new_arg_arr); continue; @@ -360,6 +365,37 @@ no_match: return NULL; } +static void report_unable_to_match_overload(AstCall* call) { + char* arg_str = bh_alloc(global_scratch_allocator, 1024); + arg_str[0] = '\0'; + + bh_arr_each(AstArgument *, arg, call->arg_arr) { + strncat(arg_str, type_get_name((*arg)->value->type), 1023); + + if (arg != &bh_arr_last(call->arg_arr)) + strncat(arg_str, ", ", 1023); + } + + if (bh_arr_length(call->named_args) > 0) { + bh_arr_each(AstNamedValue *, named_value, call->named_args) { + token_toggle_end((*named_value)->token); + strncat(arg_str, (*named_value)->token->text, 1023); + token_toggle_end((*named_value)->token); + + strncat(arg_str, "=", 1023); + strncat(arg_str, type_get_name(((AstTyped *) (*named_value)->value)->type), 1023); // CHECK: this might say 'unknown'. + + if (named_value != &bh_arr_last(call->named_args)) + strncat(arg_str, ", ", 1023); + } + } + + onyx_report_error(call->token->pos, "unable to match overloaded function with provided argument types: (%s)", arg_str); + + bh_free(global_scratch_allocator, arg_str); +} + + CheckStatus check_argument(AstArgument** parg) { CHECK(expression, (AstTyped **) parg); (*parg)->type = (*parg)->value->type; @@ -411,33 +447,7 @@ CheckStatus check_call(AstCall* call) { ((AstOverloadedFunction *) callee)->overloads); if (call->callee == NULL) { - char* arg_str = bh_alloc(global_scratch_allocator, 1024); - arg_str[0] = '\0'; - - bh_arr_each(AstArgument *, arg, call->arg_arr) { - strncat(arg_str, type_get_name((*arg)->value->type), 1023); - - if (arg != &bh_arr_last(call->arg_arr)) - strncat(arg_str, ", ", 1023); - } - - if (bh_arr_length(call->named_args) > 0) { - bh_arr_each(AstNamedValue *, named_value, call->named_args) { - token_toggle_end((*named_value)->token); - strncat(arg_str, (*named_value)->token->text, 1023); - token_toggle_end((*named_value)->token); - - strncat(arg_str, "=", 1023); - strncat(arg_str, type_get_name(((AstTyped *) (*named_value)->value)->type), 1023); // CHECK: this might say 'unknown'. - - if (named_value != &bh_arr_last(call->named_args)) - strncat(arg_str, ", ", 1023); - } - } - - onyx_report_error(call->token->pos, "unable to match overloaded function with provided argument types: (%s)", arg_str); - - bh_free(global_scratch_allocator, arg_str); + report_unable_to_match_overload(call); return Check_Error; } @@ -470,15 +480,21 @@ CheckStatus check_call(AstCall* call) { return Check_Error; } - i32 arg_count = bh_max( - bh_arr_length(call->arg_arr) + bh_arr_length(call->named_args), - (i32) callee->type->Function.param_count); - - bh_arr_grow(call->arg_arr, arg_count); - fori (i, bh_arr_length(call->arg_arr), arg_count) call->arg_arr[i] = NULL; - bh_arr_set_length(call->arg_arr, arg_count); { + i32 non_vararg_param_count = (i32) callee->type->Function.param_count; + if (non_vararg_param_count > 0 && + callee->type->Function.params[callee->type->Function.param_count - 1] == builtin_vararg_type_type) + non_vararg_param_count--; + + i32 arg_count = bh_max( + bh_arr_length(call->arg_arr) + bh_arr_length(call->named_args), + non_vararg_param_count); + + bh_arr_grow(call->arg_arr, arg_count); + fori (i, bh_arr_length(call->arg_arr), arg_count) call->arg_arr[i] = NULL; + bh_arr_set_length(call->arg_arr, arg_count); + char* err_msg = NULL; fill_in_arguments((AstNode **) call->arg_arr, call->named_args, (AstNode *) callee, &err_msg); @@ -785,6 +801,7 @@ static AstCall* binaryop_try_operator_overload(AstBinaryOp* binop) { *arg = (AstTyped *) make_argument(semstate.node_allocator, *arg); implicit_call->arg_arr = (AstArgument **) args; + implicit_call->named_args = NULL; return implicit_call; } diff --git a/src/onyxutils.c b/src/onyxutils.c index 9c5ab5ab..a0a274f1 100644 --- a/src/onyxutils.c +++ b/src/onyxutils.c @@ -353,6 +353,29 @@ static PolySolveResult solve_poly_type(AstNode* target, AstType* type_expr, Type return result; } +static Type* lookup_actual_type_in_arguments(AstPolyProc* pp, AstPolyParam* param, Arguments* args, char** err_msg) { + bh_arr(AstNode *) arg_arr = args->values; + bh_arr(AstNamedValue *) named_values = args->named_values; + + if (param->idx >= (u64) bh_arr_length(arg_arr)) { + OnyxToken* param_name = pp->base_func->params[param->idx].local->token; + + bh_arr_each(AstNamedValue *, named_value, named_values) { + if (token_equals(param_name, (*named_value)->token)) { + return resolve_expression_type((AstTyped *) (*named_value)->value); + } + } + + // nocheckin + if (err_msg) *err_msg = "Not enough arguments to polymorphic procedure. This error message may not be entirely right."; + + } else { + return resolve_expression_type((AstTyped *) arg_arr[param->idx]); + } + + return NULL; +} + static bh_arr(AstPolySolution) find_polymorphic_slns(AstPolyProc* pp, PolyProcLookupMethod pp_lookup, ptr actual, char** err_msg) { bh_arr(AstPolySolution) slns = NULL; bh_arr_new(global_heap_allocator, slns, bh_arr_length(pp->poly_params)); @@ -369,42 +392,22 @@ static bh_arr(AstPolySolution) find_polymorphic_slns(AstPolyProc* pp, PolyProcLo } if (already_solved) continue; - Type* actual_type; + Type* actual_type = NULL; if (pp_lookup == PPLM_By_Call) { - bh_arr(AstArgument *) arg_arr = ((AstCall *) actual)->arg_arr; - bh_arr(AstNamedValue *) named_values = ((AstCall *) actual)->named_args; - - if (param->idx >= (u64) bh_arr_length(arg_arr)) { - // CLEANUP: This is a really long access chain. - OnyxToken* param_name = pp->base_func->params[param->idx].local->token; - - bh_arr_each(AstNamedValue *, named_value, named_values) { - if (token_equals(param_name, (*named_value)->token)) { - actual_type = resolve_expression_type((AstTyped *) (*named_value)->value); - break; - } - } - - // nocheckin - if (err_msg) *err_msg = "Not enough arguments to polymorphic procedure. This error message may not be entirely right."; - goto sln_not_found; + Arguments args; + args.values = (bh_arr(AstNode *)) ((AstCall *) actual)->arg_arr; + args.named_values = ((AstCall *) actual)->named_args; - } else { - actual_type = resolve_expression_type(arg_arr[param->idx]->value); - } + actual_type = lookup_actual_type_in_arguments(pp, param, &args, err_msg); + if (actual_type == NULL) goto sln_not_found; } - else if (pp_lookup == PPLM_By_Value_Array) { - bh_arr(AstTyped *) arg_arr = (bh_arr(AstTyped *)) actual; + else if (pp_lookup == PPLM_By_Arguments) { + Arguments* args = (Arguments *) actual; - // nocheckin - if ((i32) param->idx >= bh_arr_length(arg_arr)) { - if (err_msg) *err_msg = "Not enough arguments to polymorphic procedure."; - goto sln_not_found; - } - - actual_type = resolve_expression_type(arg_arr[param->idx]); + actual_type = lookup_actual_type_in_arguments(pp, param, args, err_msg); + if (actual_type == NULL) goto sln_not_found; } else if (pp_lookup == PPLM_By_Function_Type) { @@ -899,7 +902,10 @@ static AstNode* lookup_default_value_by_idx(AstNode* provider, i32 idx) { case Ast_Kind_Function: { AstFunction* func = (AstFunction *) provider; - AstArgument* arg = make_argument(semstate.node_allocator, func->params[idx].default_value); + AstTyped* default_value = func->params[idx].default_value; + if (default_value == NULL) return NULL; + + AstArgument* arg = make_argument(semstate.node_allocator, default_value); return (AstNode *) arg; } @@ -910,27 +916,29 @@ static AstNode* lookup_default_value_by_idx(AstNode* provider, i32 idx) { // NOTE: The values array can be partially filled out, and is the resulting array. // Returns if all the values were filled in. b32 fill_in_arguments(bh_arr(AstNode *) values, bh_arr(AstNamedValue *) named_values, AstNode* provider, char** err_msg) { - bh_arr_each(AstNamedValue *, p_named_value, named_values) { - AstNamedValue* named_value = *p_named_value; + if (named_values != NULL) { + bh_arr_each(AstNamedValue *, p_named_value, named_values) { + AstNamedValue* named_value = *p_named_value; - token_toggle_end(named_value->token); - i32 idx = lookup_idx_by_name(provider, named_value->token->text); - if (idx == -1) { - if (err_msg) *err_msg = bh_aprintf(global_heap_allocator, "'%s' is not a valid named parameter here.", named_value->token->text); token_toggle_end(named_value->token); - return 0; - } + i32 idx = lookup_idx_by_name(provider, named_value->token->text); + if (idx == -1) { + if (err_msg) *err_msg = bh_aprintf(global_heap_allocator, "'%s' is not a valid named parameter here.", named_value->token->text); + token_toggle_end(named_value->token); + return 0; + } - assert(idx < bh_arr_length(values)); + assert(idx < bh_arr_length(values)); - if (values[idx] != NULL) { - if (err_msg) *err_msg = bh_aprintf(global_heap_allocator, "Multiple values given for parameter named '%s'.", named_value->token->text); + if (values[idx] != NULL) { + if (err_msg) *err_msg = bh_aprintf(global_heap_allocator, "Multiple values given for parameter named '%s'.", named_value->token->text); + token_toggle_end(named_value->token); + return 0; + } + + values[idx] = named_value->value; token_toggle_end(named_value->token); - return 0; } - - values[idx] = named_value->value; - token_toggle_end(named_value->token); } b32 success = 1;