added operator overload for '^[]'
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Fri, 22 Oct 2021 12:35:42 +0000 (07:35 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Fri, 22 Oct 2021 12:35:42 +0000 (07:35 -0500)
CHANGELOG
core/container/array.onyx
core/container/map.onyx
docs/todo
include/astnodes.h
src/checker.c
src/parser.c

index 65f4327c343574043219ba778ed0e2347dba59f7..461a6399424dc60cfaa52bd2d314b851bd79d58f 100644 (file)
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -8,6 +8,9 @@ are going to be changed and added in the future, but first I want to get this be
 version out there in a packaged format.
 
 Additions:
+* Multi-threading for the JS backend (--use-multi-threading)
+* threading primitives (mutex, semaphore, etc.)
+* atomic intrinsics
 * Quick-Functions
 * do-expressions
 * typeof
@@ -33,12 +36,10 @@ Additions:
     notes without having to parse comments. The syntax is "@Note".
 
 Removals:
+* the "proc" keyword.
 
 Changes:
 * initialization statements on if/while/switch are a lot more powerful.
-* the "proc" keyword is now optional in a lot of cases. There are inevitably some bugs with this change,
-    but you can always add it in when it may be necessary. Note, that for overloaded procedures, "#match"
-    is now used.
 * operator overloading is now done as a top level declaration handled through the entity
     system, instead of relying on creating a procedure. This lets you use an existing
     procedure as an operator overload. Take a look at '#operator ==' in string.onyx.
index 22be9629ff2c9327da7fc921370328bfc5fbfb07..26d8ff932e881c8f2d6db535037b1433e71a47be 100644 (file)
@@ -139,44 +139,38 @@ pop :: (arr: ^[..] $T) -> T {
     return arr.data[arr.count];
 }
 
-concat :: (arr: ^[..] $T, other: [..] T) {
+concat :: (arr: ^[..] $T, other: [] T) {
     for ^o: other do push(arr, *o);
 }
 
 
-fold_idx_elem :: #match {
-    (arr: ^[..] $T, cmp: (T, T) -> bool) -> (i32, T) {
-        return fold_idx_elem(arr.data, arr.count, cmp);
-    },
-
-    (arr: ^$T, count: i32, cmp: (T, T) -> bool) -> (i32, T) {
-        idx  := 0;
-        elem := arr[0];
-        
-        for i: 1 .. count {
-            if cmp(arr[i], elem) {
-                idx  = i;
-                elem = arr[i];
-            }
+fold_idx_elem :: (arr: [] $T, cmp: (T, T) -> bool) -> (i32, T) {
+    idx  := 0;
+    elem := arr[0];
+    
+    for i: 1 .. arr.count {
+        if cmp(arr[i], elem) {
+            idx  = i;
+            elem = arr[i];
         }
-        
-        return idx, elem;
-    },
+    }
+    
+    return idx, elem;
 }
 
-#private_file cmp_greater :: (x: $T, y: T) -> bool do return x > y;
-#private_file cmp_less    :: (x: $T, y: T) -> bool do return x < y;
+#private_file cmp_greater :: (x, y) => x > y;
+#private_file cmp_less    :: (x, y) => x < y;
 
 greatest :: #match {
-    (arr: [..] $T) -> (i32, T) { return fold_idx_elem(arr.data, arr.count, cmp_greater); },
-    (arr: [] $T)   -> (i32, T) { return fold_idx_elem(arr.data, arr.count, cmp_greater); },
-    (arr: [$N] $T) -> (i32, T) { return fold_idx_elem(cast(^T) arr, N,     cmp_greater); },
+    (arr: [..] $T) -> (i32, T) { return fold_idx_elem(arr, cmp_greater); },
+    (arr: [] $T)   -> (i32, T) { return fold_idx_elem(arr, cmp_greater); },
+    (arr: [$N] $T) -> (i32, T) { return fold_idx_elem(.{ cast(^T) arr, N }, cmp_greater); },
 }
 
 least :: #match {
-    (arr: [..] $T) -> (i32, T) { return fold_idx_elem(arr.data, arr.count, cmp_less); },
-    (arr: [] $T)   -> (i32, T) { return fold_idx_elem(arr.data, arr.count, cmp_less); },
-    (arr: [$N] $T) -> (i32, T) { return fold_idx_elem(cast(^T) arr, N,     cmp_less); },
+    (arr: [..] $T) -> (i32, T) { return fold_idx_elem(arr, cmp_less); },
+    (arr: [] $T)   -> (i32, T) { return fold_idx_elem(arr, cmp_less); },
+    (arr: [$N] $T) -> (i32, T) { return fold_idx_elem(.{ cast(^T) arr, N }, cmp_less); },
 }
 
 
index a1acf621acacb29b5d44efe62c16888df20747ee..883046eed0fe231c6ae3acfb608e008e5d897957 100644 (file)
@@ -83,7 +83,8 @@ get :: (use map: ^Map($K, $V), key: K) -> V {
     return default_value;
 }
 
-#operator [] macro (map: Map($K, $V), key: K) -> V do return (package core.map).get(^map, key);
+#operator []  macro (map: Map($K, $V), key: K) -> V do return (package core.map).get(^map, key);
+// #operator []= macro (map: Map($K, $V), key: K, value: V) do (package core.map).put(^map, key, value);
 
 get_ptr :: (use map: ^Map($K, $V), key: K) -> ^V {
     lr := lookup(map, key);
index dbbb2ea81b565276fab441eff9eda1c4d18f9022..0d98b7ce2b5d944d68670dc5be805450cd38ad9a 100644 (file)
--- a/docs/todo
+++ b/docs/todo
@@ -197,5 +197,19 @@ To-Do list for threading capability in the browser:
 
 Optimize the generation of multi-threaded modules when post-mvp features are enabled:
     [X] memory.init intrinsic
-    [ ] atomatic generation of initializers for all data segments
-    [ ] emit datacount section
\ No newline at end of file
+    [X] atomatic generation of initializers for all data segments
+    [X] emit datacount section
+
+Wishlist:
+    [ ] #operator []=
+    [ ] #operator ^[]
+        - Taking the pointer to an offset with a subscript
+        - Useful for map.get_ptr (^arr[10] or ^people["John"])
+    [ ] Complete the set of combinations of procedure declaration syntaxes
+        - Currently (x: i32) => { ... } isn't legal.
+    [ ] Tests for new language features
+        - Do blocks
+        - Code blocks
+        - Quick functions
+        - Macros
+        - Tags
index 045c8f4114a87616f8cd59403dc18e0f197d29cb..f48413fcb3650e5fbdccd987f7a775b5827b2b87 100644 (file)
@@ -276,49 +276,51 @@ typedef enum UnaryOp {
 } UnaryOp;
 
 typedef enum BinaryOp {
-    Binary_Op_Add             = 0,
-    Binary_Op_Minus           = 1,
-    Binary_Op_Multiply        = 2,
-    Binary_Op_Divide          = 3,
-    Binary_Op_Modulus         = 4,
-
-    Binary_Op_Equal           = 5,
-    Binary_Op_Not_Equal       = 6,
-    Binary_Op_Less            = 7,
-    Binary_Op_Less_Equal      = 8,
-    Binary_Op_Greater         = 9,
-    Binary_Op_Greater_Equal   = 10,
-
-    Binary_Op_And             = 11,
-    Binary_Op_Or              = 12,
-    Binary_Op_Xor             = 13,
-    Binary_Op_Shl             = 14,
-    Binary_Op_Shr             = 15,
-    Binary_Op_Sar             = 16,
-
-    Binary_Op_Bool_And        = 17,
-    Binary_Op_Bool_Or         = 18,
-
-    Binary_Op_Assign_Start    = 19,
-    Binary_Op_Assign          = 20,
-    Binary_Op_Assign_Add      = 21,
-    Binary_Op_Assign_Minus    = 22,
-    Binary_Op_Assign_Multiply = 23,
-    Binary_Op_Assign_Divide   = 24,
-    Binary_Op_Assign_Modulus  = 25,
-    Binary_Op_Assign_And      = 26,
-    Binary_Op_Assign_Or       = 27,
-    Binary_Op_Assign_Xor      = 28,
-    Binary_Op_Assign_Shl      = 29,
-    Binary_Op_Assign_Shr      = 30,
-    Binary_Op_Assign_Sar      = 31,
-    Binary_Op_Assign_End      = 32,
-
-    Binary_Op_Pipe            = 33,
-    Binary_Op_Range           = 34,
-    Binary_Op_Method_Call     = 35,
-
-    Binary_Op_Subscript       = 36,
+    Binary_Op_Add              = 0,
+    Binary_Op_Minus            = 1,
+    Binary_Op_Multiply         = 2,
+    Binary_Op_Divide           = 3,
+    Binary_Op_Modulus          = 4,
+
+    Binary_Op_Equal            = 5,
+    Binary_Op_Not_Equal        = 6,
+    Binary_Op_Less             = 7,
+    Binary_Op_Less_Equal       = 8,
+    Binary_Op_Greater          = 9,
+    Binary_Op_Greater_Equal    = 10,
+
+    Binary_Op_And              = 11,
+    Binary_Op_Or               = 12,
+    Binary_Op_Xor              = 13,
+    Binary_Op_Shl              = 14,
+    Binary_Op_Shr              = 15,
+    Binary_Op_Sar              = 16,
+
+    Binary_Op_Bool_And         = 17,
+    Binary_Op_Bool_Or          = 18,
+
+    Binary_Op_Assign_Start     = 19,
+    Binary_Op_Assign           = 20,
+    Binary_Op_Assign_Add       = 21,
+    Binary_Op_Assign_Minus     = 22,
+    Binary_Op_Assign_Multiply  = 23,
+    Binary_Op_Assign_Divide    = 24,
+    Binary_Op_Assign_Modulus   = 25,
+    Binary_Op_Assign_And       = 26,
+    Binary_Op_Assign_Or        = 27,
+    Binary_Op_Assign_Xor       = 28,
+    Binary_Op_Assign_Shl       = 29,
+    Binary_Op_Assign_Shr       = 30,
+    Binary_Op_Assign_Sar       = 31,
+    Binary_Op_Assign_End       = 32,
+
+    Binary_Op_Pipe             = 33,
+    Binary_Op_Range            = 34,
+    Binary_Op_Method_Call      = 35,
+
+    Binary_Op_Subscript        = 36,
+    Binary_Op_Subscript_Equals = 37,
+    Binary_Op_Ptr_Subscript    = 38,
 
     Binary_Op_Count
 } BinaryOp;
index 72283227b563bf9d51367f52c5d03986582e766d..58525219b5a501516c96c942507b00af3ec498c2 100644 (file)
@@ -66,7 +66,7 @@ CheckStatus check_range_literal(AstRangeLiteral** range);
 CheckStatus check_compound(AstCompound* compound);
 CheckStatus check_if_expression(AstIfExpression* if_expr);
 CheckStatus check_expression(AstTyped** expr);
-CheckStatus check_address_of(AstAddressOf* aof);
+CheckStatus check_address_of(AstAddressOf** paof);
 CheckStatus check_dereference(AstDereference* deref);
 CheckStatus check_subscript(AstSubscript** paa);
 CheckStatus check_field_access(AstFieldAccess** pfield);
@@ -606,7 +606,7 @@ static AstCall* binaryop_try_operator_overload(AstBinaryOp* binop) {
         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]);
+        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;
@@ -1256,13 +1256,38 @@ CheckStatus check_do_block(AstDoBlock** pdoblock) {
     return Check_Success;
 }
 
-CheckStatus check_address_of(AstAddressOf* aof) {
+CheckStatus check_address_of(AstAddressOf** paof) {
+    AstAddressOf* aof = *paof;
+
+    AstTyped* expr = (AstTyped *) strip_aliases((AstNode *) aof->expr);
+    if (expr->kind == Ast_Kind_Subscript && bh_arr_length(operator_overloads[Binary_Op_Ptr_Subscript]) > 0) {
+        CHECK(expression, &((AstSubscript *) expr)->addr);
+        CHECK(expression, &((AstSubscript *) expr)->expr);
+
+        AstBinaryOp op;
+        op.kind = Ast_Kind_Binary_Op;
+        op.operation = Binary_Op_Ptr_Subscript;
+        op.left  = ((AstSubscript *) expr)->addr;
+        op.right = ((AstSubscript *) expr)->expr;
+        op.token = aof->token;
+
+        AstCall* call = binaryop_try_operator_overload(&op);
+        if (call == (AstCall *) &node_that_signals_a_yield) YIELD(aof->token->pos, "Waiting for operator overload to possibly resolve.");
+        if (call != NULL) {
+            call->next = aof->next;
+            *(AstCall **) paof = call;
+
+            CHECK(call, (AstCall **) paof);
+            return Check_Success;
+        }
+    }
+
     CHECK(expression, &aof->expr);
     if (aof->expr->type == NULL) {
         YIELD(aof->token->pos, "Trying to resolve type of expression to take a reference.");
     }
 
-    AstTyped* expr = (AstTyped *) strip_aliases((AstNode *) aof->expr);
+    expr = (AstTyped *) strip_aliases((AstNode *) aof->expr);
 
     if ((expr->kind != Ast_Kind_Subscript
             && expr->kind != Ast_Kind_Dereference
@@ -1270,7 +1295,7 @@ CheckStatus check_address_of(AstAddressOf* aof) {
             && expr->kind != Ast_Kind_Memres
             && expr->kind != Ast_Kind_Local)
             || (expr->flags & Ast_Flag_Cannot_Take_Addr) != 0) {
-        ERROR(aof->token->pos, "Cannot take the address of something that is not an l-value.");
+        ERROR_(aof->token->pos, "Cannot take the address of something that is not an l-value. %s", onyx_ast_node_kind_string(expr->kind));
     }
 
     expr->flags |= Ast_Flag_Address_Taken;
@@ -1557,7 +1582,7 @@ CheckStatus check_expression(AstTyped** pexpr) {
 
         case Ast_Kind_Local: break;
 
-        case Ast_Kind_Address_Of:    retval = check_address_of((AstAddressOf *expr); break;
+        case Ast_Kind_Address_Of:    retval = check_address_of((AstAddressOf **) pexpr); break;
         case Ast_Kind_Dereference:   retval = check_dereference((AstDereference *) expr); break;
         case Ast_Kind_Slice:
         case Ast_Kind_Subscript:     retval = check_subscript((AstSubscript **) pexpr); break;
index 3e2103e6a12142a5f53605217904c68dc416fbd3..77a1ff5dbb0aae8171f9183cbe2fe706a22fbdf4 100644 (file)
@@ -2840,6 +2840,22 @@ static void parse_top_level_statement(OnyxParser* parser) {
                 AstDirectiveOperator *operator = make_node(AstDirectiveOperator, Ast_Kind_Directive_Operator);
                 operator->token = dir_token;
 
+                // These cases have to happen first because these are not necessarily "binary operators",
+                // they are just things that I want to be able to overload. []= is technically a ternary
+                // operator so all these things are horribly named anyway.
+                if (next_tokens_are(parser, 3, '^', '[', ']')) {
+                    consume_tokens(parser, 3);
+                    operator->operator = Binary_Op_Ptr_Subscript;
+                    goto operator_determined;
+                }
+
+                if (next_tokens_are(parser, 3, '[', ']', '=')) {
+                    consume_tokens(parser, 3);
+                    operator->operator = Binary_Op_Subscript_Equals;
+                    goto operator_determined;
+                }
+
+                // The default case
                 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 ']'
@@ -2850,6 +2866,7 @@ static void parse_top_level_statement(OnyxParser* parser) {
                     operator->operator = op;
                 }
 
+              operator_determined:
                 operator->overload = parse_expression(parser, 0);
 
                 ENTITY_SUBMIT(operator);