array_remove :: proc (arr: ^[..] $T, elem: T) {
move := 0;
- for i: 0, arr.count - move {
+ for i: 0 .. arr.count - move {
if arr.data[i + move] == elem do move += 1;
if move != 0 do arr.data[i] = arr.data[i + move];
- }
+ }
arr.count -= move;
}
array_delete :: proc (arr: ^[..] $T, idx: u32) {
if idx >= arr.count do return;
- for i: idx, arr.count - 1 {
+ for i: idx .. arr.count - 1 {
arr.data[i] = arr.data[i + 1];
}
}
array_contains :: proc (arr: ^[..] $T, x: T) -> bool {
- for i: 0, arr.count do if arr.data[i] == x do return true;
+ for i: 0 .. arr.count do if arr.data[i] == x do return true;
return false;
}
array_average :: proc (arr: ^[..] $T) -> T {
sum := cast(T) 0;
- for i: 0, arr.count {
+ for i: 0 .. arr.count {
sum += arr.data[i];
}
** cmp should return >0 if left > right
*/
array_sort :: proc (arr: ^[..] $T, cmp: proc (T, T) -> i32) {
- for i: 1, arr.count {
+ for i: 1 .. arr.count {
x := arr.data[i];
- j := i - 1;
+ j := i - 1;
while j >= 0 && cmp(arr.data[j], x) > 0 {
arr.data[j + 1] = arr.data[j];
array_fold :: proc (arr: ^[..] $T, init: $R, f: proc (T, R) -> R) -> R {
val := init;
- for i: 0, arr.count do val = f(arr.data[i], val);
+ for i: 0 .. arr.count do val = f(arr.data[i], val);
return val;
}
array_map :: proc (arr: ^[..] $T, f: proc (T) -> T) {
- for i: 0, arr.count do arr.data[i] = f(arr.data[i]);
+ for i: 0 .. arr.count do arr.data[i] = f(arr.data[i]);
}
memory_copy :: proc (dst_: rawptr, src_: rawptr, len: u32) {
dst := cast(^u8) dst_;
src := cast(^u8) src_;
- for i: 0, len do dst[i] = src[i];
-}
\ No newline at end of file
+ for i: 0 .. len do dst[i] = src[i];
+}
array_init(^hashes, hash_count);
array_init(^entries, 4);
- for i: 0, hash_count do array_push(^hashes, -1);
+ for i: 0 .. hash_count do array_push(^hashes, -1);
}
ptrmap_free :: proc (use pmap: ^PtrMap) {
ptrmap_delete :: proc (use pmap: ^PtrMap, key: rawptr) {
lr := ptrmap_lookup(pmap, key);
- if lr.entry_index < 0 do return;
+ if lr.entry_index < 0 do return;
if lr.entry_prev < 0 do hashes[lr.hash_index] = entries[lr.entry_index].next;
else do hashes[lr.entry_prev] = entries[lr.entry_index].next;
}
ptrmap_clear :: proc (use pmap: ^PtrMap) {
- for i: 0, hashes.count do hashes.data[i] = -1;
+ for i: 0 .. hashes.count do hashes.data[i] = -1;
entries.count = 0;
}
}
return lr;
-}
\ No newline at end of file
+}
// This works on both slices and arrays
print_array :: proc (arr: $T, sep := " ") {
- for i: 0, arr.count {
+ for i: 0 .. arr.count {
print(arr.data[i]);
if i != arr.count - 1 do print(sep);
}
len2 :: string_length(s2);
data := cast(^u8) calloc(len1 + len2);
- for i: 0, len1 do data[i] = s1[i];
- for i: 0, len2 do data[i + len1] = s2[i];
+ for i: 0 .. len1 do data[i] = s1[i];
+ for i: 0 .. len2 do data[i + len1] = s2[i];
return string.{ data, len1 + len2 };
}
// It documents the string_split function
string_split :: proc (str: string, delim: u8) -> []string {
delim_count := 0;
- for i: 0, str.count do if str[i] == delim do delim_count += 1;
+ for i: 0 .. str.count do if str[i] == delim do delim_count += 1;
strarr := cast(^string) calloc(sizeof string * (delim_count + 1));
curr_str := 0;
begin := 0;
- for i: 0, str.count {
+ for i: 0 .. str.count {
if str[i] == delim {
strarr[curr_str] = str.data[begin .. i];
begin = i + 1;
}
string_substr :: proc (str: string, sub: string) -> string {
- for i: 0, str.count {
+ for i: 0 .. str.count {
while j := 0; j < sub.count && str[i + j] == sub[j] {
j += 1;
}
string_contains :: proc (str: string, c: u8) -> bool {
- for i: 0, str.count do if str[i] == c do return true;
+ for i: 0 .. str.count do if str[i] == c do return true;
return false;
}
len_total :: len + str.count;
if cap >= len_total {
- for i: 0, str.count do data[len + i] = str[i];
+ for i: 0 .. str.count do data[len + i] = str[i];
len += str.count;
return sb;
}
data = new_data;
cap = new_cap;
- for i: 0, str.count do data[len + i] = str[i];
+ for i: 0 .. str.count do data[len + i] = str[i];
len += str.count;
return sb;
}
}
str :: cast(^u8) buf.data;
- for i: 0, buf.count do str[i] = #char "\0";
+ for i: 0 .. buf.count do str[i] = #char "\0";
c := cast(^u8) ^str[buf.count - 1];
len := 0;
out.data = str.data;
out.count = 0;
- for i: 0, str.count {
+ for i: 0 .. str.count {
if str.data[i] == #char "\n" do break;
out.count += 1;
}
Jump_Type_Count,
} JumpType;
+typedef enum ForLoopType {
+ For_Loop_Invalid,
+ For_Loop_Range,
+ For_Loop_Array,
+ For_Loop_Slice,
+ For_Loop_DynArr,
+} ForLoopType;
// Base Nodes
#define AstNode_base \
// NOTE: Local defining the iteration variable
AstLocal* var;
- AstTyped *start, *end, *step;
+ // NOTE: This can be any expression, but it is checked that
+ // it is of a type that we know how to iterate over.
+ AstTyped* iter;
+ ForLoopType loop_type;
AstBlock *stmt;
};
extern AstGlobal builtin_stack_top;
extern AstType *builtin_string_type;
extern AstType *builtin_range_type;
+extern Type *builtin_range_type_type;
typedef struct BuiltinSymbol {
char* package;
SOA :: struct {
- b : [..] i64;
a : [..] i32;
+ b : [..] i64;
}
soa_init :: proc (s: ^SOA) {
}
get_range :: proc (arr: ^[..] $T) -> range {
- return 20 .. 26;
+ return 0 .. arr.count;
}
print_range :: proc (r: range) #add_overload print {
print("\n");
}
+// NOTE: This function will be very useful for for loops. i.e.
+// for i: 0 .. 100 |> by(2) {
+// ...
+// }
+by :: proc (r: range, s: u32) -> range {
+ return range.{ low = r.low, high = r.high, step = s };
+}
+
main :: proc (args: [] cstring) {
res := compose(5, proc (x: i32) -> i32 do return x * 3;,
proc (x: i32) -> i32 do return x + 5;);
soa_deinit(^s);
}
+ print("Evens from 6 to 34:\n");
+ for i: 6 .. 34 |> by(2) {
+ print(i);
+ print(" ");
+ }
+ print("\n");
+
print_arr_details(^s.a);
print_arr_details(^s.b);
- for i: 0, 100 {
+ for i: 0 .. 100 {
array_push(^s.a, (5 * i) % 21);
array_push(^s.b, 3l * cast(i64) i);
}
- r := ^s.a |> get_range();
+ r := ^s.a |> get_range() |> by(3);
print(r);
+ print_array(^s.a);
array_sort(^s.a, cmp_dec);
- array_sort(^s.b, cmp_asc);
+ array_sort(^s.b, cmp_dec);
- print_array(s.a.data[r]);
- print_array(s.a.data[21 .. 27]);
+ print_array(^s.a);
print_array(^s.b);
print("After adding...\n");
ptrmap_init(^map, 50);
defer ptrmap_free(^map);
- for i: 0, 100 do ptrmap_put(^map, ^s.a[i], ^s.b[i]);
+ for i: 0 .. 100 do ptrmap_put(^map, ^s.a[i], ^s.b[i]);
print("Has ^a[20]? ");
print(ptrmap_has(^map, ^s.a[20]));
array_push(^iarr, 1234);
- for i: 0, 12 do array_push(^iarr, i % 5);
+ for i: 0 .. 12 do array_push(^iarr, i % 5);
print_arr_details(^iarr);
print_array(^iarr);
array_init(^barr, 10);
defer array_free(^barr);
- for i: 0, 500 {
+ for i: 0 .. 500 {
array_push(^barr, cast(u64) (3 * i * i + 4 * i - 2));
}
array_init(^varr);
defer array_free(^varr);
- for i: 0, 20 {
+ for i: 0 .. 20 {
array_push(^varr, Vec3.{
x = i,
y = i * i,
dummy := cast(^Dummy) calloc(sizeof Dummy);
defer cfree(dummy);
dummy.count = 5;
- for i: 0, dummy.count do dummy.data[i] = i * 5;
+ for i: 0 .. dummy.count do dummy.data[i] = i * 5;
print_array(dummy);
AstType *builtin_string_type;
AstType *builtin_range_type;
+Type *builtin_range_type_type;
const BuiltinSymbol builtin_symbols[] = {
{ NULL, "void", (AstNode *) &basic_type_void },
}
b32 check_for(AstFor* fornode) {
- if (check_expression(&fornode->start)) return 1;
- if (check_expression(&fornode->end)) return 1;
- if (check_expression(&fornode->step)) return 1;
+ if (check_expression(&fornode->iter)) return 1;
+ fornode->loop_type = For_Loop_Invalid;
- if (fornode->var->type_node == NULL || fornode->var->type_node != fornode->start->type_node)
- fornode->var->type_node = fornode->start->type_node;
- fill_in_type((AstTyped *) fornode->var);
+ Type* iter_type = fornode->iter->type;
+ b32 can_iterate = 0;
+ if (types_are_compatible(iter_type, builtin_range_type_type)) {
+ can_iterate = 1;
- if (!type_is_integer(fornode->start->type)) {
- onyx_report_error(fornode->start->token->pos, "expected expression of integer type for start");
- return 1;
- }
-
- if (!type_is_integer(fornode->end->type)) {
- onyx_report_error(fornode->end->token->pos, "expected expression of integer type for end");
- return 1;
- }
-
- if (!type_is_integer(fornode->step->type)) {
- onyx_report_error(fornode->step->token->pos, "expected expression of integer type for step");
- return 1;
- }
-
- // NOTE: Auto promote implicit step to the type of start
- if (fornode->step->kind == Ast_Kind_NumLit) {
- fornode->step->type_node = fornode->start->type_node;
- fornode->step->type = fornode->start->type;
- promote_numlit_to_larger((AstNumLit *) fornode->step);
- }
+ // NOTE: Blindly copy the first range member's type which will
+ // be the low value. - brendanfh 2020/09/04
+ fornode->var->type = builtin_range_type_type->Struct.memarr[0]->type;
- if (!types_are_compatible(fornode->end->type, fornode->start->type)) {
- onyx_report_error(fornode->end->token->pos, "type of end does not match type of start");
- return 1;
+ fornode->loop_type = For_Loop_Range;
}
- if (!types_are_compatible(fornode->step->type, fornode->start->type)) {
- onyx_report_error(fornode->start->token->pos, "type of step does not match type of start");
+ if (!can_iterate) {
+ onyx_report_error(fornode->iter->token->pos,
+ "Cannot iterate over a '%s'.",
+ type_get_name(iter_type));
return 1;
}
-
if (check_block(fornode->stmt)) return 1;
return 0;
return 1;
}
- if (types_are_compatible(aa->expr->type, type_build_from_ast(semstate.node_allocator, builtin_range_type))) {
+ if (types_are_compatible(aa->expr->type, builtin_range_type_type)) {
Type *of = NULL;
if (aa->addr->type->kind == Type_Kind_Pointer)
of = aa->addr->type->Pointer.elem;
if (check_expression(&range->left)) return 1;
if (check_expression(&range->right)) return 1;
- Type* expected_range_type = type_build_from_ast(semstate.node_allocator, builtin_range_type);
+ Type* expected_range_type = builtin_range_type_type;
StructMember smem;
type_lookup_member(expected_range_type, "low", &smem);
case Ast_Kind_For:
((AstFor *) nn)->var = (AstLocal *) ast_clone(a, ((AstFor *) node)->var);
- ((AstFor *) nn)->start = (AstTyped *) ast_clone(a, ((AstFor *) node)->start);
- ((AstFor *) nn)->end = (AstTyped *) ast_clone(a, ((AstFor *) node)->end);
- ((AstFor *) nn)->step = (AstTyped *) ast_clone(a, ((AstFor *) node)->step);
+ ((AstFor *) nn)->iter = (AstTyped *) ast_clone(a, ((AstFor *) node)->iter);
((AstFor *) nn)->stmt = (AstBlock *) ast_clone(a, ((AstFor *) node)->stmt);
break;
for_node->var = var_node;
expect_token(parser, ':');
- for_node->start = parse_expression(parser);
- expect_token(parser, ',');
- for_node->end = parse_expression(parser);
-
- if (parser->curr->type == ',') {
- consume_token(parser);
- for_node->step = parse_expression(parser);
- } else {
- for_node->step = make_node(AstNumLit, Ast_Kind_NumLit);
- for_node->step->type_node = (AstType *) &basic_type_i32;
- ((AstNumLit *) for_node->step)->value.i = 1;
- }
-
+ for_node->iter = parse_expression(parser);
for_node->stmt = parse_block(parser);
return for_node;
symres_expression(&((AstBinaryOp *)(*expr))->right);
(*expr)->type_node = symres_type(builtin_range_type);
+
+ // NOTE: This is a weird place to put this so maybe put it somewhere else eventually
+ // - brendanfh 2020/09/04
+ builtin_range_type_type = type_build_from_ast(semstate.node_allocator, builtin_range_type);
break;
case Ast_Kind_Function:
fornode->scope = scope_create(semstate.node_allocator, semstate.curr_scope);
scope_enter(fornode->scope);
- symbol_introduce(semstate.curr_scope, fornode->var->token, (AstNode *) fornode->var);
+ symres_expression(&fornode->iter);
- symres_expression(&fornode->start);
- symres_expression(&fornode->end);
- symres_expression(&fornode->step);
+ symbol_introduce(semstate.curr_scope, fornode->var->token, (AstNode *) fornode->var);
symres_block(fornode->stmt);
*pcode = code;
}
-EMIT_FUNC(for, AstFor* for_node) {
+EMIT_FUNC(for_range, AstFor* for_node, u64 iter_local) {
bh_arr(WasmInstruction) code = *pcode;
- AstLocal* var = for_node->var;
- u64 tmp = local_allocate(mod->local_alloc, var);
- bh_imap_put(&mod->local_map, (u64) var, tmp);
+ // NOTE: There are some aspects of the code below that rely on the
+ // low, high, and step members to be i32's. This restriction can be lifted,
+ // but it is important to change the code here.
+ // -brendanfh 2020/09/04
- b32 it_is_local = (b32) ((tmp & LOCAL_IS_WASM) != 0);
+ AstLocal* var = for_node->var;
+ b32 it_is_local = (b32) ((iter_local & LOCAL_IS_WASM) != 0);
u64 offset = 0;
- WasmType var_type = onyx_type_to_wasm_type(for_node->var->type);
- assert(var_type == WASM_TYPE_INT32 || var_type == WASM_TYPE_INT64);
- WasmInstructionType add_instr = var_type == WASM_TYPE_INT32 ? WI_I32_ADD : WI_I64_ADD;
- WasmInstructionType ge_instr = var_type == WASM_TYPE_INT32 ? WI_I32_GE_S : WI_I64_GE_S;
+ StructMember smem;
+ type_lookup_member(builtin_range_type_type, "low", &smem);
+ u64 low_local = local_raw_allocate(mod->local_alloc, onyx_type_to_wasm_type(smem.type));
+ type_lookup_member(builtin_range_type_type, "high", &smem);
+ u64 high_local = local_raw_allocate(mod->local_alloc, onyx_type_to_wasm_type(smem.type));
+ type_lookup_member(builtin_range_type_type, "step", &smem);
+ u64 step_local = local_raw_allocate(mod->local_alloc, onyx_type_to_wasm_type(smem.type));
+
+ WIL(WI_LOCAL_SET, step_local);
+ WIL(WI_LOCAL_SET, high_local);
+ WIL(WI_LOCAL_SET, low_local);
if (it_is_local) {
- emit_expression(mod, &code, for_node->start);
- WIL(WI_LOCAL_SET, tmp);
+ WIL(WI_LOCAL_GET, low_local);
+ WIL(WI_LOCAL_SET, iter_local);
} else {
emit_local_location(mod, &code, var, &offset);
- emit_expression(mod, &code, for_node->start);
+ WIL(WI_LOCAL_GET, low_local);
emit_store_instruction(mod, &code, var->type, offset);
}
bh_arr_push(mod->structured_jump_target, 2);
if (it_is_local) {
- WIL(WI_LOCAL_GET, tmp);
+ WIL(WI_LOCAL_GET, iter_local);
} else {
offset = 0;
emit_local_location(mod, &code, var, &offset);
emit_load_instruction(mod, &code, var->type, offset);
}
- emit_expression(mod, &code, for_node->end);
- WI(ge_instr);
+ WIL(WI_LOCAL_GET, high_local);
+ WI(WI_I32_GE_S);
WID(WI_COND_JUMP, 0x02);
emit_block(mod, &code, for_node->stmt, 0);
WI(WI_BLOCK_END);
if (it_is_local) {
- WIL(WI_LOCAL_GET, tmp);
- emit_expression(mod, &code, for_node->step);
- WI(add_instr);
- WIL(WI_LOCAL_SET, tmp);
+ WIL(WI_LOCAL_GET, iter_local);
+ WIL(WI_LOCAL_GET, step_local);
+ WI(WI_I32_ADD);
+ WIL(WI_LOCAL_SET, iter_local);
} else {
offset = 0;
emit_local_location(mod, &code, var, &offset);
offset = 0;
emit_local_location(mod, &code, var, &offset);
emit_load_instruction(mod, &code, var->type, offset);
- emit_expression(mod, &code, for_node->step);
- WI(add_instr);
+ WIL(WI_LOCAL_GET, step_local);
+ WI(WI_I32_ADD);
emit_store_instruction(mod, &code, var->type, offset);
}
WI(WI_LOOP_END);
WI(WI_BLOCK_END);
+ type_lookup_member(builtin_range_type_type, "low", &smem);
+ local_raw_free(mod->local_alloc, onyx_type_to_wasm_type(smem.type));
+ type_lookup_member(builtin_range_type_type, "high", &smem);
+ local_raw_free(mod->local_alloc, onyx_type_to_wasm_type(smem.type));
+ type_lookup_member(builtin_range_type_type, "step", &smem);
+ local_raw_free(mod->local_alloc, onyx_type_to_wasm_type(smem.type));
+
+ *pcode = code;
+}
+
+EMIT_FUNC(for, AstFor* for_node) {
+ bh_arr(WasmInstruction) code = *pcode;
+
+ AstLocal* var = for_node->var;
+ u64 iter_local = local_allocate(mod->local_alloc, var);
+ bh_imap_put(&mod->local_map, (u64) var, iter_local);
+
+ emit_expression(mod, &code, for_node->iter);
+
+ if (for_node->loop_type == For_Loop_Range) {
+ emit_for_range(mod, &code, for_node, iter_local);
+ } else {
+ onyx_report_error(for_node->token->pos, "Invalid for loop type. You should probably not be seeing this...");
+ }
+
local_free(mod->local_alloc, var);
*pcode = code;