changed semantics of for loops; now iterable based
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Fri, 4 Sep 2020 19:20:10 +0000 (14:20 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Fri, 4 Sep 2020 19:20:10 +0000 (14:20 -0500)
14 files changed:
core/array.onyx
core/memory.onyx
core/ptrmap.onyx
core/stdio.onyx
core/string.onyx
include/onyxastnodes.h
onyx
progs/poly_test.onyx
src/onyxbuiltins.c
src/onyxchecker.c
src/onyxclone.c
src/onyxparser.c
src/onyxsymres.c
src/onyxwasm.c

index 6e06574d28ad5b517cb8b1430199c20d02f7a088..ad37a554146d461f644654f9093428ece80da64a 100644 (file)
@@ -49,10 +49,10 @@ array_insert :: proc (arr: ^[..] $T, idx: u32, x: T) {
 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;
 }
@@ -60,7 +60,7 @@ array_remove :: proc (arr: ^[..] $T, elem: T) {
 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];
     }
 
@@ -75,7 +75,7 @@ array_fast_delete :: proc (arr: ^[..] $T, idx: u32) {
 }
 
 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;
 }
 
@@ -86,7 +86,7 @@ array_pop :: proc (arr: ^[..] $T) -> T {
 
 array_average :: proc (arr: ^[..] $T) -> T {
     sum := cast(T) 0;
-    for i: 0, arr.count {
+    for i: 0 .. arr.count {
         sum += arr.data[i];
     }
 
@@ -102,9 +102,9 @@ array_to_slice :: proc (arr: ^[..] $T) -> [] T {
 **    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];
@@ -117,10 +117,10 @@ array_sort :: proc (arr: ^[..] $T, cmp: proc (T, T) -> i32) {
 
 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]);
 }
index c1223d88aaee927801d093a27b6e977e05fffd72..91da91da69f50b76e6351ed18d364c02346a1d2b 100644 (file)
@@ -3,5 +3,5 @@ package core
 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];
+}
index 8951cd00b05bd83fca71a14453e26af72f30665f..700e77b80e49dece6edd104885d354437e60178e 100644 (file)
@@ -17,7 +17,7 @@ ptrmap_init :: proc (use pmap: ^PtrMap, hash_count: i32 = 16) {
     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) {
@@ -57,7 +57,7 @@ ptrmap_get :: proc (use pmap: ^PtrMap, key: rawptr) -> rawptr {
 
 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;
@@ -74,7 +74,7 @@ ptrmap_delete :: proc (use pmap: ^PtrMap, key: rawptr) {
 }
 
 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;
 }
 
@@ -108,4 +108,4 @@ ptrmap_lookup :: proc (use pmap: ^PtrMap, key: rawptr) -> PtrMapLookupResult {
     }
 
     return lr;
-}
\ No newline at end of file
+}
index 3d2fc0f57f32179492e4bb3e2cc6a90e2036ce26..f4c4cd6f590954b74a6050ae9f696fbed2478f37 100644 (file)
@@ -30,7 +30,7 @@ print :: proc #overloaded {
 
 // 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);
     }
index dea3170183df2e55188c8568eedbe94384dc5ab3..6e073198c9107e09891702bda85cd678c6be9faf 100644 (file)
@@ -31,8 +31,8 @@ string_concat :: proc (s1: string, s2: string) -> string {
     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 };
 }
@@ -44,14 +44,14 @@ string_free :: proc (s: string) do cfree(s.data);
 // 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;
@@ -65,7 +65,7 @@ string_split :: proc (str: string, delim: u8) -> []string {
 }
 
 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;
 
@@ -77,7 +77,7 @@ string_substr :: proc (str: string, sub: string) -> string {
 }
 
 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;
 }
 
@@ -134,7 +134,7 @@ string_builder_add_string :: proc (use sb: ^StringBuilder, str: string) -> ^Stri
     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;
     }
@@ -148,7 +148,7 @@ string_builder_add_string :: proc (use sb: ^StringBuilder, str: string) -> ^Stri
     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;
 }
@@ -168,7 +168,7 @@ i64_to_string :: proc (n_: i64, base: u64, buf: Buffer) -> string {
     }
 
     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;
@@ -275,7 +275,7 @@ string_read_line :: proc (str: ^string, out: ^string) {
     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;
     }
index 11815151e5ee52728b4623b0ddeb3ea90421af39..25677186776f75672c7f8503e1d7f9378c33ceaf 100644 (file)
@@ -270,6 +270,13 @@ typedef enum JumpType {
     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 \
@@ -337,7 +344,10 @@ struct AstFor           {
     // 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;
 };
@@ -582,6 +592,7 @@ extern AstNumLit builtin_heap_start;
 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;
diff --git a/onyx b/onyx
index 5e98dca56db5fec2f66e2311403c096a7aa01b04..135af0325f99b311e7dfca7031fbb79f3045b472 100755 (executable)
Binary files a/onyx and b/onyx differ
index 92235e0e222ee18a520dd1d27c105879922c0743..2da511587e168df2109e5db1fb9f9538a7fa8cce 100644 (file)
@@ -47,8 +47,8 @@ compose :: proc (a: A, f: proc ($A) -> $B, g: proc (B) -> $C) -> C {
 
 
 SOA :: struct {
-    b  : [..] i64;
     a  : [..] i32;
+    b  : [..] i64;
 }
 
 soa_init :: proc (s: ^SOA) {
@@ -62,7 +62,7 @@ soa_deinit :: proc (s: ^SOA) {
 }
 
 get_range :: proc (arr: ^[..] $T) -> range {
-    return 20 .. 26;
+    return 0 .. arr.count;
 }
 
 print_range :: proc (r: range) #add_overload print {
@@ -74,6 +74,14 @@ 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;);
@@ -87,22 +95,29 @@ main :: proc (args: [] cstring) {
         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");
@@ -117,7 +132,7 @@ main :: proc (args: [] cstring) {
     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]));
@@ -154,7 +169,7 @@ main2 :: proc (args: [] cstring) {
 
     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);
@@ -183,7 +198,7 @@ main2 :: proc (args: [] cstring) {
     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));
     }
 
@@ -202,7 +217,7 @@ main2 :: proc (args: [] cstring) {
     array_init(^varr);
     defer array_free(^varr);
 
-    for i: 0, 20 {
+    for i: 0 .. 20 {
         array_push(^varr, Vec3.{
             x = i,
             y = i * i,
@@ -220,7 +235,7 @@ main2 :: proc (args: [] cstring) {
     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);
 
index 4085e062a5a7c84be89b91a230d24ba30f449ea7..6362331e1a7e738455004be3d8052c91511fee82 100644 (file)
@@ -27,6 +27,7 @@ AstGlobal builtin_stack_top   = { Ast_Kind_Global, Ast_Flag_Const | Ast_Flag_Glo
 
 AstType  *builtin_string_type;
 AstType  *builtin_range_type;
+Type     *builtin_range_type_type;
 
 const BuiltinSymbol builtin_symbols[] = {
     { NULL, "void",       (AstNode *) &basic_type_void },
index fc0be94e866c5e9afce9ebdaafd4700f4207273d..52467ffbb9b4a0c128389bfbaa2277a12aabdd0a 100644 (file)
@@ -97,47 +97,28 @@ b32 check_while(AstIfWhile* whilenode) {
 }
 
 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;
@@ -839,7 +820,7 @@ b32 check_array_access(AstArrayAccess* aa) {
         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;
@@ -931,7 +912,7 @@ b32 check_range_literal(AstBinaryOp** prange) {
     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);
index f11837fb98cef4c01f2060335ac2aadb52442065..78100a00fce036b3fc96ad13d32bdd1212b9c80b 100644 (file)
@@ -206,9 +206,7 @@ AstNode* ast_clone(bh_allocator a, void* n) {
 
                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;
 
index fba93559f6fed994440fe3134eaebe94245983f9..cacb22ae9cdf02a89ae28322bb3fa3e394a8f572 100644 (file)
@@ -853,19 +853,7 @@ static AstFor* parse_for_stmt(OnyxParser* parser) {
     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;
index b09f447b7404abd35f31fb1c650058a1366f0fb7..86afa631cc0b146cb67b4bdd9a6014a9ed0f8af0 100644 (file)
@@ -306,6 +306,10 @@ static void symres_expression(AstTyped** expr) {
             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:
@@ -376,11 +380,9 @@ static void symres_for(AstFor* fornode) {
     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);
 
index 1369da029ff2c95c8c1018df3d9e0f7e8051ddee..ac45c4688e0da47c5880f06706a6c3f1a6eb1961 100644 (file)
@@ -741,27 +741,36 @@ EMIT_FUNC(while, AstIfWhile* while_node) {
     *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);
     }
 
@@ -774,14 +783,14 @@ EMIT_FUNC(for, AstFor* for_node) {
     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);
@@ -790,18 +799,18 @@ EMIT_FUNC(for, AstFor* for_node) {
     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);
     }
 
@@ -814,6 +823,31 @@ EMIT_FUNC(for, AstFor* for_node) {
     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;