From: Brendan Hansen Date: Sat, 19 Sep 2020 23:37:01 +0000 (-0500) Subject: added '~~' auto cast operator X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=ebd7b7804f5189ca51bfd50f837f675575063797;p=onyx.git added '~~' auto cast operator --- diff --git a/core/stdio.onyx b/core/stdio.onyx index 12248e00..5c63d7a8 100644 --- a/core/stdio.onyx +++ b/core/stdio.onyx @@ -4,11 +4,10 @@ package core // of the system package use package system as system -#private -print_buffer : StringBuilder; +#private_file print_buffer : StringBuilder; stdio_init :: proc () { - print_buffer = string_builder_make(2048); + print_buffer = string_builder_make(2048); } print_string :: proc (s: string) { @@ -31,9 +30,9 @@ print_range :: proc (r: range, sep := " ") { } print :: proc { - print_string, print_cstring, - print_i64, print_i32, - print_bool, print_ptr, + print_string, print_cstring, + print_i64, print_i32, + print_bool, print_ptr, print_range, } @@ -55,10 +54,10 @@ print_array :: proc (arr: $T, sep := " ") { print_buffer_flush :: proc () { if print_buffer.len == 0 do return; - ^print_buffer - |> string_builder_to_string() - |> system.output_string(); + ^print_buffer + |> string_builder_to_string() + |> system.output_string(); - ^print_buffer |> string_builder_clear(); + ^print_buffer |> string_builder_clear(); } diff --git a/include/onyxastnodes.h b/include/onyxastnodes.h index 995b927e..8c97f6a2 100644 --- a/include/onyxastnodes.h +++ b/include/onyxastnodes.h @@ -195,6 +195,7 @@ typedef enum UnaryOp { Unary_Op_Not, Unary_Op_Bitwise_Not, Unary_Op_Cast, + Unary_Op_Auto_Cast, } UnaryOp; typedef enum BinaryOp { @@ -802,6 +803,10 @@ static inline b32 node_is_type(AstNode* node) { return (node->kind > Ast_Kind_Type_Start) && (node->kind < Ast_Kind_Type_End); } +static inline b32 node_is_auto_cast(AstNode* node) { + return (node->kind == Ast_Kind_Unary_Op) && (((AstUnaryOp *) node)->operation == Unary_Op_Auto_Cast); +} + static inline CallingConvention type_function_get_cc(Type* type) { if (type == NULL) return CC_Undefined; if (type->kind != Type_Kind_Function) return CC_Undefined; diff --git a/include/onyxlex.h b/include/onyxlex.h index 58cd343e..c4cbebf2 100644 --- a/include/onyxlex.h +++ b/include/onyxlex.h @@ -61,6 +61,7 @@ typedef enum TokenType { Token_Type_Sar_Equal, Token_Type_Dot_Dot, + Token_Type_Tilde_Tilde, Token_Type_Symbol, Token_Type_Literal_String, diff --git a/onyx b/onyx index 9304849e..06eef3f0 100755 Binary files a/onyx and b/onyx differ diff --git a/progs/poly_struct.onyx b/progs/poly_struct.onyx index 138b1a48..e8a1ff44 100644 --- a/progs/poly_struct.onyx +++ b/progs/poly_struct.onyx @@ -5,6 +5,13 @@ package main use package core main :: proc (args: [] cstring) { + + x := 2.4f; + y := 1; + y += ~~x; + println(y); + + imap : I32Map(string); i32map_init(^imap); defer i32map_free(^imap); diff --git a/src/onyxchecker.c b/src/onyxchecker.c index 107e469b..b12c866f 100644 --- a/src/onyxchecker.c +++ b/src/onyxchecker.c @@ -41,17 +41,34 @@ static inline void fill_in_type(AstTyped* node) { node->type = type_build_from_ast(semstate.allocator, node->type_node); } +// NOTE: Returns 0 if it was not possible to make the types compatible. +static b32 type_check_or_auto_cast(AstTyped* node, Type* type) { + assert(type != NULL); + assert(node != NULL); + + if (types_are_compatible(node->type, type)) return 1; + if (!node_is_auto_cast((AstNode *) node)) return 0; + + // If the node is an auto cast, we convert it to a cast node which will reports errors if + // the cast is illegal in the code generation. + ((AstUnaryOp *) node)->type = type; + ((AstUnaryOp *) node)->operation = Unary_Op_Cast; + + return 1; +} + b32 check_return(AstReturn* retnode) { if (retnode->expr) { if (check_expression(&retnode->expr)) return 1; - if (!types_are_compatible(retnode->expr->type, semstate.expected_return_type)) { + if (!type_check_or_auto_cast(retnode->expr, semstate.expected_return_type)) { onyx_report_error(retnode->expr->token->pos, "Expected to return a value of type '%s', returning value of type '%s'.", type_get_name(semstate.expected_return_type), type_get_name(retnode->expr->type)); return 1; } + } else { if (semstate.expected_return_type->Basic.size > 0) { onyx_report_error(retnode->token->pos, @@ -233,10 +250,10 @@ static AstTyped* match_overloaded_function(AstCall* call, AstOverloadedFunction* fill_in_type((AstTyped *) arg); if ((*param_type)->kind == Type_Kind_VarArgs) { - if (!types_are_compatible((*param_type)->VarArgs.ptr_to_data->Pointer.elem, arg->type)) + if (!type_check_or_auto_cast(arg->value, (*param_type)->VarArgs.ptr_to_data->Pointer.elem)) goto no_match; } - else if (!types_are_compatible(*param_type, arg->type)) goto no_match; + else if (!type_check_or_auto_cast(arg->value, *param_type)) goto no_match; param_type++; arg = (AstArgument *) arg->next; @@ -252,7 +269,7 @@ no_match: AstArgument* arg = call->arguments; while (arg != NULL) { - strncat(arg_str, type_get_name(arg->type), 1023); + strncat(arg_str, type_get_name(arg->value->type), 1023); if (arg->next != NULL) strncat(arg_str, ", ", 1023); @@ -362,7 +379,6 @@ b32 check_call(AstCall* call) { if (actual->value == NULL) return 1; - actual->type = actual->value->type; actual->value->flags |= Ast_Flag_Function_Used; } @@ -384,7 +400,6 @@ b32 check_call(AstCall* call) { AstArgument* new_arg = onyx_ast_node_new(semstate.node_allocator, sizeof(AstArgument), Ast_Kind_Argument); new_arg->token = dv->token; new_arg->value = dv; - new_arg->type = dv->type; new_arg->next = NULL; *last_arg = new_arg; @@ -436,27 +451,27 @@ b32 check_call(AstCall* call) { } if (variadic_type != NULL) { - if (!types_are_compatible(variadic_type, actual->type)) { + if (!type_check_or_auto_cast(actual->value, variadic_type)) { onyx_report_error(actual->token->pos, "The function '%b' expects a value of type '%s' for the variadic parameter, '%b', got '%s'.", callee->token->text, callee->token->length, type_get_name(variadic_type), variadic_param->local->token->text, variadic_param->local->token->length, - type_get_name(actual->type)); + type_get_name(actual->value->type)); return 1; } actual->flags |= Ast_Flag_Arg_Is_VarArg; - } else if (!types_are_compatible(formal_params[arg_pos], actual->type)) { + } else if (!type_check_or_auto_cast(actual->value, formal_params[arg_pos])) { onyx_report_error(actual->token->pos, "The function '%b' expects a value of type '%s' for %d%s parameter, got '%s'.", callee->token->text, callee->token->length, type_get_name(formal_params[arg_pos]), arg_pos + 1, bh_num_suffix(arg_pos + 1), - type_get_name(actual->type)); + type_get_name(actual->value->type)); return 1; } @@ -594,11 +609,22 @@ b32 check_binaryop_compare(AstBinaryOp** pbinop) { if (rtype->kind == Type_Kind_Pointer) rtype = &basic_types[Basic_Kind_Rawptr]; if (!types_are_compatible(ltype, rtype)) { - onyx_report_error(binop->token->pos, - "Cannot compare '%s' to '%s'.", - type_get_name(ltype), - type_get_name(rtype)); - return 1; + b32 left_ac = node_is_auto_cast((AstNode *) binop->left); + b32 right_ac = node_is_auto_cast((AstNode *) binop->right); + + if (left_ac && right_ac) { + onyx_report_error(binop->token->pos, "Cannot have auto cast on both sides of binary operator."); + return 1; + } + else if (left_ac && type_check_or_auto_cast(binop->left, rtype)); + else if (right_ac && type_check_or_auto_cast(binop->right, ltype)); + else { + onyx_report_error(binop->token->pos, + "Cannot compare '%s' to '%s'.", + type_get_name(ltype), + type_get_name(rtype)); + return 1; + } } binop->type = &basic_types[Basic_Kind_Bool]; @@ -737,11 +763,22 @@ b32 check_binaryop(AstBinaryOp** pbinop, b32 assignment_is_ok) { } if (!types_are_compatible(binop->left->type, binop->right->type)) { - onyx_report_error(binop->token->pos, - "Mismatched types for binary operation. left: '%s', right: '%s'.", - type_get_name(binop->left->type), - type_get_name(binop->right->type)); - return 1; + b32 left_ac = node_is_auto_cast((AstNode *) binop->left); + b32 right_ac = node_is_auto_cast((AstNode *) binop->right); + + if (left_ac && right_ac) { + onyx_report_error(binop->token->pos, "Cannot have auto cast on both sides of binary operator."); + return 1; + } + else if (type_check_or_auto_cast(binop->left, binop->right->type)); + else if (type_check_or_auto_cast(binop->right, binop->left->type)); + else { + onyx_report_error(binop->token->pos, + "Mismatched types for binary operation. left: '%s', right: '%s'.", + type_get_name(binop->left->type), + type_get_name(binop->right->type)); + return 1; + } } binop->type = binop->left->type; @@ -806,9 +843,7 @@ b32 check_struct_literal(AstStructLiteral* sl) { type_lookup_member_by_idx(sl->type, i, &smem); Type* formal = smem.type; - // NOTE: We may want to report a different error if the struct member was named, - // since those names may not be in the correct order. - brendanfh 2020/09/12 - if (!types_are_compatible(formal, (*actual)->type)) { + if (!type_check_or_auto_cast((*actual), formal)) { onyx_report_error(sl->token->pos, "Mismatched types for %d%s member named '%s', expected '%s', got '%s'.", i + 1, bh_num_suffix(i + 1), @@ -971,13 +1006,13 @@ b32 check_range_literal(AstBinaryOp** prange) { StructMember smem; type_lookup_member(expected_range_type, "low", &smem); - if (!types_are_compatible(range->left->type, smem.type)) { + if (!type_check_or_auto_cast(range->left, smem.type)) { onyx_report_error(range->token->pos, "Expected left side of range to be a 32-bit integer."); return 1; } type_lookup_member(expected_range_type, "high", &smem); - if (!types_are_compatible(range->right->type, smem.type)) { + if (!type_check_or_auto_cast(range->right, smem.type)) { onyx_report_error(range->token->pos, "Expected right side of range to be a 32-bit integer."); return 1; } @@ -1074,7 +1109,6 @@ b32 check_expression(AstTyped** pexpr) { case Ast_Kind_Argument: retval = check_expression(&((AstArgument *) expr)->value); - expr->type = ((AstArgument *) expr)->value->type; break; case Ast_Kind_NumLit: @@ -1322,7 +1356,7 @@ b32 check_memres(AstMemRes* memres) { Type* memres_type = memres->type; - if (!types_are_compatible(memres_type, memres->initial_value->type)) { + if (!type_check_or_auto_cast(memres->initial_value, memres_type)) { onyx_report_error(memres->token->pos, "Cannot assign value of type '%s' to a '%s'.", type_get_name(memres_type), diff --git a/src/onyxlex.c b/src/onyxlex.c index 82167bfc..386fb508 100644 --- a/src/onyxlex.c +++ b/src/onyxlex.c @@ -58,6 +58,7 @@ static const char* token_type_names[] = { ">>=", ">>>=", "..", + "~~", "TOKEN_TYPE_SYMBOL", "TOKEN_TYPE_LITERAL_STRING", @@ -375,6 +376,7 @@ whitespace_skipped: LITERAL_TOKEN("/=", 0, Token_Type_Fslash_Equal); LITERAL_TOKEN("%=", 0, Token_Type_Percent_Equal); LITERAL_TOKEN("..", 0, Token_Type_Dot_Dot); + LITERAL_TOKEN("~~", 0, Token_Type_Tilde_Tilde); break; } diff --git a/src/onyxparser.c b/src/onyxparser.c index bdc363f5..c04587ce 100644 --- a/src/onyxparser.c +++ b/src/onyxparser.c @@ -334,6 +334,16 @@ static AstTyped* parse_factor(OnyxParser* parser) { break; } + case Token_Type_Tilde_Tilde: { + AstUnaryOp* ac_node = make_node(AstUnaryOp, Ast_Kind_Unary_Op); + ac_node->operation = Unary_Op_Auto_Cast; + ac_node->token = expect_token(parser, Token_Type_Tilde_Tilde); + ac_node->expr = parse_factor(parser); + + retval = (AstTyped *) ac_node; + break; + } + case Token_Type_Keyword_Cast: { AstUnaryOp* cast_node = make_node(AstUnaryOp, Ast_Kind_Unary_Op); cast_node->token = expect_token(parser, Token_Type_Keyword_Cast); diff --git a/src/onyxsymres.c b/src/onyxsymres.c index 75591637..573470dd 100644 --- a/src/onyxsymres.c +++ b/src/onyxsymres.c @@ -258,9 +258,6 @@ static void symres_unaryop(AstUnaryOp** unaryop) { } symres_expression(&(*unaryop)->expr); - - if ((*unaryop)->type_node == NULL) - (*unaryop)->type_node = ((AstUnaryOp *)(*unaryop))->expr->type_node; } static void symres_struct_literal(AstStructLiteral* sl) { diff --git a/src/onyxutils.c b/src/onyxutils.c index 1d21ecba..832272d5 100644 --- a/src/onyxutils.c +++ b/src/onyxutils.c @@ -478,7 +478,7 @@ AstFunction* polymorphic_proc_lookup(AstPolyProc* pp, PolyProcLookupMethod pp_lo } fori (i, 0, param->idx) arg = (AstArgument *) arg->next; - actual_type = arg->type; + actual_type = arg->value->type; } else if (pp_lookup == PPLM_By_Function_Type) { diff --git a/src/onyxwasm.c b/src/onyxwasm.c index fa03b7d2..f98edce5 100644 --- a/src/onyxwasm.c +++ b/src/onyxwasm.c @@ -1310,6 +1310,9 @@ EMIT_FUNC(unaryop, AstUnaryOp* unop) { } case Unary_Op_Cast: emit_cast(mod, &code, unop); break; + + // NOTE: Any remaining auto casts can be ignored since it means that a cast was not necessary. - brendanfh 2020/09/19 + case Unary_Op_Auto_Cast: emit_expression(mod, &code, unop->expr); break; } *pcode = code; @@ -1328,10 +1331,10 @@ EMIT_FUNC(call, AstCall* call) { arg = (AstArgument *) arg->next) { b32 place_on_stack = 0; - b32 arg_is_struct = type_is_structlike(arg->type); + b32 arg_is_struct = type_is_structlike(arg->value->type); if (arg->flags & Ast_Flag_Arg_Is_VarArg) place_on_stack = 1; - if (type_get_param_pass(arg->type) == Param_Pass_By_Implicit_Pointer) place_on_stack = 1; + if (type_get_param_pass(arg->value->type) == Param_Pass_By_Implicit_Pointer) place_on_stack = 1; if (place_on_stack && !arg_is_struct) WID(WI_GLOBAL_GET, stack_top_idx); @@ -1339,7 +1342,7 @@ EMIT_FUNC(call, AstCall* call) { if (place_on_stack) { if (arg_is_struct) WID(WI_GLOBAL_GET, stack_top_idx); - emit_store_instruction(mod, &code, arg->type, stack_grow_amm); + emit_store_instruction(mod, &code, arg->value->type, stack_grow_amm); if (arg->flags & Ast_Flag_Arg_Is_VarArg) vararg_count += 1; else { @@ -1348,7 +1351,7 @@ EMIT_FUNC(call, AstCall* call) { WI(WI_I32_ADD); } - stack_grow_amm += type_size_of(arg->type); + stack_grow_amm += type_size_of(arg->value->type); } }