added for loop iteration over slices and dynamic arrays
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Sat, 5 Sep 2020 04:24:05 +0000 (23:24 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Sat, 5 Sep 2020 04:24:05 +0000 (23:24 -0500)
core/builtin.onyx
onyx
progs/poly_test.onyx
src/onyxchecker.c
src/onyxwasm.c

index b07fe7d6f7592ed7b838cebdc713a35f8d7cc662..a867c8d1f55ae62cbbf7b83785863130f312ca06 100644 (file)
@@ -5,6 +5,8 @@ cstring :: #type ^u8;
 
 Buffer :: #type []void;
 
+// NOTE: Because of many implementation details, all fields of this
+// struct are required to be i32's.
 range :: struct {
     low  : i32;
     high : i32;
diff --git a/onyx b/onyx
index 135af0325f99b311e7dfca7031fbb79f3045b472..93a0ad264e39c9958cd53ffcdb64a33865eabca9 100755 (executable)
Binary files a/onyx and b/onyx differ
index 2da511587e168df2109e5db1fb9f9538a7fa8cce..78ba380752fbb25d99f11c67db3b554e220a98bc 100644 (file)
@@ -49,16 +49,19 @@ compose :: proc (a: A, f: proc ($A) -> $B, g: proc (B) -> $C) -> C {
 SOA :: struct {
     a  : [..] i32;
     b  : [..] i64;
+    c  : [..] V2;
 }
 
 soa_init :: proc (s: ^SOA) {
     array_init(^s.a);
     array_init(^s.b);
+    array_init(^s.c);
 }
 
 soa_deinit :: proc (s: ^SOA) {
     array_free(^s.a);
     array_free(^s.b);
+    array_free(^s.c);
 }
 
 get_range :: proc (arr: ^[..] $T) -> range {
@@ -82,6 +85,15 @@ by :: proc (r: range, s: u32) -> range {
     return range.{ low = r.low, high = r.high, step = s };
 }
 
+V2 :: struct { x: i32; y: i32; }
+print_v2 :: proc (v: V2) #add_overload print {
+    print("V2(");
+    print(v.x);
+    print(", ");
+    print(v.y);
+    print(")");
+}
+
 main :: proc (args: [] cstring) {
     res := compose(5, proc (x: i32) -> i32 do return x * 3;,
                       proc (x: i32) -> i32 do return x + 5;);
@@ -108,12 +120,20 @@ main :: proc (args: [] cstring) {
     for i: 0 .. 100 {
         array_push(^s.a, (5 * i) % 21);
         array_push(^s.b, 3l * cast(i64) i);
+        array_push(^s.c, V2.{ i, i * i });
     }
 
     r := ^s.a |> get_range() |> by(3);
     print(r);
     print_array(^s.a);
 
+    for vec: s.c {
+        print(vec);
+        print(" ");
+    }
+    print("\n");
+
+
     array_sort(^s.a, cmp_dec);
     array_sort(^s.b, cmp_dec);
 
index 52467ffbb9b4a0c128389bfbaa2277a12aabdd0a..3fed3fccbdd316bfaeb5053d2a5f5e0ccf46caa9 100644 (file)
@@ -108,8 +108,21 @@ b32 check_for(AstFor* fornode) {
         // 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;
-
         fornode->loop_type = For_Loop_Range;
+
+    }
+    else if (iter_type->kind == Type_Kind_Slice) {
+        can_iterate = 1;
+
+        fornode->var->type = iter_type->Slice.ptr_to_data->Pointer.elem;
+        fornode->loop_type = For_Loop_Slice;
+
+    }
+    else if (iter_type->kind == Type_Kind_DynArray) {
+        can_iterate = 1;
+
+        fornode->var->type = iter_type->DynArray.ptr_to_data->Pointer.elem;
+        fornode->loop_type = For_Loop_DynArr;
     }
 
     if (!can_iterate) {
index ac45c4688e0da47c5880f06706a6c3f1a6eb1961..1b6237eb6fe275f2d509e54205ef6c69099b060d 100644 (file)
@@ -763,12 +763,13 @@ EMIT_FUNC(for_range, AstFor* for_node, u64 iter_local) {
 
     WIL(WI_LOCAL_SET, step_local);
     WIL(WI_LOCAL_SET, high_local);
-    WIL(WI_LOCAL_SET, low_local);
 
     if (it_is_local) {
-        WIL(WI_LOCAL_GET, low_local);
+        WIL(WI_LOCAL_TEE, low_local);
         WIL(WI_LOCAL_SET, iter_local);
+
     } else {
+        WIL(WI_LOCAL_SET, low_local);
         emit_local_location(mod, &code, var, &offset);
         WIL(WI_LOCAL_GET, low_local);
         emit_store_instruction(mod, &code, var->type, offset);
@@ -833,6 +834,96 @@ EMIT_FUNC(for_range, AstFor* for_node, u64 iter_local) {
     *pcode = code;
 }
 
+EMIT_FUNC(for_slice, AstFor* for_node, u64 iter_local) {
+    bh_arr(WasmInstruction) code = *pcode;
+
+    // NOTE: This implementation is only for loops by value, not by pointer.
+
+    // At this point the stack will look like:
+    //      data
+    //      count
+    //
+    // The locals we need to have:
+    //      end_ptr
+    //      start_ptr
+    //
+
+    u64 end_ptr_local = local_raw_allocate(mod->local_alloc, WASM_TYPE_INT32);
+    u64 ptr_local     = local_raw_allocate(mod->local_alloc, WASM_TYPE_INT32);
+
+    AstLocal* var = for_node->var;
+    u64 elem_size = type_size_of(var->type);
+    b32 it_is_local = (b32) ((iter_local & LOCAL_IS_WASM) != 0);
+    u64 offset = 0;
+
+    WIL(WI_LOCAL_SET, end_ptr_local);
+    WIL(WI_LOCAL_TEE, ptr_local);
+    WIL(WI_LOCAL_GET, end_ptr_local);
+    if (elem_size != 1) {
+        WID(WI_I32_CONST, elem_size);
+        WI(WI_I32_MUL);
+    }
+    WI(WI_I32_ADD);
+    WIL(WI_LOCAL_SET, end_ptr_local);
+
+    WID(WI_BLOCK_START, 0x40);
+    WID(WI_LOOP_START, 0x40);
+    WID(WI_BLOCK_START, 0x40);
+
+    bh_arr_push(mod->structured_jump_target, 1);
+    bh_arr_push(mod->structured_jump_target, 0);
+    bh_arr_push(mod->structured_jump_target, 2);
+
+    WIL(WI_LOCAL_GET, ptr_local);
+    WIL(WI_LOCAL_GET, end_ptr_local);
+    WI(WI_I32_GE_S);
+    WID(WI_COND_JUMP, 0x02);
+
+    // NOTE: Storing structs requires that the location to store it is,
+    // the top most thing on the stack. Everything requires it to be
+    // 'under' the other element being stored.  -brendanfh 2020/09/04
+    if (!it_is_local && var->type->kind != Type_Kind_Struct) {
+        emit_local_location(mod, &code, var, &offset);
+    }
+
+    WIL(WI_LOCAL_GET, ptr_local);
+    emit_load_instruction(mod, &code, var->type, 0);
+    if (it_is_local) {
+        WIL(WI_LOCAL_SET, iter_local);
+    } else {
+        if (var->type->kind != Type_Kind_Struct) {
+            emit_store_instruction(mod, &code, var->type, offset);
+        } else {
+            emit_local_location(mod, &code, var, &offset);
+            emit_store_instruction(mod, &code, var->type, offset);
+        }
+    }
+
+    emit_block(mod, &code, for_node->stmt, 0);
+
+    bh_arr_pop(mod->structured_jump_target);
+    WI(WI_BLOCK_END);
+
+    WIL(WI_LOCAL_GET, ptr_local);
+    WIL(WI_I32_CONST, elem_size);
+    WI(WI_I32_ADD);
+    WIL(WI_LOCAL_SET, ptr_local);
+
+    bh_arr_pop(mod->structured_jump_target);
+    bh_arr_pop(mod->structured_jump_target);
+
+    if (bh_arr_last(code).type != WI_JUMP)
+        WID(WI_JUMP, 0x00);
+
+    WI(WI_LOOP_END);
+    WI(WI_BLOCK_END);
+
+    local_raw_free(mod->local_alloc, WASM_TYPE_INT32);
+    local_raw_free(mod->local_alloc, WASM_TYPE_INT32);
+
+    *pcode = code;
+}
+
 EMIT_FUNC(for, AstFor* for_node) {
     bh_arr(WasmInstruction) code = *pcode;
 
@@ -844,6 +935,14 @@ EMIT_FUNC(for, AstFor* for_node) {
 
     if (for_node->loop_type == For_Loop_Range) {
         emit_for_range(mod, &code, for_node, iter_local);
+    } else if (for_node->loop_type == For_Loop_Slice) {
+        emit_for_slice(mod, &code, for_node, iter_local);
+    } else if (for_node->loop_type == For_Loop_DynArr) {
+        // NOTE: A dynamic array is just a slice with an extra capacity field on the end.
+        // Just dropping the capacity field will mean we can just use the slice implementation.
+        //                                                  - brendanfh   2020/09/04
+        WI(WI_DROP);
+        emit_for_slice(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...");
     }