added overloadable assignment operators
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Mon, 30 Aug 2021 12:13:49 +0000 (07:13 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Mon, 30 Aug 2021 12:13:49 +0000 (07:13 -0500)
bin/onyx
core/container/array.onyx
core/io/writer.onyx
modules/ui/ui.onyx
src/onyxchecker.c
src/onyxparser.c
src/onyxsymres.c

index a5bf1b64868174f15928ee78f9cfd75223682a24..646b002479b5c76b2a210c46fd03c872c505f6f2 100755 (executable)
Binary files a/bin/onyx and b/bin/onyx differ
index 88e5180de88e4f1ded62b04c0b142bd2102c252c..2998fcb42325429ab97e1ee740e0bdee00384051 100644 (file)
@@ -107,7 +107,7 @@ remove :: (arr: ^[..] $T, elem: T) {
 
     while i := 0; i < arr.count - move {
         defer i += 1;
-        
+
         if arr.data[i + move] == elem do move += 1;
         if move != 0 do arr.data[i] = arr.data[i + move];
     }
index da730eae5bbabff93ad97e0814ccda6ff47b1530..6f9563580cd8dee4a0315f07e8b3c20c31f71a2f 100644 (file)
@@ -118,4 +118,9 @@ write :: #match {
     write_range,
 
     write_format,
+
+    // Catch all for any type. Has a high precedence so you can easily override it.
+    #precedence 1000 (w: ^Writer, a: $T) {
+        write_format(w, "{}", a);
+    }
 }
index 4fb159f6d89151758b19784568672cf65ffc9d51..da3cc025806298a504d0e94fb5e6af6a70ca945b 100644 (file)
@@ -161,7 +161,7 @@ Rectangle :: struct {
 Text_Theme :: struct {
     text_color := gfx.Color4.{ 1, 1, 1 };
 
-    font       : i32 = 0; // Default to font index 0 
+    font       := 0; // Default to font index 0 
     font_size  := 1.0f;
 }
 
index dd8b2d4a5d27e1c823307d173c4cf157a9ff2408..c7ec01e37b2fd9a34de8092108aeac2221a64ce7 100644 (file)
@@ -735,7 +735,54 @@ static void report_bad_binaryop(AstBinaryOp* binop) {
             node_get_type_name(binop->right));
 }
 
-CheckStatus check_binaryop_assignment(AstBinaryOp* binop) {
+static AstCall* binaryop_try_operator_overload(AstBinaryOp* binop) {
+    if (bh_arr_length(operator_overloads[binop->operation]) == 0) return NULL;
+
+    Arguments args = ((Arguments) { NULL, NULL });
+    bh_arr_new(global_heap_allocator, args.values, 2);
+    bh_arr_push(args.values, binop->left);
+    bh_arr_push(args.values, binop->right);
+
+    if (binop_is_assignment(binop->operation)) {
+        args.values[0] = (AstTyped *) make_address_of(context.ast_alloc, binop->left);
+
+        u32 current_checking_level_store = current_checking_level;
+        CheckStatus cs = check_address_of((AstAddressOf *) args.values[0]);
+        current_checking_level = current_checking_level_store;
+
+        if (cs == Check_Yield_Macro) return (AstCall *) &node_that_signals_a_yield;
+        if (cs == Check_Error) {
+            return NULL;
+        }
+    }
+
+    b32 should_yield = 0;
+    AstTyped* overload = find_matching_overload_by_arguments(operator_overloads[binop->operation], &args, &should_yield);
+    if (should_yield) {
+        bh_arr_free(args.values);
+        return (AstCall *) &node_that_signals_a_yield;
+    }
+
+    if (overload == NULL) {
+        bh_arr_free(args.values);
+        return NULL;
+    }
+
+    AstCall* implicit_call = onyx_ast_node_new(context.ast_alloc, sizeof(AstCall), Ast_Kind_Call);
+    implicit_call->token = binop->token;
+    implicit_call->callee = overload;
+    implicit_call->va_kind = VA_Kind_Not_VA;
+
+    bh_arr_each(AstTyped *, arg, args.values)
+        *arg = (AstTyped *) make_argument(context.ast_alloc, *arg);
+
+    implicit_call->args = args;
+    return implicit_call;
+}
+
+
+CheckStatus check_binaryop_assignment(AstBinaryOp** pbinop) {
+    AstBinaryOp* binop = *pbinop;
     if (current_checking_level == EXPRESSION_LEVEL)
         ERROR(binop->token->pos, "Assignment not valid in expression.");
 
@@ -947,38 +994,6 @@ CheckStatus check_binaryop_bool(AstBinaryOp** pbinop) {
     return Check_Success;
 }
 
-static AstCall* binaryop_try_operator_overload(AstBinaryOp* binop) {
-    if (bh_arr_length(operator_overloads[binop->operation]) == 0) return NULL;
-
-    Arguments args = ((Arguments) { NULL, NULL });
-    bh_arr_new(global_heap_allocator, args.values, 2);
-    bh_arr_push(args.values, binop->left);
-    bh_arr_push(args.values, binop->right);
-
-    b32 should_yield = 0;
-    AstTyped* overload = find_matching_overload_by_arguments(operator_overloads[binop->operation], &args, &should_yield);
-    if (should_yield) {
-        bh_arr_free(args.values);
-        return (AstCall *) &node_that_signals_a_yield;
-    }
-
-    if (overload == NULL) {
-        bh_arr_free(args.values);
-        return NULL;
-    }
-
-    AstCall* implicit_call = onyx_ast_node_new(context.ast_alloc, sizeof(AstCall), Ast_Kind_Call);
-    implicit_call->token = binop->token;
-    implicit_call->callee = overload;
-    implicit_call->va_kind = VA_Kind_Not_VA;
-
-    bh_arr_each(AstTyped *, arg, args.values)
-        *arg = (AstTyped *) make_argument(context.ast_alloc, *arg);
-
-    implicit_call->args = args;
-    return implicit_call;
-}
-
 CheckStatus check_binaryop(AstBinaryOp** pbinop) {
     AstBinaryOp* binop = *pbinop;
 
@@ -993,8 +1008,6 @@ CheckStatus check_binaryop(AstBinaryOp** pbinop) {
         binop->flags |= Ast_Flag_Comptime;
     }
 
-    if (binop_is_assignment(binop->operation)) return check_binaryop_assignment(binop);
-
     if (expression_types_must_be_known) {
         if (binop->left->type == NULL || binop->right->type == NULL) {
             ERROR(binop->token->pos, "Internal compiler error: one of the operands types is unknown here.");
@@ -1029,6 +1042,8 @@ CheckStatus check_binaryop(AstBinaryOp** pbinop) {
         }
     }
 
+    if (binop_is_assignment(binop->operation)) return check_binaryop_assignment(pbinop);
+
     // NOTE: Comparision operators and boolean operators are handled separately.
     if (binop_is_compare(binop->operation)) 
         return check_binaryop_compare(pbinop);
index 74126e773e286a5c42ed503358320ab18ccb994e..58c34b4028925b1264d44b0d99f6260da70b1101 100644 (file)
@@ -251,7 +251,7 @@ static b32 parse_possible_struct_literal(OnyxParser* parser, AstTyped* left, Ast
 
 static b32 parse_possible_array_literal(OnyxParser* parser, AstTyped* left, AstTyped** ret) {
     if (!next_tokens_are(parser, 2, '.', '[')) return 0;
-    
+
     AstArrayLiteral* al = make_node(AstArrayLiteral, Ast_Kind_Array_Literal);
     al->token = parser->curr;
     al->atnode = left;
@@ -263,7 +263,7 @@ static b32 parse_possible_array_literal(OnyxParser* parser, AstTyped* left, AstT
     expect_token(parser, '[');
     while (!consume_token_if_next(parser, ']')) {
         if (parser->hit_unexpected_token) return 1;
-        
+
         AstTyped* value = parse_expression(parser, 0);
         bh_arr_push(al->values, value);
 
@@ -451,9 +451,9 @@ static AstTyped* parse_factor(OnyxParser* parser) {
             str_node->token     = expect_token(parser, Token_Type_Literal_String);
             str_node->addr      = 0;
             str_node->flags    |= Ast_Flag_Comptime;
-            
+
             ENTITY_SUBMIT(str_node);
-            
+
             retval = (AstTyped *) str_node;
             break;
         }
@@ -523,9 +523,9 @@ static AstTyped* parse_factor(OnyxParser* parser) {
                 fc->token = parser->prev - 1;
                 fc->filename_token = expect_token(parser, Token_Type_Literal_String);
                 fc->type = type_make_slice(parser->allocator, &basic_types[Basic_Kind_U8]);
-                
+
                 ENTITY_SUBMIT(fc);
-                
+
                 retval = (AstTyped *) fc;
                 break;
             }
@@ -541,7 +541,7 @@ static AstTyped* parse_factor(OnyxParser* parser) {
                 AstStrLit* filename = make_node(AstStrLit, Ast_Kind_StrLit);
                 filename->token = str_token;
                 filename->addr  = 0;
-                
+
                 ENTITY_SUBMIT(filename);
                 retval = (AstTyped *) filename;
                 break;
@@ -692,7 +692,7 @@ static AstTyped* parse_factor(OnyxParser* parser) {
             case '.': {
                 if (parse_possible_struct_literal(parser, retval, &retval)) return retval;
                 if (parse_possible_array_literal(parser, retval, &retval))  return retval;
-                
+
                 consume_token(parser);
                 AstFieldAccess* field = make_node(AstFieldAccess, Ast_Kind_Field_Access);
                 field->token = expect_token(parser, Token_Type_Symbol);
@@ -943,7 +943,7 @@ static AstTyped* parse_expression(OnyxParser* parser, b32 assignment_allowed) {
         right = parse_factor(parser);
         bin_op->right = right;
     }
-    
+
 expression_done:
     bh_arr_free(tree_stack);
     return root;
@@ -1869,7 +1869,7 @@ static AstStructType* parse_struct(OnyxParser* parser) {
 
     while (!consume_token_if_next(parser, '}')) {
         if (parser->hit_unexpected_token) return s_node;
-        
+
         member_is_used = consume_token_if_next(parser, Token_Type_Keyword_Use);
 
         if (next_tokens_are(parser, 3, Token_Type_Symbol, ':', ':')) {
@@ -2069,7 +2069,7 @@ static AstOverloadedFunction* parse_overloaded_function(OnyxParser* parser, Onyx
         if (parser->curr->type != '}')
             expect_token(parser, ',');
     }
-    
+
     ENTITY_SUBMIT(ofunc);
     return ofunc;
 }
@@ -2132,7 +2132,7 @@ static AstFunction* parse_function_definition(OnyxParser* parser, OnyxToken* tok
         pp->token = func_def->token;
         pp->poly_params = polymorphic_vars;
         pp->base_func = func_def;
-        
+
         return (AstFunction *) pp;
 
     } else {
@@ -2522,7 +2522,7 @@ static void parse_top_level_statement(OnyxParser* parser) {
     else if (parse_possible_directive(parser, "private_file")) private_kind = Ast_Flag_Private_File;
 
     AstBinding* binding = NULL;
-    
+
     switch ((u16) parser->curr->type) {
         case Token_Type_Keyword_Use: {
             AstNode* use_node = parse_use_stmt(parser);
@@ -2545,19 +2545,19 @@ static void parse_top_level_statement(OnyxParser* parser) {
 
                 goto submit_binding_to_entities;
             }
-            
+
             AstMemRes* memres = make_node(AstMemRes, Ast_Kind_Memres);
             memres->token = symbol;
 
             if (parser->curr->type != '=')
                 memres->type_node = parse_type(parser);
-            
+
             if (consume_token_if_next(parser, '='))
                 memres->initial_value = parse_expression(parser, 1);
-            
-            
+
+
             ENTITY_SUBMIT(memres);
-            
+
             binding = make_node(AstBinding, Ast_Kind_Binding);
             binding->token = symbol;
             binding->flags |= private_kind;
@@ -2585,28 +2585,28 @@ static void parse_top_level_statement(OnyxParser* parser) {
                     include->name = bh_strdup(parser->allocator, str_token->text);
                     token_toggle_end(str_token);
                 }
-                
+
                 ENTITY_SUBMIT(include);
                 return;
             }
             else if (parse_possible_directive(parser, "load_path")) {
                 AstInclude* include = make_node(AstInclude, Ast_Kind_Load_Path);
                 include->token = dir_token;
-                
+
                 OnyxToken* str_token = expect_token(parser, Token_Type_Literal_String);
                 if (str_token != NULL) {
                     token_toggle_end(str_token);
                     include->name = bh_strdup(parser->allocator, str_token->text);
                     token_toggle_end(str_token);
                 }
-                
+
                 ENTITY_SUBMIT(include);
                 return;
             }
             else if (parse_possible_directive(parser, "error")) {
                 AstDirectiveError *error = make_node(AstDirectiveError, Ast_Kind_Directive_Error);
                 error->token = dir_token;
-                error->error_msg = expect_token(parser, Token_Type_Literal_String); 
+                error->error_msg = expect_token(parser, Token_Type_Literal_String);
 
                 ENTITY_SUBMIT(error);
                 return;
@@ -2618,7 +2618,7 @@ static void parse_top_level_statement(OnyxParser* parser) {
                 BinaryOp op = binary_op_from_token_type(parser->curr->type);
                 consume_token(parser);
                 if (op == Binary_Op_Subscript) expect_token(parser, ']');    // #operator [] ... needs to consume the other ']'
-                
+
                 if (op == Binary_Op_Count) {
                     onyx_report_error(parser->curr->pos, "Invalid binary operator.");
                 } else {
@@ -2686,7 +2686,7 @@ submit_binding_to_entities:
             target_scope = parser->package->private_scope;
         if (binding->flags & Ast_Flag_Private_File)
             target_scope = parser->file_scope;
-        
+
         ENTITY_SUBMIT_IN_SCOPE(binding, target_scope);
     }
 }
@@ -2703,7 +2703,7 @@ static AstPackage* parse_package_expression(OnyxParser* parser) {
         OnyxToken* symbol = expect_token(parser, Token_Type_Symbol);
 
         bh_arr_push(package_node->path, symbol);
-        
+
         if (consume_token_if_next(parser, '.'));
         else break;
     }
@@ -2713,7 +2713,7 @@ static AstPackage* parse_package_expression(OnyxParser* parser) {
         total_package_name_length += (*token)->length + 1;
     }
 
-    char* package_name = bh_alloc_array(context.ast_alloc, char, total_package_name_length); 
+    char* package_name = bh_alloc_array(context.ast_alloc, char, total_package_name_length);
     *package_name = '\0';
 
     bh_arr_each(OnyxToken *, token, package_node->path) {
@@ -2738,7 +2738,7 @@ static Package* parse_file_package(OnyxParser* parser) {
     }
 
     AstPackage* package_node = parse_package_expression(parser);
-    
+
     char aggregate_name[2048];
     aggregate_name[0] = '\0';
 
@@ -2749,7 +2749,7 @@ static Package* parse_file_package(OnyxParser* parser) {
 
         strncat(aggregate_name, (*symbol)->text, 2047);
         Package* newpackage = package_lookup_or_create(aggregate_name, context.global_scope, parser->allocator);
-        
+
         AstPackage* pnode = make_node(AstPackage, Ast_Kind_Package);
         pnode->token = *symbol;
         pnode->package = newpackage;
@@ -2767,7 +2767,7 @@ static Package* parse_file_package(OnyxParser* parser) {
     }
 
     package_node->package = prevpackage;
-    
+
     return package_node->package;
 }
 
index 18f6ef5e533060c1eeecae025c2158f0b045531e..d853a4d30e74ecb71c641eb1dc8c7b7647a06289 100644 (file)
@@ -68,7 +68,7 @@ static void scope_leave() {
 
 static SymresStatus symres_symbol(AstNode** symbol_node) {
     OnyxToken* token = (*symbol_node)->token;
-    AstNode* res = symbol_resolve(curr_scope, token);    
+    AstNode* res = symbol_resolve(curr_scope, token);
 
     if (!res) { // :SymresStall
         if (report_unresolved_symbols) {
@@ -906,7 +906,7 @@ SymresStatus symres_function(AstFunction* func) {
             //
             //     Foo :: struct (T: type_expr) {
             //         use t : T;
-            // 
+            //
             //         something_else := 5 + 6 * 8;
             //     }
             //
@@ -1078,7 +1078,7 @@ static SymresStatus symres_polyproc(AstPolyProc* pp) {
         // because I think the following should be possible:
         //
         //     baked_proc :: (x: $T, $f: (T) -> T) -> T ...
-        // 
+        //
         // The type of 'f' depends on resolving the value for the polyvar 'T'.
         SYMRES(type, &param->type_expr);
     }
@@ -1127,10 +1127,10 @@ static SymresStatus symres_process_directive(AstNode* directive) {
                 return Symres_Error;
             }
 
-            if (binop_is_assignment(operator->operator)) {
+            /*if (binop_is_assignment(operator->operator)) {
                 onyx_report_error(overload->token->pos, "'%s' is not currently overloadable.", binaryop_string[operator->operator]);
                 return Symres_Error;
-            }
+            }*/
 
             add_overload_option(&operator_overloads[operator->operator], 0, operator->overload);
             break;
@@ -1207,7 +1207,7 @@ void symres_entity(Entity* ent) {
         }
 
         case Entity_Type_Static_If:               ss = symres_static_if(ent->static_if); break;
-        
+
         case Entity_Type_Foreign_Function_Header:
         case Entity_Type_Function_Header:         ss = symres_function_header(ent->function); break;
         case Entity_Type_Function:                ss = symres_function(ent->function);        break;