polyprocs can be passed as arguments; code cleanup and bugfixes
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Mon, 31 Aug 2020 18:40:58 +0000 (13:40 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Mon, 31 Aug 2020 18:40:58 +0000 (13:40 -0500)
15 files changed:
Makefile
core/alloc.onyx
core/builtin.onyx
core/memory.onyx
core/stdio.onyx
core/string.onyx
core/wasi.onyx
docs/plan
include/onyxastnodes.h
onyx
progs/poly_test.onyx
src/onyxchecker.c
src/onyxclone.c
src/onyxutils.c
src/onyxwasm.c

index 2ddccb14f25ffb6a0636969b9d523a5180d2d1ab..0dbd8ab96957bd49b326ccf799a407a45a08fde6 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
-RELEASE=1
+RELEASE=0
 
 OBJ_FILES=\
        build/onyxlex.o \
index 7372b0755472fee51eeae1caedf03637ad028f94..2d82bae8abfcfe8e0436d55082ec0799fb9ef3c7 100644 (file)
@@ -95,20 +95,21 @@ heap_free :: proc (ptr: rawptr) {
 #private
 heap_resize :: proc (ptr: rawptr, new_size: u32, align: u32) -> rawptr {
     hb_ptr := cast(^heap_block) (cast(u32) ptr - sizeof heap_block);
+    old_size := hb_ptr.size - sizeof heap_block;
 
     // If there is already enough space in the current allocated block,
     // just return the block that already exists and has the memory in it.
-    if hb_ptr.size >= new_size do return ptr;
+    if old_size >= new_size do return ptr;
 
     // If we are at the end of the allocation space, just extend it
     if hb_ptr.size + cast(u32) ptr >= cast(u32) heap_state.next_alloc {
-        hb_ptr.size = new_size;
+        hb_ptr.size = new_size + sizeof heap_block;
         heap_state.next_alloc = cast(rawptr) (cast(u32) ptr + hb_ptr.size);
         return ptr;
     }
 
     new_ptr := heap_alloc(new_size, align);
-    memory_copy(new_ptr, ptr, hb_ptr.size);
+    memory_copy(new_ptr, ptr, old_size);
     heap_free(ptr);
     return new_ptr;
 }
index a3158dea46d403a2b8600a2b55e90de92f1dc8e5..d740644116fc6a6b286f464a76abee811472adf2 100644 (file)
@@ -133,6 +133,26 @@ array_to_slice :: proc (arr: ^[..] $T) -> [] T {
     return arr.data[0 : arr.count];
 }
 
+//
+// Simple insertion sort
+//    cmp should return >0 if left > right
+//
+array_sort :: proc (arr: ^[..] $T, cmp: proc (T, T) -> i32) {
+    for i: 1, arr.count {
+        x := arr.data[i];
+        j := i - 1; 
+
+        while j >= 0 && cmp(arr.data[j], x) > 0 {
+            arr.data[j + 1] = arr.data[j];
+            j -= 1;
+        }
+
+        arr.data[j + 1] = x;
+    }
+}
+
+cmp_asc :: proc (a: $T, b: T) -> i32 do return cast(i32) (a - b);
+cmp_dec :: proc (a: $T, b: T) -> i32 do return cast(i32) (b - a);
 
 context : struct {
        allocator      : Allocator;
index 85f0db4033ab2342c31b6ec0cbe6aaa904315d1b..aa6ff6e5da53be352d53b78a51689587beadc953 100644 (file)
@@ -1,19 +1,7 @@
 package memory
 
 memory_copy :: proc (dst_: rawptr, src_: rawptr, len: u32) {
-       if len % 8 == 0 {
-               dst := cast(^u64) dst_;
-               src := cast(^u64) src_;
-               for i: 0, len >> 3 do dst[i] = src[i];
-               
-       } elseif len % 4 == 0 {
-               dst := cast(^u32) dst_;
-               src := cast(^u32) src_;
-               for i: 0, len >> 2 do dst[i] = src[i];
-
-       } else {
-               dst := cast(^u8) dst_;
-               src := cast(^u8) src_;
-               for i: 0, len do dst[i] = src[i];
-       }
+       dst := cast(^u8) dst_;
+       src := cast(^u8) src_;
+       for i: 0, len do dst[i] = src[i];
 }
\ No newline at end of file
index b6afabe558b0fa0c2416b5949ca4133ea11f6a2c..d9360c75ea81047b9205efbf4acbba230ec25bc2 100644 (file)
@@ -15,6 +15,16 @@ print_i32     :: proc (n: i32, base := 10)  do string_builder_append(^cout_state
 print_bool    :: proc (b: bool) do string_builder_append(^cout_state.sb, b);
 print_ptr     :: proc (p: rawptr) do string_builder_append(^cout_state.sb, cast(i64) p, 16l);
 
+// This works on both slices and arrays
+print_array :: proc (arr: $T, sep := " ") {
+    for i: 0, arr.count {
+        print(arr.data[i]);
+        if i != arr.count - 1 do print(sep);
+    }
+
+    print("\n");
+}
+
 print :: proc #overloaded {
        print_string,
        print_cstring,
index c56d6f6e3d4e4b033739a2d20a37bb9d75676abf..5ee643ae117173b1837082ec7ba04420dd315e93 100644 (file)
@@ -88,6 +88,33 @@ string_contains :: proc (str: string, c: u8) -> bool {
     return false;
 }
 
+string_strip_leading_whitespace :: proc (str: ^string) {
+    while true do switch str.data[0] {
+        case #char " ", #char "\t", #char "\n", #char "\r" {
+            str.data += 1;
+            str.count -= 1;
+        }
+
+        case #default do return;
+    }
+}
+
+string_strip_trailing_whitespace :: proc (str: ^string) {
+    while true do switch str.data[str.count - 1] {
+        case #char " ", #char "\t", #char "\n", #char "\r" {
+            str.count -= 1;
+        }
+
+        case #default do return;
+    }
+}
+
+
+
+
+//
+// String Builder
+//
 StringBuilder :: struct {
     alloc : Allocator;
 
@@ -227,4 +254,51 @@ string_builder_to_string :: proc (use sb: ^StringBuilder) -> string {
 string_builder_clear :: proc (use sb: ^StringBuilder) -> ^StringBuilder {
     len = 0;
     return sb;
-}
\ No newline at end of file
+}
+
+string_read_u32 :: proc (str: ^string, out: ^u32) {
+    n := 0;
+
+    string_strip_leading_whitespace(str);
+    while str.data[0] >= #char "0" && str.data[0] <= #char "9" {
+        n *= 10;
+        n += cast(u32) (str.data[0] - #char "0");
+
+        str.data += 1;
+        str.count -= 1;
+    }
+
+    *out = n;
+}
+
+string_read_char :: proc (str: ^string, out: ^u8) {
+    *out = str.data[0];
+    str.data += 1;
+    str.count -= 1;
+}
+
+// Goes up to but not including the closest newline or EOF
+string_read_line :: proc (str: ^string, out: ^string) {
+    out.data = str.data;
+    out.count = 0;
+
+    for i: 0, str.count {
+        if str.data[i] == #char "\n" do break;
+        out.count += 1;
+    }
+
+    str.data += out.count;
+    str.count -= out.count;
+}
+
+string_advance_line :: proc (str: ^string) {
+    adv := 0;
+    while str.data[adv] != #char "\n" do adv += 1;
+
+    str.data += adv;
+    str.count -= adv;
+}
+
+string_read :: proc #overloaded {
+    string_read_u32, string_read_char
+}
index a871a85346e83c374f9c3961278c9e4fc5667d58..d96d67bafc832d8a5683724ebd0f230eea1b2652 100644 (file)
@@ -438,8 +438,8 @@ proc #export "_start" {
 
        args_sizes_get(^argc, ^argv_buf_size);
 
-       argv := cast(^^u8) calloc(sizeof ^u8 * argc);
-       argv_buf := cast(^u8) calloc(argv_buf_size);
+       argv := cast(^cstring) calloc(sizeof cstring * argc);
+       argv_buf := cast(cstring) calloc(argv_buf_size);
 
        args_get(argv, argv_buf);
 
index d135c900883fb041183414035f5f6790a3d4c3d4..32e05738673f4eeb1456a49db3fd32ec7e0207ef 100644 (file)
--- a/docs/plan
+++ b/docs/plan
@@ -223,7 +223,7 @@ HOW:
             - add infos to warnings
             - no more preformatted strings, just write them inline ffs
 
-        [ ] #file and #line directives
+        [X] #file and #line directives
             - string and u32 respectively that represent the current file and line number where the directive is
 
         [ ] transmute
index ca2d678cda7a1b2135453b40f4e5caaa93ac5f8f..84d721f4f102ec3207d008ed82bc81a5db850e1e 100644 (file)
@@ -594,7 +594,12 @@ void initialize_builtins(bh_allocator a, ProgramInfo* prog);
 AstTyped* ast_reduce(bh_allocator a, AstTyped* node);
 AstNode* ast_clone(bh_allocator a, void* n);
 void promote_numlit_to_larger(AstNumLit* num);
-AstFunction* polymorphic_proc_lookup(AstPolyProc* pp, AstCall* call);
+
+typedef enum PolyProcLookupMethod {
+    PPLM_By_Call,
+    PPLM_By_Function_Type,
+} PolyProcLookupMethod;
+AstFunction* polymorphic_proc_lookup(AstPolyProc* pp, PolyProcLookupMethod pp_lookup, ptr actual, OnyxFilePos pos);
 
 // NOTE: Useful inlined functions
 static inline b32 is_lval(AstNode* node) {
diff --git a/onyx b/onyx
index 18f0a4645e8ffb6b21e1f24135b24523e067fe8e..a791f6afd2353990c2bd967a51e84082ad9352f8 100755 (executable)
Binary files a/onyx and b/onyx differ
index 50bb842ec93e831d19c0cf92bb4a2766ff4bb222..a83027a7c3c517fbebcd81989e60136f1328188e 100644 (file)
@@ -30,16 +30,6 @@ print_arr_details :: proc (arr: ^[..] $T) {
     print("\n\n");
 }
 
-// This works on both slices and arrays
-print_arr :: proc (arr: $T, sep := " ") {
-    for i: 0, arr.count {
-        print(arr.data[i]);
-        if i != arr.count - 1 do print(sep);
-    }
-
-    print("\n");
-}
-
 print_vec :: proc (v: Vec3) #add_overload print {
     print("Vec3(");
     print(v.x);
@@ -64,8 +54,8 @@ Dummy :: struct {
 
 
 SOA :: struct {
-    a  : [..] i32;
     b  : [..] i64;
+    a  : [..] i32;
 }
 
 soa_init :: proc (s: ^SOA) {
@@ -78,7 +68,7 @@ soa_deinit :: proc (s: ^SOA) {
     array_free(^s.b);
 }
 
-main :: proc (args: [] cstring) {
+main2 :: proc (args: [] cstring) {
     s : SOA;
     soa_init(^s);
     defer soa_deinit(^s);
@@ -91,16 +81,18 @@ main :: proc (args: [] cstring) {
         array_push(^s.b, 3l * cast(i64) i);
     }
 
-    print_arr(^s.a);
-    array_to_slice(^s.a) |> print_arr();
-    array_to_slice(^s.b) |> print_arr();
+    array_sort(^s.a, cmp_dec);
+    array_sort(^s.b, cmp_asc);
+
+    print_array(^s.a);
+    print_array(^s.b);
 
     print("After adding...\n");
     print_arr_details(^s.a);
     print_arr_details(^s.b);
 }
 
-main2 :: proc (args: [] cstring) {
+main :: proc (args: [] cstring) {
     print(cast(u32) __heap_start, 16);
 
     iarr_backing : [32] i32;
@@ -116,23 +108,23 @@ main2 :: proc (args: [] cstring) {
     for i: 0, 12 do array_push(^iarr, i % 5);
 
     print_arr_details(^iarr);
-    print_arr(^iarr);
+    print_array(^iarr);
 
     array_delete(^iarr, 4);
 
     print_arr_details(^iarr);
-    print_arr(^iarr);
+    print_array(^iarr);
 
     array_remove(^iarr, 1);
     array_remove(^iarr, 4);
 
     print_arr_details(^iarr);
-    print_arr(^iarr);
+    print_array(^iarr);
 
     array_insert(^iarr, 2, 5678);
 
     print_arr_details(^iarr);
-    print_arr(^iarr);
+    print_array(^iarr);
     print(array_average(^iarr));
     print("\n");
 
@@ -147,7 +139,7 @@ main2 :: proc (args: [] cstring) {
     }
 
     print_arr_details(^barr);
-    print_arr(^barr);
+    print_array(^barr);
     array_average(^barr) |> print();
     print("\n");
 
@@ -170,15 +162,16 @@ main2 :: proc (args: [] cstring) {
     }
 
     array_push(^varr, Vec3.{ 4, 2, 3 });
+    array_sort(^varr, cmp_vec3);
 
     print_arr_details(^varr);
-    print_arr(varr, "\n");
+    print_array(varr, "\n");
 
 
     dummy := Dummy.{ data = calloc(sizeof [5] i32) };
     for i: 0, dummy.count do dummy.data[i] = i * 5;
 
-    print_arr(dummy);
+    print_array(dummy);
 
     print(get_count(iarr));
     print("\n");
@@ -195,3 +188,9 @@ Vec3 :: struct {
     y: i32;
     z: i32;
 }
+
+cmp_vec3 :: proc (v1: Vec3, v2: Vec3) -> i32 {
+    if v1.x != v2.x do return v1.x - v2.x;
+    if v1.y != v2.y do return v1.y - v2.y;
+    return v1.z - v2.z;
+}
\ No newline at end of file
index de3e90fc893c9680089a09ffa71b977be57e19f3..b80a47287c9a20a0e8833a0286138de0e3bd56ae 100644 (file)
@@ -233,6 +233,21 @@ no_match:
 }
 
 b32 check_call(AstCall* call) {
+    // All the things that need to be done when checking a call node.
+    //      1. Ensure the callee is not a symbol
+    //      2. Check the callee expression (since it could be a variable or a field access, etc)
+    //      3. Check all arguments
+    //          * Cannot pass overloaded functions
+    //          * Cannot pass a non-simple struct
+    //      4. If callee is an overloaded function, use the argument types to determine which overload is used.
+    //      5. If callee is polymorphic, use the arguments type to generate a polymorphic function.
+    //      6. If an argument is polymorphic, generate the correct polymorphic function.
+    //      7. Fill in default arguments
+    //      8. If callee is an intrinsic, turn call into an Intrinsic_Call node
+    //      9. Check types of formal and actual params against each other
+
+
+
     AstFunction* callee = (AstFunction *) call->callee;
 
     if (callee->kind == Ast_Kind_Symbol) {
@@ -242,27 +257,30 @@ b32 check_call(AstCall* call) {
 
     if (check_expression(&call->callee)) return 1;
 
+    b32 has_polymorphic_args = 0;
+
     // NOTE: Check arguments
-    AstNode** prev_param = (AstNode **) &call->arguments;
-    AstArgument* actual_param = call->arguments;
-    while (actual_param != NULL) {
-        if (check_expression((AstTyped **) &actual_param)) return 1;
+    AstArgument* actual = call->arguments;
+    while (actual != NULL) {
+        if (check_expression((AstTyped **) &actual)) return 1;
 
-        if (actual_param->value->kind == Ast_Kind_Overloaded_Function) {
-            onyx_report_error(actual_param->token->pos, "Cannot pass overloaded functions as parameters.");
+        if (actual->value->kind == Ast_Kind_Overloaded_Function) {
+            onyx_report_error(actual->token->pos, "Cannot pass overloaded functions as parameters.");
             return 1;
         }
 
-        if (type_is_structlike_strict(actual_param->value->type)) {
-            if (!type_structlike_is_simple(actual_param->value->type)) {
-                onyx_report_error(actual_param->token->pos,
+        if (type_is_structlike_strict(actual->value->type)) {
+            if (!type_structlike_is_simple(actual->value->type)) {
+                onyx_report_error(actual->token->pos,
                     "Can only pass simple structs as parameters (no nested structures). passing by pointer is the only way for now.");
                 return 1;
             }
         }
 
-        prev_param = (AstNode **) &actual_param->next;
-        actual_param = (AstArgument *) actual_param->next;
+        if (actual->value->kind == Ast_Kind_Polymorphic_Proc)
+            has_polymorphic_args = 1;
+
+        actual = (AstArgument *) actual->next;
     }
 
     if (callee->kind == Ast_Kind_Overloaded_Function) {
@@ -273,7 +291,12 @@ b32 check_call(AstCall* call) {
     }
 
     if (callee->kind == Ast_Kind_Polymorphic_Proc) {
-        call->callee = (AstTyped *) polymorphic_proc_lookup((AstPolyProc *) call->callee, call);
+        call->callee = (AstTyped *) polymorphic_proc_lookup(
+                (AstPolyProc *) call->callee,
+                PPLM_By_Call,
+                call,
+                call->token->pos);
+
         if (call->callee == NULL) return 1;
 
         callee = (AstFunction *) call->callee;
@@ -289,6 +312,29 @@ b32 check_call(AstCall* call) {
         return 1;
     }
 
+    if (has_polymorphic_args) {
+        actual = call->arguments;
+        u32 arg_idx = 0;
+
+        while (actual != NULL) {
+            if (actual->value->kind == Ast_Kind_Polymorphic_Proc) {
+                actual->value = (AstTyped *) polymorphic_proc_lookup(
+                    (AstPolyProc *) actual->value,
+                    PPLM_By_Function_Type,
+                    callee->type->Function.params[arg_idx],
+                    actual->token->pos);
+
+                if (actual->value == NULL) return 1;
+
+                actual->type = actual->value->type;
+                actual->value->flags |= Ast_Flag_Function_Used;
+            }
+                    
+            actual = (AstArgument *) actual->next;
+            arg_idx++;
+        }
+    }
+
     if (callee->kind == Ast_Kind_Function) {
         if (call->arg_count < bh_arr_length(callee->params)) {
             AstArgument** last_arg = &call->arguments;
@@ -379,22 +425,22 @@ b32 check_call(AstCall* call) {
     call->type = callee->type->Function.return_type;
 
     Type **formal_params = callee->type->Function.params;
-    actual_param = call->arguments;
+    actual = call->arguments;
 
     i32 arg_pos = 0;
-    while (arg_pos < callee->type->Function.param_count && actual_param != NULL) {
-        if (!types_are_compatible(formal_params[arg_pos], actual_param->type)) {
-            onyx_report_error(actual_param->token->pos,
+    while (arg_pos < callee->type->Function.param_count && actual != NULL) {
+        if (!types_are_compatible(formal_params[arg_pos], actual->type)) {
+            onyx_report_error(actual->token->pos,
                     "The function '%b' expects a value of type '%s' for parameter '%d', got '%s'.",
                     callee->token->text, callee->token->length,
                     type_get_name(formal_params[arg_pos]),
                     arg_pos,
-                    type_get_name(actual_param->type));
+                    type_get_name(actual->type));
             return 1;
         }
 
         arg_pos++;
-        actual_param = (AstArgument *) actual_param->next;
+        actual = (AstArgument *) actual->next;
     }
 
     if (arg_pos < callee->type->Function.param_count) {
@@ -402,7 +448,7 @@ b32 check_call(AstCall* call) {
         return 1;
     }
 
-    if (actual_param != NULL) {
+    if (actual != NULL) {
         onyx_report_error(call->token->pos, "Too many arguments to function call.");
         return 1;
     }
@@ -597,12 +643,16 @@ b32 check_binaryop(AstBinaryOp** pbinop, b32 assignment_is_ok) {
     }
 
     if (!type_is_numeric(binop->left->type) && !type_is_pointer(binop->left->type)) {
-        onyx_report_error(binop->token->pos, "Expected numeric or pointer type for left side of binary operator.");
+        onyx_report_error(binop->token->pos,
+                "Expected numeric or pointer type for left side of binary operator, got '%s'.",
+                type_get_name(binop->left->type));
         return 1;
     }
 
     if (!type_is_numeric(binop->right->type)) {
-        onyx_report_error(binop->token->pos, "Expected numeric type for right side of binary operator.");
+        onyx_report_error(binop->token->pos,
+                "Expected numeric type for right side of binary operator, got '%s'.",
+                type_get_name(binop->right->type));
         return 1;
     }
 
index bbf5852646eace7d9483995ca8d2dd36e7a29f92..1f5049afc5f9b6169af6b3a4101c03d94119dff9 100644 (file)
@@ -12,7 +12,6 @@ static inline b32 should_clone(AstNode* node) {
                case Ast_Kind_NumLit:
                case Ast_Kind_StrLit:
                case Ast_Kind_Package:
-               case Ast_Kind_Function_Type:
                case Ast_Kind_Struct_Type:
                case Ast_Kind_Enum_Type:
                case Ast_Kind_Enum_Value:
@@ -24,8 +23,8 @@ static inline b32 should_clone(AstNode* node) {
        }
 }
 
-static inline i32 ast_kind_to_size(AstKind kind) {
-       switch (kind) {
+static inline i32 ast_kind_to_size(AstNode* node) {
+       switch (node->kind) {
         case Ast_Kind_Error: return sizeof(AstNode);
         case Ast_Kind_Program: return sizeof(AstNode);
         case Ast_Kind_Package: return sizeof(AstPackage);
@@ -49,7 +48,7 @@ static inline i32 ast_kind_to_size(AstKind kind) {
         case Ast_Kind_Type: return sizeof(AstType);
         case Ast_Kind_Basic_Type: return sizeof(AstBasicType);
         case Ast_Kind_Pointer_Type: return sizeof(AstPointerType);
-        case Ast_Kind_Function_Type: return sizeof(AstFunctionType);
+        case Ast_Kind_Function_Type: return sizeof(AstFunctionType) + ((AstFunctionType *) node)->param_count * sizeof(AstType *);
         case Ast_Kind_Array_Type: return sizeof(AstArrayType);
         case Ast_Kind_Slice_Type: return sizeof(AstSliceType);
         case Ast_Kind_DynArr_Type: return sizeof(AstDynArrType);
@@ -113,13 +112,13 @@ AstNode* ast_clone(bh_allocator a, void* n) {
        if (node == NULL) return NULL;
        if (!should_clone(node)) return node;
 
-       i32 node_size = ast_kind_to_size(node->kind);
+       i32 node_size = ast_kind_to_size(node);
        // bh_printf("Cloning %s with size %d\n", onyx_ast_node_kind_string(node->kind), node_size);
 
        AstNode* nn = onyx_ast_node_new(a, node_size, node->kind);
        memmove(nn, node, node_size);
 
-       switch (node->kind) {
+       switch ((u16) node->kind) {
                case Ast_Kind_Binary_Op:
                        ((AstBinaryOp *) nn)->left  = (AstTyped *) ast_clone(a, ((AstBinaryOp *) node)->left);
                        ((AstBinaryOp *) nn)->right = (AstTyped *) ast_clone(a, ((AstBinaryOp *) node)->right);
@@ -274,6 +273,14 @@ AstNode* ast_clone(bh_allocator a, void* n) {
                        ((AstTypeAlias *) nn)->to = (AstType *) ast_clone(a, ((AstTypeAlias *) node)->to);
                        break;
 
+               case Ast_Kind_Function_Type:
+                       ((AstFunctionType *) nn)->return_type = (AstType *) ast_clone(a, ((AstFunctionType *) node)->return_type);
+                       ((AstFunctionType *) nn)->param_count = ((AstFunctionType *) node)->param_count;
+                       fori (i, 0, ((AstFunctionType *) nn)->param_count) {
+                               ((AstFunctionType *) nn)->params[i] = (AstType *) ast_clone(a, ((AstFunctionType *) node)->params[i]);
+                       }
+                       break;
+
                case Ast_Kind_Binding:
                        bh_printf("Cloning binding: %b\n", node->token->text, node->token->length);
                        ((AstTyped *) nn)->type_node = (AstType *) ast_clone(a, ((AstTyped *) node)->type_node);
@@ -304,22 +311,6 @@ AstNode* ast_clone(bh_allocator a, void* n) {
 
                        break;
                }
-
-               case Ast_Kind_NumLit:
-               case Ast_Kind_StrLit:
-               case Ast_Kind_File_Contents:
-               case Ast_Kind_Jump:
-               case Ast_Kind_Type:
-               case Ast_Kind_Basic_Type:
-               case Ast_Kind_Struct_Member:
-                       return nn;
-
-               //default: {
-               //      AstNode* new_node = make_node(a, AstNode, node->kind);
-               //      new_node->token = node->token;
-               //      new_node->flags = node->flags;
-               //      new_node->next = ast_clone(a, node->next);
-               //}
        }
 
        return nn;
index 481aed417404109027ad994f967c8462ac041dd0..538cb06fd654ed1ce7d3d70b63014d4af0a620bd 100644 (file)
@@ -379,7 +379,7 @@ static Type* solve_poly_type(AstNode* target, AstType* type_expr, Type* actual)
     return NULL;
 }
 
-AstFunction* polymorphic_proc_lookup(AstPolyProc* pp, AstCall* call) {
+AstFunction* polymorphic_proc_lookup(AstPolyProc* pp, PolyProcLookupMethod pp_lookup, ptr actual, OnyxFilePos pos) {
     if (pp->concrete_funcs == NULL) {
         bh_table_init(global_heap_allocator, pp->concrete_funcs, 8);
     }
@@ -387,19 +387,42 @@ AstFunction* polymorphic_proc_lookup(AstPolyProc* pp, AstCall* call) {
     scope_clear(pp->poly_scope);
 
     bh_arr_each(AstPolyParam, param, pp->poly_params) {
-        AstArgument* arg = call->arguments;
-        if (param->idx >= call->arg_count) {
-            onyx_report_error(call->token->pos, "Not enough arguments to polymorphic procedure.");
-            return NULL;
+        Type* actual_type;
+        if (pp_lookup == PPLM_By_Call) {
+            AstArgument* arg = ((AstCall *) actual)->arguments;
+            if (param->idx >= ((AstCall *) actual)->arg_count) {
+                onyx_report_error(pos, "Not enough arguments to polymorphic procedure.");
+                return NULL;
+            }
+
+            fori (i, 0, param->idx) arg = (AstArgument *) arg->next;
+            actual_type = arg->type;
         }
 
-        fori (i, 0, param->idx) arg = (AstArgument *) arg->next;
-        Type* arg_type = arg->type;
+        else if (pp_lookup == PPLM_By_Function_Type) {
+            Type* ft = (Type*) actual;
+            if (param->idx >= ft->Function.param_count) {
+                onyx_report_error(pos, "Incompatible polymorphic argument to function paramter.");
+                return NULL;
+            }
 
-        Type* resolved_type = solve_poly_type(param->poly_sym, param->type_expr, arg_type);
+            actual_type = ft->Function.params[param->idx];
+        }
+
+        else {
+            onyx_report_error(pos, "Cannot resolve polymorphic function type.");
+            return NULL;
+        }
+
+        Type* resolved_type = solve_poly_type(param->poly_sym, param->type_expr, actual_type);
 
         if (resolved_type == NULL) {
-            onyx_report_error(call->token->pos, "Unable to match polymorphic procedure type.");
+            if (pp_lookup == PPLM_By_Call) {
+                onyx_report_error(pos, "Unable to match polymorphic procedure type.");
+            }
+            else if (pp_lookup == PPLM_By_Function_Type) {
+                onyx_report_error(pos, "Unable to match polymorphic procedure type.");
+            }
             return NULL;
         }
 
@@ -412,7 +435,8 @@ AstFunction* polymorphic_proc_lookup(AstPolyProc* pp, AstCall* call) {
     static char key_buf[1024];
     fori (i, 0, 1024) key_buf[i] = 0;
     bh_table_each_start(AstNode *, pp->poly_scope->symbols);
-        strncat(key_buf, bh_bprintf("%s=", key), 1023);
+        strncat(key_buf, key, 1023);
+        strncat(key_buf, "=", 1023);
         strncat(key_buf, type_get_name(((AstTypeRawAlias *) value)->to), 1023);
         strncat(key_buf, ";", 1023);
     bh_table_each_end;
@@ -434,7 +458,7 @@ AstFunction* polymorphic_proc_lookup(AstPolyProc* pp, AstCall* call) {
     goto no_errors;
 
 has_error:
-    onyx_report_error(call->token->pos, "Error in polymorphic procedure generated from this call site.");
+    onyx_report_error(pos, "Error in polymorphic procedure generated from this call site.");
     return NULL;
 
 no_errors:
index 312c78c5017bc0fe8b454a013f7f1411d40c477c..48dfb87fa59d02a118b66b8195261b4d46d571e6 100644 (file)
@@ -1927,7 +1927,7 @@ static i32 get_element_idx(OnyxWasmModule* mod, AstFunction* func) {
     }
 }
 
-static inline b32 should_EMIT_FUNCtion(AstFunction* fd) {
+static inline b32 should_emit_function(AstFunction* fd) {
     // NOTE: Don't output intrinsic functions
     if (fd->flags & Ast_Flag_Intrinsic) return 0;
 
@@ -1947,8 +1947,8 @@ static inline b32 should_EMIT_FUNCtion(AstFunction* fd) {
 }
 
 
-static void EMIT_FUNCtion(OnyxWasmModule* mod, AstFunction* fd) {
-    if (!should_EMIT_FUNCtion(fd)) return;
+static void emit_function(OnyxWasmModule* mod, AstFunction* fd) {
+    if (!should_emit_function(fd)) return;
 
     i32 type_idx = generate_type_idx(mod, fd->type);
 
@@ -2357,7 +2357,7 @@ void onyx_wasm_module_compile(OnyxWasmModule* module, ProgramInfo* program) {
 
         switch (entity->type) {
             case Entity_Type_Function_Header: {
-                if (!should_EMIT_FUNCtion(entity->function)) break;
+                if (!should_emit_function(entity->function)) break;
 
                 u64 func_idx;
                 if ((entity->function->flags & Ast_Flag_Foreign) != 0)
@@ -2395,7 +2395,7 @@ void onyx_wasm_module_compile(OnyxWasmModule* module, ProgramInfo* program) {
                 break;
             }
 
-            case Entity_Type_Function: EMIT_FUNCtion(module, entity->function); break;
+            case Entity_Type_Function: emit_function(module, entity->function); break;
             case Entity_Type_Global:   emit_global(module,   entity->global); break;
 
             default: break;