return string.{ len = len, data = s };
}
-
string_length :: proc #overloaded {
proc (s: ^u8) -> u32 {
len := 0;
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.{
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;
[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
- 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
#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))
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;
// 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
//
// '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; };
// 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;
AstBlock *stmt;
};
-struct AstIf {
+struct AstIfWhile {
AstNode_base;
+
+ Scope *scope;
+ AstLocal *local;
+ AstBinaryOp *assignment;
+
AstTyped *cond;
AstBlock *true_stmt;
// 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; };
}
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 {
}
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;
+ }
}
#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 } };
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);
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)) {
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)) {
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) {
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: {
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);
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);
}
// '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;
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);
}
// '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;
}
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);
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) {
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;
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 {
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);
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;
*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);
}
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;
}