From: Brendan Hansen Date: Fri, 18 Jun 2021 17:43:46 +0000 (-0500) Subject: added precedence option to overloads X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=8c08c718c49d259fa2071bbc93ce63a1002a7813;p=onyx.git added precedence option to overloads --- diff --git a/bin/onyx b/bin/onyx index 3d359792..28ba7ff1 100755 Binary files a/bin/onyx and b/bin/onyx differ diff --git a/core/io/stream.onyx b/core/io/stream.onyx index 987c3220..d94abde3 100644 --- a/core/io/stream.onyx +++ b/core/io/stream.onyx @@ -266,6 +266,10 @@ dynamic_string_stream_make :: (init_size := 128, a := context.allocator) -> Dyna }; } +dynamic_string_stream_free :: (use dds: ^DynamicStringStream) { + array.free(^data); +} + dynamic_string_stream_to_str :: (use dds: ^DynamicStringStream) -> str { return data.data[0 .. curr_pos]; } diff --git a/include/onyxastnodes.h b/include/onyxastnodes.h index eb9a399f..490976c9 100644 --- a/include/onyxastnodes.h +++ b/include/onyxastnodes.h @@ -830,10 +830,20 @@ struct AstFunction { struct Entity* entity_body; }; +typedef struct OverloadOption OverloadOption; +struct OverloadOption { + // This is u64 because padding will make it that anyway. + // Consider: would there be any practical benefit to having the precedence setting + // be a compile-time known value? as opposed to a hardcoded value? + u64 precedence; + + AstTyped* option; +}; + struct AstOverloadedFunction { AstTyped_base; - bh_arr(AstTyped *) overloads; + bh_arr(OverloadOption) 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 @@ -937,6 +947,8 @@ struct AstDirectiveAddOverload { // then resolved to an overloaded function. AstNode *overloaded_function; + // See note in OverloadOption. This could be refactored into an OverloadOption? + u64 precedence; AstTyped *overload; }; @@ -1207,7 +1219,7 @@ typedef struct IntrinsicMap { extern bh_table(OnyxIntrinsic) intrinsic_table; -extern bh_arr(AstTyped *) operator_overloads[Binary_Op_Count]; +extern bh_arr(OverloadOption) operator_overloads[Binary_Op_Count]; void initialize_builtins(bh_allocator a); void introduce_build_options(bh_allocator a); @@ -1261,8 +1273,9 @@ AstFunction* polymorphic_proc_solidify(AstPolyProc* pp, bh_arr(AstPolySolution) AstNode* polymorphic_proc_try_solidify(AstPolyProc* pp, bh_arr(AstPolySolution) slns, OnyxToken* tkn); AstFunction* polymorphic_proc_build_only_header(AstPolyProc* pp, PolyProcLookupMethod pp_lookup, ptr actual); -AstTyped* find_matching_overload_by_arguments(bh_arr(AstTyped *) overloads, Arguments* args); -AstTyped* find_matching_overload_by_type(bh_arr(AstTyped *) overloads, Type* type); +void add_overload_option(bh_arr(OverloadOption)* poverloads, u64 precedence, AstTyped* overload); +AstTyped* find_matching_overload_by_arguments(bh_arr(OverloadOption) overloads, Arguments* args); +AstTyped* find_matching_overload_by_type(bh_arr(OverloadOption) overloads, Type* type); void report_unable_to_match_overload(AstCall* call); AstStructType* polymorphic_struct_lookup(AstPolyStructType* ps_type, bh_arr(AstPolySolution) slns, OnyxFilePos pos); diff --git a/include/onyxutils.h b/include/onyxutils.h index a67833c9..cd726711 100644 --- a/include/onyxutils.h +++ b/include/onyxutils.h @@ -26,7 +26,7 @@ AstNode* symbol_resolve(Scope* start_scope, OnyxToken* tkn); AstNode* try_symbol_raw_resolve_from_node(AstNode* node, char* symbol); AstNode* try_symbol_resolve_from_node(AstNode* node, OnyxToken* token); -void build_all_overload_options(bh_arr(AstTyped *) overloads, bh_imap* all_overloads); +void build_all_overload_options(bh_arr(OverloadOption) overloads, bh_imap* all_overloads); u32 char_to_base16_value(char x); diff --git a/src/onyxbuiltins.c b/src/onyxbuiltins.c index 0a8abaf0..54475b59 100644 --- a/src/onyxbuiltins.c +++ b/src/onyxbuiltins.c @@ -329,7 +329,7 @@ static IntrinsicMap builtin_intrinsics[] = { { NULL, ONYX_INTRINSIC_UNDEFINED }, }; -bh_arr(AstTyped *) operator_overloads[Binary_Op_Count] = { 0 }; +bh_arr(OverloadOption) operator_overloads[Binary_Op_Count] = { 0 }; void initialize_builtins(bh_allocator a) { // HACK diff --git a/src/onyxparser.c b/src/onyxparser.c index 08a5256f..b5c7d61f 100644 --- a/src/onyxparser.c +++ b/src/onyxparser.c @@ -1918,12 +1918,19 @@ static AstOverloadedFunction* parse_overloaded_function(OnyxParser* parser, Onyx bh_arr_new(global_heap_allocator, ofunc->overloads, 4); + u64 precedence = 0; while (!consume_token_if_next(parser, '}')) { if (parser->hit_unexpected_token) return ofunc; - AstTyped* o_node = parse_expression(parser, 0); + if (parse_possible_directive(parser, "precedence")) { + AstNumLit* pre = parse_int_literal(parser); + if (parser->hit_unexpected_token) return ofunc; - bh_arr_push(ofunc->overloads, o_node); + precedence = bh_max(pre->value.l, 0); + } + + AstTyped* option = parse_expression(parser, 0); + add_overload_option(&ofunc->overloads, precedence++, option); if (parser->curr->type != '}') expect_token(parser, ','); @@ -2370,6 +2377,16 @@ static void parse_top_level_statement(OnyxParser* parser) { add_overload->overloaded_function = (AstNode *) parse_expression(parser, 0); expect_token(parser, ','); + + if (parse_possible_directive(parser, "precedence")) { + AstNumLit* pre = parse_int_literal(parser); + if (parser->hit_unexpected_token) return; + + add_overload->precedence = bh_max(pre->value.l, 0); + } else { + add_overload->precedence = 0; + } + add_overload->overload = parse_expression(parser, 0); ENTITY_SUBMIT(add_overload); diff --git a/src/onyxsymres.c b/src/onyxsymres.c index deb1bbfe..76e328ca 100644 --- a/src/onyxsymres.c +++ b/src/onyxsymres.c @@ -877,8 +877,8 @@ static SymresStatus symres_global(AstGlobal* global) { } static SymresStatus symres_overloaded_function(AstOverloadedFunction* ofunc) { - bh_arr_each(AstTyped *, node, ofunc->overloads) { - SYMRES(expression, node); + bh_arr_each(OverloadOption, overload, ofunc->overloads) { + SYMRES(expression, &overload->option); } return Symres_Success; } @@ -1023,7 +1023,7 @@ static SymresStatus symres_process_directive(AstNode* directive) { } else { AstOverloadedFunction* ofunc = (AstOverloadedFunction *) add_overload->overloaded_function; SYMRES(expression, (AstTyped **) &add_overload->overload); - bh_arr_push(ofunc->overloads, (AstTyped *) add_overload->overload); + add_overload_option(&ofunc->overloads, add_overload->precedence, add_overload->overload); } break; @@ -1050,7 +1050,7 @@ static SymresStatus symres_process_directive(AstNode* directive) { return Symres_Error; } - bh_arr_push(operator_overloads[operator->operator], operator->overload); + add_overload_option(&operator_overloads[operator->operator], 0, operator->overload); break; } diff --git a/src/onyxutils.c b/src/onyxutils.c index cca3892d..e737e804 100644 --- a/src/onyxutils.c +++ b/src/onyxutils.c @@ -978,6 +978,32 @@ 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) // +void add_overload_option(bh_arr(OverloadOption)* poverloads, u64 precedence, AstTyped* overload) { + bh_arr(OverloadOption) overloads = *poverloads; + + i32 index = -1; + fori (i, 0, bh_arr_length(overloads)) { + if (overloads[i].precedence > precedence) { + index = i; + break; + } + } + + if (index < 0) { + bh_arr_push(overloads, ((OverloadOption) { + .precedence = precedence, + .option = overload, + })); + + } else { + bh_arr_insertn(overloads, index, 1); + overloads[index].precedence = precedence; + overloads[index].option = overload; + } + + *poverloads = overloads; +} + // NOTE: The job of this function is to take a set of overloads, and traverse it to add all possible // overloads that are reachable. This is slightly more difficult than it may seem. In this language, // overloaded procedures have a strict ordering to their overloads, which determines how the correct @@ -996,20 +1022,20 @@ AstFunction* polymorphic_proc_build_only_header(AstPolyProc* pp, PolyProcLookupM // an "entries" array that, so long as nothing is ever removed from it, will maintain the order in // which entries were put into the map. This is useful because a simple recursive algorithm can // collect all the overloads into the map, and also use the map to provide a base case. -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; +void build_all_overload_options(bh_arr(OverloadOption) overloads, bh_imap* all_overloads) { + bh_arr_each(OverloadOption, overload, overloads) { + if (bh_imap_has(all_overloads, (u64) overload->option)) continue; - bh_imap_put(all_overloads, (u64) *node, 1); + bh_imap_put(all_overloads, (u64) overload->option, 1); - if ((*node)->kind == Ast_Kind_Overloaded_Function) { - AstOverloadedFunction* sub_overload = (AstOverloadedFunction *) *node; + if (overload->option->kind == Ast_Kind_Overloaded_Function) { + AstOverloadedFunction* sub_overload = (AstOverloadedFunction *) overload->option; build_all_overload_options(sub_overload->overloads, all_overloads); } } } -AstTyped* find_matching_overload_by_arguments(bh_arr(AstTyped *) overloads, Arguments* param_args) { +AstTyped* find_matching_overload_by_arguments(bh_arr(OverloadOption) 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)); @@ -1077,7 +1103,7 @@ AstTyped* find_matching_overload_by_arguments(bh_arr(AstTyped *) overloads, Argu return matched_overload; } -AstTyped* find_matching_overload_by_type(bh_arr(AstTyped *) overloads, Type* type) { +AstTyped* find_matching_overload_by_type(bh_arr(OverloadOption) overloads, Type* type) { if (type->kind != Type_Kind_Function) return NULL; bh_imap all_overloads; diff --git a/tests/overload_precedence b/tests/overload_precedence new file mode 100644 index 00000000..7f67e0c9 --- /dev/null +++ b/tests/overload_precedence @@ -0,0 +1,4 @@ +Option M +Option X +Option R +Option Z diff --git a/tests/overload_precedence.onyx b/tests/overload_precedence.onyx new file mode 100644 index 00000000..f3f04822 --- /dev/null +++ b/tests/overload_precedence.onyx @@ -0,0 +1,20 @@ +#load "core/std" + +use package core + +overloaded :: #match { + #precedence 10 (x: i32) { println("Option X"); }, + #precedence 5 (y: i32) { println("Option Y"); }, + #precedence 4 (z: i32) { println("Option Z"); }, +} + +main :: (args: [] cstr) { + overloaded(10); + overloaded(x=10); + overloaded(r=10); + overloaded(z=10); +} + +#add_match overloaded, #precedence 3 (q: i32) { println("Option Q"); } +#add_match overloaded, #precedence 2 (r: i32) { println("Option R"); } +#add_match overloaded, #precedence 1 (m: i32) { println("Option M"); }