extern AstFunction *builtin_initialize_data_segments;
extern AstFunction *builtin_run_init_procedures;
extern bh_arr(AstFunction *) init_procedures;
+extern AstOverloadedFunction *builtin_implicit_bool_cast;
+
typedef struct BuiltinSymbol {
char* package;
b32 cast_is_legal(Type* from_, Type* to_, char** err_msg);
char* get_function_name(AstFunction* func);
-b32 implicit_cast_to_bool(AstTyped **pnode);
+TypeMatch implicit_cast_to_bool(AstTyped **pnode);
AstNode* strip_aliases(AstNode* node);
return 1;
}
-b32 implicit_cast_to_bool(AstTyped **pnode) {
+
+
+static bh_imap implicit_cast_to_bool_cache;
+
+TypeMatch implicit_cast_to_bool(AstTyped **pnode) {
AstTyped *node = *pnode;
- if ((node->type->kind == Type_Kind_Basic &&
- node->type->Basic.kind == Basic_Kind_Rawptr)
+ if ((node->type->kind == Type_Kind_Basic && node->type->Basic.kind == Basic_Kind_Rawptr)
|| (node->type->kind == Type_Kind_Pointer)) {
AstNumLit *zero = make_int_literal(context.ast_alloc, 0);
zero->type = &basic_types[Basic_Kind_Rawptr];
cmp->type = &basic_types[Basic_Kind_Bool];
*pnode = (AstTyped *) cmp;
- return 1;
+ return TYPE_MATCH_SUCCESS;
}
if (node->type->kind == Type_Kind_Slice ||
cmp->type = &basic_types[Basic_Kind_Bool];
*pnode = (AstTyped *) cmp;
- return 1;
+ return TYPE_MATCH_SUCCESS;
+ }
+
+ if (implicit_cast_to_bool_cache.entries == NULL) {
+ bh_imap_init(&implicit_cast_to_bool_cache, global_heap_allocator, 8);
}
- return 0;
+ if (!bh_imap_has(&implicit_cast_to_bool_cache, (u64) node)) {
+ AstArgument *implicit_arg = make_argument(context.ast_alloc, node);
+
+ Arguments *args = bh_alloc_item(context.ast_alloc, Arguments);
+ bh_arr_new(context.ast_alloc, args->values, 1);
+ bh_arr_push(args->values, (AstTyped *) implicit_arg);
+
+ bh_imap_put(&implicit_cast_to_bool_cache, (u64) node, (u64) args);
+ }
+
+ Arguments *args = (Arguments *) bh_imap_get(&implicit_cast_to_bool_cache, (u64) node);
+ AstFunction *overload = (AstFunction *) find_matching_overload_by_arguments(builtin_implicit_bool_cast->overloads, args);
+
+ if (overload == NULL) return TYPE_MATCH_FAILED;
+ if (overload == (AstFunction *) &node_that_signals_a_yield) return TYPE_MATCH_YIELD;
+
+ AstCall *implicit_call = onyx_ast_node_new(context.ast_alloc, sizeof(AstCall), Ast_Kind_Call);
+ implicit_call->token = node->token;
+ implicit_call->callee = (AstTyped *) overload;
+ implicit_call->va_kind = VA_Kind_Not_VA;
+ implicit_call->args.values = args->values;
+
+ *(AstCall **) pnode = implicit_call;
+ bh_imap_delete(&implicit_cast_to_bool_cache, (u64) node);
+
+ return TYPE_MATCH_YIELD;
}
char* get_function_name(AstFunction* func) {
AstFunction *builtin_initialize_data_segments = NULL;
AstFunction *builtin_run_init_procedures = NULL;
bh_arr(AstFunction *) init_procedures = NULL;
+AstOverloadedFunction *builtin_implicit_bool_cast;
const BuiltinSymbol builtin_symbols[] = {
{ NULL, "void", (AstNode *) &basic_type_void },
return;
}
+ builtin_implicit_bool_cast = (AstOverloadedFunction *) symbol_raw_resolve(p->scope, "__implicit_bool_cast");
+ if (builtin_implicit_bool_cast == NULL || builtin_implicit_bool_cast->kind != Ast_Kind_Overloaded_Function) {
+ onyx_report_error((OnyxFilePos) { 0 }, Error_Critical, "'__implicit_bool_cast' #match procedure not found.");
+ return;
+ }
+
builtin_link_options_type = (AstType *) symbol_raw_resolve(p->scope, "Link_Options");
if (builtin_link_options_type == NULL) {
onyx_report_error((OnyxFilePos) { 0 }, Error_Critical, "'Link_Options' type not found.");
CHECK(expression, &ifnode->cond);
if (!type_is_bool(ifnode->cond->type)) {
- if (!implicit_cast_to_bool(&ifnode->cond)) {
+ TypeMatch implicit_cast = implicit_cast_to_bool(&ifnode->cond);
+ if (implicit_cast == TYPE_MATCH_YIELD) YIELD(ifnode->token->pos, "Waiting for implicit cast to bool to check.");
+ if (implicit_cast == TYPE_MATCH_FAILED) {
ERROR_(ifnode->token->pos, "Expected expression of type 'bool' for condition, got '%s'", type_get_name(ifnode->cond->type));
}
}
CHECK(expression, &whilenode->cond);
if (!type_is_bool(whilenode->cond->type)) {
- if (!implicit_cast_to_bool(&whilenode->cond)) {
+ TypeMatch implicit_cast = implicit_cast_to_bool(&whilenode->cond);
+ if (implicit_cast == TYPE_MATCH_YIELD) YIELD(whilenode->token->pos, "Waiting for implicit cast to bool to check.");
+ if (implicit_cast == TYPE_MATCH_FAILED) {
ERROR_(whilenode->token->pos, "Expected expression of type 'bool' for condition, got '%s'", type_get_name(whilenode->cond->type));
}
}
if (type_is_bool(binop->left->type)) {
left_is_bool = 1;
- } else if (implicit_cast_to_bool(&binop->left)) {
- left_is_bool = 1;
+ } else {
+ TypeMatch implicit_cast = implicit_cast_to_bool(&binop->left);
+ if (implicit_cast == TYPE_MATCH_YIELD) YIELD(binop->token->pos, "Waiting for implicit cast to bool to check.");
+ if (implicit_cast == TYPE_MATCH_SUCCESS) {
+ left_is_bool = 1;
+ }
}
if (type_is_bool(binop->right->type)) {
right_is_bool = 1;
- } else if (implicit_cast_to_bool(&binop->right)) {
- right_is_bool = 1;
+ } else {
+ TypeMatch implicit_cast = implicit_cast_to_bool(&binop->right);
+ if (implicit_cast == TYPE_MATCH_YIELD) YIELD(binop->token->pos, "Waiting for implicit cast to bool to check.");
+ if (implicit_cast == TYPE_MATCH_SUCCESS) {
+ right_is_bool = 1;
+ }
}
if (!left_is_bool || !right_is_bool) {
if (unaryop->operation == Unary_Op_Not) {
if (!type_is_bool(unaryop->expr->type)) {
- if (!implicit_cast_to_bool(&unaryop->expr)) {
+ TypeMatch implicit_cast = implicit_cast_to_bool(&unaryop->expr);
+ if (implicit_cast == TYPE_MATCH_YIELD) YIELD(unaryop->token->pos, "Waiting for implicit cast to bool to check.");
+ if (implicit_cast == TYPE_MATCH_FAILED) {
ERROR_(unaryop->token->pos,
"Bool negation operator expected bool type, got '%s'.",
node_get_type_name(unaryop->expr));
CHECK(expression, &if_expr->false_expr);
TYPE_CHECK(&if_expr->cond, &basic_types[Basic_Kind_Bool]) {
- if (!implicit_cast_to_bool(&if_expr->cond)) {
+ TypeMatch implicit_cast = implicit_cast_to_bool(&if_expr->cond);
+ if (implicit_cast == TYPE_MATCH_YIELD) YIELD(if_expr->token->pos, "Waiting for implicit cast to bool to check.");
+ if (implicit_cast == TYPE_MATCH_FAILED) {
ERROR_(if_expr->token->pos, "If-expression expected boolean for condition, got '%s'.",
type_get_name(if_expr->cond->type));
}
// NOTE: Overload is not something that is known to be overloadable.
if (overload == NULL) continue;
- if (overload == (AstFunction *) &node_that_signals_a_yield) return (AstTyped *) overload;
if (overload->kind != Ast_Kind_Function) continue;
- if (overload->type == NULL) {
+ if (overload == (AstFunction *) &node_that_signals_a_yield || overload->type == NULL) {
// If it was not possible to create the type for this procedure, tell the
// caller that this should yield and try again later.
// #init, in the specified order. It should theoritically only be called once on the main thread.
__run_init_procedures :: () -> void ---
+// This overloaded procedure allow you to define an implicit rule for how to convert any value
+// into a boolean. A default is provided for ALL pointer types and array types, but this can
+// be used for structures or distinct types.
+__implicit_bool_cast :: #match -> bool {}
+
#local {
#if runtime.runtime == .Onyx {