added initializer to if and while; added else on while
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Mon, 24 Aug 2020 02:17:54 +0000 (21:17 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Mon, 24 Aug 2020 02:17:54 +0000 (21:17 -0500)
core/string.onyx
docs/plan
include/bh.h
include/onyxastnodes.h
onyx
progs/wasi_test.onyx
src/onyxbuiltins.c
src/onyxchecker.c
src/onyxparser.c
src/onyxsymres.c
src/onyxwasm.c

index e414f022ee3ad22a40130b671e8f1b18e562b181..c3b41433ecd7f586451cb6b891fe050f9a4db391 100644 (file)
@@ -18,7 +18,6 @@ string_make_from_cstring :: proc (s: cstring) -> string {
     return string.{ len = len, data = s };
 }
 
-
 string_length :: proc #overloaded {
     proc (s: ^u8) -> u32 {
         len := 0;
@@ -82,21 +81,18 @@ string_split :: proc (a: Allocator, str: string, delim: u8) -> StringSplitResult
 
 
 StringBuilder :: struct {
-    // FIX(nested-structs): This should not be a pointer eventually.
-    // Currently nested structures cannot be passed as arguments.
-    // When this issue is fixed, change this to Allocator.
-    alloc : ^Allocator;
+    alloc : Allocator;
 
     data  : ^u8 = null;
     len   : u32 = 0;
     cap   : u32 = 0;
 }
 
-string_builder_make :: proc (a: ^Allocator, initial_cap: u32) -> StringBuilder {
+string_builder_make :: proc (a: Allocator, initial_cap: u32) -> StringBuilder {
     data: ^u8 = null;
 
     if initial_cap > 0 {
-        data = cast(^u8) alloc(*a, initial_cap);
+        data = cast(^u8) alloc(a, initial_cap);
     }
 
     return StringBuilder.{
@@ -118,7 +114,7 @@ string_builder_add_string :: proc (use sb: ^StringBuilder, str: string) -> ^Stri
     new_cap := cap;
     while new_cap < len_total do new_cap <<= 1;
 
-    new_data := cast(^u8) resize(*alloc, data, new_cap);
+    new_data := cast(^u8) resize(alloc, data, new_cap);
     if new_data == null do return sb;
 
     data = new_data;
index 0cc1c40c230a045d534d10e4bbb3de9ebbb56de2..0a230bab7f4d4c31231c8307b77e89b57893c924 100644 (file)
--- a/docs/plan
+++ b/docs/plan
@@ -187,6 +187,18 @@ HOW:
         [X] returning structs
             - This will put forward a lot of the work that will be done for multiple return values
 
+        [X] intializers in if / while
+            if err := some_function(...); err != 0 {
+                print(err);
+            }
+
+        [X] else on while
+            while ... {
+
+            } else {
+                // Loop never run
+            }
+
         [ ] 'use' enums and packages at an arbitrary scope
 
         [ ] convert to using an 'atom' like table
@@ -201,7 +213,7 @@ HOW:
             - struct member names
             - array length
 
-        [ ] Make the lexer much faster
+        [X] Make the lexer much faster
             - Technically it isn't slow right now
             - But, profiling says we are spending 50% of the program execution time in the lexer
             - That is awful
index b0633fc414f9d8b652ea7635cc17bf2facf74636..d1930ca83357312484019d5c0f1568ef13770cfe 100644 (file)
@@ -162,6 +162,8 @@ u8* double_to_ieee754(f64 f, b32 reverse);
 #define bh_align_of(Type)                bh_offset_of(struct { char c; Type member; }, member)
 #define bh_swap(Type, a, b)                do { Type tmp = (a); (a) = (b); (b) = tmp; } while(0)
 
+#define bh_align(x, a) if ((x) % (a) != 0) (x) += (a) - ((x) % (a));
+
 #define bh_pointer_add(ptr, amm)        ((void *)((u8 *) ptr + amm))
 #define BH_BIT(x)                        (1 << (x))
 #define BH_MASK_SET(var, set, mask)     ((set) ? (var) |= (mask) : (var) &= ~(mask))
index aefd7c78e2915a85c0247049e76da709f84b4781..c9814df06f15d90c44e41fd8e81b843b9bb21961 100644 (file)
@@ -30,9 +30,8 @@ typedef struct AstBreak AstBreak;
 typedef struct AstContinue AstContinue;
 
 typedef struct AstBlock AstBlock;
-typedef struct AstIf AstIf;
+typedef struct AstIfWhile AstIfWhile;
 typedef struct AstFor AstFor;
-typedef struct AstWhile AstWhile;
 typedef struct AstDefer AstDefer;
 
 typedef struct AstType AstType;
@@ -248,14 +247,12 @@ typedef enum CallingConvention {
 
 
 // Base Nodes
-#define AstNode_members {     \
+#define AstNode_base \
     AstKind kind;             \
     u32 flags;                \
     OnyxToken *token;         \
-    AstNode *next;            \
-};
-#define AstNode_base struct AstNode_members;
-struct AstNode AstNode_members;
+    AstNode *next;            
+struct AstNode { AstNode_base };
 
 // NOTE: 'type_node' is filled out by the parser.
 // For a type such as '^^i32', the tree would look something like
@@ -268,13 +265,11 @@ struct AstNode AstNode_members;
 //
 // 'type' is filled out afterwards. If it is NULL, the Type* is built
 // using the type_node. This can then be used to typecheck this node.
-#define AstTyped_members     { \
-    AstNode_base;              \
-    AstType *type_node;        \
-    Type *type;                \
-}
-#define AstTyped_base struct AstTyped_members;
-struct AstTyped AstTyped_members;
+#define AstTyped_base       \
+    AstNode_base;           \
+    AstType *type_node;     \
+    Type *type;                
+struct AstTyped { AstTyped_base };
 
 // Expression Nodes
 struct AstBinOp         { AstTyped_base; BinaryOp operation; AstTyped *left, *right; };
@@ -308,7 +303,6 @@ struct AstContinue      { AstNode_base; u64 count; };
 
 // Structure Nodes
 struct AstBlock         { AstNode_base; AstNode *body; Scope *scope; bh_arr(AstLocal *) locals; };
-struct AstWhile         { AstNode_base; AstTyped *cond; AstBlock *stmt; };
 struct AstDefer         { AstNode_base; AstNode *stmt; };
 struct AstFor           {
     AstNode_base;
@@ -323,8 +317,13 @@ struct AstFor           {
 
     AstBlock *stmt;
 };
-struct AstIf {
+struct AstIfWhile {
     AstNode_base;
+
+    Scope *scope;
+    AstLocal *local;
+    AstBinaryOp *assignment;
+
     AstTyped *cond;
 
     AstBlock *true_stmt;
@@ -336,9 +335,12 @@ struct AstIf {
 // without the 'next' member. This is because types
 // can't be in expressions so a 'next' thing
 // doesn't make sense.
-#define AstType_members { AstKind kind; u32 flags; OnyxToken* token; char* name; }
-#define AstType_base struct AstType_members;
-struct AstType AstType_members;
+#define AstType_base    \
+    AstKind kind;       \
+    u32 flags;          \
+    OnyxToken* token;   \
+    char* name;
+struct AstType { AstType_base };
 
 struct AstBasicType     { AstType_base; Type* type; };
 struct AstPointerType   { AstType_base; AstType* elem; };
diff --git a/onyx b/onyx
index 0acd7e5597013097b9412cf2746d829cd57e7b50..4775a53ced31956564e0e8af7153bb33f6b3f45d 100755 (executable)
Binary files a/onyx and b/onyx differ
index 5f7dfb93f02f460bfd094ca09dd677d38a69b8ba..b7d737df347e5778042902e6d7be41943cc41a70 100644 (file)
@@ -62,101 +62,101 @@ print_u64_with_base :: proc (n_: u64, base: u64) {
 }
 
 print_string :: proc (s: string) -> u32 {
-       vec := IOVec.{ buf = s.data, len = s.len };
-       tmp : Size;
-       fd_write(1, IOVecArray.{ ^vec, 1 }, ^tmp);
-       fd_datasync(1);
+    vec := IOVec.{ buf = s.data, len = s.len };
+    tmp : Size;
+    fd_write(1, IOVecArray.{ ^vec, 1 }, ^tmp);
+    fd_datasync(1);
 
-       return tmp;
+    return tmp;
 }
 
 print_u8 :: proc (s: cstring) -> u32 {
-       return string_make(s) |> print_string();
+    return string_make(s) |> print_string();
 }
 
 print :: proc #overloaded { print_string, print_u8 }
 
 print_rights :: proc (rights: Rights) {
-       print_u64_with_base(cast(u64) rights, 2l);
-       print("\n");
-
-       if rights & Rights.DataSync != cast(Rights) 0 do print("DataSync\n");
-       if rights & Rights.Read != cast(Rights) 0 do print("Read\n");
-       if rights & Rights.Seek != cast(Rights) 0 do print("Seek\n");
-       if rights & Rights.FdStatSetFlags != cast(Rights) 0 do print("FdStatSetFlags\n");
-       if rights & Rights.Sync != cast(Rights) 0 do print("Sync\n");
-       if rights & Rights.Tell != cast(Rights) 0 do print("Tell\n");
-       if rights & Rights.Write != cast(Rights) 0 do print("Write\n");
-       if rights & Rights.Advise != cast(Rights) 0 do print("Advise\n");
-       if rights & Rights.Allocate != cast(Rights) 0 do print("Allocate\n");
-       if rights & Rights.PathCreateDirectory != cast(Rights) 0 do print("PathCreateDirectory\n");
-       if rights & Rights.PathCreateFile != cast(Rights) 0 do print("PathCreateFile\n");
-       if rights & Rights.PathLinkSource != cast(Rights) 0 do print("PathLinkSource\n");
-       if rights & Rights.PathLinkTarget != cast(Rights) 0 do print("PathLinkTarget\n");
-       if rights & Rights.PathOpen != cast(Rights) 0 do print("PathOpen\n");
-       if rights & Rights.ReadDir != cast(Rights) 0 do print("ReadDir\n");
-       if rights & Rights.PathReadlink != cast(Rights) 0 do print("PathReadlink\n");
-       if rights & Rights.PathRenameSource != cast(Rights) 0 do print("PathRenameSource\n");
-       if rights & Rights.PathRenameTarget != cast(Rights) 0 do print("PathRenameTarget\n");
-       if rights & Rights.PathFilestatGet != cast(Rights) 0 do print("PathFilestatGet\n");
-       if rights & Rights.PathFilestateSetSize != cast(Rights) 0 do print("PathFilestateSetSize\n");
-       if rights & Rights.PathFilestateSetTimes != cast(Rights) 0 do print("PathFilestateSetTimes\n");
-       if rights & Rights.FilestatGet != cast(Rights) 0 do print("FilestatGet\n");
-       if rights & Rights.FilestatSetSize != cast(Rights) 0 do print("FilestatSetSize\n");
-       if rights & Rights.FilestatSetTimes != cast(Rights) 0 do print("FilestatSetTimes\n");
-       if rights & Rights.PathSymlink != cast(Rights) 0 do print("PathSymlink\n");
-       if rights & Rights.PathRemoveDirectory != cast(Rights) 0 do print("PathRemoveDirectory\n");
-       if rights & Rights.PathUnlinkFile != cast(Rights) 0 do print("PathUnlinkFile\n");
-       if rights & Rights.PollFDReadWrite != cast(Rights) 0 do print("PollFDReadWrite\n");
-       if rights & Rights.SockShutdown != cast(Rights) 0 do print("SockShutdown\n");
+    print_u64_with_base(cast(u64) rights, 2l);
+    print("\n");
+
+    if rights & Rights.DataSync != cast(Rights) 0 do print("DataSync\n");
+    if rights & Rights.Read != cast(Rights) 0 do print("Read\n");
+    if rights & Rights.Seek != cast(Rights) 0 do print("Seek\n");
+    if rights & Rights.FdStatSetFlags != cast(Rights) 0 do print("FdStatSetFlags\n");
+    if rights & Rights.Sync != cast(Rights) 0 do print("Sync\n");
+    if rights & Rights.Tell != cast(Rights) 0 do print("Tell\n");
+    if rights & Rights.Write != cast(Rights) 0 do print("Write\n");
+    if rights & Rights.Advise != cast(Rights) 0 do print("Advise\n");
+    if rights & Rights.Allocate != cast(Rights) 0 do print("Allocate\n");
+    if rights & Rights.PathCreateDirectory != cast(Rights) 0 do print("PathCreateDirectory\n");
+    if rights & Rights.PathCreateFile != cast(Rights) 0 do print("PathCreateFile\n");
+    if rights & Rights.PathLinkSource != cast(Rights) 0 do print("PathLinkSource\n");
+    if rights & Rights.PathLinkTarget != cast(Rights) 0 do print("PathLinkTarget\n");
+    if rights & Rights.PathOpen != cast(Rights) 0 do print("PathOpen\n");
+    if rights & Rights.ReadDir != cast(Rights) 0 do print("ReadDir\n");
+    if rights & Rights.PathReadlink != cast(Rights) 0 do print("PathReadlink\n");
+    if rights & Rights.PathRenameSource != cast(Rights) 0 do print("PathRenameSource\n");
+    if rights & Rights.PathRenameTarget != cast(Rights) 0 do print("PathRenameTarget\n");
+    if rights & Rights.PathFilestatGet != cast(Rights) 0 do print("PathFilestatGet\n");
+    if rights & Rights.PathFilestateSetSize != cast(Rights) 0 do print("PathFilestateSetSize\n");
+    if rights & Rights.PathFilestateSetTimes != cast(Rights) 0 do print("PathFilestateSetTimes\n");
+    if rights & Rights.FilestatGet != cast(Rights) 0 do print("FilestatGet\n");
+    if rights & Rights.FilestatSetSize != cast(Rights) 0 do print("FilestatSetSize\n");
+    if rights & Rights.FilestatSetTimes != cast(Rights) 0 do print("FilestatSetTimes\n");
+    if rights & Rights.PathSymlink != cast(Rights) 0 do print("PathSymlink\n");
+    if rights & Rights.PathRemoveDirectory != cast(Rights) 0 do print("PathRemoveDirectory\n");
+    if rights & Rights.PathUnlinkFile != cast(Rights) 0 do print("PathUnlinkFile\n");
+    if rights & Rights.PollFDReadWrite != cast(Rights) 0 do print("PollFDReadWrite\n");
+    if rights & Rights.SockShutdown != cast(Rights) 0 do print("SockShutdown\n");
 }
 
 readline :: proc (buf: ^u8, bufsize: u32) -> u32 {
-       iov := IOVec.{ buf, bufsize };
-       nread : Size;
-       fd_pread(0, IOVecArray.{ ^iov, 1 }, 0l, ^nread);
+    iov := IOVec.{ buf, bufsize };
+    nread : Size;
+    fd_pread(0, IOVecArray.{ ^iov, 1 }, 0l, ^nread);
 
-       return nread;
+    return nread;
 }
 
 readdir :: proc (fd: FileDescriptor) {
-       buf : [1024] u8;
-       bufused : Size;
-
-       if fd_readdir(fd, cast(^u8) buf, 1024, cast(DirCookie) 0, ^bufused) != Errno.Success {
-               print("Failed to readdir\n");
-               return;
-       }
-
-       dirent := cast(^DirEnt) buf;
-       while true {
-               print(string.{ cast(^u8) (cast(u32) dirent + sizeof DirEnt), dirent.d_namlen });
-               print("\n");
-
-               print("\td_namlen: ");
-               print_u64_with_base(cast(u64) dirent.d_namlen, 16l);
-               print("\n");
-               print("\td_type: ");
-               print_u64_with_base(cast(u64) dirent.d_type, 16l);
-               print("\n");
-
-               bufused -= sizeof DirEnt + dirent.d_namlen;
-               dirent = cast(^DirEnt) (cast(u32) dirent + sizeof DirEnt + dirent.d_namlen);
-
-               if bufused <= 0 do break;
-       }
+    buf : [1024] u8;
+    bufused : Size;
+
+    if fd_readdir(fd, cast(^u8) buf, 1024, cast(DirCookie) 0, ^bufused) != Errno.Success {
+        print("Failed to readdir\n");
+        return;
+    }
+
+    dirent := cast(^DirEnt) buf;
+    while true {
+        print(string.{ cast(^u8) (cast(u32) dirent + sizeof DirEnt), dirent.d_namlen });
+        print("\n");
+
+        print("\td_namlen: ");
+        print_u64_with_base(cast(u64) dirent.d_namlen, 16l);
+        print("\n");
+        print("\td_type: ");
+        print_u64_with_base(cast(u64) dirent.d_type, 16l);
+        print("\n");
+
+        bufused -= sizeof DirEnt + dirent.d_namlen;
+        dirent = cast(^DirEnt) (cast(u32) dirent + sizeof DirEnt + dirent.d_namlen);
+
+        if bufused <= 0 do break;
+    }
 }
 
 timer_start :: proc -> Timestamp {
-       curr_time: Timestamp;
-       clock_time_get(ClockID.Realtime, cast(Timestamp) 1, ^curr_time);
-       return curr_time;
+    curr_time: Timestamp;
+    clock_time_get(ClockID.Realtime, cast(Timestamp) 1, ^curr_time);
+    return curr_time;
 }
 
 timer_end :: proc (start_time: Timestamp) -> Timestamp {
-       curr_time: Timestamp;
-       clock_time_get(ClockID.Realtime, cast(Timestamp) 1, ^curr_time);
-       return (curr_time - start_time) / 1000000l;
+    curr_time: Timestamp;
+    clock_time_get(ClockID.Realtime, cast(Timestamp) 1, ^curr_time);
+    return (curr_time - start_time) / 1000000l;
 }
 
 is_prime :: proc (n: u32) -> bool {
@@ -166,125 +166,143 @@ is_prime :: proc (n: u32) -> bool {
 }
 
 Vec3 :: struct {
-       x: f32;
-       y: f32;
-       z: f32;
+    x: f32;
+    y: f32;
+    z: f32;
 }
 
 S :: struct {
-       name: string;
-       age:  u32;
-       pos:  Vec3;
+    name: string;
+    age:  u32;
+    pos:  Vec3;
 }
 
 output_s :: proc (sb: ^StringBuilder, s: ^S) -> ^StringBuilder {
-       sb  |> sba("Hello, I'm ")
-               |> sba(s.name)
-               |> sba(". I am ")
-               |> sba(cast(u64) s.age)
-               |> sba(" years old. I am at (")
-               |> sba(cast(u64) s.pos.x) |> sba(", ")
-               |> sba(cast(u64) s.pos.y) |> sba(", ")
-               |> sba(cast(u64) s.pos.z) |> sba(").\n");
-
-       return sb;
+    sb  |> sba("Hello, I'm ")
+        |> sba(s.name)
+        |> sba(". I am ")
+        |> sba(cast(u64) s.age)
+        |> sba(" years old. I am at (")
+        |> sba(cast(u64) s.pos.x) |> sba(", ")
+        |> sba(cast(u64) s.pos.y) |> sba(", ")
+        |> sba(cast(u64) s.pos.z) |> sba(").\n");
+
+    return sb;
 }
 
 main :: proc (argc: u32, argv: ^cstring) {
-       sb := string_builder_make(^heap_allocator, 256);
-
-       timer := timer_start();
-       defer {
-               ^sb |> string_builder_clear()
-                       |> sba("Time taken: ")
-                       |> sba(cast(u64) timer_end(timer), 10l)
-                       |> sba("ms\n")
-                       |> string_builder_to_string()
-                       |> print();
-       }
-
-       ^sb |> sba("There are ")
-               |> sba(cast(u64) argc)
-               |> sba(" arguments.\n");
-
-       for i: 0, argc do ^sb |> sba(argv[i]) |> sba(" ");
-       ^sb |> sba("\n")
-               |> string_builder_to_string()
-               |> print();
-
-       fd: FileDescriptor = -1;
-       err := path_open(3,
-               LookupFlags.SymLinkFollow,
-               string_make(argv[1]),
-               cast(OFlags) 0,
-               Rights.DataSync | Rights.Write | Rights.Read | Rights.Tell | Rights.Seek | Rights.Advise | Rights.PathOpen | Rights.PathCreateFile,
-               Rights.DataSync | Rights.Write | Rights.Read | Rights.Tell | Rights.Seek | Rights.Advise | Rights.PathOpen | Rights.PathCreateFile,
-               FDFlags.Sync,
-               ^fd);
-
-       defer if fd != -1 do fd_close(fd);
-
-
-       if err != Errno.Success {
-               print("Failed to open file\n");
-               print("Error code: ");
-               print_u64_with_base(cast(u64) err, 16l);
-               proc_exit(1);
-       }
-
-       print_u64_with_base(cast(u64) fd, 16l);
-       print("\n");
-
-       filelen : Filesize;
-       if fd_seek(fd, 0l, Whence.End, ^filelen) != Errno.Success {
-               print("Failed to seek in file\n");
-               proc_exit(1);
-       }
-       print("the size is: ");
-       print_u64_with_base(cast(u64) filelen, 10l);
-       print("\n");
-
-       sum := 0l;
-       for i: 0, 20000 do if is_prime(i) do sum += cast(u64) i;
-       print("Sum of primes less than 20000 is: ");
-       print_u64_with_base(sum, 10l);
-       print("\n");
-
-
-       matches := string_split(heap_allocator, "This is a test string to test splitting. It surprisingly works very well.", #char " ");
-       defer free(heap_allocator, matches.tokens);
-
-       string_builder_clear(^sb);
-       for i: 0, matches.count {
-               ^sb |> sba(matches.tokens[i])
-                       |> sba("\n");
-       }
-
-       ^sb |> string_builder_to_string() |> print();
-
-       program := "+ + * s - /";
-       tokens := string_split(heap_allocator, program, #char " ");
-       defer free(heap_allocator, tokens.tokens);
-
-       acc := 0;
-       for i: 0, tokens.count {
-               tok :: tokens.tokens[i].data[0];
-
-               if     tok == #char "+" do acc += 1;
-               elseif tok == #char "-" do acc -= 1;
-               elseif tok == #char "*" do acc *= 2;
-               elseif tok == #char "/" do acc /= 2;
-               elseif tok == #char "s" do acc *= acc;
-       }
-
-       string_builder_clear(^sb);
-       ^sb |> sba("The program evaluated to '") |> sba(cast(u64) acc) |> sba("'\n");
-       ^sb |> string_builder_to_string() |> print();
-       ^sb |> string_builder_clear();
-
-       person := S.{ name = "Tester", age = 45, pos = Vec3.{ 1.0f, 2.0f, 3.0f } };
-       ^sb |> output_s(^person)
-               |> sba("Here is another message in the same string!\n")
-               |> string_builder_to_string()
-               |> print();
+    sb := string_builder_make(heap_allocator, 256);
+
+    timer := timer_start();
+    defer {
+        ^sb |> string_builder_clear()
+            |> sba("Time taken: ")
+            |> sba(cast(u64) timer_end(timer), 10l)
+            |> sba("ms\n")
+            |> string_builder_to_string()
+            |> print();
+    }
+
+    ^sb |> sba("There are ")
+        |> sba(cast(u64) argc)
+        |> sba(" arguments.\n");
+
+    for i: 0, argc do ^sb |> sba(argv[i]) |> sba(" ");
+    ^sb |> sba("\n")
+        |> string_builder_to_string()
+        |> print();
+
+    fd: FileDescriptor = -1;
+    if err := path_open(3,
+        LookupFlags.SymLinkFollow,
+        string_make(argv[1]),
+        cast(OFlags) 0,
+        Rights.DataSync | Rights.Write | Rights.Read | Rights.Tell | Rights.Seek | Rights.Advise | Rights.PathOpen | Rights.PathCreateFile,
+        Rights.DataSync | Rights.Write | Rights.Read | Rights.Tell | Rights.Seek | Rights.Advise | Rights.PathOpen | Rights.PathCreateFile,
+        FDFlags.Sync,
+        ^fd);
+        err != Errno.Success {
+        print("Failed to open file\n");
+        print("Error code: ");
+        print_u64_with_base(cast(u64) err, 16l);
+        proc_exit(1);
+    }
+    defer fd_close(fd);
+
+    print_u64_with_base(cast(u64) fd, 16l);
+    print("\n");
+
+    filelen : Filesize;
+    if fd_seek(fd, 0l, Whence.End, ^filelen) != Errno.Success {
+        print("Failed to seek in file\n");
+        proc_exit(1);
+    }
+    print("the size is: ");
+    print_u64_with_base(cast(u64) filelen, 10l);
+    print("\n");
+
+    sum := 0l;
+    for i: 0, 20000 do if is_prime(i) do sum += cast(u64) i;
+    print("Sum of primes less than 20000 is: ");
+    print_u64_with_base(sum, 10l);
+    print("\n");
+
+
+    matches := string_split(heap_allocator, "This is a test string to test splitting. It surprisingly works very well.", #char " ");
+    defer free(heap_allocator, matches.tokens);
+
+    string_builder_clear(^sb);
+    for i: 0, matches.count {
+        ^sb |> sba(matches.tokens[i])
+            |> sba("\n");
+    }
+
+    ^sb |> string_builder_to_string() |> print();
+
+    program := "+ + * s - /";
+    tokens := string_split(heap_allocator, program, #char " ");
+    defer free(heap_allocator, tokens.tokens);
+
+    acc := 0;
+    for i: 0, tokens.count {
+        tok :: tokens.tokens[i].data[0];
+
+        if     tok == #char "+" do acc += 1;
+        elseif tok == #char "-" do acc -= 1;
+        elseif tok == #char "*" do acc *= 2;
+        elseif tok == #char "/" do acc /= 2;
+        elseif tok == #char "s" do acc *= acc;
+    }
+
+    string_builder_clear(^sb);
+    ^sb |> sba("The program evaluated to '") |> sba(cast(u64) acc) |> sba("'\n");
+    ^sb |> string_builder_to_string() |> print();
+    ^sb |> string_builder_clear();
+
+    person := S.{ name = "Tester", age = 45, pos = Vec3.{ 1.0f, 2.0f, 3.0f } };
+    ^sb |> output_s(^person)
+        |> sba("Here is another message in the same string!\n")
+        |> string_builder_to_string()
+        |> print();
+
+    if res := 5 + 4; res == 9 {
+        ^sb |> string_builder_clear()
+            |> sba("This worked! ")
+            |> sba(cast(u64) ^res)
+            |> sba("\n")
+            |> string_builder_to_string()
+            |> print();
+    } else {
+        ^sb |> string_builder_clear()
+            |> sba("This did not work! ")
+            |> sba(cast(u64) ^res)
+            |> sba("\n")
+            |> string_builder_to_string()
+            |> print();
+    }
+
+    while i := 0; i < 10 {
+        print("Looping\n");
+        i += 1;
+    }
 }
index 77e1972e1682b86ff782cf61e633d538722c1491..67f1a2c54efe217207ac955f9669a06872729310 100644 (file)
@@ -3,19 +3,19 @@
 #include "onyxmsgs.h"
 #include "onyxutils.h"
 
-AstBasicType basic_type_void   = { { Ast_Kind_Basic_Type, 0, NULL, "void"   }, &basic_types[Basic_Kind_Void]  };
-AstBasicType basic_type_bool   = { { Ast_Kind_Basic_Type, 0, NULL, "bool"   }, &basic_types[Basic_Kind_Bool]  };
-AstBasicType basic_type_i8     = { { Ast_Kind_Basic_Type, 0, NULL, "i8"     }, &basic_types[Basic_Kind_I8]    };
-AstBasicType basic_type_u8     = { { Ast_Kind_Basic_Type, 0, NULL, "u8"     }, &basic_types[Basic_Kind_U8]    };
-AstBasicType basic_type_i16    = { { Ast_Kind_Basic_Type, 0, NULL, "i16"    }, &basic_types[Basic_Kind_I16]   };
-AstBasicType basic_type_u16    = { { Ast_Kind_Basic_Type, 0, NULL, "u16"    }, &basic_types[Basic_Kind_U16]   };
-AstBasicType basic_type_i32    = { { Ast_Kind_Basic_Type, 0, NULL, "i32"    }, &basic_types[Basic_Kind_I32]   };
-AstBasicType basic_type_u32    = { { Ast_Kind_Basic_Type, 0, NULL, "u32"    }, &basic_types[Basic_Kind_U32]   };
-AstBasicType basic_type_i64    = { { Ast_Kind_Basic_Type, 0, NULL, "i64"    }, &basic_types[Basic_Kind_I64]   };
-AstBasicType basic_type_u64    = { { Ast_Kind_Basic_Type, 0, NULL, "u64"    }, &basic_types[Basic_Kind_U64]   };
-AstBasicType basic_type_f32    = { { Ast_Kind_Basic_Type, 0, NULL, "f32"    }, &basic_types[Basic_Kind_F32]   };
-AstBasicType basic_type_f64    = { { Ast_Kind_Basic_Type, 0, NULL, "f64"    }, &basic_types[Basic_Kind_F64]   };
-AstBasicType basic_type_rawptr = { { Ast_Kind_Basic_Type, 0, NULL, "rawptr" }, &basic_types[Basic_Kind_Rawptr] };
+AstBasicType basic_type_void   = { Ast_Kind_Basic_Type, 0, NULL, "void"  , &basic_types[Basic_Kind_Void]  };
+AstBasicType basic_type_bool   = { Ast_Kind_Basic_Type, 0, NULL, "bool"  , &basic_types[Basic_Kind_Bool]  };
+AstBasicType basic_type_i8     = { Ast_Kind_Basic_Type, 0, NULL, "i8"    , &basic_types[Basic_Kind_I8]    };
+AstBasicType basic_type_u8     = { Ast_Kind_Basic_Type, 0, NULL, "u8"    , &basic_types[Basic_Kind_U8]    };
+AstBasicType basic_type_i16    = { Ast_Kind_Basic_Type, 0, NULL, "i16"   , &basic_types[Basic_Kind_I16]   };
+AstBasicType basic_type_u16    = { Ast_Kind_Basic_Type, 0, NULL, "u16"   , &basic_types[Basic_Kind_U16]   };
+AstBasicType basic_type_i32    = { Ast_Kind_Basic_Type, 0, NULL, "i32"   , &basic_types[Basic_Kind_I32]   };
+AstBasicType basic_type_u32    = { Ast_Kind_Basic_Type, 0, NULL, "u32"   , &basic_types[Basic_Kind_U32]   };
+AstBasicType basic_type_i64    = { Ast_Kind_Basic_Type, 0, NULL, "i64"   , &basic_types[Basic_Kind_I64]   };
+AstBasicType basic_type_u64    = { Ast_Kind_Basic_Type, 0, NULL, "u64"   , &basic_types[Basic_Kind_U64]   };
+AstBasicType basic_type_f32    = { Ast_Kind_Basic_Type, 0, NULL, "f32"   , &basic_types[Basic_Kind_F32]   };
+AstBasicType basic_type_f64    = { Ast_Kind_Basic_Type, 0, NULL, "f64"   , &basic_types[Basic_Kind_F64]   };
+AstBasicType basic_type_rawptr = { Ast_Kind_Basic_Type, 0, NULL, "rawptr", &basic_types[Basic_Kind_Rawptr] };
 
 static OnyxToken builtin_heap_start_token = { Token_Type_Symbol, 12, "__heap_start ", { 0 } };
 static OnyxToken builtin_stack_top_token  = { Token_Type_Symbol, 11, "__stack_top ",  { 0 } };
index a90494eeea8809ec616a4c7e622e873c433a5e7a..feace16df03ba6673912bbe6b70e99909d1e1a9f 100644 (file)
@@ -9,8 +9,8 @@ CHECK(block, AstBlock* block);
 CHECK(statement_chain, AstNode* start);
 CHECK(statement, AstNode* stmt);
 CHECK(return, AstReturn* retnode);
-CHECK(if, AstIf* ifnode);
-CHECK(while, AstWhile* whilenode);
+CHECK(if, AstIfWhile* ifnode);
+CHECK(while, AstIfWhile* whilenode);
 CHECK(for, AstFor* fornode);
 CHECK(call, AstCall* call);
 CHECK(binaryop, AstBinaryOp** pbinop, b32 assignment_is_ok);
@@ -62,7 +62,9 @@ CHECK(return, AstReturn* retnode) {
     return 0;
 }
 
-CHECK(if, AstIf* ifnode) {
+CHECK(if, AstIfWhile* ifnode) {
+    if (ifnode->assignment != NULL) check_statement((AstNode *) ifnode->assignment);
+
     if (check_expression(&ifnode->cond)) return 1;
 
     if (!type_is_bool(ifnode->cond->type)) {
@@ -78,7 +80,9 @@ CHECK(if, AstIf* ifnode) {
     return 0;
 }
 
-CHECK(while, AstWhile* whilenode) {
+CHECK(while, AstIfWhile* whilenode) {
+    if (whilenode->assignment != NULL) check_statement((AstNode *) whilenode->assignment);
+
     if (check_expression(&whilenode->cond)) return 1;
 
     if (!type_is_bool(whilenode->cond->type)) {
@@ -88,7 +92,10 @@ CHECK(while, AstWhile* whilenode) {
         return 1;
     }
 
-    return check_block(whilenode->stmt);
+    if (whilenode->true_stmt)  if (check_block(whilenode->true_stmt))  return 1;
+    if (whilenode->false_stmt) if (check_block(whilenode->false_stmt)) return 1;
+
+    return 0;
 }
 
 CHECK(for, AstFor* fornode) {
@@ -900,8 +907,8 @@ CHECK(statement, AstNode* stmt) {
         case Ast_Kind_Continue:   return 0;
 
         case Ast_Kind_Return:     return check_return((AstReturn *) stmt);
-        case Ast_Kind_If:         return check_if((AstIf *) stmt);
-        case Ast_Kind_While:      return check_while((AstWhile *) stmt);
+        case Ast_Kind_If:         return check_if((AstIfWhile *) stmt);
+        case Ast_Kind_While:      return check_while((AstIfWhile *) stmt);
         case Ast_Kind_For:        return check_for((AstFor *) stmt);
         case Ast_Kind_Block:      return check_block((AstBlock *) stmt);
         case Ast_Kind_Defer: {
@@ -1113,8 +1120,8 @@ CHECK(node, AstNode* node) {
         case Ast_Kind_Overloaded_Function:  return check_overloaded_function((AstOverloadedFunction *) node);
         case Ast_Kind_Block:                return check_block((AstBlock *) node);
         case Ast_Kind_Return:               return check_return((AstReturn *) node);
-        case Ast_Kind_If:                   return check_if((AstIf *) node);
-        case Ast_Kind_While:                return check_while((AstWhile *) node);
+        case Ast_Kind_If:                   return check_if((AstIfWhile *) node);
+        case Ast_Kind_While:                return check_while((AstIfWhile *) node);
         case Ast_Kind_Call:                 return check_call((AstCall *) node);
         case Ast_Kind_Binary_Op:            return check_binaryop((AstBinaryOp **) &node, 1);
         default:                            return check_expression((AstTyped **) &node);
index 1794b7f09fdeefa463985b151db8fbae62082d5e..bbd2cfa9d01d740d6950bbda7766893a3f0db607 100644 (file)
@@ -27,8 +27,8 @@ static AstNumLit*     parse_float_literal(OnyxParser* parser);
 static b32            parse_possible_struct_literal(OnyxParser* parser, AstTyped** ret);
 static AstTyped*      parse_factor(OnyxParser* parser);
 static AstTyped*      parse_expression(OnyxParser* parser);
-static AstIf*         parse_if_stmt(OnyxParser* parser);
-static AstWhile*      parse_while_stmt(OnyxParser* parser);
+static AstIfWhile*    parse_if_stmt(OnyxParser* parser);
+static AstIfWhile*    parse_while_stmt(OnyxParser* parser);
 static AstFor*        parse_for_stmt(OnyxParser* parser);
 static b32            parse_possible_symbol_declaration(OnyxParser* parser, AstNode** ret);
 static AstReturn*     parse_return_statement(OnyxParser* parser);
@@ -705,15 +705,31 @@ expression_done:
 }
 
 // 'if' <expr> <stmt> ('elseif' <cond> <stmt>)* ('else' <block>)?
-static AstIf* parse_if_stmt(OnyxParser* parser) {
+static AstIfWhile* parse_if_stmt(OnyxParser* parser) {
     expect_token(parser, Token_Type_Keyword_If);
 
+    AstIfWhile* if_node = make_node(AstIfWhile, Ast_Kind_If);
+    AstIfWhile* root_if = if_node;
+
+    if ((parser->curr + 1)->type == ':') {
+        if_node->local = make_node(AstLocal, Ast_Kind_Local);
+        if_node->local->token = expect_token(parser, Token_Type_Symbol);
+
+        expect_token(parser, ':');
+
+        AstBinaryOp* assignment = make_node(AstBinaryOp, Ast_Kind_Binary_Op);
+        assignment->operation = Binary_Op_Assign;
+        assignment->token = expect_token(parser, '=');
+        assignment->left = (AstTyped *) if_node->local;
+        assignment->right = parse_expression(parser);
+
+        if_node->assignment = assignment;
+        expect_token(parser, ';');
+    }
+
     AstTyped* cond = parse_expression(parser);
     AstBlock* true_stmt = parse_block(parser);
 
-    AstIf* if_node = make_node(AstIf, Ast_Kind_If);
-    AstIf* root_if = if_node;
-
     if_node->cond = cond;
     if (true_stmt != NULL)
         if_node->true_stmt = true_stmt;
@@ -722,7 +738,7 @@ static AstIf* parse_if_stmt(OnyxParser* parser) {
         if (parser->hit_unexpected_token) return root_if;
 
         consume_token(parser);
-        AstIf* elseif_node = make_node(AstIf, Ast_Kind_If);
+        AstIfWhile* elseif_node = make_node(AstIfWhile, Ast_Kind_If);
 
         cond = parse_expression(parser);
         true_stmt = parse_block(parser);
@@ -747,16 +763,34 @@ static AstIf* parse_if_stmt(OnyxParser* parser) {
 }
 
 // 'while' <expr> <block>
-static AstWhile* parse_while_stmt(OnyxParser* parser) {
+static AstIfWhile* parse_while_stmt(OnyxParser* parser) {
     OnyxToken* while_token = expect_token(parser, Token_Type_Keyword_While);
+    AstIfWhile* while_node = make_node(AstIfWhile, Ast_Kind_While);
+    while_node->token = while_token;
 
-    AstTyped* cond = parse_expression(parser);
-    AstBlock* stmt = parse_block(parser);
+    if ((parser->curr + 1)->type == ':') {
+        while_node->local = make_node(AstLocal, Ast_Kind_Local);
+        while_node->local->token = expect_token(parser, Token_Type_Symbol);
 
-    AstWhile* while_node = make_node(AstWhile, Ast_Kind_While);
-    while_node->token = while_token;
-    while_node->cond = cond;
-    while_node->stmt = stmt;
+        expect_token(parser, ':');
+
+        AstBinaryOp* assignment = make_node(AstBinaryOp, Ast_Kind_Binary_Op);
+        assignment->operation = Binary_Op_Assign;
+        assignment->token = expect_token(parser, '=');
+        assignment->left = (AstTyped *) while_node->local;
+        assignment->right = parse_expression(parser);
+
+        while_node->assignment = assignment;
+        expect_token(parser, ';');
+    }
+
+    while_node->cond = parse_expression(parser);
+    while_node->true_stmt = parse_block(parser);
+
+    if (parser->curr->type == Token_Type_Keyword_Else) {
+        consume_token(parser);
+        while_node->false_stmt = parse_block(parser);
+    }
 
     return while_node;
 }
index 66206ac5a14c243df629d5ff46507a364b8ecdbc..603e5a6329aba20daab54860b46e1bddf8652f49 100644 (file)
@@ -16,8 +16,8 @@ static void symres_align_of(AstAlignOf* so);
 static void symres_field_access(AstFieldAccess** fa);
 static void symres_expression(AstTyped** expr);
 static void symres_return(AstReturn* ret);
-static void symres_if(AstIf* ifnode);
-static void symres_while(AstWhile* whilenode);
+static void symres_if(AstIfWhile* ifnode);
+static void symres_while(AstIfWhile* whilenode);
 static void symres_for(AstFor* fornode);
 static void symres_statement_chain(AstNode** walker);
 static b32  symres_statement(AstNode** stmt);
@@ -325,22 +325,40 @@ static void symres_return(AstReturn* ret) {
         symres_expression(&ret->expr);
 }
 
-static void symres_if(AstIf* ifnode) {
+static void symres_if(AstIfWhile* ifnode) {
+    if (ifnode->assignment != NULL) {
+        ifnode->scope = scope_create(semstate.node_allocator, semstate.curr_scope);
+        scope_enter(ifnode->scope);
+
+        symbol_introduce(semstate.curr_scope, ifnode->local->token, (AstNode *) ifnode->local);
+
+        symres_statement((AstNode **) &ifnode->assignment);
+    }
+
     symres_expression(&ifnode->cond);
 
-    // BUG: This will not work for the following case:
-    //  if cond foo := 10
-    //  else foo := 20
-    //
-    // The declaration will cause a problem but semantically the above
-    // doesn't make sense.
     if (ifnode->true_stmt != NULL)  symres_statement((AstNode **) &ifnode->true_stmt);
     if (ifnode->false_stmt != NULL) symres_statement((AstNode **) &ifnode->false_stmt);
+
+    if (ifnode->assignment != NULL) scope_leave();
 }
 
-static void symres_while(AstWhile* whilenode) {
+static void symres_while(AstIfWhile* whilenode) {
+    if (whilenode->assignment != NULL) {
+        whilenode->scope = scope_create(semstate.node_allocator, semstate.curr_scope);
+        scope_enter(whilenode->scope);
+
+        symbol_introduce(semstate.curr_scope, whilenode->local->token, (AstNode *) whilenode->local);
+
+        symres_statement((AstNode **) &whilenode->assignment);
+    }
+
     symres_expression(&whilenode->cond);
-    symres_block(whilenode->stmt);
+
+    if (whilenode->true_stmt)  symres_block(whilenode->true_stmt);
+    if (whilenode->false_stmt) symres_block(whilenode->false_stmt);
+
+    if (whilenode->assignment != NULL) scope_leave();
 }
 
 static void symres_for(AstFor* fornode) {
@@ -363,8 +381,8 @@ static b32 symres_statement(AstNode** stmt) {
     switch ((*stmt)->kind) {
         case Ast_Kind_Local:      symres_local((AstLocal **) stmt);                  return 1;
         case Ast_Kind_Return:     symres_return((AstReturn *) *stmt);                return 0;
-        case Ast_Kind_If:         symres_if((AstIf *) *stmt);                        return 0;
-        case Ast_Kind_While:      symres_while((AstWhile *) *stmt);                  return 0;
+        case Ast_Kind_If:         symres_if((AstIfWhile *) *stmt);                   return 0;
+        case Ast_Kind_While:      symres_while((AstIfWhile *) *stmt);                return 0;
         case Ast_Kind_For:        symres_for((AstFor *) *stmt);                      return 0;
         case Ast_Kind_Call:       symres_call((AstCall *) *stmt);                    return 0;
         case Ast_Kind_Argument:   symres_expression((AstTyped **) &((AstArgument *) *stmt)->value); return 0;
index 7c23f9ad1e11250b346212123094a7f74fd4c5a8..dad44852a8d6f31a221478f0deba958d89ab04bc 100644 (file)
@@ -306,6 +306,9 @@ static u64 local_allocate(LocalAllocator* la, AstLocal* local) {
         if (la->max_stack < la->curr_stack)
             la->max_stack = la->curr_stack;
 
+        if (size % alignment != 0)
+            size += alignment - (size % alignment);
+
         if (la->max_stack - la->curr_stack >= size) {
             la->curr_stack += size;
         } else {
@@ -354,8 +357,8 @@ COMPILE_FUNC(statement,                     AstNode* stmt);
 COMPILE_FUNC(assignment,                    AstBinaryOp* assign);
 COMPILE_FUNC(store_instruction,             Type* type, u32 offset);
 COMPILE_FUNC(load_instruction,              Type* type, u32 offset);
-COMPILE_FUNC(if,                            AstIf* if_node);
-COMPILE_FUNC(while,                         AstWhile* while_node);
+COMPILE_FUNC(if,                            AstIfWhile* if_node);
+COMPILE_FUNC(while,                         AstIfWhile* while_node);
 COMPILE_FUNC(for,                           AstFor* for_node);
 COMPILE_FUNC(defer,                         AstDefer* defer);
 COMPILE_FUNC(deferred_stmts,                AstNode* node);
@@ -445,8 +448,8 @@ COMPILE_FUNC(statement, AstNode* stmt) {
 
     switch (stmt->kind) {
         case Ast_Kind_Return:     compile_return(mod, &code, (AstReturn *) stmt); break;
-        case Ast_Kind_If:         compile_if(mod, &code, (AstIf *) stmt); break;
-        case Ast_Kind_While:      compile_while(mod, &code, (AstWhile *) stmt); break;
+        case Ast_Kind_If:         compile_if(mod, &code, (AstIfWhile *) stmt); break;
+        case Ast_Kind_While:      compile_while(mod, &code, (AstIfWhile *) stmt); break;
         case Ast_Kind_For:        compile_for(mod, &code, (AstFor *) stmt); break;
         case Ast_Kind_Break:      compile_structured_jump(mod, &code, ((AstBreak *) stmt)->count); break;
         case Ast_Kind_Continue:   compile_structured_jump(mod, &code, -((AstContinue *) stmt)->count); break;
@@ -635,21 +638,26 @@ COMPILE_FUNC(load_instruction, Type* type, u32 offset) {
     *pcode = code;
 }
 
-COMPILE_FUNC(if, AstIf* if_node) {
+COMPILE_FUNC(if, AstIfWhile* if_node) {
     bh_arr(WasmInstruction) code = *pcode;
 
+    if (if_node->assignment != NULL) {
+        bh_imap_put(&mod->local_map, (u64) if_node->local, local_allocate(mod->local_alloc, if_node->local));
+
+        compile_assignment(mod, &code, if_node->assignment);
+    }
+
     compile_expression(mod, &code, if_node->cond);
     WID(WI_IF_START, 0x40);
 
     bh_arr_push(mod->structured_jump_target, 0);
-
     if (if_node->true_stmt) compile_block(mod, &code, if_node->true_stmt, 0);
 
     if (if_node->false_stmt) {
         WI(WI_ELSE);
 
         if (if_node->false_stmt->kind == Ast_Kind_If) {
-            compile_if(mod, &code, (AstIf *) if_node->false_stmt);
+            compile_if(mod, &code, (AstIfWhile *) if_node->false_stmt);
         } else {
             compile_block(mod, &code, if_node->false_stmt, 0);
         }
@@ -657,33 +665,68 @@ COMPILE_FUNC(if, AstIf* if_node) {
 
     bh_arr_pop(mod->structured_jump_target);
 
+    if (if_node->assignment != NULL) {
+        local_free(mod->local_alloc, if_node->local);
+    }
+
     WI(WI_IF_END);
 
     *pcode = code;
 }
 
-COMPILE_FUNC(while, AstWhile* while_node) {
+COMPILE_FUNC(while, AstIfWhile* while_node) {
     bh_arr(WasmInstruction) code = *pcode;
 
-    WID(WI_BLOCK_START, 0x40);
-    WID(WI_LOOP_START, 0x40);
+    if (while_node->assignment != NULL) {
+        bh_imap_put(&mod->local_map, (u64) while_node->local, local_allocate(mod->local_alloc, while_node->local));
 
-    compile_expression(mod, &code, while_node->cond);
-    WI(WI_I32_EQZ);
-    WID(WI_COND_JUMP, 0x01);
+        compile_assignment(mod, &code, while_node->assignment);
+    }
 
-    bh_arr_push(mod->structured_jump_target, 1);
-    bh_arr_push(mod->structured_jump_target, 2);
+    if (while_node->false_stmt == NULL) {
+        WID(WI_BLOCK_START, 0x40);
+        WID(WI_LOOP_START, 0x40);
 
-    compile_block(mod, &code, while_node->stmt, 0);
+        compile_expression(mod, &code, while_node->cond);
+        WI(WI_I32_EQZ);
+        WID(WI_COND_JUMP, 0x01);
 
-    bh_arr_pop(mod->structured_jump_target);
-    bh_arr_pop(mod->structured_jump_target);
+        bh_arr_push(mod->structured_jump_target, 1);
+        bh_arr_push(mod->structured_jump_target, 2);
 
-    WID(WI_JUMP, 0x00);
+        compile_block(mod, &code, while_node->true_stmt, 0);
 
-    WI(WI_LOOP_END);
-    WI(WI_BLOCK_END);
+        bh_arr_pop(mod->structured_jump_target);
+        bh_arr_pop(mod->structured_jump_target);
+
+        WID(WI_JUMP, 0x00);
+
+        WI(WI_LOOP_END);
+        WI(WI_BLOCK_END);
+
+    } else {
+        compile_expression(mod, &code, while_node->cond);
+
+        bh_arr_push(mod->structured_jump_target, 1);
+        bh_arr_push(mod->structured_jump_target, 2);
+        WID(WI_IF_START, 0x40);
+
+        WID(WI_LOOP_START, 0x40);
+        compile_block(mod, &code, while_node->true_stmt, 0);
+        compile_expression(mod, &code, while_node->cond);
+        WID(WI_COND_JUMP, 0x00);
+        WI(WI_LOOP_END);
+
+        WI(WI_ELSE);
+        compile_block(mod, &code, while_node->false_stmt, 0);
+        WID(WI_IF_END, 0x40);
+
+        bh_arr_pop(mod->structured_jump_target);
+        bh_arr_pop(mod->structured_jump_target);
+    }
+
+    if (while_node->assignment != NULL)
+        local_free(mod->local_alloc, while_node->local);
 
     *pcode = code;
 }