From a98e93f03f7bd62ebf589b473c61ab5daf37f02c Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 22 Aug 2016 11:52:49 +0100 Subject: [PATCH] File Library and TypeDecl syntax change --- build.bat | 4 +- examples/basic.odin | 9 +- examples/{demo001.odin => demo.odin} | 77 +++------ examples/file.odin | 107 +++++++++++++ examples/game.odin | 7 +- examples/math.odin | 14 +- examples/runtime.odin | 230 ++++++++++++++++++++++++--- examples/win32.odin | 100 ++++++++---- src/checker/checker.cpp | 4 + src/checker/type.cpp | 20 ++- src/codegen/print_llvm.cpp | 31 ++-- src/codegen/ssa.cpp | 5 +- src/gb/gb.h | 6 +- src/main.cpp | 28 ++-- src/parser.cpp | 41 +++-- 15 files changed, 515 insertions(+), 168 deletions(-) rename examples/{demo001.odin => demo.odin} (89%) create mode 100644 examples/file.odin diff --git a/build.bat b/build.bat index 3707dd6e8..ce58a8839 100644 --- a/build.bat +++ b/build.bat @@ -45,8 +45,8 @@ pushd %build_dir% cl %compiler_settings% "..\src\main.cpp" ^ /link %linker_settings% -OUT:%exe_name% ^ - && odin run ..\examples/demo001.odin - rem odin run ..\examples/demo001.odin + && odin run ..\examples/demo.odin + rem odin run ..\examples/demo.odin :do_not_compile_exe diff --git a/examples/basic.odin b/examples/basic.odin index 548f93fff..2341d7f80 100644 --- a/examples/basic.odin +++ b/examples/basic.odin @@ -1,9 +1,9 @@ #load "runtime.odin" +#load "win32.odin" +#load "file.odin" print_string :: proc(s: string) { - for i := 0; i < len(s); i++ { - putchar(s[i] as i32); - } + file_write(file_get_standard(FILE_STANDARD_OUTPUT), ^s[0], len(s)); } byte_reverse :: proc(b: []byte) { @@ -53,6 +53,9 @@ print_rune :: proc(r: rune) { print_string(str); } +print_space :: proc() { print_rune(' '); } +print_nl :: proc() { print_rune('\n'); } + print_int :: proc(i: int) { print_int_base(i, 10); } diff --git a/examples/demo001.odin b/examples/demo.odin similarity index 89% rename from examples/demo001.odin rename to examples/demo.odin index f0ac2f4db..cc909e9d3 100644 --- a/examples/demo001.odin +++ b/examples/demo.odin @@ -4,12 +4,12 @@ #load "game.odin" main :: proc() { - _ = hellope(); - procedures(); - variables(); - constants(); - types(); - data_control(); + // _ = hellope(); + // procedures(); + // variables(); + // constants(); + // types(); + // data_control(); run_game(); } @@ -263,21 +263,21 @@ types :: proc() { - type Vec4: {4}f32; - type Array3Int: [3]int; + Vec4 :: type {4}f32; + Array3Int :: type [3]int; - type Vec3: struct { + Vec3 :: type struct { x, y, z: f32 } - type BinaryNode: struct { + BinaryNode :: type struct { left, right: ^BinaryNode, // same format as procedure argument data: rawptr, } - type AddProc: proc(a, b: int) -> int + AddProc :: type proc(a, b: int) -> int - type Packed: struct #packed { + Packed :: type struct #packed { a: u8, b: u16, c: u32, @@ -286,7 +286,7 @@ types :: proc() { { - type MyInt: int + MyInt :: type int; x: int = 1; y: MyInt = 2; // z := x + y; // Failure - types cannot implicit convert* @@ -347,7 +347,7 @@ types :: proc() { f := {4}f32{1}; // broadcasts to all // g := {4}f32{1, 2}; // require either 1 or 4 elements - type Vec2: {2}f32; + Vec2 :: type {2}f32; h := Vec2{1, 2}; @@ -428,7 +428,7 @@ void main() { { // size, align, offset - type Thing: struct { + Thing :: type struct { a: u8, b: u16, c, d, e: u32, @@ -527,46 +527,17 @@ data_control :: proc() { context.allocator = __default_allocator(); defer context.allocator = prev_allocator; - // C strings, yuk! - to_c_string := proc(s: string) -> ^u8 { - c := alloc(len(s)+1) as ^u8; - mem_copy(c, ^s[0], len(s)); - c[len(s)] = 0; - return c; - }; - - - fopen :: proc(filename, mode: ^u8) -> rawptr #foreign - fclose :: proc(f: rawptr) -> i32 #foreign - - filename := to_c_string("../examples/base.odin"); - mode := to_c_string("rb"); - defer dealloc(filename); - defer dealloc(mode); - - f := fopen(filename, mode); - if f == null { + /* + type File: struct { filename: string } + type FileError: int + open_file :: proc(filename: string) -> (File, FileError) { ... } + close_file :: proc(f: ^File) { ... } + f, err := open_file("Test"); + if err != 0 { // handle error } - defer if f != null { - _ = fclose(f); - } - - // rest of code - - // Better version - /* - type File: struct { filename: string } - type FileError: int - open_file :: proc(filename: string) -> (File, FileError) { ... } - close_file :: proc(f: ^File) { ... } - f, err := open_file("Test"); - if err != 0 { - // handle error - } - defer close_file(^f); - - */ + defer close_file(^f); + */ } diff --git a/examples/file.odin b/examples/file.odin new file mode 100644 index 000000000..6c2654168 --- /dev/null +++ b/examples/file.odin @@ -0,0 +1,107 @@ +#load "win32.odin" + +FileHandle :: type HANDLE; + +File :: type struct { + handle: FileHandle, +} + +file_open :: proc(name: string) -> (File, bool) { + buf: [300]byte; + _ = copy(buf[:], name as []byte); + handle := CreateFileA(^buf[0], FILE_GENERIC_READ, FILE_SHARE_READ, null, OPEN_EXISTING, 0, null); + + f: File; + f.handle = handle as FileHandle; + success := f.handle != INVALID_HANDLE_VALUE as FileHandle; + return f, success; +} + +file_create :: proc(name: string) -> (File, bool) { + buf: [300]byte; + _ = copy(buf[:], name as []byte); + handle := CreateFileA(^buf[0], FILE_GENERIC_WRITE, FILE_SHARE_READ, null, CREATE_ALWAYS, 0, null); + + f: File; + f.handle = handle as FileHandle; + success := f.handle != INVALID_HANDLE_VALUE as FileHandle; + return f, success; +} + + +file_close :: proc(f: ^File) { + CloseHandle(f.handle); +} + +file_write :: proc(f: ^File, buf: rawptr, len: int) -> bool { + bytes_written: i32; + return WriteFile(f.handle, buf, len as i32, ^bytes_written, null) != 0; +} + +FileStandardType :: type int; +FILE_STANDARD_INPUT : FileStandardType : 0; +FILE_STANDARD_OUTPUT : FileStandardType : 1; +FILE_STANDARD_ERROR : FileStandardType : 2; +FILE_STANDARD__COUNT : FileStandardType : 3; + +__std_file_set := false; +__std_files: [FILE_STANDARD__COUNT]File; + +file_get_standard :: proc(std: FileStandardType) -> ^File { + if (!__std_file_set) { + __std_files[FILE_STANDARD_INPUT] .handle = GetStdHandle(STD_INPUT_HANDLE); + __std_files[FILE_STANDARD_OUTPUT].handle = GetStdHandle(STD_OUTPUT_HANDLE); + __std_files[FILE_STANDARD_ERROR] .handle = GetStdHandle(STD_ERROR_HANDLE); + __std_file_set = true; + } + return ^__std_files[std as int]; +} + + +read_entire_file :: proc(name: string) -> (string, bool) { + buf: [300]byte; + _ = copy(buf[:], name as []byte); + c_string := ^buf[0]; + + + f, file_ok := file_open(name); + if !file_ok { + return "", false; + } + defer file_close(^f); + + length: i64; + file_size_ok := GetFileSizeEx(f.handle as HANDLE, ^length) != 0; + if !file_size_ok { + return "", false; + } + + data: ^u8 = alloc(length as int); + if data == null { + return "", false; + } + + single_read_length: i32; + total_read: i64; + + for total_read < length { + remaining := length - total_read; + to_read: u32; + MAX :: 0x7fffffff; + if remaining <= MAX { + to_read = remaining as u32; + } else { + to_read = MAX; + } + + ReadFile(f.handle as HANDLE, ^data[total_read], to_read, ^single_read_length, null); + if single_read_length <= 0 { + dealloc(data); + return "", false; + } + + total_read += single_read_length as i64; + } + + return data[:length] as string, true; +} diff --git a/examples/game.odin b/examples/game.odin index 7f5ae4e57..6a1579057 100644 --- a/examples/game.odin +++ b/examples/game.odin @@ -1,5 +1,4 @@ #load "basic.odin" -#load "win32.odin" #load "opengl.odin" #load "math.odin" @@ -28,13 +27,13 @@ win32_print_last_error :: proc() { // Yuk! to_c_string :: proc(s: string) -> ^u8 { c_str: ^u8 = heap_alloc(len(s)+1); - mem_copy(c_str, ^s[0], len(s)); + memory_copy(c_str, ^s[0], len(s)); c_str[len(s)] = 0; return c_str; } -type Window: struct { +Window :: type struct { width, height: int, wc: WNDCLASSEXA, dc: HDC, @@ -123,7 +122,7 @@ display_window :: proc(w: ^Window) { } -type Entity: struct { +Entity :: type struct { pos: Vec2, dim: Vec2, } diff --git a/examples/math.odin b/examples/math.odin index ba0fbc33e..af3c8a6d4 100644 --- a/examples/math.odin +++ b/examples/math.odin @@ -13,14 +13,16 @@ MATH_LOG_TEN :: 2.30258509299404568401799145468436421; MATH_EPSILON :: 1.19209290e-7; +τ :: MATH_TAU; +π :: MATH_PI; -type Vec2: {2}f32 -type Vec3: {3}f32 -type Vec4: {4}f32 +Vec2 :: type {2}f32; +Vec3 :: type {3}f32; +Vec4 :: type {4}f32; -type Mat2: {4}f32 -type Mat3: {9}f32 -type Mat4: {16}f32 +Mat2 :: type {4}f32; +Mat3 :: type {9}f32; +Mat4 :: type {16}f32; fsqrt :: proc(x: f32) -> f32 #foreign "llvm.sqrt.f32" diff --git a/examples/runtime.odin b/examples/runtime.odin index 49dfae29a..22adf04ef 100644 --- a/examples/runtime.odin +++ b/examples/runtime.odin @@ -1,17 +1,203 @@ -putchar :: proc(c: i32) -> i32 #foreign - -mem_compare :: proc(dst, src : rawptr, len: int) -> i32 #foreign "memcmp" -mem_copy :: proc(dst, src : rawptr, len: int) -> i32 #foreign "memcpy" -mem_move :: proc(dst, src : rawptr, len: int) -> i32 #foreign "memmove" - debug_trap :: proc() #foreign "llvm.debugtrap" // TODO(bill): make custom heap procedures -heap_realloc :: proc(ptr: rawptr, sz: int) -> rawptr #foreign "realloc" -heap_alloc :: proc(sz: int) -> rawptr { return heap_realloc(null, sz); } -heap_free :: proc(ptr: rawptr) { _ = heap_realloc(ptr, 0); } +heap_alloc :: proc(len: int) -> rawptr { + return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len); +} +heap_free :: proc(ptr: rawptr) { + _ = HeapFree(GetProcessHeap(), 0, ptr); +} + +memory_compare :: proc(dst, src: rawptr, len: int) -> int { + s1, s2: ^u8 = dst, src; + for i := 0; i < len; i++ { + if s1[i] != s2[i] { + return (s1[i] - s2[i]) as int; + } + } + return 0; +} + +memory_copy :: proc(dst, src: rawptr, n: int) #inline { + if dst == src { + return; + } + + v128b :: type {4}u32; + static_assert(align_of(v128b) == 16); + + d, s: ^u8 = dst, src; + + for ; s as uint % 16 != 0 && n != 0; n-- { + d[0] = s[0]; + d, s = ^d[1], ^s[1]; + } + + if d as uint % 16 == 0 { + for ; n >= 16; d, s, n = ^d[16], ^s[16], n-16 { + (d as ^v128b)[0] = (s as ^v128b)[0]; + } + + if n&8 != 0 { + (d as ^u64)[0] = (s as ^u64)[0]; + d, s = ^d[8], ^s[8]; + } + if n&4 != 0 { + (d as ^u32)[0] = (s as ^u32)[0]; + d, s = ^d[4], ^s[4]; + } + if n&2 != 0 { + (d as ^u16)[0] = (s as ^u16)[0]; + d, s = ^d[2], ^s[2]; + } + if n&1 != 0 { + d[0] = s[0]; + d, s = ^d[1], ^s[1]; + } + return; + } + + // IMPORTANT NOTE(bill): Little endian only + LS :: proc(a, b: u32) -> u32 #inline { return a << b; } + RS :: proc(a, b: u32) -> u32 #inline { return a >> b; } + /* NOTE(bill): Big endian version + LS :: proc(a, b: u32) -> u32 #inline { return a >> b; } + RS :: proc(a, b: u32) -> u32 #inline { return a << b; } + */ + + w, x: u32; + + if d as uint % 4 == 1 { + w = (s as ^u32)^; + d[0] = s[0]; + d[1] = s[1]; + d[2] = s[2]; + d, s, n = ^d[3], ^s[3], n-3; + + for n > 16 { + d32 := d as ^u32; + x = (^s[1] as ^u32)^; d32[0] = LS(w, 24) | RS(x, 8); + w = (^s[5] as ^u32)^; d32[1] = LS(x, 24) | RS(w, 8); + x = (^s[9] as ^u32)^; d32[2] = LS(w, 24) | RS(x, 8); + w = (^s[13] as ^u32)^; d32[3] = LS(x, 24) | RS(w, 8); + + d, s, n = ^d[16], ^s[16], n-16; + } + + } else if d as uint % 4 == 2 { + w = (s as ^u32)^; + d[0] = s[0]; + d[1] = s[1]; + d, s, n = ^d[2], ^s[2], n-2; + + for n > 17 { + d32 := d as ^u32; + x = (^s[2] as ^u32)^; d32[0] = LS(w, 16) | RS(x, 16); + w = (^s[6] as ^u32)^; d32[1] = LS(x, 16) | RS(w, 16); + x = (^s[10] as ^u32)^; d32[2] = LS(w, 16) | RS(x, 16); + w = (^s[14] as ^u32)^; d32[3] = LS(x, 16) | RS(w, 16); + + d, s, n = ^d[16], ^s[16], n-16; + } + + } else if d as uint % 4 == 3 { + w = (s as ^u32)^; + d[0] = s[0]; + d, s, n = ^d[1], ^s[1], n-1; + + for n > 18 { + d32 := d as ^u32; + x = (^s[3] as ^u32)^; d32[0] = LS(w, 8) | RS(x, 24); + w = (^s[7] as ^u32)^; d32[1] = LS(x, 8) | RS(w, 24); + x = (^s[11] as ^u32)^; d32[2] = LS(w, 8) | RS(x, 24); + w = (^s[15] as ^u32)^; d32[3] = LS(x, 8) | RS(w, 24); + + d, s, n = ^d[16], ^s[16], n-16; + } + } + + if n&16 != 0 { + (d as ^v128b)[0] = (s as ^v128b)[0]; + d, s = ^d[16], ^s[16]; + } + if n&8 != 0 { + (d as ^u64)[0] = (s as ^u64)[0]; + d, s = ^d[8], ^s[8]; + } + if n&4 != 0 { + (d as ^u32)[0] = (s as ^u32)[0]; + d, s = ^d[4], ^s[4]; + } + if n&2 != 0 { + (d as ^u16)[0] = (s as ^u16)[0]; + d, s = ^d[2], ^s[2]; + } + if n&1 != 0 { + d[0] = s[0]; + } +} + +memory_move :: proc(dst, src: rawptr, n: int) #inline { + d, s: ^u8 = dst, src; + if d == s { + return; + } + if d >= ^s[n] || ^d[n] <= s { + memory_copy(d, s, n); + return; + } + + // TODO(bill): Vectorize the shit out of this + if d < s { + if s as int % size_of(int) == d as int % size_of(int) { + for d as int % size_of(int) != 0 { + if n == 0 { + return; + } + n--; + d[0] = s[0]; + d, s = ^d[1], ^s[1]; + } + di, si := d as ^int, s as ^int; + for n >= size_of(int) { + di[0] = si[0]; + di, si = ^di[1], ^si[1]; + n -= size_of(int); + } + } + for ; n > 0; n-- { + d[0] = s[0]; + d, s = ^d[1], ^s[1]; + } + } else { + if s as int % size_of(int) == d as int % size_of(int) { + for ^d[n] as int % size_of(int) != 0 { + if n == 0 { + return; + } + n--; + d[0] = s[0]; + d, s = ^d[1], ^s[1]; + } + for n >= size_of(int) { + n -= size_of(int); + di, si := ^d[n] as ^int, ^s[n] as ^int; + di[0] = si[0]; + } + for ; n > 0; n-- { + d[0] = s[0]; + d, s = ^d[1], ^s[1]; + } + } + for n > 0 { + n--; + d[n] = s[n]; + } + } +} + __string_eq :: proc(a, b : string) -> bool { if len(a) != len(b) { return false; @@ -19,10 +205,10 @@ __string_eq :: proc(a, b : string) -> bool { if ^a[0] == ^b[0] { return true; } - return mem_compare(^a[0], ^b[0], len(a)) == 0; + return memory_compare(^a[0], ^b[0], len(a)) == 0; } -__string_ne :: proc(a, b : string) -> bool { +__string_ne :: proc(a, b : string) -> bool #inline { return !__string_eq(a, b); } @@ -48,30 +234,30 @@ __string_cmp :: proc(a, b : string) -> int { return 0; } -__string_lt :: proc(a, b : string) -> bool { return __string_cmp(a, b) < 0; } -__string_gt :: proc(a, b : string) -> bool { return __string_cmp(a, b) > 0; } -__string_le :: proc(a, b : string) -> bool { return __string_cmp(a, b) <= 0; } -__string_ge :: proc(a, b : string) -> bool { return __string_cmp(a, b) >= 0; } +__string_lt :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) < 0; } +__string_gt :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) > 0; } +__string_le :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) <= 0; } +__string_ge :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) >= 0; } -type AllocationMode: int; +AllocationMode :: type int; ALLOCATION_ALLOC :: 0; ALLOCATION_DEALLOC :: 1; ALLOCATION_DEALLOC_ALL :: 2; ALLOCATION_RESIZE :: 3; -type AllocatorProc: proc(allocator_data: rawptr, mode: AllocationMode, - size, alignment: int, - old_memory: rawptr, old_size: int, flags: u64) -> rawptr; +AllocatorProc :: type proc(allocator_data: rawptr, mode: AllocationMode, + size, alignment: int, + old_memory: rawptr, old_size: int, flags: u64) -> rawptr; -type Allocator: struct { +Allocator :: type struct { procedure: AllocatorProc, data: rawptr, } -type Context: struct { +Context :: type struct { thread_id: i32, user_index: i32, @@ -157,7 +343,7 @@ __default_allocator_proc :: proc(allocator_data: rawptr, mode: AllocationMode, if mode == ALLOCATION_ALLOC { return heap_alloc(size); } else if mode == ALLOCATION_RESIZE { - return heap_realloc(old_memory, size); + return default_resize_align(old_memory, old_size, size, alignment); } else if mode == ALLOCATION_DEALLOC { heap_free(old_memory); } else if mode == ALLOCATION_DEALLOC_ALL { diff --git a/examples/win32.odin b/examples/win32.odin index 13bddc4f7..2a8beb450 100644 --- a/examples/win32.odin +++ b/examples/win32.odin @@ -1,7 +1,3 @@ -STD_INPUT_HANDLE :: -10; -STD_OUTPUT_HANDLE :: -11; -STD_ERROR_HANDLE :: -12; - CS_VREDRAW :: 1; CS_HREDRAW :: 2; CW_USEDEFAULT :: 0x80000000; @@ -21,27 +17,29 @@ WM_QUIT :: 0x12; PM_REMOVE :: 1; -COLOR_BACKGROUND: rawptr : 1; // NOTE(bill): cast to HBRUSH when needed +COLOR_BACKGROUND :: 1 as HBRUSH; -type HANDLE: rawptr -type HWND: HANDLE -type HDC: HANDLE -type HINSTANCE: HANDLE -type HICON: HANDLE -type HCURSOR: HANDLE -type HMENU: HANDLE -type HBRUSH: HANDLE -type WPARAM: uint -type LPARAM: int -type LRESULT: int -type ATOM: i16 -type BOOL: i32 -type POINT: struct { x, y: i32 } +HANDLE :: type rawptr; +HWND :: type HANDLE; +HDC :: type HANDLE; +HINSTANCE :: type HANDLE; +HICON :: type HANDLE; +HCURSOR :: type HANDLE; +HMENU :: type HANDLE; +HBRUSH :: type HANDLE; +WPARAM :: type uint; +LPARAM :: type int; +LRESULT :: type int; +ATOM :: type i16; +BOOL :: type i32; +POINT :: type struct { x, y: i32 }; -type WNDPROC: proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT +INVALID_HANDLE_VALUE :: (-1 as int) as HANDLE; -type WNDCLASSEXA: struct { +WNDPROC :: type proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT + +WNDCLASSEXA :: type struct { size, style: u32, wnd_proc: WNDPROC, cls_extra, wnd_extra: i32, @@ -53,7 +51,7 @@ type WNDCLASSEXA: struct { sm: HICON, } -type MSG: struct { +MSG :: type struct { hwnd: HWND, message: u32, wparam: WPARAM, @@ -63,9 +61,7 @@ type MSG: struct { } -GetStdHandle :: proc(h: i32) -> HANDLE #foreign -CloseHandle :: proc(h: HANDLE) -> i32 #foreign -WriteFileA :: proc(h: HANDLE, buf: rawptr, len: i32, written_result: ^i32, overlapped: rawptr) -> i32 #foreign + GetLastError :: proc() -> i32 #foreign ExitProcess :: proc(exit_code: u32) #foreign GetDesktopWindow :: proc() -> HWND #foreign @@ -113,6 +109,52 @@ GetQueryPerformanceFrequency :: proc() -> i64 { +// File Stuff + +CloseHandle :: proc(h: HANDLE) -> i32 #foreign +GetStdHandle :: proc(h: i32) -> HANDLE #foreign +CreateFileA :: proc(filename: ^u8, desired_access, share_mode: u32, + security: rawptr, + creation, flags_and_attribs: u32, template_file: HANDLE) -> HANDLE #foreign +ReadFile :: proc(h: HANDLE, buf: rawptr, to_read: u32, bytes_read: ^i32, overlapped: rawptr) -> BOOL #foreign +WriteFile :: proc(h: HANDLE, buf: rawptr, len: i32, written_result: ^i32, overlapped: rawptr) -> i32 #foreign + +GetFileSizeEx :: proc(file_handle: HANDLE, file_size: ^i64) -> BOOL #foreign + +FILE_SHARE_READ :: 0x00000001; +FILE_SHARE_WRITE :: 0x00000002; +FILE_SHARE_DELETE :: 0x00000004; +FILE_GENERIC_ALL :: 0x10000000; +FILE_GENERIC_EXECUTE :: 0x20000000; +FILE_GENERIC_WRITE :: 0x40000000; +FILE_GENERIC_READ :: 0x80000000; + +STD_INPUT_HANDLE :: -10; +STD_OUTPUT_HANDLE :: -11; +STD_ERROR_HANDLE :: -12; + +CREATE_NEW :: 1; +CREATE_ALWAYS :: 2; +OPEN_EXISTING :: 3; +OPEN_ALWAYS :: 4; +TRUNCATE_EXISTING :: 5; + + +HeapAlloc :: proc(h: HANDLE, flags: u32, bytes: int) -> rawptr #foreign +HeapFree :: proc(h: HANDLE, flags: u32, memory: rawptr) -> BOOL #foreign +GetProcessHeap :: proc() -> HANDLE #foreign + +HEAP_ZERO_MEMORY :: 0x00000008; + + + + + + + + + + // Windows OpenGL @@ -139,12 +181,12 @@ PFD_DEPTH_DONTCARE :: 0x20000000; PFD_DOUBLEBUFFER_DONTCARE :: 0x40000000; PFD_STEREO_DONTCARE :: 0x80000000; -type HGLRC: HANDLE -type PROC: proc() -type wglCreateContextAttribsARBType: proc(hdc: HDC, hshareContext: rawptr, attribList: ^i32) -> HGLRC +HGLRC :: type HANDLE; +PROC :: type proc(); +wglCreateContextAttribsARBType :: type proc(hdc: HDC, hshareContext: rawptr, attribList: ^i32) -> HGLRC; -type PIXELFORMATDESCRIPTOR: struct { +PIXELFORMATDESCRIPTOR :: type struct { size, version, flags: u32, diff --git a/src/checker/checker.cpp b/src/checker/checker.cpp index d16cb3ad2..2a084c543 100644 --- a/src/checker/checker.cpp +++ b/src/checker/checker.cpp @@ -343,6 +343,10 @@ void init_universal_scope(void) { entity->Builtin.id = id; add_global_entity(entity); } + +// Custom Runtime Types + { + } } diff --git a/src/checker/type.cpp b/src/checker/type.cpp index e3af314ae..6613228e6 100644 --- a/src/checker/type.cpp +++ b/src/checker/type.cpp @@ -288,21 +288,25 @@ b32 is_type_named(Type *t) { return t->kind == Type_Named; } b32 is_type_boolean(Type *t) { + t = get_base_type(t); if (t->kind == Type_Basic) return (t->basic.flags & BasicFlag_Boolean) != 0; return false; } b32 is_type_integer(Type *t) { + t = get_base_type(t); if (t->kind == Type_Basic) return (t->basic.flags & BasicFlag_Integer) != 0; return false; } b32 is_type_unsigned(Type *t) { + t = get_base_type(t); if (t->kind == Type_Basic) return (t->basic.flags & BasicFlag_Unsigned) != 0; return false; } b32 is_type_numeric(Type *t) { + t = get_base_type(t); if (t->kind == Type_Basic) return (t->basic.flags & BasicFlag_Numeric) != 0; if (t->kind == Type_Vector) @@ -310,36 +314,45 @@ b32 is_type_numeric(Type *t) { return false; } b32 is_type_string(Type *t) { + t = get_base_type(t); if (t->kind == Type_Basic) return (t->basic.flags & BasicFlag_String) != 0; return false; } b32 is_type_typed(Type *t) { + t = get_base_type(t); if (t->kind == Type_Basic) return (t->basic.flags & BasicFlag_Untyped) == 0; return true; } b32 is_type_untyped(Type *t) { + t = get_base_type(t); if (t->kind == Type_Basic) return (t->basic.flags & BasicFlag_Untyped) != 0; return false; } b32 is_type_ordered(Type *t) { + t = get_base_type(t); if (t->kind == Type_Basic) return (t->basic.flags & BasicFlag_Ordered) != 0; + if (t->kind == Type_Pointer) + return true; return false; } b32 is_type_constant_type(Type *t) { + t = get_base_type(t); if (t->kind == Type_Basic) return (t->basic.flags & BasicFlag_ConstantType) != 0; return false; } b32 is_type_float(Type *t) { + t = get_base_type(t); if (t->kind == Type_Basic) return (t->basic.flags & BasicFlag_Float) != 0; return false; } b32 is_type_pointer(Type *t) { + t = get_base_type(t); if (t->kind == Type_Basic) return (t->basic.flags & BasicFlag_Pointer) != 0; return t->kind == Type_Pointer; @@ -361,9 +374,11 @@ b32 is_type_u8(Type *t) { return false; } b32 is_type_slice(Type *t) { + t = get_base_type(t); return t->kind == Type_Slice; } b32 is_type_u8_slice(Type *t) { + t = get_base_type(t); if (t->kind == Type_Slice) return is_type_u8(t->slice.elem); return false; @@ -372,6 +387,7 @@ b32 is_type_vector(Type *t) { return t->kind == Type_Vector; } b32 is_type_proc(Type *t) { + t = get_base_type(t); return t->kind == Type_Proc; } Type *base_vector_type(Type *t) { @@ -548,8 +564,10 @@ i64 type_align_of(BaseTypeSizes s, gbAllocator allocator, Type *t) { return type_align_of(s, allocator, t->array.elem); case Type_Vector: { i64 size = type_size_of(s, allocator, t->vector.elem); + size *= t->vector.count; + size = next_pow2(size); // TODO(bill): Type_Vector type_align_of - return gb_clamp(size, s.max_align, 2*s.max_align); + return gb_clamp(size, s.max_align, 4*s.max_align); } break; case Type_Structure: { diff --git a/src/codegen/print_llvm.cpp b/src/codegen/print_llvm.cpp index d3974d17c..6a983d09d 100644 --- a/src/codegen/print_llvm.cpp +++ b/src/codegen/print_llvm.cpp @@ -219,7 +219,11 @@ void ssa_print_exact_value(gbFile *f, ssaModule *m, ExactValue value, Type *type if (value.value_integer == 0) { ssa_fprintf(f, "null"); } else { - GB_PANIC("TODO(bill): Pointer constant"); + ssa_fprintf(f, "inttoptr ("); + ssa_print_type(f, m->sizes, t_int); + ssa_fprintf(f, " %llu to ", value.value_integer); + ssa_print_type(f, m->sizes, t_rawptr); + ssa_fprintf(f, ")"); } } else { ssa_fprintf(f, "%lld", value.value_integer); @@ -241,7 +245,11 @@ void ssa_print_exact_value(gbFile *f, ssaModule *m, ExactValue value, Type *type if (value.value_pointer == NULL) { ssa_fprintf(f, "null"); } else { - GB_PANIC("TODO(bill): ExactValue_Pointer"); + ssa_fprintf(f, "inttoptr ("); + ssa_print_type(f, m->sizes, t_int); + ssa_fprintf(f, " %llu to ", cast(u64)cast(uintptr)value.value_pointer); + ssa_print_type(f, m->sizes, t_rawptr); + ssa_fprintf(f, ")"); } break; default: @@ -580,8 +588,7 @@ void ssa_print_instr(gbFile *f, ssaModule *m, ssaValue *value) { } break; case ssaInstr_MemCopy: { - ssa_fprintf(f, "call void @llvm.memmove.p0i8.p0i8."); - ssa_print_type(f, m->sizes, t_int); + ssa_fprintf(f, "call void @memory_move"); ssa_fprintf(f, "(i8* "); ssa_print_value(f, m, instr->CopyMemory.dst, t_rawptr); ssa_fprintf(f, ", i8* "); @@ -590,11 +597,7 @@ void ssa_print_instr(gbFile *f, ssaModule *m, ssaValue *value) { ssa_print_type(f, m->sizes, t_int); ssa_fprintf(f, " "); ssa_print_value(f, m, instr->CopyMemory.len, t_int); - char *vol_str = "false"; - if (instr->CopyMemory.is_volatile) { - vol_str = "true"; - } - ssa_fprintf(f, ", i32 %d, i1 %s)\n", instr->CopyMemory.align, vol_str); + ssa_fprintf(f, ")\n"); } break; @@ -671,7 +674,7 @@ void ssa_print_instr(gbFile *f, ssaModule *m, ssaValue *value) { void ssa_print_proc(gbFile *f, ssaModule *m, ssaProcedure *proc) { if (proc->body == NULL) { - ssa_fprintf(f, "declare "); + ssa_fprintf(f, "\ndeclare "); } else { ssa_fprintf(f, "\ndefine "); } @@ -777,14 +780,6 @@ void ssa_print_llvm_ir(gbFile *f, ssaModule *m) { } - ssa_fprintf(f, "declare void @llvm.memmove.p0i8.p0i8."); - ssa_print_type(f, m->sizes, t_int); - ssa_fprintf(f, "(i8*, i8*, "); - ssa_print_type(f, m->sizes, t_int); - ssa_fprintf(f, ", i32, i1) argmemonly nounwind \n\n"); - - - gb_for_array(member_index, m->members.entries) { auto *entry = &m->members.entries[member_index]; ssaValue *v = entry->value; diff --git a/src/codegen/ssa.cpp b/src/codegen/ssa.cpp index 7760b725e..0d9780e74 100644 --- a/src/codegen/ssa.cpp +++ b/src/codegen/ssa.cpp @@ -811,9 +811,10 @@ void ssa_emit_defer_stmts(ssaProcedure *proc, ssaDeferKind kind, ssaBlock *block while (i --> 0) { ssaDefer d = proc->defer_stmts[i]; if (kind == ssaDefer_Return) { - ssa_build_defer_stmt(proc, d); + ssa_build_defer_stmt(proc, d); } else if (kind == ssaDefer_Default) { - if (proc->scope_index == d.scope_index) { + if (proc->scope_index == d.scope_index && + d.scope_index > 1) { ssa_build_defer_stmt(proc, d); gb_array_pop(proc->defer_stmts); continue; diff --git a/src/gb/gb.h b/src/gb/gb.h index a75d6d97d..94671e1fd 100644 --- a/src/gb/gb.h +++ b/src/gb/gb.h @@ -3616,9 +3616,9 @@ gb_inline void gb_zero_size(void *ptr, isize size) { gb_memset(ptr, 0, size); } gb_inline void *gb_memcopy(void *dest, void const *source, isize n) { #if defined(_MSC_VER) // TODO(bill): Is this good enough? - __movsb(cast(u8 *gb_restrict)dest, cast(u8 *gb_restrict)source, n); + __movsb(cast(u8 *)dest, cast(u8 *)source, n); #elif defined(GB_CPU_X86) - __asm__ __volatile__("rep movsb" : "+D"(cast(u8 *gb_restrict)dest), "+S"(cast(u8 *gb_restrict)source), "+c"(n) : : "memory"); + __asm__ __volatile__("rep movsb" : "+D"(cast(u8 *)dest), "+S"(cast(u8 *)source), "+c"(n) : : "memory"); #else u8 *d = cast(u8 *)dest; u8 const *s = cast(u8 const *)source; @@ -5753,7 +5753,7 @@ void gb_sort(void *base_, isize count, isize size, gbCompareProc cmp) { Type radix_piece = (radix_value >> byte_index) & 0xff; \ dest[offsets[radix_piece]++] = source[i]; \ } \ - gb_swap(Type *gb_restrict, source, dest); \ + gb_swap(Type *, source, dest); \ } \ } diff --git a/src/main.cpp b/src/main.cpp index b641ac89d..df9bd5205 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -80,19 +80,23 @@ int main(int argc, char **argv) { i32 exit_code = win32_exec_command_line_app( "../misc/llvm-bin/opt -mem2reg %s -o %.*s.bc", output_name, cast(int)base_name_len, output_name); - if (exit_code == 0) { - win32_exec_command_line_app( - "clang -o %.*s.exe %.*s.bc -Wno-override-module " - "-lKernel32.lib -lUser32.lib -lGdi32.lib -lOpengl32.lib " - , - cast(int)base_name_len, output_name, - cast(int)base_name_len, output_name); - if (run_output) { - win32_exec_command_line_app("%.*s.exe", cast(int)base_name_len, output_name); - } - } else { - } + if (exit_code != 0) + return exit_code; + exit_code = win32_exec_command_line_app( + "clang -o %.*s.exe %.*s.bc " + "-Wno-override-module " + // "-nostartfiles " + "-lKernel32.lib -lUser32.lib -lGdi32.lib -lOpengl32.lib " + , + cast(int)base_name_len, output_name, + cast(int)base_name_len, output_name); + if (exit_code != 0) + return exit_code; + + if (run_output) { + win32_exec_command_line_app("%.*s.exe", cast(int)base_name_len, output_name); + } return 0; } } diff --git a/src/parser.cpp b/src/parser.cpp index c10c98184..a0d6084a7 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -441,7 +441,7 @@ void ast_file_err_(AstFile *file, char *function, Token token, char *fmt, ...) { // NOTE(bill): And this below is why is I/we need a new language! Discriminated unions are a pain in C/C++ gb_inline AstNode *make_node(AstFile *f, AstNodeKind kind) { gbArena *arena = &f->arena; - if (gb_arena_size_remaining(arena, GB_DEFAULT_MEMORY_ALIGNMENT) < gb_size_of(AstNode)) { + if (gb_arena_size_remaining(arena, GB_DEFAULT_MEMORY_ALIGNMENT) <= gb_size_of(AstNode)) { // NOTE(bill): If a syntax error is so bad, just quit! gb_exit(1); } @@ -1735,7 +1735,9 @@ AstNode *parse_decl(AstFile *f, AstNode *name_list, isize name_count) { AstNode *type = NULL; isize value_count = 0; if (allow_token(f, Token_Colon)) { - type = parse_identifier_or_type(f); + if (!allow_token(f, Token_type)) { + type = parse_identifier_or_type(f); + } } else if (f->cursor[0].kind != Token_Eq && f->cursor[0].kind != Token_Semicolon) { ast_file_err(f, f->cursor[0], "Expected type separator `:` or `=`"); } @@ -1748,13 +1750,30 @@ AstNode *parse_decl(AstFile *f, AstNode *name_list, isize name_count) { declaration_kind = Declaration_Immutable; next_token(f); - if (f->cursor[0].kind == Token_proc && + if (f->cursor[0].kind == Token_type) { + Token token = expect_token(f, Token_type); + if (name_count != 1) { + ast_file_err(f, ast_node_token(name_list), "You can only declare one type at a time"); + return make_bad_decl(f, name_list->Ident.token, token); + } + + if (type != NULL) { + ast_file_err(f, f->cursor[-1], "Expected either `type` or nothing between : and :"); + // NOTE(bill): Do not fail though + } + + AstNode *type = parse_type(f); + // if (type->kind != AstNode_StructType) { + // expect_token(f, Token_Semicolon); + // } + return make_type_decl(f, token, name_list, type); + } else if (f->cursor[0].kind == Token_proc && declaration_kind == Declaration_Immutable) { // NOTE(bill): Procedure declarations Token proc_token = f->cursor[0]; AstNode *name = name_list; if (name_count != 1) { - ast_file_err(f, proc_token, "You can only declare one procedure at a time (at the moment)"); + ast_file_err(f, proc_token, "You can only declare one procedure at a time"); return make_bad_decl(f, name->Ident.token, proc_token); } @@ -1945,14 +1964,6 @@ AstNode *parse_stmt(AstFile *f) { AstNode *s = NULL; Token token = f->cursor[0]; switch (token.kind) { - case Token_type: { - Token token = expect_token(f, Token_type); - AstNode *name = parse_identifier(f); - expect_token(f, Token_Colon); - AstNode *type = parse_type(f); - return make_type_decl(f, token, name, type); - } break; - // Operands case Token_Identifier: case Token_Integer: @@ -1966,7 +1977,11 @@ AstNode *parse_stmt(AstFile *f) { case Token_Xor: case Token_Not: s = parse_simple_stmt(f); - if (s->kind != AstNode_ProcDecl && !allow_token(f, Token_Semicolon)) { + if (s->kind != AstNode_ProcDecl && + (s->kind == AstNode_TypeDecl && + s->TypeDecl.type->kind != AstNode_StructType && + s->TypeDecl.type->kind != AstNode_ProcType) && + !allow_token(f, Token_Semicolon)) { // CLEANUP(bill): Semicolon handling in parser ast_file_err(f, f->cursor[0], "Expected `;` after statement, got `%.*s`",