From: Brendan Hansen Date: Sat, 18 Jul 2020 02:56:03 +0000 (-0500) Subject: Added basic function overloading X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=6b4891e977d77f40f779d98b86a8dabacbba45b6;p=onyx.git Added basic function overloading --- diff --git a/include/onyxastnodes.h b/include/onyxastnodes.h index 6e3a2366..ceacab39 100644 --- a/include/onyxastnodes.h +++ b/include/onyxastnodes.h @@ -30,10 +30,10 @@ typedef struct AstPointerType AstPointerType; typedef struct AstFunctionType AstFunctionType; typedef struct AstBinding AstBinding; -typedef struct AstFunction AstFunction; -typedef struct AstForeign AstForeign; -typedef struct AstGlobal AstGlobal; typedef struct AstUse AstUse; +typedef struct AstGlobal AstGlobal; +typedef struct AstFunction AstFunction; +typedef struct AstOverloadedFunction AstOverloadedFunction; typedef enum AstKind { Ast_Kind_Error, @@ -42,6 +42,7 @@ typedef enum AstKind { Ast_Kind_Binding, Ast_Kind_Function, + Ast_Kind_Overloaded_Function, Ast_Kind_Foreign, Ast_Kind_Block, Ast_Kind_Local_Group, @@ -255,6 +256,11 @@ struct AstFunction { }; }; }; +struct AstOverloadedFunction { + AstTyped_base; + + bh_arr(AstTyped *) overloads; +}; // NOTE: Simple data structure for storing what comes out of the parser typedef struct ParserOutput { diff --git a/onyx b/onyx index e31cecd7..caa0034a 100755 Binary files a/onyx and b/onyx differ diff --git a/progs/arrays.onyx b/progs/arrays.onyx index 24246274..c4f6bd4c 100644 --- a/progs/arrays.onyx +++ b/progs/arrays.onyx @@ -1,6 +1,24 @@ use "progs/intrinsics" use "progs/print_funcs" +global_arr :: global ^i32; + +min_i32 :: proc (a: i32, b: i32) -> i32 { + least := a; + if b < a least = b; + return least; +} + +min_i64 :: proc (a: i64, b: i64) -> i64 { + least := a; + if b < a least = b; + return least; +} + +min :: proc #overloaded { + min_i32, min_i64, min_f32, min_f64 +} + // NOTE: in-place insertion sort sort :: proc (src: ^i32, len: i32) { i := 0; @@ -21,17 +39,17 @@ sort :: proc (src: ^i32, len: i32) { } } -global_arr :: global ^i32; - -print_i32arr :: proc (arr: ^i32, len: i32) { +printarr :: proc (arr: ^i32, len: i32) { i := 0; while i < len { - print_i32(arr[i]); + print(arr[i]); i += 1; } } main :: proc #export { + print(min(10.0, 12.0)); + global_arr = 0 as ^i32; len :: 10; @@ -41,11 +59,11 @@ main :: proc #export { i += 1; } - print_i32arr(global_arr, len); + printarr(global_arr, len); sort(global_arr, len); - print_i32(1234567); - print_i32arr(global_arr, len); + print(1234567); + printarr(global_arr, len); } diff --git a/progs/print_funcs.onyx b/progs/print_funcs.onyx index 3ac27828..ac1e750e 100644 --- a/progs/print_funcs.onyx +++ b/progs/print_funcs.onyx @@ -3,3 +3,11 @@ print_i32 :: proc #foreign "host" "print" (value: i32) --- print_f32 :: proc #foreign "host" "print" (value: f32) --- print_i64 :: proc #foreign "host" "print" (value: i64) --- print_f64 :: proc #foreign "host" "print" (value: f64) --- + +print :: proc #overloaded { + print_bool, + print_i32, + print_f32, + print_i64, + print_f64 +} diff --git a/src/onyxchecker.c b/src/onyxchecker.c index 90a3e6ca..a61df5be 100644 --- a/src/onyxchecker.c +++ b/src/onyxchecker.c @@ -2,7 +2,6 @@ #include "onyxsempass.h" #include "onyxparser.h" -static b32 check_function(SemState* state, AstFunction* func); static b32 check_block(SemState* state, AstBlock* block); static b32 check_statement_chain(SemState* state, AstNode* start); static b32 check_statement(SemState* state, AstNode* stmt); @@ -14,6 +13,13 @@ static b32 check_binaryop(SemState* state, AstBinaryOp* binop); static b32 check_expression(SemState* state, AstTyped* expr); static b32 check_array_access(SemState* state, AstArrayAccess* expr); static b32 check_global(SemState* state, AstGlobal* global); +static b32 check_function(SemState* state, AstFunction* func); +static b32 check_overloaded_function(SemState* state, AstOverloadedFunction* func); + +static inline void fill_in_type(SemState* state, AstTyped* node) { + if (node->type == NULL) + node->type = type_build_from_ast(state->allocator, node->type_node); +} static b32 check_return(SemState* state, AstReturn* retnode) { if (retnode->expr) { @@ -71,6 +77,46 @@ static b32 check_while(SemState* state, AstWhile* whilenode) { return check_statement(state, whilenode->stmt); } +static AstTyped* match_overloaded_function(SemState* state, AstCall* call, AstOverloadedFunction* ofunc) { + u64 param_count = 0; + for (AstArgument* arg = call->arguments; + arg != NULL; + arg = (AstArgument *) arg->next) param_count++; + + bh_arr_each(AstTyped *, node, ofunc->overloads) { + AstFunction* overload = (AstFunction *) *node; + + fill_in_type(state, (AstTyped *) overload); + + TypeFunction* ol_type = &overload->type->Function; + + if (ol_type->param_count != param_count) continue; + + AstArgument* arg = call->arguments; + Type** param_type = ol_type->params; + while (arg != NULL) { + fill_in_type(state, (AstTyped *) arg); + + if (!types_are_compatible(*param_type, arg->type)) goto no_match; + + param_type++; + arg = (AstArgument *) arg->next; + } + + return (AstTyped *) overload; + +no_match: + continue; + } + + onyx_message_add(state->msgs, + ONYX_MESSAGE_TYPE_LITERAL, + call->token->pos, + "unable to match overloaded function"); + + return NULL; +} + static b32 check_call(SemState* state, AstCall* call) { AstFunction* callee = (AstFunction *) call->callee; @@ -82,10 +128,23 @@ static b32 check_call(SemState* state, AstCall* call) { return 1; } - if (callee->type == NULL) { - callee->type = type_build_from_ast(state->node_allocator, callee->type_node); + // NOTE: Check arguments + AstArgument* actual_param = call->arguments; + while (actual_param != NULL) { + if (check_expression(state, (AstTyped *) actual_param)) return 1; + actual_param = (AstArgument *) actual_param->next; + } + + if (callee->kind == Ast_Kind_Overloaded_Function) { + call->callee = (AstNode *) match_overloaded_function(state, call, (AstOverloadedFunction *) callee); + callee = (AstFunction *) call->callee; + + if (callee == NULL) return 1; } + // NOTE: Build callee's type + fill_in_type(state, (AstTyped *) callee); + if (callee->type->kind != Type_Kind_Function) { onyx_message_add(state->msgs, ONYX_MESSAGE_TYPE_CALL_NON_FUNCTION, @@ -160,15 +219,11 @@ static b32 check_call(SemState* state, AstCall* call) { call->type = callee->type->Function.return_type; AstLocal* formal_param = callee->params; - AstArgument* actual_param = call->arguments; + actual_param = call->arguments; i32 arg_pos = 0; while (formal_param != NULL && actual_param != NULL) { - if (check_expression(state, (AstTyped *) actual_param)) return 1; - - if (formal_param->type == NULL) { - formal_param->type = type_build_from_ast(state->node_allocator, formal_param->type_node); - } + fill_in_type(state, (AstTyped *) formal_param); if (!types_are_compatible(formal_param->type, actual_param->type)) { onyx_message_add(state->msgs, @@ -338,9 +393,7 @@ static b32 check_expression(SemState* state, AstTyped* expr) { return 1; } - if (expr->type == NULL) { - expr->type = type_build_from_ast(state->node_allocator, expr->type_node); - } + fill_in_type(state, expr); i32 retval = 0; switch (expr->kind) { @@ -403,6 +456,7 @@ static b32 check_expression(SemState* state, AstTyped* expr) { break; case Ast_Kind_Function: break; + case Ast_Kind_Overloaded_Function: break; default: retval = 1; @@ -414,8 +468,7 @@ static b32 check_expression(SemState* state, AstTyped* expr) { } static b32 check_global(SemState* state, AstGlobal* global) { - if (global->type == NULL) - global->type = type_build_from_ast(state->allocator, global->type_node); + fill_in_type(state, (AstTyped *) global); if (global->type == NULL) { onyx_message_add(state->msgs, @@ -471,9 +524,7 @@ static b32 check_block(SemState* state, AstBlock* block) { static b32 check_function(SemState* state, AstFunction* func) { for (AstLocal *param = func->params; param != NULL; param = (AstLocal *) param->next) { - if (param->type == NULL) { - param->type = type_build_from_ast(state->node_allocator, param->type_node); - } + fill_in_type(state, (AstTyped *) param); if (param->type == NULL) { onyx_message_add(state->msgs, @@ -492,9 +543,7 @@ static b32 check_function(SemState* state, AstFunction* func) { } } - if (func->type == NULL) { - func->type = type_build_from_ast(state->node_allocator, func->type_node); - } + fill_in_type(state, (AstTyped *) func); if ((func->flags & Ast_Flag_Exported) != 0) { if ((func->flags & Ast_Flag_Foreign) != 0) { @@ -538,16 +587,41 @@ static b32 check_function(SemState* state, AstFunction* func) { return 0; } +static b32 check_overloaded_function(SemState* state, AstOverloadedFunction* func) { + bh_arr_each(AstTyped *, node, func->overloads) { + if ((*node)->kind == Ast_Kind_Overloaded_Function) { + onyx_message_add(state->msgs, + ONYX_MESSAGE_TYPE_LITERAL, + (*node)->token->pos, + "overload option can not be another overloaded function (yet)"); + + return 1; + } + + if ((*node)->kind != Ast_Kind_Function) { + onyx_message_add(state->msgs, + ONYX_MESSAGE_TYPE_LITERAL, + (*node)->token->pos, + "overload option not function"); + + return 1; + } + } + + return 0; +} + static b32 check_node(SemState* state, AstNode* node) { switch (node->kind) { - case Ast_Kind_Function: return check_function(state, (AstFunction *) node); - case Ast_Kind_Block: return check_block(state, (AstBlock *) node); - case Ast_Kind_Return: return check_return(state, (AstReturn *) node); - case Ast_Kind_If: return check_if(state, (AstIf *) node); - case Ast_Kind_While: return check_while(state, (AstWhile *) node); - case Ast_Kind_Call: return check_call(state, (AstCall *) node); - case Ast_Kind_Binary_Op: return check_binaryop(state, (AstBinaryOp *) node); - default: return check_expression(state, (AstTyped *) node); + case Ast_Kind_Function: return check_function(state, (AstFunction *) node); + case Ast_Kind_Overloaded_Function: return check_overloaded_function(state, (AstOverloadedFunction *) node); + case Ast_Kind_Block: return check_block(state, (AstBlock *) node); + case Ast_Kind_Return: return check_return(state, (AstReturn *) node); + case Ast_Kind_If: return check_if(state, (AstIf *) node); + case Ast_Kind_While: return check_while(state, (AstWhile *) node); + case Ast_Kind_Call: return check_call(state, (AstCall *) node); + case Ast_Kind_Binary_Op: return check_binaryop(state, (AstBinaryOp *) node); + default: return check_expression(state, (AstTyped *) node); } } diff --git a/src/onyxparser.c b/src/onyxparser.c index a6c5d20a..034a6840 100644 --- a/src/onyxparser.c +++ b/src/onyxparser.c @@ -740,12 +740,32 @@ static b32 parse_possible_directive(OnyxParser* parser, const char* dir) { // 'proc' * ('->' )? static AstFunction* parse_function_definition(OnyxParser* parser) { - AstFunction* func_def = make_node(AstFunction, Ast_Kind_Function); bh_arr_new(global_heap_allocator, func_def->locals, 4); func_def->token = expect_token(parser, Token_Type_Keyword_Proc); while (parser->curr->type == '#') { + if (parse_possible_directive(parser, "overloaded")) { + AstOverloadedFunction* ofunc = make_node(AstOverloadedFunction, Ast_Kind_Overloaded_Function); + ofunc->token = func_def->token; + + bh_arr_new(global_heap_allocator, ofunc->overloads, 4); + + expect_token(parser, '{'); + while (parser->curr->type != '}') { + AstTyped* sym_node = make_node(AstTyped, Ast_Kind_Symbol); + sym_node->token = expect_token(parser, Token_Type_Symbol); + + bh_arr_push(ofunc->overloads, sym_node); + + if (parser->curr->type != '}') + expect_token(parser, ','); + } + + consume_token(parser); + return (AstFunction *) ofunc; + } + if (parse_possible_directive(parser, "intrinsic")) { func_def->flags |= Ast_Flag_Intrinsic; @@ -913,7 +933,7 @@ static AstNode* parse_top_level_statement(OnyxParser* parser) { if (global->exported_name == NULL) global->exported_name = symbol; - } else { + } else if (node->kind != Ast_Kind_Overloaded_Function) { // HACK bh_arr_push(parser->results.nodes_to_process, (AstNode *) node); } diff --git a/src/onyxsymres.c b/src/onyxsymres.c index 58f988bd..37fa5307 100644 --- a/src/onyxsymres.c +++ b/src/onyxsymres.c @@ -21,6 +21,7 @@ static b32 symres_statement(SemState* state, AstNode* stmt); static void symres_block(SemState* state, AstBlock* block); static void symres_function(SemState* state, AstFunction* func); static void symres_global(SemState* state, AstGlobal* global); +static void symres_overloaded_function(SemState* state, AstOverloadedFunction* ofunc); static void symbol_introduce(SemState* state, OnyxToken* tkn, AstNode* symbol) { token_toggle_end(tkn); @@ -318,6 +319,14 @@ static void symres_global(SemState* state, AstGlobal* global) { global->type_node = symres_type(state, global->type_node); } +static void symres_overloaded_function(SemState* state, AstOverloadedFunction* ofunc) { + bh_arr_each(AstTyped *, node, ofunc->overloads) { + if ((*node)->kind == Ast_Kind_Symbol) { + *node = (AstTyped *) symbol_resolve(state, (*node)->token); + } + } +} + static void symres_top_node(SemState* state, AstNode** node) { switch ((*node)->kind) { case Ast_Kind_Call: @@ -336,6 +345,10 @@ static void symres_top_node(SemState* state, AstNode** node) { symres_function(state, (AstFunction *) *node); break; + case Ast_Kind_Overloaded_Function: + symres_overloaded_function(state, (AstOverloadedFunction *) *node); + break; + default: DEBUG_HERE; break; diff --git a/src/onyxutils.c b/src/onyxutils.c index d45042ee..24487a7b 100644 --- a/src/onyxutils.c +++ b/src/onyxutils.c @@ -15,6 +15,7 @@ static const char* ast_node_names[] = { "BINDING", "FUNCTION", + "OVERLOADED_FUNCTION", "FOREIGN", "BLOCK", "SCOPE", diff --git a/src/onyxwasm.c b/src/onyxwasm.c index cccb53c5..9ac75ced 100644 --- a/src/onyxwasm.c +++ b/src/onyxwasm.c @@ -1213,7 +1213,7 @@ static i32 output_memorysection(OnyxWasmModule* module, bh_buffer* buff) { u8* leb = uint_to_uleb128((u64) 1, &leb_len); bh_buffer_append(&vec_buff, leb, leb_len); - output_limits(4, 20, &vec_buff); + output_limits(4, -1, &vec_buff); leb = uint_to_uleb128((u64) (vec_buff.length), &leb_len); bh_buffer_append(buff, leb, leb_len);