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
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.
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); },
}
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);
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
} 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;
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);
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;
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
&& 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;
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;
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 ']'
operator->operator = op;
}
+ operator_determined:
operator->overload = parse_expression(parser, 0);
ENTITY_SUBMIT(operator);