added '~~' auto cast operator
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Sat, 19 Sep 2020 23:37:01 +0000 (18:37 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Sat, 19 Sep 2020 23:37:01 +0000 (18:37 -0500)
core/stdio.onyx
include/onyxastnodes.h
include/onyxlex.h
onyx
progs/poly_struct.onyx
src/onyxchecker.c
src/onyxlex.c
src/onyxparser.c
src/onyxsymres.c
src/onyxutils.c
src/onyxwasm.c

index 12248e004181997e26953d0ac0734f1c50ae51e1..5c63d7a81a65e004f02e8b6298634a73a9b41dfe 100644 (file)
@@ -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();
 }
 
index 995b927ee441a721d33a4c3bd14ea6878df8489f..8c97f6a2a24c19c77c3f106f1e3832d8f5d3f588 100644 (file)
@@ -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;
index 58cd343efa41b099669fd603d4e06223f5405111..c4cbebf237e45641524eca88948150085ceb130e 100644 (file)
@@ -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 9304849e4314e31947d6b40fb229bc73e2c290d0..06eef3f0a9e66132fa468f7eb81cbd7aeb34fd99 100755 (executable)
Binary files a/onyx and b/onyx differ
index 138b1a48061549d8667bdf9b280666376f4eac38..e8a1ff448829a0ab8155a62a46823f190a6676e6 100644 (file)
@@ -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);
index 107e469b3ce6740910da0db51e7bd564088d8973..b12c866fa0fd26321de0322da9792a2ff2a53c76 100644 (file)
@@ -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),
index 82167bfc305d8ed68ce927d65516e6b82447b744..386fb508a2c513493196d69de60efe8745cd6e3e 100644 (file)
@@ -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;
     }
 
index bdc363f544f1cb1f63b7811fb099329193986fb0..c04587cec227257187e1bfc2b3455fdaef7b2e99 100644 (file)
@@ -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);
index 755916370f80631a5d60eab9dace7a96f007145b..573470ddc8abcc4043f19f7b6a9fb5b829fb3c5f 100644 (file)
@@ -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) {
index 1d21ecba173532a35ed4fdb80fd7dff3b4889892..832272d53d2abc775a6210638d20924dd1e193a1 100644 (file)
@@ -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) {
index fa03b7d2dc1a9f7b96d58e021eb0f6381a7f6e32..f98edce5e1c33f8e539b877a5c3631ba54881741 100644 (file)
@@ -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);
         }
     }