From de94978f45c967137b4cb394b964dc54982c0cfa Mon Sep 17 00:00:00 2001 From: Brendan Hansen Date: Fri, 22 Oct 2021 07:35:42 -0500 Subject: [PATCH] added operator overload for '^[]' --- CHANGELOG | 7 ++-- core/container/array.onyx | 46 +++++++++----------- core/container/map.onyx | 3 +- docs/todo | 18 +++++++- include/astnodes.h | 88 ++++++++++++++++++++------------------- src/checker.c | 37 +++++++++++++--- src/parser.c | 17 ++++++++ 7 files changed, 135 insertions(+), 81 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 65f4327c..461a6399 100644 --- 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. diff --git a/core/container/array.onyx b/core/container/array.onyx index 22be9629..26d8ff93 100644 --- a/core/container/array.onyx +++ b/core/container/array.onyx @@ -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); }, } diff --git a/core/container/map.onyx b/core/container/map.onyx index a1acf621..883046ee 100644 --- a/core/container/map.onyx +++ b/core/container/map.onyx @@ -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); diff --git a/docs/todo b/docs/todo index dbbb2ea8..0d98b7ce 100644 --- 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 diff --git a/include/astnodes.h b/include/astnodes.h index 045c8f41..f48413fc 100644 --- a/include/astnodes.h +++ b/include/astnodes.h @@ -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; diff --git a/src/checker.c b/src/checker.c index 72283227..58525219 100644 --- a/src/checker.c +++ b/src/checker.c @@ -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; diff --git a/src/parser.c b/src/parser.c index 3e2103e6..77a1ff5d 100644 --- a/src/parser.c +++ b/src/parser.c @@ -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); -- 2.25.1