From: Brendan Hansen Date: Mon, 12 Apr 2021 19:27:31 +0000 (-0500) Subject: overloads of overloads X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=38a62f9813e78f114d45fc48ea81be39ec76b90d;p=onyx.git overloads of overloads --- diff --git a/.vimspector.json b/.vimspector.json index d343fe44..165d6642 100644 --- a/.vimspector.json +++ b/.vimspector.json @@ -6,7 +6,7 @@ "type": "cppdbg", "request": "launch", "program": "${workspaceFolder}/bin/onyx", - "args": ["-VVV", "tmp/a"], + "args": ["-VVV", "tmp/better_overloads.onyx"], "stopAtEntry": true, "cwd": "${workspaceFolder}", "environment": [], diff --git a/bin/onyx b/bin/onyx index ad5f0d5c..478d0549 100755 Binary files a/bin/onyx and b/bin/onyx differ diff --git a/examples/14_overloaded_procs.onyx b/examples/14_overloaded_procs.onyx index ddf56f41..ad91d8f3 100644 --- a/examples/14_overloaded_procs.onyx +++ b/examples/14_overloaded_procs.onyx @@ -1,3 +1,27 @@ +// CLEANUP: FINISH THIS EXAMPLE WHEN OVERLOADS ARE BETTER + + +// Overloaded procedures, if you're not familiar with the concept, means that a +// given procedure has multiple implementations and which one is used depends on +// the arguments provided. For the sake of simplicity, both for the internal +// compiler architecture, and for the programmer, Onyx does not support implicitly +// overloaded procedures. This means that if you write, +// +// foo :: (x: i32) { ... } +// foo :: (x: str) { ... } +// +// you will get a compile time error saying that the symbol 'foo' was defined +// multiple times. Instead, to do the above in Onyx, you create a explicitly +// overloaded procedure, +// +// foo :: proc { +// (x: i32) { ... }, +// (y: str) { ... }, +// } +// + + + #load "core/std" use package core diff --git a/include/onyxastnodes.h b/include/onyxastnodes.h index 5d30efbc..7a5039b8 100644 --- a/include/onyxastnodes.h +++ b/include/onyxastnodes.h @@ -792,6 +792,11 @@ struct AstOverloadedFunction { AstTyped_base; bh_arr(AstTyped *) overloads; + + // CLEANUP: This is unused right now, but should be used to cache + // the complete set of overloads that can be used by an overloaded + // function. + bh_imap all_overloads; }; struct AstPackage { diff --git a/src/onyxchecker.c b/src/onyxchecker.c index 0d64b75c..ef55f05d 100644 --- a/src/onyxchecker.c +++ b/src/onyxchecker.c @@ -1502,13 +1502,9 @@ CheckStatus check_function(AstFunction* func) { CheckStatus check_overloaded_function(AstOverloadedFunction* func) { bh_arr_each(AstTyped *, node, func->overloads) { - if ((*node)->kind == Ast_Kind_Overloaded_Function) { - onyx_report_error((*node)->token->pos, "Overload option can not be another overloaded function."); - - return Check_Error; - } - - if ((*node)->kind != Ast_Kind_Function && (*node)->kind != Ast_Kind_Polymorphic_Proc) { + if ( (*node)->kind != Ast_Kind_Function + && (*node)->kind != Ast_Kind_Polymorphic_Proc + && (*node)->kind != Ast_Kind_Overloaded_Function) { onyx_report_error((*node)->token->pos, "Overload option not procedure. Got '%s'", onyx_ast_node_kind_string((*node)->kind)); diff --git a/src/onyxutils.c b/src/onyxutils.c index 67af166c..ded50804 100644 --- a/src/onyxutils.c +++ b/src/onyxutils.c @@ -943,20 +943,40 @@ AstFunction* polymorphic_proc_build_only_header(AstPolyProc* pp, PolyProcLookupM // * Resolving an overload from a TypeFunction (so an overloaded procedure can be passed as a parameter) // +static void build_all_overload_options(bh_arr(AstTyped *) overloads, bh_imap* all_overloads) { + bh_arr_each(AstTyped *, node, overloads) { + if (bh_imap_has(all_overloads, (u64) *node)) continue; + + bh_imap_put(all_overloads, (u64) *node, 1); + + if ((*node)->kind == Ast_Kind_Overloaded_Function) { + AstOverloadedFunction* sub_overload = (AstOverloadedFunction *) *node; + build_all_overload_options(sub_overload->overloads, all_overloads); + } + } +} + AstTyped* find_matching_overload_by_arguments(bh_arr(AstTyped *) overloads, Arguments* param_args) { Arguments args; arguments_clone(&args, param_args); arguments_ensure_length(&args, bh_arr_length(args.values) + bh_arr_length(args.named_values)); + // CLEANUP SPEED: This currently rebuilds the complete set of overloads every time one is looked up. + // This should be cached in the AstOverloadedFunction or somewhere like that. + bh_imap all_overloads; + bh_imap_init(&all_overloads, global_heap_allocator, bh_arr_length(overloads) * 2); + build_all_overload_options(overloads, &all_overloads); + AstTyped *matched_overload = NULL; - bh_arr_each(AstTyped *, node, overloads) { + bh_arr_each(bh__imap_entry, entry, all_overloads.entries) { + AstTyped* node = (AstTyped *) entry->key; arguments_copy(&args, param_args); AstFunction* overload = NULL; - switch ((*node)->kind) { - case Ast_Kind_Function: overload = (AstFunction *) *node; break; - case Ast_Kind_Polymorphic_Proc: overload = polymorphic_proc_build_only_header((AstPolyProc *) *node, PPLM_By_Arguments, param_args); break; + switch (node->kind) { + case Ast_Kind_Function: overload = (AstFunction *) node; break; + case Ast_Kind_Polymorphic_Proc: overload = polymorphic_proc_build_only_header((AstPolyProc *) node, PPLM_By_Arguments, param_args); break; } // NOTE: Overload is not something that is known to be overloadable. @@ -989,11 +1009,12 @@ AstTyped* find_matching_overload_by_arguments(bh_arr(AstTyped *) overloads, Argu } if (all_arguments_work) { - matched_overload = *node; + matched_overload = node; break; } } + bh_imap_free(&all_overloads); bh_arr_free(args.values); return matched_overload; } @@ -1010,6 +1031,10 @@ void report_unable_to_match_overload(AstCall* call) { } if (bh_arr_length(call->args.named_values) > 0) { + if (bh_arr_length(call->args.values) > 0) { + strncat(arg_str, ", ", 1023); + } + bh_arr_each(AstNamedValue *, named_value, call->args.named_values) { token_toggle_end((*named_value)->token); strncat(arg_str, (*named_value)->token->text, 1023);