};
}
+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];
}
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
// then resolved to an overloaded function.
AstNode *overloaded_function;
+ // See note in OverloadOption. This could be refactored into an OverloadOption?
+ u64 precedence;
AstTyped *overload;
};
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);
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);
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);
{ 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
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, ',');
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);
}
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;
}
} 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;
return Symres_Error;
}
- bh_arr_push(operator_overloads[operator->operator], operator->overload);
+ add_overload_option(&operator_overloads[operator->operator], 0, operator->overload);
break;
}
// * 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
// 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));
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;
--- /dev/null
+Option M
+Option X
+Option R
+Option Z
--- /dev/null
+#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"); }