return 0;
}
-
-static AstTyped* match_overloaded_function(AstCall* call, AstOverloadedFunction* ofunc) {
- bh_arr_each(AstTyped *, node, ofunc->overloads) {
+static AstTyped* match_overloaded_function(bh_arr(AstTyped *) arg_arr, bh_arr(AstTyped *) overloads) {
+ bh_arr_each(AstTyped *, node, overloads) {
AstFunction* overload = (AstFunction *) *node;
fill_in_type((AstTyped *) overload);
TypeFunction* ol_type = &overload->type->Function;
- if (call->arg_count < ol_type->needed_param_count) continue;
+ if (bh_arr_length(arg_arr) < (i32) ol_type->needed_param_count) continue;
Type** param_type = ol_type->params;
- bh_arr_each(AstArgument*, arg, call->arg_arr) {
- fill_in_type((AstTyped *) *arg);
- if ((*param_type)->kind == Type_Kind_VarArgs) {
- if (!type_check_or_auto_cast(&(*arg)->value, (*param_type)->VarArgs.ptr_to_data->Pointer.elem))
- goto no_match;
- }
- else if (!type_check_or_auto_cast(&(*arg)->value, *param_type)) goto no_match;
+ bh_arr_each(AstTyped*, arg, arg_arr) {
+ fill_in_type(*arg);
+
+ Type* type_to_match = *param_type;
+ if ((*param_type)->kind == Type_Kind_VarArgs)
+ type_to_match = (*param_type)->VarArgs.ptr_to_data->Pointer.elem;
+
+ AstTyped** value = arg;
+ if ((*arg)->kind == Ast_Kind_Argument)
+ value = &((AstArgument *) *arg)->value;
+
+ if (!type_check_or_auto_cast(value, type_to_match)) goto no_match;
param_type++;
}
no_match:
continue;
}
-
- char* arg_str = bh_alloc(global_scratch_allocator, 1024);
- arg_str[0] = '\0';
-
- bh_arr_each(AstArgument *, arg, call->arg_arr) {
- strncat(arg_str, type_get_name((*arg)->value->type), 1023);
-
- if (arg != &bh_arr_last(call->arg_arr))
- strncat(arg_str, ", ", 1023);
- }
-
- onyx_report_error(call->token->pos, "unable to match overloaded function with provided argument types: (%s)", arg_str);
-
- bh_free(global_scratch_allocator, arg_str);
return NULL;
}
}
if (callee->kind == Ast_Kind_Overloaded_Function) {
- call->callee = match_overloaded_function(call, (AstOverloadedFunction *) callee);
- callee = (AstFunction *) call->callee;
+ call->callee = match_overloaded_function(
+ (bh_arr(AstTyped *)) call->arg_arr,
+ ((AstOverloadedFunction *) callee)->overloads);
+
+ if (call->callee == NULL) {
+ char* arg_str = bh_alloc(global_scratch_allocator, 1024);
+ arg_str[0] = '\0';
+
+ bh_arr_each(AstArgument *, arg, call->arg_arr) {
+ strncat(arg_str, type_get_name((*arg)->value->type), 1023);
+
+ if (arg != &bh_arr_last(call->arg_arr))
+ strncat(arg_str, ", ", 1023);
+ }
+
+ onyx_report_error(call->token->pos, "unable to match overloaded function with provided argument types: (%s)", arg_str);
+
+ bh_free(global_scratch_allocator, arg_str);
+ return Check_Error;
+ }
- if (callee == NULL) return Check_Error;
+ callee = (AstFunction *) call->callee;
}
if (callee->kind == Ast_Kind_Polymorphic_Proc) {
return Check_Error;
}
+ if (binop->left->type->kind != Type_Kind_Basic || binop->right->type->kind != Type_Kind_Basic) {
+ bh_arr(AstTyped *) args = NULL;
+ bh_arr_new(global_heap_allocator, args, 2);
+ bh_arr_push(args, binop->left);
+ bh_arr_push(args, binop->right);
+
+ AstTyped* overload = match_overloaded_function(args, operator_overloads[binop->operation]);
+ if (overload == NULL) {
+ bh_arr_free(args);
+ goto not_overloaded;
+ }
+
+ AstCall* implicit_call = onyx_ast_node_new(semstate.node_allocator, sizeof(AstCall), Ast_Kind_Call);
+ implicit_call->token = binop->token;
+ implicit_call->arg_count = 2;
+ implicit_call->callee = overload;
+ implicit_call->va_kind = VA_Kind_Not_VA;
+
+ bh_arr_each(AstTyped *, arg, args) {
+ AstArgument* new_arg = onyx_ast_node_new(semstate.node_allocator, sizeof(AstArgument), Ast_Kind_Argument);
+ new_arg->token = (*arg)->token;
+ new_arg->type = (*arg)->type;
+ new_arg->value = *arg;
+ new_arg->va_kind = VA_Kind_Not_VA;
+
+ *arg = (AstTyped *) new_arg;
+ }
+
+ implicit_call->arg_arr = (AstArgument **) args;
+
+ CHECK(call, implicit_call);
+
+ // NOTE: Not a binary op
+ *pbinop = (AstBinaryOp *) implicit_call;
+ return Check_Success;
+ }
+
+not_overloaded:
+
if (!type_is_numeric(binop->left->type) && !type_is_pointer(binop->left->type)) {
onyx_report_error(binop->token->pos,
"Expected numeric or pointer type for left side of binary operator, got '%s'.",
}
if ((binop_allowed[binop->operation] & effective_flags) == 0) {
- onyx_report_error(binop->token->pos, "Binary operator not allowed for arguments of type '%s'.",
- type_get_name(binop->type));
+ onyx_report_error(binop->token->pos, "Binary operator not allowed for arguments of type '%s' and '%s'.",
+ type_get_name(binop->left->type),
+ type_get_name(binop->right->type));
return Check_Error;
}
}
}
+static BinaryOp binary_op_from_token_type(TokenType t) {
+ switch (t) {
+ case Token_Type_Equal_Equal: return Binary_Op_Equal;
+ case Token_Type_Not_Equal: return Binary_Op_Not_Equal;
+ case Token_Type_Less_Equal: return Binary_Op_Less_Equal;
+ case Token_Type_Greater_Equal: return Binary_Op_Greater_Equal;
+ case '<': return Binary_Op_Less;
+ case '>': return Binary_Op_Greater;
+
+ case '+': return Binary_Op_Add;
+ case '-': return Binary_Op_Minus;
+ case '*': return Binary_Op_Multiply;
+ case '/': return Binary_Op_Divide;
+ case '%': return Binary_Op_Modulus;
+
+ case '&': return Binary_Op_And;
+ case '|': return Binary_Op_Or;
+ case '^': return Binary_Op_Xor;
+ case Token_Type_Shift_Left: return Binary_Op_Shl;
+ case Token_Type_Shift_Right: return Binary_Op_Shr;
+ case Token_Type_Shift_Arith_Right: return Binary_Op_Sar;
+
+ case Token_Type_And_And: return Binary_Op_Bool_And;
+ case Token_Type_Or_Or: return Binary_Op_Bool_Or;
+
+ case '=': return Binary_Op_Assign;
+ case Token_Type_Plus_Equal: return Binary_Op_Assign_Add;
+ case Token_Type_Minus_Equal: return Binary_Op_Assign_Minus;
+ case Token_Type_Star_Equal: return Binary_Op_Assign_Multiply;
+ case Token_Type_Fslash_Equal: return Binary_Op_Assign_Divide;
+ case Token_Type_Percent_Equal: return Binary_Op_Assign_Modulus;
+ case Token_Type_And_Equal: return Binary_Op_Assign_And;
+ case Token_Type_Or_Equal: return Binary_Op_Assign_Or;
+ case Token_Type_Xor_Equal: return Binary_Op_Assign_Xor;
+ case Token_Type_Shl_Equal: return Binary_Op_Assign_Shl;
+ case Token_Type_Shr_Equal: return Binary_Op_Assign_Shr;
+ case Token_Type_Sar_Equal: return Binary_Op_Assign_Sar;
+
+ case Token_Type_Pipe: return Binary_Op_Pipe;
+ case Token_Type_Dot_Dot: return Binary_Op_Range;
+ default: return Binary_Op_Count;
+ }
+}
+
// <expr> + <expr>
// <expr> - <expr>
// <expr> * <expr>
while (1) {
if (parser->hit_unexpected_token) return root;
- bin_op_kind = Binary_Op_Count;
- switch ((u16) parser->curr->type) {
- case Token_Type_Equal_Equal: bin_op_kind = Binary_Op_Equal; break;
- case Token_Type_Not_Equal: bin_op_kind = Binary_Op_Not_Equal; break;
- case Token_Type_Less_Equal: bin_op_kind = Binary_Op_Less_Equal; break;
- case Token_Type_Greater_Equal: bin_op_kind = Binary_Op_Greater_Equal; break;
- case '<': bin_op_kind = Binary_Op_Less; break;
- case '>': bin_op_kind = Binary_Op_Greater; break;
-
- case '+': bin_op_kind = Binary_Op_Add; break;
- case '-': bin_op_kind = Binary_Op_Minus; break;
- case '*': bin_op_kind = Binary_Op_Multiply; break;
- case '/': bin_op_kind = Binary_Op_Divide; break;
- case '%': bin_op_kind = Binary_Op_Modulus; break;
-
- case '&': bin_op_kind = Binary_Op_And; break;
- case '|': bin_op_kind = Binary_Op_Or; break;
- case '^': bin_op_kind = Binary_Op_Xor; break;
- case Token_Type_Shift_Left: bin_op_kind = Binary_Op_Shl; break;
- case Token_Type_Shift_Right: bin_op_kind = Binary_Op_Shr; break;
- case Token_Type_Shift_Arith_Right: bin_op_kind = Binary_Op_Sar; break;
-
- case Token_Type_And_And: bin_op_kind = Binary_Op_Bool_And; break;
- case Token_Type_Or_Or: bin_op_kind = Binary_Op_Bool_Or; break;
-
- case '=': bin_op_kind = Binary_Op_Assign; break;
- case Token_Type_Plus_Equal: bin_op_kind = Binary_Op_Assign_Add; break;
- case Token_Type_Minus_Equal: bin_op_kind = Binary_Op_Assign_Minus; break;
- case Token_Type_Star_Equal: bin_op_kind = Binary_Op_Assign_Multiply; break;
- case Token_Type_Fslash_Equal: bin_op_kind = Binary_Op_Assign_Divide; break;
- case Token_Type_Percent_Equal: bin_op_kind = Binary_Op_Assign_Modulus; break;
- case Token_Type_And_Equal: bin_op_kind = Binary_Op_Assign_And; break;
- case Token_Type_Or_Equal: bin_op_kind = Binary_Op_Assign_Or; break;
- case Token_Type_Xor_Equal: bin_op_kind = Binary_Op_Assign_Xor; break;
- case Token_Type_Shl_Equal: bin_op_kind = Binary_Op_Assign_Shl; break;
- case Token_Type_Shr_Equal: bin_op_kind = Binary_Op_Assign_Shr; break;
- case Token_Type_Sar_Equal: bin_op_kind = Binary_Op_Assign_Sar; break;
-
- case Token_Type_Pipe: bin_op_kind = Binary_Op_Pipe; break;
- case Token_Type_Dot_Dot: bin_op_kind = Binary_Op_Range; break;
- default: goto expression_done;
- }
-
- if (bin_op_kind != Binary_Op_Count) {
- bin_op_tok = parser->curr;
- consume_token(parser);
-
- AstBinaryOp* bin_op;
- if (bin_op_kind == Binary_Op_Pipe) {
- bin_op = make_node(AstBinaryOp, Ast_Kind_Pipe);
+ bin_op_kind = binary_op_from_token_type(parser->curr->type);
+ if (bin_op_kind == Binary_Op_Count) goto expression_done;
- } else if (bin_op_kind == Binary_Op_Range) {
- bin_op = (AstBinaryOp *) make_node(AstRangeLiteral, Ast_Kind_Range_Literal);
+ bin_op_tok = parser->curr;
+ consume_token(parser);
- } else {
- bin_op = make_node(AstBinaryOp, Ast_Kind_Binary_Op);
- }
+ AstBinaryOp* bin_op;
+ if (bin_op_kind == Binary_Op_Pipe) {
+ bin_op = make_node(AstBinaryOp, Ast_Kind_Pipe);
- bin_op->token = bin_op_tok;
- bin_op->operation = bin_op_kind;
+ } else if (bin_op_kind == Binary_Op_Range) {
+ bin_op = (AstBinaryOp *) make_node(AstRangeLiteral, Ast_Kind_Range_Literal);
- while ( !bh_arr_is_empty(tree_stack) &&
- get_precedence(bh_arr_last(tree_stack)->operation) >= get_precedence(bin_op_kind))
- bh_arr_pop(tree_stack);
+ } else {
+ bin_op = make_node(AstBinaryOp, Ast_Kind_Binary_Op);
+ }
- if (bh_arr_is_empty(tree_stack)) {
- // NOTE: new is now the root node
- bin_op->left = root;
- root = (AstTyped *) bin_op;
- } else {
- bin_op->left = bh_arr_last(tree_stack)->right;
- bh_arr_last(tree_stack)->right = (AstTyped *) bin_op;
- }
+ bin_op->token = bin_op_tok;
+ bin_op->operation = bin_op_kind;
- bh_arr_push(tree_stack, bin_op);
+ while ( !bh_arr_is_empty(tree_stack) &&
+ get_precedence(bh_arr_last(tree_stack)->operation) >= get_precedence(bin_op_kind))
+ bh_arr_pop(tree_stack);
- right = parse_factor(parser);
- bin_op->right = right;
+ if (bh_arr_is_empty(tree_stack)) {
+ // NOTE: new is now the root node
+ bin_op->left = root;
+ root = (AstTyped *) bin_op;
+ } else {
+ bin_op->left = bh_arr_last(tree_stack)->right;
+ bh_arr_last(tree_stack)->right = (AstTyped *) bin_op;
}
+
+ bh_arr_push(tree_stack, bin_op);
+
+ right = parse_factor(parser);
+ bin_op->right = right;
}
bh_arr_free(tree_stack);
AstFunction* func_def = make_node(AstFunction, Ast_Kind_Function);
func_def->token = proc_token;
+ func_def->operator_overload = -1;
bh_arr_new(global_heap_allocator, func_def->allocate_exprs, 4);
bh_arr_new(global_heap_allocator, func_def->params, 4);
expect_token(parser, Token_Type_Symbol);
} else {
+ if (bh_arr_length(parser->block_stack) != 0) {
+ onyx_report_error(parser->curr->pos, "#add_overload cannot be placed on procedures inside of other scopes");
+ }
+
func_def->overloaded_function = (AstNode *) parse_expression(parser);
}
}
+ else if (parse_possible_directive(parser, "operator")) {
+ BinaryOp op = binary_op_from_token_type(parser->curr->type);
+ consume_token(parser);
+
+ if (op == Binary_Op_Count) {
+ onyx_report_error(parser->curr->pos, "Invalid binary operator.");
+ } else {
+ func_def->operator_overload = op;
+ }
+ }
+
else if (parse_possible_directive(parser, "intrinsic")) {
func_def->flags |= Ast_Flag_Intrinsic;