code cleanup with procedure calling; needs even more cleanup
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Sat, 26 Sep 2020 18:46:39 +0000 (13:46 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Sat, 26 Sep 2020 18:46:39 +0000 (13:46 -0500)
include/onyxastnodes.h
onyx
progs/vararg_test.onyx
src/onyxchecker.c
src/onyxsymres.c
src/onyxwasm.c

index b937438f9321b7e124a97b06ebeb66e951b5e581..11995de39e126b286589f8b8af3893c1b6c489f5 100644 (file)
@@ -188,11 +188,7 @@ typedef enum AstFlags {
 
     Ast_Flag_Cannot_Take_Addr      = BH_BIT(20),
 
-    Ast_Flag_Arg_Is_VarArg         = BH_BIT(21),
-
-    Ast_Flag_Arg_Is_Untyped_VarArg = BH_BIT(22),
-
-    Ast_Flag_Struct_Mem_Used       = BH_BIT(23),
+    Ast_Flag_Struct_Mem_Used       = BH_BIT(21),
 } AstFlags;
 
 typedef enum UnaryOp {
@@ -443,9 +439,7 @@ struct AstUnaryOp       { AstTyped_base; UnaryOp operation; AstTyped *expr; };
 struct AstNumLit        { AstTyped_base; union { i32 i; i64 l; f32 f; f64 d; } value; };
 struct AstStrLit        { AstTyped_base; u64 addr; u64 length; };
 struct AstLocal         { AstTyped_base; };
-struct AstCall          { AstTyped_base; AstArgument *arguments; u64 arg_count; AstTyped *callee; };
-struct AstIntrinsicCall { AstTyped_base; AstArgument *arguments; u64 arg_count; OnyxIntrinsic intrinsic; };
-struct AstArgument      { AstTyped_base; AstTyped *value; };
+struct AstArgument      { AstTyped_base; AstTyped *value; VarArgKind va_kind; };
 struct AstAddressOf     { AstTyped_base; AstTyped *expr; };
 struct AstDereference   { AstTyped_base; AstTyped *expr; };
 struct AstArrayAccess   { AstTyped_base; AstTyped *addr; AstTyped *expr; u64 elem_size; };
@@ -461,6 +455,29 @@ struct AstStructLiteral {
     bh_arr(AstStructMember *) named_values;
     bh_arr(AstTyped *) values;
 };
+struct AstCall {
+    AstTyped_base;
+
+    AstArgument *arguments;
+    u64 arg_count;
+
+    bh_arr(AstArgument *) arg_arr;
+    AstTyped *callee;
+
+    VarArgKind va_kind;
+};
+struct AstIntrinsicCall {
+    AstTyped_base;
+
+    AstArgument *arguments;
+    u64 arg_count;
+
+    bh_arr(AstArgument *) arg_arr;
+
+    OnyxIntrinsic intrinsic;
+
+    VarArgKind va_kind;
+};
 
 // Intruction Node
 struct AstReturn        { AstNode_base; AstTyped* expr; };
diff --git a/onyx b/onyx
index 730b313e12ee5142c888724334bab81dcc50d37b..0c8c465e7c6380edb449ada383101e4bf0aecedf 100755 (executable)
Binary files a/onyx and b/onyx differ
index 7fd5e44e9073b3348e109333363711a14f493f48..aac4c49797bcfd2916231a4ed1e0857412537cf7 100644 (file)
@@ -8,10 +8,12 @@ old_va_test :: proc (prefix: string, va: ..i32) {
     for v: va do println(v);
 }
 
-vararg_get :: proc (va: vararg, ret: ^$T) {
+vararg_get :: proc (va: vararg, ret: ^$T) -> bool {
+    if va.count <= 0 do return false;
     *ret = *cast(^T) va.data;
     va.data = cast(rawptr) (cast(^u8) va.data + sizeof T);
-    // *va = cast(rawptr) (cast(^u8) *va + sizeof T);
+    va.count -= 1;
+    return true;
 }
 
 // va is just a rawptr with no bounds checking
index 815ee18c199d75ef652baefe9913a7fe8344de14..9e298475558bd55a805199ed985e99890bce2377 100644 (file)
@@ -283,6 +283,17 @@ no_match:
     return NULL;
 }
 
+typedef struct PolyArg {
+    AstArgument* arg;
+    u64          pos;
+} PolyArg;
+
+typedef enum ArgState {
+    AS_Expecting_Exact,
+    AS_Expecting_Typed_VA,
+    AS_Expecting_Untyped_VA,
+} ArgState;
+
 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
@@ -295,20 +306,18 @@ b32 check_call(AstCall* call) {
     //      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
+    //      9. Check types of formal and actual params against each other, handling varargs
 
 
 
+    if (check_expression(&call->callee)) return 1;
     AstFunction* callee = (AstFunction *) call->callee;
 
-    if (callee->kind == Ast_Kind_Symbol) {
-        onyx_report_error(callee->token->pos, "Unresolved symbol '%b'.", callee->token->text, callee->token->length);
-        return 1;
-    }
-
-    if (check_expression(&call->callee)) return 1;
+    bh_arr(AstArgument *) arg_arr = NULL;
+    bh_arr_new(global_heap_allocator, arg_arr, call->arg_count);
 
-    b32 has_polymorphic_args = 0;
+    bh_arr(PolyArg) poly_args = NULL;
+    bh_arr_new(global_heap_allocator, arg_arr, 1);
 
     // NOTE: Check arguments
     AstArgument* actual = call->arguments;
@@ -316,13 +325,20 @@ b32 check_call(AstCall* call) {
         if (check_expression((AstTyped **) &actual)) return 1;
 
         if (actual->value->kind == Ast_Kind_Overloaded_Function) {
-            onyx_report_error(actual->token->pos, "Cannot pass overloaded functions as parameters.");
+            onyx_report_error(actual->token->pos,
+                "Cannot pass overloaded function '%b' as argument.",
+                actual->value->token->text, actual->value->token->length);
             return 1;
         }
 
-        if (actual->value->kind == Ast_Kind_Polymorphic_Proc)
-            has_polymorphic_args = 1;
+        if (actual->value->kind == Ast_Kind_Polymorphic_Proc) {
+            bh_arr_push(poly_args, ((PolyArg) {
+                .arg = actual,
+                .pos = bh_arr_length(arg_arr),
+            }));
+        }
 
+        bh_arr_push(arg_arr, actual);
         actual = (AstArgument *) actual->next;
     }
 
@@ -355,35 +371,21 @@ b32 check_call(AstCall* call) {
         return 1;
     }
 
-    if (has_polymorphic_args) {
-        actual = call->arguments;
-        u32 arg_idx = 0;
+    bh_arr_each(PolyArg, pa, poly_args) {
+        pa->arg->value = (AstTyped *) polymorphic_proc_lookup(
+            (AstPolyProc *) pa->arg->value,
+            PPLM_By_Function_Type,
+            callee->type->Function.params[pa->pos],
+            pa->arg->token->pos);
 
-        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 (pa->arg->value == NULL) return 1;
 
-                if (actual->value == NULL) return 1;
-
-                actual->value->flags |= Ast_Flag_Function_Used;
-            }
-
-            actual = (AstArgument *) actual->next;
-            arg_idx++;
-        }
+        pa->arg->value->flags |= Ast_Flag_Function_Used;
     }
 
     if (callee->kind == Ast_Kind_Function) {
-        if (call->arg_count < bh_arr_length(callee->params)) {
-            AstArgument** last_arg = &call->arguments;
-            while (*last_arg != NULL)
-                last_arg = (AstArgument **) &(*last_arg)->next;
-
-            while (call->arg_count < bh_arr_length(callee->params)
+        if (bh_arr_length(arg_arr) < bh_arr_length(callee->params)) {
+            while (bh_arr_length(arg_arr) < bh_arr_length(callee->params)
                 && callee->params[call->arg_count].default_value != NULL) {
                 AstTyped* dv = callee->params[call->arg_count].default_value;
 
@@ -392,10 +394,7 @@ b32 check_call(AstCall* call) {
                 new_arg->value = dv;
                 new_arg->next = NULL;
 
-                *last_arg = new_arg;
-                last_arg = (AstArgument **) &(*last_arg)->next;
-
-                call->arg_count++;
+                bh_arr_push(arg_arr, new_arg);
             }
         }
     }
@@ -407,7 +406,6 @@ b32 check_call(AstCall* call) {
         call->callee = NULL;
 
         token_toggle_end(callee->intrinsic_name);
-
         char* intr_name = callee->intrinsic_name->text;
 
         if (bh_table_has(OnyxIntrinsic, intrinsic_table, intr_name)) {
@@ -423,74 +421,73 @@ b32 check_call(AstCall* call) {
     }
 
     call->type = callee->type->Function.return_type;
+    call->va_kind = VA_Kind_Not_VA;
 
     Type **formal_params = callee->type->Function.params;
-    actual = call->arguments;
 
     Type* variadic_type = NULL;
     AstParam* variadic_param = NULL;
 
-    i32 arg_state = 0;
-
+    ArgState arg_state = AS_Expecting_Exact;
     i32 arg_pos = 0;
-    while (1) {
-        if (actual == NULL) break;
-
+    while (arg_pos < bh_arr_length(arg_arr)) {
         switch (arg_state) {
-            case 0: {
+            case AS_Expecting_Exact: {
                 if (arg_pos >= callee->type->Function.param_count) goto type_checking_done;
 
                 if (formal_params[arg_pos]->kind == Type_Kind_VarArgs) {
                     variadic_type = formal_params[arg_pos]->VarArgs.ptr_to_data->Pointer.elem;
                     variadic_param = &callee->params[arg_pos];
-                    arg_state = 1;
+                    arg_state = AS_Expecting_Typed_VA;
                     continue;
                 }
 
+                // CLEANUP POTENTIAL BUG if the builtin_vararg_type_type is ever rebuilt
                 if (formal_params[arg_pos] == builtin_vararg_type_type) {
-                    arg_state = 2
+                    arg_state = AS_Expecting_Untyped_VA
                     continue;
                 }
 
-                if (!type_check_or_auto_cast(actual->value, formal_params[arg_pos])) {
-                    onyx_report_error(actual->token->pos,
+                if (!type_check_or_auto_cast(arg_arr[arg_pos]->value, formal_params[arg_pos])) {
+                    onyx_report_error(arg_arr[arg_pos]->token->pos,
                             "The function '%b' expects a value of type '%s' for %d%s parameter, got '%s'.",
                             callee->token->text, callee->token->length,
                             type_get_name(formal_params[arg_pos]),
                             arg_pos + 1,
                             bh_num_suffix(arg_pos + 1),
-                            type_get_name(actual->value->type));
+                            type_get_name(arg_arr[arg_pos]->value->type));
                     return 1;
                 }
 
+                arg_arr[arg_pos]->va_kind = VA_Kind_Not_VA;
                 break;
             }
 
-            case 1: {
-                if (!type_check_or_auto_cast(actual->value, variadic_type)) {
-                    onyx_report_error(actual->token->pos,
+            case AS_Expecting_Typed_VA: {
+                if (!type_check_or_auto_cast(arg_arr[arg_pos]->value, variadic_type)) {
+                    onyx_report_error(arg_arr[arg_pos]->token->pos,
                             "The function '%b' expects a value of type '%s' for the variadic parameter, '%b', got '%s'.",
                             callee->token->text, callee->token->length,
                             type_get_name(variadic_type),
                             variadic_param->local->token->text,
                             variadic_param->local->token->length,
-                            type_get_name(actual->value->type));
+                            type_get_name(arg_arr[arg_pos]->value->type));
                     return 1;
                 }
 
-                actual->flags |= Ast_Flag_Arg_Is_VarArg;
+                arg_arr[arg_pos]->va_kind = VA_Kind_Typed;
+                call->va_kind = VA_Kind_Typed;
                 break;
             }
 
-            case 2: {
-                // Untyped varargs
-                actual->flags |= Ast_Flag_Arg_Is_Untyped_VarArg;
+            case AS_Expecting_Untyped_VA: {
+                arg_arr[arg_pos]->va_kind = VA_Kind_Untyped;
+                call->va_kind = VA_Kind_Untyped;
                 break;
             }
         }
 
         arg_pos++;
-        actual = (AstArgument *) actual->next;
     }
 
 type_checking_done:
@@ -500,12 +497,15 @@ type_checking_done:
         return 1;
     }
 
-    if (actual != NULL) {
+    if (arg_pos < bh_arr_length(arg_arr)) {
         onyx_report_error(call->token->pos, "Too many arguments to function call.");
         return 1;
     }
 
     callee->flags |= Ast_Flag_Function_Used;
+    call->arg_arr = arg_arr;
+
+    bh_arr_free(poly_args);
 
     return 0;
 }
index 7add1d583f3fb356435a7d7d3f12e6ef9f5ce305..c7545d47cc4dc577a46a85c1beba99105ee3deef 100644 (file)
@@ -599,7 +599,8 @@ void symres_function(AstFunction* func) {
 
         } else if (param->vararg_kind == VA_Kind_Untyped) {
             // HACK
-            builtin_vararg_type_type = type_build_from_ast(semstate.node_allocator, builtin_vararg_type);
+            if (builtin_vararg_type_type == NULL)
+                builtin_vararg_type_type = type_build_from_ast(semstate.node_allocator, builtin_vararg_type);
 
             param->local->type = builtin_vararg_type_type;
         }
index 83dee10f3dca4636342b70f4ed36d7a19829d6f3..60d9e95cec626e34714c3892bf2cf13fc3c2ccd7 100644 (file)
@@ -1326,22 +1326,14 @@ EMIT_FUNC(call, AstCall* call) {
 
     u32 vararg_count = 0;
     u32 vararg_offset = -1;
-    VarArgKind vararg_type = VA_Kind_Not_VA;
 
-    for (AstArgument *arg = call->arguments;
-            arg != NULL;
-            arg = (AstArgument *) arg->next) {
+    bh_arr_each(AstArgument *, parg, call->arg_arr) {
+        AstArgument* arg = *parg;
 
         b32 place_on_stack = 0;
         b32 arg_is_struct  = type_is_structlike(arg->value->type);
 
-        if (arg->flags & Ast_Flag_Arg_Is_VarArg) {
-            vararg_type = VA_Kind_Typed;
-            if (vararg_offset == -1) vararg_offset = stack_grow_amm;
-            place_on_stack = 1;
-        }
-        if (arg->flags & Ast_Flag_Arg_Is_Untyped_VarArg) {
-            vararg_type = VA_Kind_Untyped;
+        if (arg->va_kind != VA_Kind_Not_VA) {
             if (vararg_offset == -1) vararg_offset = stack_grow_amm;
             place_on_stack = 1;
         }
@@ -1355,7 +1347,7 @@ EMIT_FUNC(call, AstCall* call) {
             if (arg_is_struct) WID(WI_GLOBAL_GET, stack_top_idx);
             emit_store_instruction(mod, &code, arg->value->type, stack_grow_amm);
 
-            if (vararg_type != VA_Kind_Not_VA) vararg_count += 1;
+            if (arg->va_kind != VA_Kind_Not_VA) vararg_count += 1;
             else {
                 WID(WI_GLOBAL_GET, stack_top_idx);
                 WID(WI_I32_CONST, stack_grow_amm);
@@ -1366,35 +1358,33 @@ EMIT_FUNC(call, AstCall* call) {
         }
     }
 
-    if (vararg_type != VA_Kind_Not_VA) {
-        switch (vararg_type) {
-            case VA_Kind_Typed: {
-                WID(WI_GLOBAL_GET, vararg_offset);
-                WID(WI_I32_CONST, vararg_count);
-                break;
-            }
-
-            case VA_Kind_Untyped: {
-                WID(WI_GLOBAL_GET, stack_top_idx);
-                WID(WI_GLOBAL_GET, stack_top_idx);
-                WID(WI_I32_CONST, vararg_offset);
-                WI(WI_I32_ADD);
-                emit_store_instruction(mod, &code, &basic_types[Basic_Kind_I32], stack_grow_amm);
+    switch (call->va_kind) {
+        case VA_Kind_Typed: {
+            WID(WI_GLOBAL_GET, vararg_offset);
+            WID(WI_I32_CONST, vararg_count);
+            break;
+        }
 
-                WID(WI_GLOBAL_GET, stack_top_idx);
-                WID(WI_I32_CONST, vararg_count);
-                emit_store_instruction(mod, &code, &basic_types[Basic_Kind_I32], stack_grow_amm + 4);
+        case VA_Kind_Untyped: {
+            WID(WI_GLOBAL_GET, stack_top_idx);
+            WID(WI_GLOBAL_GET, stack_top_idx);
+            WID(WI_I32_CONST, vararg_offset);
+            WI(WI_I32_ADD);
+            emit_store_instruction(mod, &code, &basic_types[Basic_Kind_I32], stack_grow_amm);
 
-                WID(WI_GLOBAL_GET, stack_top_idx);
-                WID(WI_I32_CONST, stack_grow_amm);
-                WI(WI_I32_ADD);
+            WID(WI_GLOBAL_GET, stack_top_idx);
+            WID(WI_I32_CONST, vararg_count);
+            emit_store_instruction(mod, &code, &basic_types[Basic_Kind_I32], stack_grow_amm + 4);
 
-                stack_grow_amm += 8;
-                break;
-            }
+            WID(WI_GLOBAL_GET, stack_top_idx);
+            WID(WI_I32_CONST, stack_grow_amm);
+            WI(WI_I32_ADD);
 
-            default: break;
+            stack_grow_amm += 8;
+            break;
         }
+
+        default: break;
     }
 
     CallingConvention cc = type_function_get_cc(call->callee->type);