From: Brendan Hansen Date: Mon, 24 Aug 2020 02:17:54 +0000 (-0500) Subject: added initializer to if and while; added else on while X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=334622ed8766396049366050abb2976024cd4100;p=onyx.git added initializer to if and while; added else on while --- diff --git a/core/string.onyx b/core/string.onyx index e414f022..c3b41433 100644 --- a/core/string.onyx +++ b/core/string.onyx @@ -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; diff --git a/docs/plan b/docs/plan index 0cc1c40c..0a230bab 100644 --- 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 diff --git a/include/bh.h b/include/bh.h index b0633fc4..d1930ca8 100644 --- a/include/bh.h +++ b/include/bh.h @@ -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)) diff --git a/include/onyxastnodes.h b/include/onyxastnodes.h index aefd7c78..c9814df0 100644 --- a/include/onyxastnodes.h +++ b/include/onyxastnodes.h @@ -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 0acd7e55..4775a53c 100755 Binary files a/onyx and b/onyx differ diff --git a/progs/wasi_test.onyx b/progs/wasi_test.onyx index 5f7dfb93..b7d737df 100644 --- a/progs/wasi_test.onyx +++ b/progs/wasi_test.onyx @@ -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; + } } diff --git a/src/onyxbuiltins.c b/src/onyxbuiltins.c index 77e1972e..67f1a2c5 100644 --- a/src/onyxbuiltins.c +++ b/src/onyxbuiltins.c @@ -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 } }; diff --git a/src/onyxchecker.c b/src/onyxchecker.c index a90494ee..feace16d 100644 --- a/src/onyxchecker.c +++ b/src/onyxchecker.c @@ -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); diff --git a/src/onyxparser.c b/src/onyxparser.c index 1794b7f0..bbd2cfa9 100644 --- a/src/onyxparser.c +++ b/src/onyxparser.c @@ -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' ('elseif' )* ('else' )? -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' -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; } diff --git a/src/onyxsymres.c b/src/onyxsymres.c index 66206ac5..603e5a63 100644 --- a/src/onyxsymres.c +++ b/src/onyxsymres.c @@ -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; diff --git a/src/onyxwasm.c b/src/onyxwasm.c index 7c23f9ad..dad44852 100644 --- a/src/onyxwasm.c +++ b/src/onyxwasm.c @@ -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; }