working very of named arguments for function calls
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Fri, 15 Jan 2021 02:39:46 +0000 (20:39 -0600)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Fri, 15 Jan 2021 02:39:46 +0000 (20:39 -0600)
bin/onyx
include/onyxastnodes.h
onyx.exe
src/onyxastnodes.c
src/onyxchecker.c
src/onyxutils.c

index bb4dec3c8906134d0fb029a197d5ca05753b2e4e..a9abe2a7e55846529288a4e5694f675ad4c90d4b 100755 (executable)
Binary files a/bin/onyx and b/bin/onyx differ
index 825d2d966db1fceff05f0a1198fad0a690a97735..3db3515480a788c4890dbb7f6d1be3649fd56b14 100644 (file)
@@ -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);
index 2307f9647a4dd127cbe30aa8bfab4bc5ac96de78..2bb8a31ecfa509c37c64a48559fdd8fa081000e6 100644 (file)
Binary files a/onyx.exe and b/onyx.exe differ
index 17dc02b1f98978675b7f9c9e0234eadf8976d838..bb41ae4b6e6b481801a49b125db743e0334d87ff 100644 (file)
@@ -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);
 
index f9640cad87fefc68fe28cbd672615d103e7935ed..344056745f82ef2e350ed192916715b9297010e1 100644 (file)
@@ -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;
 }
 
index 9c5ab5ab831f73fef5c0f770889d443b472b6ff9..a0a274f147b810901d2fdd417c08d4012c98631d 100644 (file)
@@ -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;