overloads of overloads
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Mon, 12 Apr 2021 19:27:31 +0000 (14:27 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Mon, 12 Apr 2021 19:27:31 +0000 (14:27 -0500)
.vimspector.json
bin/onyx
examples/14_overloaded_procs.onyx
include/onyxastnodes.h
src/onyxchecker.c
src/onyxutils.c

index d343fe44f7d0399f9abd970744b1355789c3589c..165d6642bec0c768744afaac8da9bb7dcf1bed3e 100644 (file)
@@ -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": [],
index ad5f0d5c5860ba6254d510f9107f5e57239ebebc..478d054936f6b358c2c31bfaa23f38a4fb9b5a57 100755 (executable)
Binary files a/bin/onyx and b/bin/onyx differ
index ddf56f41c5dd009bcefd9aa428a6f83486b5c8e7..ad91d8f36aa320e3878f8aec6bfae6a8fd72a167 100644 (file)
@@ -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
index 5d30efbc1cbac87976df62762243f253ec38892a..7a5039b856d2cc6bde71c043946082415e529301 100644 (file)
@@ -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 {
index 0d64b75ca9e56de76071816a4404eaffa096236d..ef55f05d0f889c8ef8b8be74aa4358cbb45331b2 100644 (file)
@@ -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));
 
index 67af166c4f383c18539bac5e57d078f8567f2b9d..ded508040be48c2bc51fc258a11ea43547251553 100644 (file)
@@ -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);