From: Brendan Hansen Date: Sat, 26 Sep 2020 18:46:39 +0000 (-0500) Subject: code cleanup with procedure calling; needs even more cleanup X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=2ec7dc1d12dc26a50b014f65a260cfee10e82d9c;p=onyx.git code cleanup with procedure calling; needs even more cleanup --- diff --git a/include/onyxastnodes.h b/include/onyxastnodes.h index b937438f..11995de3 100644 --- a/include/onyxastnodes.h +++ b/include/onyxastnodes.h @@ -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 730b313e..0c8c465e 100755 Binary files a/onyx and b/onyx differ diff --git a/progs/vararg_test.onyx b/progs/vararg_test.onyx index 7fd5e44e..aac4c497 100644 --- a/progs/vararg_test.onyx +++ b/progs/vararg_test.onyx @@ -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 diff --git a/src/onyxchecker.c b/src/onyxchecker.c index 815ee18c..9e298475 100644 --- a/src/onyxchecker.c +++ b/src/onyxchecker.c @@ -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; } diff --git a/src/onyxsymres.c b/src/onyxsymres.c index 7add1d58..c7545d47 100644 --- a/src/onyxsymres.c +++ b/src/onyxsymres.c @@ -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; } diff --git a/src/onyxwasm.c b/src/onyxwasm.c index 83dee10f..60d9e95c 100644 --- a/src/onyxwasm.c +++ b/src/onyxwasm.c @@ -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);