diff --git a/README.md b/README.md index 995f5eb38..c742e5706 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,8 @@ The Odin programming language is fast, concise, readable, pragmatic and open sou * metaprogramming * designed for good programmers +Website: [https://odin.handmade.network/](https://odin.handmade.network/) + ## Demonstrations: * First Talk & Demo - [Talk](https://youtu.be/TMCkT-uASaE?t=338) @@ -19,6 +21,8 @@ The Odin programming language is fast, concise, readable, pragmatic and open sou * [Introspection, Modules, and Record Layout](https://www.youtube.com/watch?v=UFq8rhWhx4s) * [push_allocator & Minimal Dependency Building](https://www.youtube.com/watch?v=f_LGVOAMb78) * [when, for, & procedure overloading](https://www.youtube.com/watch?v=OzeOekzyZK8) +* [when, for, & procedure overloading](https://www.youtube.com/watch?v=OzeOekzyZK8) +* [Context Types, Unexported Entities, Labelled Branches](https://www.youtube.com/watch?v=CkHVwT1Qk-g) ## Requirements to build and run diff --git a/code/demo.odin b/code/demo.odin index 197aa83fe..ba157a977 100644 --- a/code/demo.odin +++ b/code/demo.odin @@ -1,10 +1,18 @@ +#import "atomic.odin"; +#import "decimal.odin"; #import "fmt.odin"; -#import "os.odin"; +#import "hash.odin"; #import "math.odin"; +#import "mem.odin"; +#import "opengl.odin"; +#import "os.odin"; +#import "strconv.odin"; +#import "strings.odin"; +#import "sync.odin"; +#import "types.odin"; +#import "utf8.odin"; +#import "utf16.odin"; main :: proc() { - x := 1+2i+3j+4k; - y := conj(x); - z := x/y; - fmt.println(z, abs(z)); + } diff --git a/code/game.odin b/code/game.odin index b49b78b59..fc32eaf58 100644 --- a/code/game.odin +++ b/code/game.odin @@ -1,4 +1,5 @@ -#import "win32.odin" when ODIN_OS == "windows"; +#import win32 "sys/windows.odin" when ODIN_OS == "windows"; +#import wgl "sys/wgl.odin" when ODIN_OS == "windows"; #import "fmt.odin"; #import "math.odin"; #import "os.odin"; @@ -12,11 +13,11 @@ time_now :: proc() -> f64 { counter: i64; win32.QueryPerformanceCounter(^counter); - result := counter as f64 / win32_perf_count_freq as f64; + result := cast(f64)counter / cast(f64)win32_perf_count_freq; return result; } win32_print_last_error :: proc() { - err_code := win32.GetLastError() as int; + err_code := cast(int)win32.GetLastError(); if err_code != 0 { fmt.println("GetLastError: %", err_code); } @@ -24,42 +25,42 @@ win32_print_last_error :: proc() { // Yuk! to_c_string :: proc(s: string) -> []u8 { - c_str := new_slice(u8, s.count+1); - copy(c_str, s as []byte); - c_str[s.count] = 0; + c_str := make([]u8, len(s)+1); + copy(c_str, cast([]byte)s); + c_str[len(s)] = 0; return c_str; } Window :: struct { - width, height: int; - wc: win32.WNDCLASSEXA; - dc: win32.HDC; - hwnd: win32.HWND; - opengl_context, rc: win32.HGLRC; - c_title: []u8; + width, height: int, + wc: win32.WndClassExA, + dc: win32.Hdc, + hwnd: win32.Hwnd, + opengl_context, rc: wgl.Hglrc, + c_title: []u8, } -make_window :: proc(title: string, msg, height: int, window_proc: win32.WNDPROC) -> (Window, bool) { +make_window :: proc(title: string, msg, height: int, window_proc: win32.Wnd_Proc) -> (Window, bool) { using win32; w: Window; w.width, w.height = msg, height; class_name := "Win32-Odin-Window\x00"; - c_class_name := class_name.data; - if title[title.count-1] != 0 { + c_class_name := ^class_name[0]; + if title[len(title)-1] != 0 { w.c_title = to_c_string(title); } else { - w.c_title = title as []u8; + w.c_title = cast([]u8)title; } instance := GetModuleHandleA(nil); - w.wc = WNDCLASSEXA{ - size = size_of(WNDCLASSEXA) as u32, + w.wc = WndClassExA{ + size = size_of(WndClassExA), style = CS_VREDRAW | CS_HREDRAW, - instance = instance as HINSTANCE, + instance = cast(Hinstance)instance, class_name = c_class_name, wnd_proc = window_proc, }; @@ -70,10 +71,10 @@ make_window :: proc(title: string, msg, height: int, window_proc: win32.WNDPROC) } w.hwnd = CreateWindowExA(0, - c_class_name, w.c_title.data, + c_class_name, ^w.c_title[0], WS_VISIBLE | WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX, CW_USEDEFAULT, CW_USEDEFAULT, - w.width as i32, w.height as i32, + cast(i32)w.width, cast(i32)w.height, nil, nil, instance, nil); if w.hwnd == nil { @@ -85,7 +86,7 @@ make_window :: proc(title: string, msg, height: int, window_proc: win32.WNDPROC) { pfd := PIXELFORMATDESCRIPTOR{ - size = size_of(PIXELFORMATDESCRIPTOR) as u32, + size = size_of(PIXELFORMATDESCRIPTOR), version = 1, flags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, pixel_type = PFD_TYPE_RGBA, @@ -97,19 +98,20 @@ make_window :: proc(title: string, msg, height: int, window_proc: win32.WNDPROC) }; SetPixelFormat(w.dc, ChoosePixelFormat(w.dc, ^pfd), nil); - w.opengl_context = wglCreateContext(w.dc); - wglMakeCurrent(w.dc, w.opengl_context); + w.opengl_context = wgl.CreateContext(w.dc); + wgl.MakeCurrent(w.dc, w.opengl_context); attribs := [8]i32{ - WGL_CONTEXT_MAJOR_VERSION_ARB, 2, - WGL_CONTEXT_MINOR_VERSION_ARB, 1, - WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB, + wgl.CONTEXT_MAJOR_VERSION_ARB, 2, + wgl.CONTEXT_MINOR_VERSION_ARB, 1, + wgl.CONTEXT_PROFILE_MASK_ARB, wgl.CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB, 0, // NOTE(bill): tells the proc that this is the end of attribs }; - wglCreateContextAttribsARB := wglGetProcAddress(("wglCreateContextAttribsARB\x00" as string).data) as wglCreateContextAttribsARBType; - w.rc = wglCreateContextAttribsARB(w.dc, 0, ^attribs[0]); - wglMakeCurrent(w.dc, w.rc); + wgl_str := "wglCreateContextAttribsARB\x00"; + wglCreateContextAttribsARB := cast(wgl.Create_Context_Attribs_ARB_Type)wgl.GetProcAddress(^wgl_str[0]); + w.rc = wglCreateContextAttribsARB(w.dc, nil, ^attribs[0]); + wgl.MakeCurrent(w.dc, w.rc); SwapBuffers(w.dc); } @@ -117,7 +119,7 @@ make_window :: proc(title: string, msg, height: int, window_proc: win32.WNDPROC) } destroy_window :: proc(w: ^Window) { - free(w.c_title.data); + free(w.c_title); } display_window :: proc(w: ^Window) { @@ -129,7 +131,7 @@ run :: proc() { using win32; using math; - win32_proc :: proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT #no_inline { + win32_proc :: proc(hwnd: win32.Hwnd, msg: u32, wparam: win32.Wparam, lparam: win32.Lparam) -> win32.Lresult #no_inline { if msg == WM_DESTROY || msg == WM_CLOSE || msg == WM_QUIT { os.exit(0); return 0; @@ -137,7 +139,7 @@ run :: proc() { return DefWindowProcA(hwnd, msg, wparam, lparam); } - window, window_success := make_window("Odin Language Demo", 854, 480, win32_proc); + window, window_success := make_window("Odin Language Demo", 854, 480, cast(Wnd_Proc)win32_proc); if !window_success { return; } @@ -153,10 +155,10 @@ run :: proc() { for running { curr_time := time_now(); - dt := (curr_time - prev_time) as f32; + dt := cast(f32)(curr_time - prev_time); prev_time = curr_time; - msg: MSG; + msg: Msg; for PeekMessageA(^msg, nil, 0, 0, PM_REMOVE) > 0 { if msg.message == WM_QUIT { running = false; @@ -178,7 +180,7 @@ run :: proc() { if is_key_down(Key_Code.UP) { v[1] += 1; } if is_key_down(Key_Code.DOWN) { v[1] -= 1; } - v = vec2_norm0(v); + v = norm(v); pos += v * Vec2{SPEED * dt}; } @@ -188,8 +190,8 @@ run :: proc() { gl.Clear(gl.COLOR_BUFFER_BIT); gl.LoadIdentity(); - gl.Ortho(0, window.width as f64, - 0, window.height as f64, 0, 1); + gl.Ortho(0, cast(f64)window.width, + 0, cast(f64)window.height, 0, 1); draw_rect :: proc(x, y, w, h: f32) { gl.Begin(gl.TRIANGLES); @@ -207,9 +209,14 @@ run :: proc() { draw_rect(pos.x, pos.y, 50, 50); display_window(^window); - ms_to_sleep := (16 - 1000*dt) as i32; + ms_to_sleep := cast(i32)(16 - 1000*dt); if ms_to_sleep > 0 { win32.Sleep(ms_to_sleep); } } } + + +main :: proc() { + run(); +} diff --git a/code/old_demos/demo001.odin b/code/old_demos/demo001.odin index c3fc0f663..5f30af8fe 100644 --- a/code/old_demos/demo001.odin +++ b/code/old_demos/demo001.odin @@ -136,7 +136,7 @@ bounds_checking :: proc() { { base: [10]int; - s := base[2:6]; + s := base[2..6]; a, b := -1, 6; #no_bounds_check { @@ -164,7 +164,7 @@ type_introspection :: proc() { info = type_info_of_val(x); // by value // See: runtime.odin - match type i in info { + match i in info { case Type_Info.Integer: fmt.println("integer!"); case Type_Info.Float: @@ -174,7 +174,7 @@ type_introspection :: proc() { } // Unsafe cast - integer_info := cast(^Type_Info.Integer)info; + integer_info := cast(^Type_Info.Integer)cast(rawptr)info; } { @@ -263,12 +263,12 @@ crazy_introspection :: proc() { } fruit_ti := type_info(Fruit); - name := (cast(^Type_Info.Named)fruit_ti).name; // Unsafe casts - info := cast(^Type_Info.Enum)type_info_base(fruit_ti); // Unsafe casts + name := (union_cast(^Type_Info.Named)fruit_ti).name; // Unsafe casts + info, _ := union_cast(^Type_Info.Enum)type_info_base(fruit_ti); // Unsafe casts - fmt.printf("% :: enum % {\n", name, info.base); - for i := 0; i < info.values.count; i += 1 { - fmt.printf("\t%\t= %,\n", info.names[i], info.values[i]); + fmt.printf("%s :: enum %T {\n", name, info.base); + for i := 0; i < len(info.values); i++ { + fmt.printf("\t%s\t= %v,\n", info.names[i], info.values[i]); } fmt.printf("}\n"); diff --git a/code/old_demos/demo002.odin b/code/old_demos/demo002.odin index 57b1b5c73..78cdb194a 100644 --- a/code/old_demos/demo002.odin +++ b/code/old_demos/demo002.odin @@ -1,9 +1,9 @@ // Demo 002 -#include "basic.odin" -#include "math.odin" -// #include "game.odin" +#load "fmt.odin"; +#load "math.odin"; +// #load "game.odin" -#thread_local tls_int: int +#thread_local tls_int: int; main :: proc() { // Forenotes @@ -25,64 +25,64 @@ main :: proc() { // #thread_local - see runtime.odin and above at `tls_int` // #foreign_system_library - see win32.odin - // struct_compound_literals() - // enumerations() - // variadic_procedures() - // new_builtins() - // match_statement() - // namespacing() - // subtyping() - // tagged_unions() + // struct_compound_literals(); + // enumerations(); + // variadic_procedures(); + // new_builtins(); + // match_statement(); + // namespacing(); + // subtyping(); + // tagged_unions(); } struct_compound_literals :: proc() { - Thing :: type struct { - id: int - x: f32 - name: string - } + Thing :: struct { + id: int, + x: f32, + name: string, + }; { - t1: Thing - t1.id = 1 + t1: Thing; + t1.id = 1; - t3 := Thing{} - t4 := Thing{1, 2, "Fred"} - // t5 := Thing{1, 2} + t3 := Thing{}; + t4 := Thing{1, 2, "Fred"}; + // t5 := Thing{1, 2}; t6 := Thing{ name = "Tom", x = 23, - } + }; } } enumerations :: proc() { { - Fruit :: type enum { + Fruit :: enum { APPLE, // 0 BANANA, // 1 PEAR, // 2 - } + }; - f := Fruit.APPLE + f := Fruit.APPLE; // g12: int = Fruit.BANANA - g: int = Fruit.BANANA as int + g: int = cast(int)Fruit.BANANA; // However, you can use enums are index values as _any_ integer allowed } { - Fruit1 :: type enum int { + Fruit1 :: enum int { APPLE, BANANA, PEAR, } - Fruit2 :: type enum u8 { + Fruit2 :: enum u8 { APPLE, BANANA, PEAR, } - Fruit3 :: type enum u8 { + Fruit3 :: enum u8 { APPLE = 1, BANANA, // 2 PEAR = 5, @@ -95,32 +95,32 @@ enumerations :: proc() { variadic_procedures :: proc() { print_ints :: proc(args: ..int) { - for i := 0; i < len(args); i++ { + for arg, i in args { if i > 0 { - print_string(", ") + print(", "); } - print_int(args[i]) + print(arg); } } print_ints(); // nl() - print_ints(1); nl() - print_ints(1, 2, 3); nl() + print_ints(1); nl(); + print_ints(1, 2, 3); nl(); print_prefix_f32s :: proc(prefix: string, args: ..f32) { - print_string(prefix) - print_string(": ") - for i := 0; i < len(args); i++ { + print(prefix); + print(": "); + for arg, i in args { if i > 0 { - print_string(", ") + print(", "); } - print_f32(args[i]) + print(arg); } } - print_prefix_f32s("a"); nl() - print_prefix_f32s("b", 1); nl() -7 print_prefix_f32s("c", 1, 2, 3); nl() + print_prefix_f32s("a"); nl(); + print_prefix_f32s("b", 1); nl(); + print_prefix_f32s("c", 1, 2, 3); nl(); // Internally, the variadic procedures get allocated to an array on the stack, // and this array is passed a slice @@ -134,28 +134,28 @@ variadic_procedures :: proc() { new_builtins :: proc() { { - a := new(int) - b := new_slice(int, 12) - c := new_slice(int, 12, 16) + a := new(int); + b := make([]int, 12); + c := make([]int, 12, 16); - defer delete(a) - defer delete(b) - defer delete(c) + defer free(a); + defer free(b); + defer free(c); // NOTE(bill): These use the current context's allocator not the default allocator // see runtime.odin - // Q: Should this be `free` rather than `delete` and should I overload it for slices too? + // Q: Should this be `free` rather than `free` and should I overload it for slices too? { - prev_context := context - defer context = prev_context + prev_context := context; + defer __context = prev_context; // Q: Should I add a `push_context` feature to the language? - context.allocator = __default_allocator() + __context.allocator = default_allocator(); - a := new(int) - defer delete(a) + a := new(int); + defer free(a); // Do whatever @@ -163,8 +163,8 @@ new_builtins :: proc() { } { - a: int = 123 - b: type_of_val(a) = 321 + a: int = 123; + b: type_of_val(a) = 321; // NOTE(bill): This matches the current naming scheme // size_of @@ -179,22 +179,22 @@ new_builtins :: proc() { { // Compile time assert - COND :: true - compile_assert(COND) + COND :: true; + compile_assert(COND); // compile_assert(!COND) // Runtime assert - x := true - assert(x) - // assert(!x) + x := true; + assert(x); + // assert(!x); } { - x: ^u32 = null; - y := ptr_offset(x, 100) - z := ptr_sub(y, x) - w := slice_ptr(x, 12) - t := slice_ptr(x, 12, 16) + x: ^u32 = nil; + y := x+100; + z := y-x; + w := slice_ptr(x, 12); + t := slice_ptr(x, 12, 16); // NOTE(bill): These are here because I've removed: // pointer arithmetic @@ -203,32 +203,32 @@ new_builtins :: proc() { // Reason - a: [16]int + a: [16]int; a[1] = 1; - b := ^a + b := ^a; // Auto pointer deref // consistent with record members - assert(b[1] == 1) + assert(b[1] == 1); // Q: Should I add them back in at the cost of inconsitency? } { - a, b := -1, 2 - print_int(min(a, b)); nl() - print_int(max(a, b)); nl() - print_int(abs(a)); nl() + a, b := -1, 2; + print(min(a, b)); nl(); + print(max(a, b)); nl(); + print(abs(a)); nl(); // These work at compile time too - A :: -1 - B :: 2 - C :: min(A, B) - D :: max(A, B) - E :: abs(A) + A :: -1; + B :: 2; + C :: min(A, B); + D :: max(A, B); + E :: abs(A); - print_int(C); nl() - print_int(D); nl() - print_int(E); nl() + print(C); nl(); + print(D); nl(); + print(E); nl(); } } @@ -240,47 +240,47 @@ match_statement :: proc() { { match x := 5; x { case 1: // cases must be constant expression - print_string("1!\n") + print("1!\n"); // break by default case 2: s := "2!\n"; // Each case has its own scope - print_string(s) - break // explicit break + print(s); + break; // explicit break case 3, 4: // multiple cases - print_string("3 or 4!\n") + print("3 or 4!\n"); case 5: - print_string("5!\n") - fallthrough // explicit fallthrough + print("5!\n"); + fallthrough; // explicit fallthrough default: - print_string("default!\n") + print("default!\n"); } match x := 1.5; x { case 1.5: - print_string("1.5!\n") + print("1.5!\n"); // break by default - case MATH_TAU: - print_string("τ!\n") + case TAU: + print("τ!\n"); default: - print_string("default!\n") + print("default!\n"); } match x := "Hello"; x { case "Hello": - print_string("greeting\n") + print("greeting\n"); // break by default case "Goodbye": - print_string("farewell\n") + print("farewell\n"); default: - print_string("???\n") + print("???\n"); } @@ -288,41 +288,41 @@ match_statement :: proc() { - a := 53 + a := 53; match { case a == 1: - print_string("one\n") + print("one\n"); case a == 2: - print_string("a couple\n") + print("a couple\n"); case a < 7, a == 7: - print_string("a few\n") + print("a few\n"); case a < 12: // intentional bug - print_string("several\n") + print("several\n"); case a >= 12 && a < 100: - print_string("dozens\n") + print("dozens\n"); case a >= 100 && a < 1000: - print_string("hundreds\n") + print("hundreds\n"); default: - print_string("a fuck ton\n") + print("a fuck ton\n"); } // Identical to this - b := 53 + b := 53; if b == 1 { - print_string("one\n") + print("one\n"); } else if b == 2 { - print_string("a couple\n") + print("a couple\n"); } else if b < 7 || b == 7 { - print_string("a few\n") + print("a few\n"); } else if b < 12 { // intentional bug - print_string("several\n") + print("several\n"); } else if b >= 12 && b < 100 { - print_string("dozens\n") + print("dozens\n"); } else if b >= 100 && b < 1000 { - print_string("hundreds\n") + print("hundreds\n"); } else { - print_string("a fuck ton\n") + print("a fuck ton\n"); } // However, match statements allow for `break` and `fallthrough` unlike @@ -330,45 +330,43 @@ match_statement :: proc() { } } -Vector3 :: type struct { - x, y, z: f32 -} +Vector3 :: struct {x, y, z: f32} print_floats :: proc(args: ..f32) { - for i := 0; i < len(args); i++ { + for arg, i in args { if i > 0 { - print_string(", ") + print(", "); } - print_f32(args[i]) + print(arg); } - print_nl() + println(); } namespacing :: proc() { { - Thing :: type struct { - x: f32 - name: string - } + Thing :: #type struct { + x: f32, + name: string, + }; - a: Thing - a.x = 3 + a: Thing; + a.x = 3; { - Thing :: type struct { - y: int - test: bool + Thing :: #type struct { + y: int, + test: bool, } - b: Thing // Uses this scope's Thing - b.test = true + b: Thing; // Uses this scope's Thing + b.test = true; } } - +/* { - Entity :: type struct { - Guid :: type int - Nested :: type struct { - MyInt :: type int + Entity :: struct { + Guid :: int + Nested :: struct { + MyInt :: int i: int } @@ -408,8 +406,8 @@ namespacing :: proc() { guid = 27832 name = "Bob" - print_int(e.guid as int); nl() - print_string(e.name); nl() + print(e.guid as int); nl() + print(e.name); nl() } { @@ -417,16 +415,16 @@ namespacing :: proc() { guid = 78456 name = "Thing" - print_int(e.guid as int); nl() - print_string(e.name); nl() + print(e.guid as int); nl() + print(e.name); nl() } } { - Entity :: type struct { - Guid :: type int - Nested :: type struct { - MyInt :: type int + Entity :: struct { + Guid :: int + Nested :: struct { + MyInt :: int i: int } @@ -445,40 +443,40 @@ namespacing :: proc() { e.i = Entity.CONSTANT } - +*/ { - Entity :: type struct { + Entity :: struct { position: Vector3 } print_pos_1 :: proc(entity: ^Entity) { - print_string("print_pos_1: ") - print_floats(entity.position.x, entity.position.y, entity.position.z) + print("print_pos_1: "); + print_floats(entity.position.x, entity.position.y, entity.position.z); } print_pos_2 :: proc(entity: ^Entity) { - using entity - print_string("print_pos_2: ") - print_floats(position.x, position.y, position.z) + using entity; + print("print_pos_2: "); + print_floats(position.x, position.y, position.z); } print_pos_3 :: proc(using entity: ^Entity) { - print_string("print_pos_3: ") - print_floats(position.x, position.y, position.z) + print("print_pos_3: "); + print_floats(position.x, position.y, position.z); } print_pos_4 :: proc(using entity: ^Entity) { - using position - print_string("print_pos_4: ") - print_floats(x, y, z) + using position; + print("print_pos_4: "); + print_floats(x, y, z); } - e := Entity{position = Vector3{1, 2, 3}} - print_pos_1(^e) - print_pos_2(^e) - print_pos_3(^e) - print_pos_4(^e) + e := Entity{position = Vector3{1, 2, 3}}; + print_pos_1(^e); + print_pos_2(^e); + print_pos_3(^e); + print_pos_4(^e); // This is similar to C++'s `this` pointer that is implicit and only available in methods } @@ -488,46 +486,46 @@ subtyping :: proc() { { // C way for subtyping/subclassing - Entity :: type struct { - position: Vector3 + Entity :: struct { + position: Vector3, } - Frog :: type struct { - entity: Entity - jump_height: f32 + Frog :: struct { + entity: Entity, + jump_height: f32, } - f: Frog - f.entity.position = Vector3{1, 2, 3} + f: Frog; + f.entity.position = Vector3{1, 2, 3}; - using f.entity - position = Vector3{1, 2, 3} + using f.entity; + position = Vector3{1, 2, 3}; } { // C++ way for subtyping/subclassing - Entity :: type struct { + Entity :: struct { position: Vector3 } - Frog :: type struct { - using entity: Entity - jump_height: f32 + Frog :: struct { + using entity: Entity, + jump_height: f32, } - f: Frog - f.position = Vector3{1, 2, 3} + f: Frog; + f.position = Vector3{1, 2, 3}; print_pos :: proc(using entity: Entity) { - print_string("print_pos: ") - print_floats(position.x, position.y, position.z) + print("print_pos: "); + print_floats(position.x, position.y, position.z); } - print_pos(f.entity) - print_pos(f) + print_pos(f.entity); + // print_pos(f); // Subtype Polymorphism } @@ -535,79 +533,79 @@ subtyping :: proc() { { // More than C++ way for subtyping/subclassing - Entity :: type struct { - position: Vector3 + Entity :: struct { + position: Vector3, } - Frog :: type struct { - jump_height: f32 - using entity: ^Entity // Doesn't have to be first member! + Frog :: struct { + jump_height: f32, + using entity: ^Entity, // Doesn't have to be first member! } - f: Frog - f.entity = new(Entity) - f.position = Vector3{1, 2, 3} + f: Frog; + f.entity = new(Entity); + f.position = Vector3{1, 2, 3}; print_pos :: proc(using entity: ^Entity) { - print_string("print_pos: ") - print_floats(position.x, position.y, position.z) + print("print_pos: "); + print_floats(position.x, position.y, position.z); } - print_pos(f.entity) - print_pos(^f) - print_pos(f) + print_pos(f.entity); + // print_pos(^f); + // print_pos(f); } { // More efficient subtyping - Entity :: type struct { - position: Vector3 + Entity :: struct { + position: Vector3, } - Frog :: type struct { - jump_height: f32 - using entity: ^Entity + Frog :: struct { + jump_height: f32, + using entity: ^Entity, } - MAX_ENTITES :: 64 - entities: [MAX_ENTITES]Entity - entity_count := 0 + MAX_ENTITES :: 64; + entities: [MAX_ENTITES]Entity; + entity_count := 0; next_entity :: proc(entities: []Entity, entity_count: ^int) -> ^Entity { - e := ^entities[entity_count^] - entity_count^++ - return e + e := ^entities[entity_count^]; + entity_count^++; + return e; } - f: Frog - f.entity = next_entity(entities[:], ^entity_count) - f.position = Vector3{3, 4, 6} + f: Frog; + f.entity = next_entity(entities[..], ^entity_count); + f.position = Vector3{3, 4, 6}; - using f.position - print_floats(x, y, z) + using f.position; + print_floats(x, y, z); } { // Down casting - Entity :: type struct { - position: Vector3 + Entity :: struct { + position: Vector3, } - Frog :: type struct { - jump_height: f32 - using entity: Entity + Frog :: struct { + jump_height: f32, + using entity: Entity, } - f: Frog - f.jump_height = 564 - e := ^f.entity + f: Frog; + f.jump_height = 564; + e := ^f.entity; - frog := e down_cast ^Frog - print_string("down_cast: ") - print_f32(frog.jump_height); nl() + frog := down_cast(^Frog)e; + print("down_cast: "); + print(frog.jump_height); nl(); // NOTE(bill): `down_cast` is unsafe and there are not check are compile time or run time // Q: Should I completely remove `down_cast` as I added it in about 30 minutes @@ -616,51 +614,51 @@ subtyping :: proc() { { // Multiple "inheritance"/subclassing - Entity :: type struct { - position: Vector3 + Entity :: struct { + position: Vector3, } - Climber :: type struct { - speed: f32 + Climber :: struct { + speed: f32, } - Frog :: type struct { - using entity: Entity - using climber: Climber + Frog :: struct { + using entity: Entity, + using climber: Climber, } } } tagged_unions :: proc() { { - EntityKind :: type enum { + EntityKind :: enum { INVALID, FROG, GIRAFFE, HELICOPTER, } - Entity :: type struct { + Entity :: struct { kind: EntityKind using data: raw_union { frog: struct { - jump_height: f32 - colour: u32 - } + jump_height: f32, + colour: u32, + }, giraffe: struct { - neck_length: f32 - spot_count: int - } + neck_length: f32, + spot_count: int, + }, helicopter: struct { - blade_count: int - weight: f32 - pilot_name: string - } + blade_count: int, + weight: f32, + pilot_name: string, + }, } } - e: Entity - e.kind = EntityKind.FROG - e.frog.jump_height = 12 + e: Entity; + e.kind = EntityKind.FROG; + e.frog.jump_height = 12; f: type_of_val(e.frog); @@ -669,35 +667,35 @@ tagged_unions :: proc() { } { - Entity :: type union { - Frog: struct { - jump_height: f32 - colour: u32 - } - Giraffe: struct { - neck_length: f32 - spot_count: int - } - Helicopter: struct { - blade_count: int - weight: f32 - pilot_name: string - } + Entity :: union { + Frog{ + jump_height: f32, + colour: u32, + }, + Giraffe{ + neck_length: f32, + spot_count: int, + }, + Helicopter{ + blade_count: int, + weight: f32, + pilot_name: string, + }, } - using Entity - f1: Frog = Frog{12, 0xff9900} - f2: Entity = Frog{12, 0xff9900} // Implicit cast - f3 := Frog{12, 0xff9900} as Entity // Explicit cast + using Entity; + f1: Frog = Frog{12, 0xff9900}; + f2: Entity = Frog{12, 0xff9900}; // Implicit cast + f3 := cast(Entity)Frog{12, 0xff9900}; // Explicit cast // f3.Frog.jump_height = 12 // There are "members" of a union - e, f, g, h: Entity - f = Frog{12, 0xff9900} - g = Giraffe{2.1, 23} - h = Helicopter{4, 1000, "Frank"} + e, f, g, h: Entity; + f = Frog{12, 0xff9900}; + g = Giraffe{2.1, 23}; + h = Helicopter{4, 1000, "Frank"}; @@ -705,18 +703,18 @@ tagged_unions :: proc() { // Requires a pointer to the union // `x` will be a pointer to type of the case - match type x : ^f { + match x in ^f { case Frog: - print_string("Frog!\n") - print_f32(x.jump_height); nl() - x.jump_height = 3 - print_f32(x.jump_height); nl() + print("Frog!\n"); + print(x.jump_height); nl(); + // x.jump_height = 3; + print(x.jump_height); nl(); case Giraffe: - print_string("Giraffe!\n") + print("Giraffe!\n"); case Helicopter: - print_string("ROFLCOPTER!\n") + print("ROFLCOPTER!\n"); default: - print_string("invalid entity\n") + print("invalid entity\n"); } @@ -724,26 +722,26 @@ tagged_unions :: proc() { // Or it takes the pointer the data and not a copy - fp := ^f as ^Frog // Unsafe - print_f32(fp.jump_height); nl() + // fp := cast(^Frog)^f; // Unsafe + // print(fp.jump_height); nl(); // Internals of a tagged union /* struct { - data: [size_of_biggest_tag]u8 - tag_index: int + data: [size_of_biggest_tag]u8, + tag_index: int, } */ // This is to allow for pointer casting if needed // Advantage over subtyping version - MAX_ENTITES :: 64 - entities: [MAX_ENTITES]Entity + MAX_ENTITES :: 64; + entities: [MAX_ENTITES]Entity; - entities[0] = Frog{} - entities[1] = Helicopter{} + entities[0] = Frog{}; + entities[1] = Helicopter{}; // etc. } @@ -751,13 +749,13 @@ tagged_unions :: proc() { { // Transliteration of code from this actual compiler // Some stuff is missing - Type :: type struct {} - Scope :: type struct {} - Token :: type struct {} - AstNode :: type struct {} - ExactValue :: type struct {} + Type :: struct {}; + Scope :: struct {}; + Token :: struct {}; + AstNode :: struct {}; + ExactValue :: struct {}; - EntityKind :: type enum { + EntityKind :: enum { Invalid, Constant, Variable, @@ -768,37 +766,37 @@ tagged_unions :: proc() { Count, } - Entity :: type struct { - Guid :: type i64 + Guid :: i64; + Entity :: struct { - kind: EntityKind - guid: Guid + kind: EntityKind, + guid: Guid, - scope: ^Scope - token: Token - type_: ^Type + scope: ^Scope, + token: Token, + type_: ^Type, using data: raw_union { Constant: struct { - value: ExactValue - } + value: ExactValue, + }, Variable: struct { - visited: bool // Cycle detection - used: bool // Variable is used - is_field: bool // Is struct field - anonymous: bool // Variable is an anonymous - } + visited: bool, // Cycle detection + used: bool, // Variable is used + is_field: bool, // Is struct field + anonymous: bool, // Variable is an anonymous + }, UsingVariable: struct { - } + }, TypeName: struct { - } + }, Procedure: struct { - used: bool - } + used: bool, + }, Builtin: struct { - id: int - } - } + id: int, + }, + }, } // Plus all the constructing procedures that go along with them!!!! @@ -806,60 +804,54 @@ tagged_unions :: proc() { } { - Type :: type struct {} - Scope :: type struct {} - Token :: type struct {} - AstNode :: type struct {} - ExactValue :: type struct {} + Type :: struct {}; + Scope :: struct {}; + Token :: struct {}; + AstNode :: struct {}; + ExactValue :: struct {}; - Entity :: type union { - Base :: type struct { - Guid :: type i64 - guid: Guid + Guid :: i64; + Entity_Base :: struct { - scope: ^Scope - token: Token - type_: ^Type - } - - - Constant: struct { - using base: Base - value: ExactValue - } - Variable: struct { - using base: Base - visited: bool // Cycle detection - used: bool // Variable is used - is_field: bool // Is struct field - anonymous: bool // Variable is an anonymous - } - UsingVariable: struct { - using base: Base - } - TypeName: struct { - using base: Base - } - Procedure: struct { - using base: Base - used: bool - } - Builtin: struct { - using base: Base - id: int - } } - using Entity + Entity :: union { + guid: Guid, - e: Entity + scope: ^Scope, + token: Token, + type_: ^Type, + + Constant{ + value: ExactValue, + }, + Variable{ + visited: bool, // Cycle detection + used: bool, // Variable is used + is_field: bool, // Is struct field + anonymous: bool, // Variable is an anonymous + }, + UsingVariable{ + }, + TypeName{ + }, + Procedure{ + used: bool, + }, + Builtin{ + id: int, + }, + } + + using Entity; + + e: Entity; e = Variable{ - base = Base{}, used = true, anonymous = false, - } + }; @@ -871,30 +863,30 @@ tagged_unions :: proc() { { // `Raw` unions still have uses, especially for mathematic types - Vector2 :: type raw_union { - using xy_: struct { x, y: f32 } - e: [2]f32 - v: {2}f32 + Vector2 :: raw_union { + using xy_: struct { x, y: f32 }, + e: [2]f32, + v: [vector 2]f32, } - Vector3 :: type raw_union { - using xyz_: struct { x, y, z: f32 } - xy: Vector2 - e: [3]f32 - v: {3}f32 + Vector3 :: raw_union { + using xyz_: struct { x, y, z: f32 }, + xy: Vector2, + e: [3]f32, + v: [vector 3]f32, } - v2: Vector2 - v2.x = 1 - v2.e[0] = 1 - v2.v[0] = 1 + v2: Vector2; + v2.x = 1; + v2.e[0] = 1; + v2.v[0] = 1; - v3: Vector3 - v3.x = 1 - v3.e[0] = 1 - v3.v[0] = 1 - v3.xy.x = 1 + v3: Vector3; + v3.x = 1; + v3.e[0] = 1; + v3.v[0] = 1; + v3.xy.x = 1; } } -nl :: proc() { print_nl() } +nl :: proc() { println(); } diff --git a/code/old_demos/demo004.odin b/code/old_demos/demo004.odin index 80812cd18..86588d60d 100644 --- a/code/old_demos/demo004.odin +++ b/code/old_demos/demo004.odin @@ -1,14 +1,14 @@ -#import "fmt.odin" -#import "utf8.odin" -#import "hash.odin" -#import "mem.odin" +#import "fmt.odin"; +#import "utf8.odin"; +#import "hash.odin"; +#import "mem.odin"; main :: proc() { { // New Standard Library stuff - s := "Hello" + s := "Hello"; fmt.println(s, utf8.valid_string(s), - hash.murmur64(s.data, s.count)) + hash.murmur64(cast([]byte)s)); // utf8.odin // hash.odin @@ -19,15 +19,15 @@ main :: proc() { } { - arena: mem.Arena - mem.init_arena_from_context(^arena, mem.megabytes(16)) // Uses default allocator - defer mem.free_arena(^arena) + arena: mem.Arena; + mem.init_arena_from_context(^arena, mem.megabytes(16)); // Uses default allocator + defer mem.free_arena(^arena); push_allocator mem.arena_allocator(^arena) { - x := new(int) - x^ = 1337 + x := new(int); + x^ = 1337; - fmt.println(x^) + fmt.println(x^); } /* @@ -48,14 +48,14 @@ main :: proc() { // You can also "push" a context - c := current_context() // Create copy of the allocator - c.allocator = mem.arena_allocator(^arena) + c := context; // Create copy of the allocator + c.allocator = mem.arena_allocator(^arena); push_context c { - x := new(int) - x^ = 365 + x := new(int); + x^ = 365; - fmt.println(x^) + fmt.println(x^); } } diff --git a/code/old_demos/demo005.odin b/code/old_demos/demo005.odin index 4198cffb6..f9d1a4a4c 100644 --- a/code/old_demos/demo005.odin +++ b/code/old_demos/demo005.odin @@ -42,12 +42,12 @@ syntax :: proc() { }; Thing2 :: struct {x: f32, y: int, z: ^[]int}; - // Slice interals are now just a `ptr+count` - slice: []int; compile_assert(size_of_val(slice) == 2*size_of(int)); + // Slice interals are now just a `ptr+len+cap` + slice: []int; compile_assert(size_of_val(slice) == 3*size_of(int)); // Helper type - Help the reader understand what it is quicker - My_Int :: type int; - My_Proc :: type proc(int) -> f32; + My_Int :: #type int; + My_Proc :: #type proc(int) -> f32; // All declarations with : are either variable or constant @@ -59,6 +59,7 @@ syntax :: proc() { c_proc :: proc() { /* code here */ }; +/* x += 1; x -= 1; // ++ and -- have been removed @@ -67,7 +68,7 @@ syntax :: proc() { // Question: Should they be added again? // They were removed as they are redundant and statements, not expressions // like in C/C++ - +*/ // You can now build files as a `.dll` // `odin build_dll demo.odin` @@ -85,7 +86,7 @@ syntax :: proc() { Prefix_Type :: struct {x: int, y: f32, z: rawptr}; -thread_local my_tls: Prefix_Type; +#thread_local my_tls: Prefix_Type; prefixes :: proc() { using var: Prefix_Type; @@ -98,7 +99,7 @@ prefixes :: proc() { foo :: proc(using immutable pt: Prefix_Type, immutable int_ptr: ^int) { // int_ptr = nil; // Not valid - int_ptr^ = 123; // Is valid + // int_ptr^ = 123; // Not valid } @@ -154,6 +155,7 @@ foreign_procedures :: proc() { } special_expressions :: proc() { +/* // Block expression x := { a: f32 = 123; @@ -168,7 +170,7 @@ special_expressions :: proc() { // TODO: Type cohesion is not yet finished give 123; }; // semicolon is required as it's an expression - +*/ // This is allows for inline blocks of code and will be a useful feature to have when // macros will be implemented into the language @@ -191,17 +193,17 @@ loops :: proc() { break; } - for i in 0..<123 { // 123 exclusive + for i in 0..123 { // 123 exclusive } - for i in 0...122 { // 122 inclusive + for i in 0..123-1 { // 122 inclusive } - for val, idx in 12..<16 { + for val, idx in 12..16 { fmt.println(val, idx); } - primes := [...]int{2, 3, 5, 7, 11, 13, 17, 19}; + primes := [..]int{2, 3, 5, 7, 11, 13, 17, 19}; for p in primes { fmt.println(p); @@ -224,7 +226,7 @@ loops :: proc() { when false { for i, size := 0; i < name.count; i += size { r: rune; - r, size = utf8.decode_rune(name[i:]); + r, size = utf8.decode_rune(name[i..]); fmt.printf("%r\n", r); } } diff --git a/core/_preload.odin b/core/_preload.odin index f06d9bafb..0b5efc0d5 100644 --- a/core/_preload.odin +++ b/core/_preload.odin @@ -277,17 +277,17 @@ default_allocator :: proc() -> Allocator { __string_eq :: proc(a, b: string) -> bool { - if a.count != b.count { + if len(a) != len(b) { return false; } - if a.data == b.data { + if ^a[0] == ^b[0] { return true; } return __string_cmp(a, b) == 0; } __string_cmp :: proc(a, b: string) -> int { - return __mem_compare(a.data, b.data, min(a.count, b.count)); + return __mem_compare(^a[0], ^b[0], min(len(a), len(b))); } __string_ne :: proc(a, b: string) -> bool #inline { return !__string_eq(a, b); } @@ -426,19 +426,19 @@ Raw_Any :: struct #ordered { Raw_String :: struct #ordered { data: ^byte, - count: int, + len: int, }; Raw_Slice :: struct #ordered { - data: rawptr, - count: int, - capacity: int, + data: rawptr, + len: int, + cap: int, }; Raw_Dynamic_Array :: struct #ordered { data: rawptr, - count: int, - capacity: int, + len: int, + cap: int, allocator: Allocator, }; @@ -448,11 +448,22 @@ Raw_Dynamic_Map :: struct #ordered { }; +__dynamic_array_make :: proc(array_: rawptr, elem_size, elem_align: int, len, cap: int) { + array := cast(^Raw_Dynamic_Array)array_; + __check_context(); + array.allocator = context.allocator; + assert(array.allocator.procedure != nil); -__dynamic_array_reserve :: proc(array_: rawptr, elem_size, elem_align: int, capacity: int) -> bool { + if cap > 0 { + __dynamic_array_reserve(array_, elem_size, elem_align, cap); + array.len = len; + } +} + +__dynamic_array_reserve :: proc(array_: rawptr, elem_size, elem_align: int, cap: int) -> bool { array := cast(^Raw_Dynamic_Array)array_; - if capacity <= array.capacity { + if cap <= array.cap { return true; } @@ -462,8 +473,8 @@ __dynamic_array_reserve :: proc(array_: rawptr, elem_size, elem_align: int, capa } assert(array.allocator.procedure != nil); - old_size := array.capacity * elem_size; - new_size := capacity * elem_size; + old_size := array.cap * elem_size; + new_size := cap * elem_size; allocator := array.allocator; new_data := allocator.procedure(allocator.data, Allocator_Mode.RESIZE, new_size, elem_align, array.data, old_size, 0); @@ -472,7 +483,7 @@ __dynamic_array_reserve :: proc(array_: rawptr, elem_size, elem_align: int, capa } array.data = new_data; - array.capacity = capacity; + array.cap = cap; return true; } @@ -482,43 +493,43 @@ __dynamic_array_append :: proc(array_: rawptr, elem_size, elem_align: int, array := cast(^Raw_Dynamic_Array)array_; if item_count <= 0 || items == nil { - return array.count; + return array.len; } ok := true; - if array.capacity <= array.count+item_count { - capacity := 2 * array.capacity + max(8, item_count); - ok = __dynamic_array_reserve(array, elem_size, elem_align, capacity); + if array.cap <= array.len+item_count { + cap := 2 * array.cap + max(8, item_count); + ok = __dynamic_array_reserve(array, elem_size, elem_align, cap); } if !ok { // TODO(bill): Better error handling for failed reservation - return array.count; + return array.len; } data := cast(^byte)array.data; assert(data != nil); - __mem_copy(data + (elem_size*array.count), items, elem_size * item_count); - array.count += item_count; - return array.count; + __mem_copy(data + (elem_size*array.len), items, elem_size * item_count); + array.len += item_count; + return array.len; } __dynamic_array_append_nothing :: proc(array_: rawptr, elem_size, elem_align: int) -> int { array := cast(^Raw_Dynamic_Array)array_; ok := true; - if array.capacity <= array.count+1 { - capacity := 2 * array.capacity + max(8, 1); - ok = __dynamic_array_reserve(array, elem_size, elem_align, capacity); + if array.cap <= array.len+1 { + cap := 2 * array.cap + max(8, 1); + ok = __dynamic_array_reserve(array, elem_size, elem_align, cap); } if !ok { // TODO(bill): Better error handling for failed reservation - return array.count; + return array.len; } data := cast(^byte)array.data; assert(data != nil); - __mem_zero(data + (elem_size*array.count), elem_size); - array.count++; - return array.count; + __mem_zero(data + (elem_size*array.len), elem_size); + array.len++; + return array.len; } __slice_append :: proc(slice_: rawptr, elem_size, elem_align: int, @@ -526,17 +537,17 @@ __slice_append :: proc(slice_: rawptr, elem_size, elem_align: int, slice := cast(^Raw_Slice)slice_; if item_count <= 0 || items == nil { - return slice.count; + return slice.len; } - item_count = min(slice.capacity-slice.count, item_count); + item_count = min(slice.cap-slice.len, item_count); if item_count > 0 { data := cast(^byte)slice.data; assert(data != nil); - __mem_copy(data + (elem_size*slice.count), items, elem_size * item_count); - slice.count += item_count; + __mem_copy(data + (elem_size*slice.len), items, elem_size * item_count); + slice.len += item_count; } - return slice.count; + return slice.len; } @@ -583,9 +594,9 @@ __Map_Header :: struct #ordered { value_offset: int, } -__dynamic_map_reserve :: proc(using header: __Map_Header, capacity: int) -> bool { - h := __dynamic_array_reserve(^m.hashes, size_of(int), align_of(int), capacity); - e := __dynamic_array_reserve(^m.entries, entry_size, entry_align, capacity); +__dynamic_map_reserve :: proc(using header: __Map_Header, cap: int) -> bool { + h := __dynamic_array_reserve(^m.hashes, size_of(int), align_of(int), cap); + e := __dynamic_array_reserve(^m.entries, entry_size, entry_align, cap); return h && e; } @@ -594,18 +605,22 @@ __dynamic_map_rehash :: proc(using header: __Map_Header, new_count: int) { nm: Raw_Dynamic_Map; new_header.m = ^nm; + header_hashes := cast(^Raw_Dynamic_Array)^header.m.hashes; + nm_hashes := cast(^Raw_Dynamic_Array)^nm.hashes; + + reserve(nm.hashes, new_count); - nm.hashes.count = nm.hashes.capacity; - __dynamic_array_reserve(^nm.entries, entry_size, entry_align, m.entries.count); + nm_hashes.len = nm_hashes.cap; + __dynamic_array_reserve(^nm.entries, entry_size, entry_align, m.entries.len); for _, i in nm.hashes { nm.hashes[i] = -1; } - for i := 0; i < nm.entries.count; i++ { + for i := 0; i < nm.entries.len; i++ { entry_header := __dynamic_map_get_entry(new_header, i); data := cast(^byte)entry_header; - if nm.hashes.count == 0 { + if len(nm.hashes) == 0 { __dynamic_map_grow(new_header); } @@ -626,7 +641,7 @@ __dynamic_map_rehash :: proc(using header: __Map_Header, new_count: int) { __dynamic_map_grow(new_header); } } - free_ptr_with_allocator(header.m.hashes.allocator, header.m.hashes.data); + free_ptr_with_allocator(header_hashes.allocator, header_hashes.data); free_ptr_with_allocator(header.m.entries.allocator, header.m.entries.data); header.m^ = nm; } @@ -644,7 +659,7 @@ __dynamic_map_get :: proc(h: __Map_Header, key: __Map_Key) -> rawptr { __dynamic_map_set :: proc(using h: __Map_Header, key: __Map_Key, value: rawptr) { index: int; - if m.hashes.count == 0 { + if len(m.hashes) == 0 { __dynamic_map_grow(h); } fr := __dynamic_map_find(h, key); @@ -672,12 +687,12 @@ __dynamic_map_set :: proc(using h: __Map_Header, key: __Map_Key, value: rawptr) __dynamic_map_grow :: proc(using h: __Map_Header) { - new_count := 2*m.entries.count + 8; + new_count := 2*m.entries.len + 8; __dynamic_map_rehash(h, new_count); } __dynamic_map_full :: proc(using h: __Map_Header) -> bool { - return cast(int)(0.75 * cast(f64)m.hashes.count) <= m.entries.count; + return cast(int)(0.75 * cast(f64)len(m.hashes)) <= m.entries.len; } @@ -693,8 +708,8 @@ __dynamic_map_hash_equal :: proc(h: __Map_Header, a, b: __Map_Key) -> bool { __dynamic_map_find :: proc(using h: __Map_Header, key: __Map_Key) -> __Map_Find_Result { fr := __Map_Find_Result{-1, -1, -1}; - if m.hashes.count > 0 { - fr.hash_index = cast(int)(key.hash % cast(u64)m.hashes.count); + if len(m.hashes) > 0 { + fr.hash_index = cast(int)(key.hash % cast(u64)len(m.hashes)); fr.entry_index = m.hashes[fr.hash_index]; for fr.entry_index >= 0 { entry := __dynamic_map_get_entry(h, fr.entry_index); @@ -709,7 +724,7 @@ __dynamic_map_find :: proc(using h: __Map_Header, key: __Map_Key) -> __Map_Find_ } __dynamic_map_add_entry :: proc(using h: __Map_Header, key: __Map_Key) -> int { - prev := m.entries.count; + prev := m.entries.len; c := __dynamic_array_append_nothing(^m.entries, entry_size, entry_align); if c != prev { end := __dynamic_map_get_entry(h, c-1); @@ -739,10 +754,10 @@ __dynamic_map_erase :: proc(using h: __Map_Header, fr: __Map_Find_Result) { __dynamic_map_get_entry(h, fr.entry_prev).next = __dynamic_map_get_entry(h, fr.entry_index).next; } - if fr.entry_index == m.entries.count-1 { - m.entries.count--; + if fr.entry_index == m.entries.len-1 { + m.entries.len--; } - __mem_copy(__dynamic_map_get_entry(h, fr.entry_index), __dynamic_map_get_entry(h, m.entries.count-1), entry_size); + __mem_copy(__dynamic_map_get_entry(h, fr.entry_index), __dynamic_map_get_entry(h, m.entries.len-1), entry_size); last := __dynamic_map_find(h, __dynamic_map_get_entry(h, fr.entry_index).key); if last.entry_prev >= 0 { __dynamic_map_get_entry(h, last.entry_prev).next = fr.entry_index; diff --git a/core/decimal.odin b/core/decimal.odin index 07031104b..6d9593895 100644 --- a/core/decimal.odin +++ b/core/decimal.odin @@ -14,14 +14,14 @@ decimal_to_string :: proc(buf: []byte, a: ^Decimal) -> string { for _, i in buf { buf[i] = '0'; } - return buf.count; + return len(buf); } n := 10 + a.count + abs(a.decimal_point); // TODO(bill): make this work with a buffer that's not big enough - assert(buf.count >= n); + assert(len(buf) >= n); buf = buf[..n]; if a.count == 0 { @@ -118,7 +118,7 @@ shift_right :: proc(a: ^Decimal, k: uint) { for n > 0 { dig := n>>k; n &= mask; - if w < a.digits.count { + if w < len(a.digits) { a.digits[w] = cast(byte)('0' + dig); w++; } else if dig > 0 { @@ -144,7 +144,7 @@ shift_left :: proc(a: ^Decimal, k: uint) { quo := n/10; rem := n - 10*quo; w--; - if w < a.digits.count { + if w < len(a.digits) { a.digits[w] = cast(byte)('0' + rem); } else if rem != 0 { a.trunc = true; @@ -156,7 +156,7 @@ shift_left :: proc(a: ^Decimal, k: uint) { quo := n/10; rem := n - 10*quo; w--; - if w < a.digits.count { + if w < len(a.digits) { a.digits[w] = cast(byte)('0' + rem); } else if rem != 0 { a.trunc = true; @@ -165,7 +165,7 @@ shift_left :: proc(a: ^Decimal, k: uint) { } a.count += delta; - a.count = min(a.count, a.digits.count); + a.count = min(a.count, len(a.digits)); a.decimal_point += delta; trim(a); } diff --git a/core/fmt.odin b/core/fmt.odin index 480155c08..a39e5db2e 100644 --- a/core/fmt.odin +++ b/core/fmt.odin @@ -48,23 +48,23 @@ fprint :: proc(fd: os.Handle, args: ..any) -> int { data: [_BUFFER_SIZE]byte; buf := data[..0]; bprint(^buf, ..args); - os.write(fd, buf[..buf.count]); - return buf.count; + os.write(fd, buf[..len(buf)]); + return len(buf); } fprintln :: proc(fd: os.Handle, args: ..any) -> int { data: [_BUFFER_SIZE]byte; buf := data[..0]; bprintln(^buf, ..args); - os.write(fd, buf[..buf.count]); - return buf.count; + os.write(fd, buf[..len(buf)]); + return len(buf); } fprintf :: proc(fd: os.Handle, fmt: string, args: ..any) -> int { data: [_BUFFER_SIZE]byte; buf := data[..0]; bprintf(^buf, fmt, ..args); - os.write(fd, buf[..buf.count]); - return buf.count; + os.write(fd, buf[..len(buf)]); + return len(buf); } @@ -83,7 +83,7 @@ fprint_type :: proc(fd: os.Handle, info: ^Type_Info) { data: [_BUFFER_SIZE]byte; buf := data[..0]; write_type(^buf, info); - os.write(fd, buf[..buf.count]); + os.write(fd, buf[..len(buf)]); } write_type :: proc(buf: ^[]byte, ti: ^Type_Info) { @@ -147,14 +147,14 @@ write_type :: proc(buf: ^[]byte, ti: ^Type_Info) { write_type(buf, info.results); } case Tuple: - count := info.names.count; + count := len(info.names); if count != 1 { write_string(buf, "("); } for name, i in info.names { if i > 0 { write_string(buf, ", "); } type := info.types[i]; - if name.count > 0 { + if len(name) > 0 { write_string(buf, name); write_string(buf, ": "); } @@ -233,12 +233,12 @@ write_type :: proc(buf: ^[]byte, ti: ^Type_Info) { variant_type := type_info_base(info.variant_types[i]); variant := union_cast(^Struct)variant_type; - vc := variant.names.count-cf.names.count; + vc := len(variant.names)-len(cf.names); for j in 0..vc { if j > 0 { write_string(buf, ", "); } - index := j + cf.names.count; + index := j + len(cf.names); write_string(buf, variant.names[index]); write_string(buf, ": "); write_type(buf, variant.types[index]); @@ -279,14 +279,14 @@ bprint :: proc(buf: ^[]byte, args: ..any) -> int { prev_string := false; for arg, i in args { - is_string := arg.data != nil && types.is_string(arg.type_info); + is_string := arg != nil && types.is_string(arg.type_info); if i > 0 && !is_string && !prev_string { write_byte(buf, ' '); } fmt_value(^fi, args[i], 'v'); prev_string = is_string; } - return buf.count; + return len(buf); } bprintln :: proc(buf: ^[]byte, args: ..any) -> int { @@ -300,7 +300,7 @@ bprintln :: proc(buf: ^[]byte, args: ..any) -> int { fmt_value(^fi, args[i], 'v'); } write_byte(buf, '\n'); - return buf.count; + return len(buf); } sprint :: proc(buf: []byte, args: ..any) -> string { @@ -328,7 +328,7 @@ parse_int :: proc(s: string, offset: int) -> (result: int, offset: int, ok: bool ok := true; i := 0; - for o in offset..s.count { + for o in offset..len(s) { c := cast(rune)s[offset+i]; if !is_digit(c) { break; @@ -349,11 +349,11 @@ _arg_number :: proc(fi: ^Fmt_Info, arg_count: int, ) -> (index: int, offset: int, ok: bool) { parse_arg_number :: proc(format: string) -> (int, int, bool) { - if format.count < 3 { + if len(format) < 3 { return 0, 1, false; } - for i in 1..format.count { + for i in 1..len(format) { if format[i] == ']' { width, new_index, ok := parse_int(format, 1); if !ok || new_index != i { @@ -367,7 +367,7 @@ _arg_number :: proc(fi: ^Fmt_Info, } - if format.count <= offset || format[offset] != '[' { + if len(format) <= offset || format[offset] != '[' { return arg_index, offset, false; } fi.reordered = true; @@ -383,7 +383,7 @@ int_from_arg :: proc(args: []any, arg_index: int) -> (int, int, bool) { num := 0; new_arg_index := arg_index; ok := true; - if arg_index < args.count { + if arg_index < len(args) { arg := args[arg_index]; arg.type_info = type_info_base(arg.type_info); match i in arg { @@ -439,7 +439,7 @@ fmt_write_padding :: proc(fi: ^Fmt_Info, width: int) { pad_byte = '0'; } - count := min(width, fi.buf.capacity-fi.buf.count); + count := min(width, cap(fi.buf)-len(fi.buf)); for _ in 0..count { append(fi.buf, pad_byte); } @@ -585,7 +585,7 @@ fmt_float :: proc(fi: ^Fmt_Info, v: f64, bit_size: int, verb: rune) { } buf: [128]byte; str := strconv.append_float(buf[1..1], v, 'f', prec, bit_size); - str = cast(string)buf[..str.count+1]; + str = cast(string)buf[..len(str)+1]; if str[1] == '+' || str[1] == '-' { str = str[1..]; } else { @@ -602,9 +602,9 @@ fmt_float :: proc(fi: ^Fmt_Info, v: f64, bit_size: int, verb: rune) { } if fi.plus || str[0] != '+' { - if fi.zero && fi.width_set && fi.width > str.count { + if fi.zero && fi.width_set && fi.width > len(str) { write_byte(fi.buf, str[0]); - fmt_write_padding(fi, fi.width - str.count); + fmt_write_padding(fi, fi.width - len(str)); write_string(fi.buf, str[1..]); } else { _pad(fi, str); @@ -685,7 +685,7 @@ fmt_enum :: proc(fi: ^Fmt_Info, v: any, verb: rune) { break; } } - } else if e.values.count == 0 { + } else if len(e.values) == 0 { write_string(fi.buf, ""); ok = true; } else { @@ -780,7 +780,7 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) { write_byte(fi.buf, '['); defer write_byte(fi.buf, ']'); array := cast(^Raw_Dynamic_Array)v.data; - for i in 0..array.count { + for i in 0..array.len { if i > 0 { write_string(fi.buf, ", "); } @@ -802,7 +802,7 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) { entry_type := union_cast(^Struct)ed.elem; entry_size := ed.elem_size; - for i in 0..entries.count { + for i in 0..entries.len { if i > 0 { write_string(fi.buf, ", "); } @@ -831,11 +831,11 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) { write_byte(fi.buf, '['); defer write_byte(fi.buf, ']'); slice := cast(^[]byte)v.data; - for i in 0..slice.count { + for i in 0..len(slice) { if i > 0 { write_string(fi.buf, ", "); } - data := slice.data + i*info.elem_size; + data := ^slice[0] + i*info.elem_size; fmt_arg(fi, any{info.elem, cast(rawptr)data}, 'v'); } @@ -941,7 +941,7 @@ fmt_quaternion :: proc(fi: ^Fmt_Info, c: quaternion256, bits: int, verb: rune) { } fmt_arg :: proc(fi: ^Fmt_Info, arg: any, verb: rune) { - if arg.data == nil || arg.type_info == nil { + if arg == nil { write_string(fi.buf, ""); return; } @@ -987,7 +987,7 @@ fmt_arg :: proc(fi: ^Fmt_Info, arg: any, verb: rune) { bprintf :: proc(b: ^[]byte, fmt: string, args: ..any) -> int { fi := Fmt_Info{}; - end := fmt.count; + end := len(fmt); arg_index := 0; was_prev_index := false; for i := 0; i < end; { @@ -1026,7 +1026,7 @@ bprintf :: proc(b: ^[]byte, fmt: string, args: ..any) -> int { } } - arg_index, i, was_prev_index = _arg_number(^fi, arg_index, fmt, i, args.count); + arg_index, i, was_prev_index = _arg_number(^fi, arg_index, fmt, i, len(args)); // Width if i < end && fmt[i] == '*' { @@ -1056,7 +1056,7 @@ bprintf :: proc(b: ^[]byte, fmt: string, args: ..any) -> int { fi.good_arg_index = false; } if i < end && fmt[i] == '*' { - arg_index, i, was_prev_index = _arg_number(^fi, arg_index, fmt, i, args.count); + arg_index, i, was_prev_index = _arg_number(^fi, arg_index, fmt, i, len(args)); i++; fi.prec, arg_index, fi.prec_set = int_from_arg(args, arg_index); if fi.prec < 0 { @@ -1077,7 +1077,7 @@ bprintf :: proc(b: ^[]byte, fmt: string, args: ..any) -> int { } if !was_prev_index { - arg_index, i, was_prev_index = _arg_number(^fi, arg_index, fmt, i, args.count); + arg_index, i, was_prev_index = _arg_number(^fi, arg_index, fmt, i, len(args)); } if i >= end { @@ -1092,7 +1092,7 @@ bprintf :: proc(b: ^[]byte, fmt: string, args: ..any) -> int { write_byte(b, '%'); } else if !fi.good_arg_index { write_string(b, "%!(BAD ARGUMENT NUMBER)"); - } else if arg_index >= args.count { + } else if arg_index >= len(args) { write_string(b, "%!(MISSING ARGUMENT)"); } else { fmt_arg(^fi, args[arg_index], verb); @@ -1100,13 +1100,13 @@ bprintf :: proc(b: ^[]byte, fmt: string, args: ..any) -> int { } } - if !fi.reordered && arg_index < args.count { + if !fi.reordered && arg_index < len(args) { write_string(b, "%!(EXTRA "); for arg, index in args[arg_index..] { if index > 0 { write_string(b, ", "); } - if arg.data == nil || arg.type_info == nil { + if arg == nil { write_string(b, ""); } else { fmt_arg(^fi, args[index], 'v'); @@ -1115,5 +1115,5 @@ bprintf :: proc(b: ^[]byte, fmt: string, args: ..any) -> int { write_string(b, ")"); } - return b.count; + return len(b); } diff --git a/core/hash.odin b/core/hash.odin index 6d61594d2..5ed4863e0 100644 --- a/core/hash.odin +++ b/core/hash.odin @@ -50,8 +50,8 @@ murmur32 :: proc(data: []byte) -> u32 { c2_32: u32 : 0x1b873593; h1: u32 = 0; - nblocks := data.count/4; - p := data.data; + nblocks := len(data)/4; + p := ^data[0]; p1 := p + 4*nblocks; for ; p < p1; p += 4 { @@ -69,7 +69,7 @@ murmur32 :: proc(data: []byte) -> u32 { tail := data[nblocks*4 ..]; k1: u32; - match tail.count&3 { + match len(tail)&3 { case 3: k1 ~= cast(u32)tail[2] << 16; fallthrough; @@ -84,7 +84,7 @@ murmur32 :: proc(data: []byte) -> u32 { h1 ~= k1; } - h1 ~= cast(u32)data.count; + h1 ~= cast(u32)len(data); h1 ~= h1 >> 16; h1 *= 0x85ebca6b; @@ -137,11 +137,11 @@ murmur64 :: proc(data: []byte) -> u64 { m :: 0x5bd1e995; r :: 24; - h1: u32 = cast(u32)SEED ~ cast(u32)data.count; + h1: u32 = cast(u32)SEED ~ cast(u32)len(data); h2: u32 = SEED >> 32; - data32 := slice_ptr(cast(^u32)^data[0], data.count/size_of(u32)); - len := data.count; + data32 := slice_ptr(cast(^u32)^data[0], len(data)/size_of(u32)); + len := len(data); i := 0; for len >= 8 { @@ -174,7 +174,8 @@ murmur64 :: proc(data: []byte) -> u64 { len -= 4; } - data8 := slice_to_bytes(data32[i..])[..3]; + // TODO(bill): Fix this + #no_bounds_check data8 := slice_to_bytes(data32[i..])[..3]; match len { case 3: h2 ~= cast(u32)data8[2] << 16; diff --git a/core/mem.odin b/core/mem.odin index 1560ca410..f3396b7ac 100644 --- a/core/mem.odin +++ b/core/mem.odin @@ -19,7 +19,7 @@ copy_non_overlapping :: proc(dst, src: rawptr, len: int) -> rawptr { return __mem_copy_non_overlapping(dst, src, len); } compare :: proc(a, b: []byte) -> int { - return __mem_compare(a.data, b.data, min(a.count, b.count)); + return __mem_compare(^a[0], ^b[0], min(len(a), len(b))); } @@ -102,7 +102,7 @@ init_arena_from_memory :: proc(using a: ^Arena, data: []byte) { init_arena_from_context :: proc(using a: ^Arena, size: int) { backing = context.allocator; - memory = new_slice(byte, size); + memory = make([]byte, size); temp_count = 0; } @@ -133,7 +133,7 @@ arena_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode, case ALLOC: total_size := size + alignment; - if arena.offset + total_size > arena.memory.count { + if arena.offset + total_size > len(arena.memory) { fmt.fprintln(os.stderr, "Arena out of memory"); return nil; } @@ -161,15 +161,15 @@ arena_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode, begin_arena_temp_memory :: proc(a: ^Arena) -> Arena_Temp_Memory { tmp: Arena_Temp_Memory; tmp.arena = a; - tmp.original_count = a.memory.count; + tmp.original_count = len(a.memory); a.temp_count++; return tmp; } end_arena_temp_memory :: proc(using tmp: Arena_Temp_Memory) { - assert(arena.memory.count >= original_count); + assert(len(arena.memory) >= original_count); assert(arena.temp_count > 0); - arena.memory.count = original_count; + arena.memory = arena.memory[..original_count]; arena.temp_count--; } diff --git a/core/opengl.odin b/core/opengl.odin index 4e3ab9c39..88ea8c4b4 100644 --- a/core/opengl.odin +++ b/core/opengl.odin @@ -35,10 +35,10 @@ string_data :: proc(s: string) -> ^u8 #inline { return ^s[0]; } _libgl := win32.LoadLibraryA(string_data("opengl32.dll\x00")); GetProcAddress :: proc(name: string) -> proc() #cc_c { - assert(name[name.count-1] == 0); - res := wgl.GetProcAddress(name.data); + assert(name[len(name)-1] == 0); + res := wgl.GetProcAddress(^name[0]); if res == nil { - res = win32.GetProcAddress(_libgl, name.data); + res = win32.GetProcAddress(_libgl, ^name[0]); } return res; } diff --git a/core/os_windows.odin b/core/os_windows.odin index b834a2726..ecb093ab4 100644 --- a/core/os_windows.odin +++ b/core/os_windows.odin @@ -49,11 +49,11 @@ ERROR_FILE_IS_PIPE: Errno : 1<<29 + 0; // "Argv" arguments converted to Odin strings -args := _alloc_command_line_arguments(); +immutable args := _alloc_command_line_arguments(); open :: proc(path: string, mode: int, perm: u32) -> (Handle, Errno) { - if path.count == 0 { + if len(path) == 0 { return INVALID_HANDLE, ERROR_FILE_NOT_FOUND; } @@ -110,7 +110,7 @@ close :: proc(fd: Handle) { write :: proc(fd: Handle, data: []byte) -> (int, Errno) { bytes_written: i32; - e := win32.WriteFile(cast(win32.Handle)fd, data.data, cast(i32)data.count, ^bytes_written, nil); + e := win32.WriteFile(cast(win32.Handle)fd, ^data[0], cast(i32)len(data), ^bytes_written, nil); if e == win32.FALSE { err := win32.GetLastError(); return 0, cast(Errno)err; @@ -120,7 +120,7 @@ write :: proc(fd: Handle, data: []byte) -> (int, Errno) { read :: proc(fd: Handle, data: []byte) -> (int, Errno) { bytes_read: i32; - e := win32.ReadFile(cast(win32.Handle)fd, data.data, cast(u32)data.count, ^bytes_read, nil); + e := win32.ReadFile(cast(win32.Handle)fd, ^data[0], cast(u32)len(data), ^bytes_read, nil); if e == win32.FALSE { err := win32.GetLastError(); return 0, cast(Errno)err; @@ -180,7 +180,7 @@ last_write_time_by_name :: proc(name: string) -> File_Time { data: win32.File_Attribute_Data; buf: [1024]byte; - assert(buf.count > name.count); + assert(len(buf) > len(name)); copy(buf[..], cast([]byte)name); @@ -213,8 +213,8 @@ read_entire_file :: proc(name: string) -> ([]byte, bool) { return nil, false; } - data := new_slice(u8, length); - if data.data == nil { + data := make([]byte, length); + if ^data[0] == nil { return nil, false; } @@ -286,10 +286,9 @@ _alloc_command_line_arguments :: proc() -> []string { wstr_len++; } len := 2*wstr_len-1; - buf := new_slice(byte, len+1); + buf := make([]byte, len+1); str := slice_ptr(wstr, wstr_len+1); - i, j := 0, 0; for str[j] != 0 { match { @@ -334,7 +333,7 @@ _alloc_command_line_arguments :: proc() -> []string { arg_count: i32; arg_list_ptr := win32.CommandLineToArgvW(win32.GetCommandLineW(), ^arg_count); - arg_list := new_slice(string, arg_count); + arg_list := make([]string, arg_count); for _, i in arg_list { arg_list[i] = alloc_ucs2_to_utf8((arg_list_ptr+i)^); } diff --git a/core/strconv.odin b/core/strconv.odin index 998129829..e083bfd82 100644 --- a/core/strconv.odin +++ b/core/strconv.odin @@ -131,50 +131,33 @@ generic_ftoa :: proc(buf: []byte, val: f64, fmt: byte, prec, bit_size: int) -> [ format_digits :: proc(buf: []byte, shortest: bool, neg: bool, digs: Decimal_Slice, prec: int, fmt: byte) -> []byte { match fmt { case 'f', 'F': - add_bytes :: proc(dst: ^[]byte, w: ^int, bytes: ..byte) { - for b in bytes { - if dst.capacity <= w^ { - break; - } - dst.count++; - dst[w^] = b; - w^++; - } - } - - dst := buf[..]; - w := 0; - if neg { - add_bytes(^dst, ^w, '-'); - } else { - add_bytes(^dst, ^w, '+'); - } + append(buf, neg ? '-' : '+'); // integer, padded with zeros when needed if digs.decimal_point > 0 { m := min(digs.count, digs.decimal_point); - add_bytes(^dst, ^w, ..digs.digits[..m]); + append(buf, ..digs.digits[..m]); for ; m < digs.decimal_point; m++ { - add_bytes(^dst, ^w, '0'); + append(buf, '0'); } } else { - add_bytes(^dst, ^w, '0'); + append(buf, '0'); } // fractional part if prec > 0 { - add_bytes(^dst, ^w, '.'); + append(buf, '.'); for i in 0..prec { c: byte = '0'; if j := digs.decimal_point + i; 0 <= j && j < digs.count { c = digs.digits[j]; } - add_bytes(^dst, ^w, c); + append(buf, c); } } - return buf[..w]; + return buf; case 'e', 'E': panic("strconv: e/E float printing is not yet supported"); @@ -308,7 +291,7 @@ append_bits :: proc(buf: []byte, u: u64, base: int, is_signed: bool, bit_size: i } a: [65]byte; - i := a.count; + i := len(a); neg: bool; u, neg = is_integer_negative(u, is_signed, bit_size); diff --git a/core/strings.odin b/core/strings.odin index 7b2f09230..846c7398c 100644 --- a/core/strings.odin +++ b/core/strings.odin @@ -1,15 +1,14 @@ new_c_string :: proc(s: string) -> ^byte { - c := new_slice(byte, s.count+1); + c := make([]byte, len(s)+1); copy(c, cast([]byte)s); - c[s.count] = 0; - return c.data; + c[len(s)] = 0; + return ^c[0]; } to_odin_string :: proc(c: ^byte) -> string { - s: string; - s.data = c; - for (c+s.count)^ != 0 { - s.count++; + len := 0; + for (c+len)^ != 0 { + len++; } - return s; + return cast(string)slice_ptr(c, len); } diff --git a/core/sys/wgl.odin b/core/sys/wgl.odin index 9edbdda11..57e974a7b 100644 --- a/core/sys/wgl.odin +++ b/core/sys/wgl.odin @@ -7,6 +7,7 @@ CONTEXT_FLAGS_ARB :: 0x2094; CONTEXT_PROFILE_MASK_ARB :: 0x9126; CONTEXT_FORWARD_COMPATIBLE_BIT_ARB :: 0x0002; CONTEXT_CORE_PROFILE_BIT_ARB :: 0x00000001; +CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB :: 0x00000002; Hglrc :: Handle; Color_Ref :: u32; diff --git a/core/utf8.odin b/core/utf8.odin index a90e4e45b..b933448b9 100644 --- a/core/utf8.odin +++ b/core/utf8.odin @@ -94,7 +94,7 @@ encode_rune :: proc(r: rune) -> ([4]byte, int) { decode_rune :: proc(s: string) -> (rune, int) #inline { return decode_rune(cast([]byte)s); } decode_rune :: proc(s: []byte) -> (rune, int) { - n := s.count; + n := len(s); if n < 1 { return RUNE_ERROR, 0; } @@ -138,7 +138,7 @@ decode_last_rune :: proc(s: []byte) -> (rune, int) { size: int; start, end, limit: int; - end = s.count; + end = len(s); if end == 0 { return RUNE_ERROR, 0; } @@ -183,7 +183,7 @@ valid_rune :: proc(r: rune) -> bool { } valid_string :: proc(s: string) -> bool { - n := s.count; + n := len(s); for i := 0; i < n; { si := s[i]; if si < RUNE_SELF { // ascii @@ -220,7 +220,7 @@ rune_start :: proc(b: byte) -> bool #inline { return b&0xc0 != 0x80; } rune_count :: proc(s: string) -> int #inline { return rune_count(cast([]byte)s); } rune_count :: proc(s: []byte) -> int { count := 0; - n := s.count; + n := len(s); for i := 0; i < n; { defer count++; diff --git a/src/check_expr.c b/src/check_expr.c index 55dcdb941..5370f76b3 100644 --- a/src/check_expr.c +++ b/src/check_expr.c @@ -250,7 +250,9 @@ void check_assignment(Checker *c, Operand *operand, Type *type, String context_n return; } target_type = default_type(operand->type); - GB_ASSERT(is_type_typed(target_type)); + if (!is_type_any(type)) { + GB_ASSERT_MSG(is_type_typed(target_type), "%s", type_to_string(type)); + } add_type_info_type(c, type); add_type_info_type(c, target_type); } @@ -1963,7 +1965,9 @@ void check_comparison(Checker *c, Operand *x, Operand *y, TokenKind op) { switch (op) { case Token_CmpEq: case Token_NotEq: - defined = is_type_comparable(x->type); + defined = is_type_comparable(x->type) || + (is_operand_nil(*x) && type_has_nil(y->type)) || + (is_operand_nil(*y) && type_has_nil(x->type)); break; case Token_Lt: case Token_Gt: @@ -1973,6 +1977,7 @@ void check_comparison(Checker *c, Operand *x, Operand *y, TokenKind op) { } break; } + #if 0 // CLEANUP(bill) NOTE(bill): there is an auto assignment to `any` which needs to be checked if (is_type_any(x->type) && !is_type_any(y->type)) { err_type = x->type; @@ -1981,8 +1986,14 @@ void check_comparison(Checker *c, Operand *x, Operand *y, TokenKind op) { err_type = y->type; defined = false; } + #endif if (!defined) { + if (x->type == err_type && is_operand_nil(*x)) { + err_type = y->type; + } + gb_printf_err("%d %d\n", is_operand_nil(*x), type_has_nil(y->type)); + gb_printf_err("%d %d\n", is_operand_nil(*y), type_has_nil(x->type)); gbString type_string = type_to_string(err_type); err_str = gb_string_make(c->tmp_allocator, gb_bprintf("operator `%.*s` not defined for type `%s`", LIT(token_strings[op]), type_string)); @@ -2659,7 +2670,9 @@ void convert_to_typed(Checker *c, Operand *operand, Type *target_type, i32 level break; case Basic_UntypedNil: - if (!type_has_nil(target_type)) { + if (is_type_any(target_type)) { + target_type = t_untyped_nil; + } else if (!type_has_nil(target_type)) { operand->mode = Addressing_Invalid; convert_untyped_error(c, operand, target_type); return; @@ -3070,11 +3083,11 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id } } - Operand prev_operand = *operand; switch (id) { case BuiltinProc_new: - case BuiltinProc_new_slice: + // case BuiltinProc_new_slice: + case BuiltinProc_make: case BuiltinProc_size_of: case BuiltinProc_align_of: case BuiltinProc_offset_of: @@ -3090,6 +3103,53 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id GB_PANIC("Implement builtin procedure: %.*s", LIT(builtin_procs[id].name)); break; + case BuiltinProc_len: + case BuiltinProc_cap: { + // len :: proc(Type) -> int + // cap :: proc(Type) -> int + Type *op_type = type_deref(operand->type); + Type *type = t_int; + AddressingMode mode = Addressing_Invalid; + ExactValue value = {0}; + if (is_type_string(op_type) && id == BuiltinProc_len) { + if (operand->mode == Addressing_Constant) { + mode = Addressing_Constant; + String str = operand->value.value_string; + value = exact_value_integer(str.len); + type = t_untyped_integer; + } else { + mode = Addressing_Value; + } + } else if (is_type_array(op_type)) { + Type *at = core_type(op_type); + mode = Addressing_Constant; + value = exact_value_integer(at->Array.count); + type = t_untyped_integer; + } else if (is_type_vector(op_type) && id == BuiltinProc_len) { + Type *at = core_type(op_type); + mode = Addressing_Constant; + value = exact_value_integer(at->Vector.count); + type = t_untyped_integer; + } else if (is_type_slice(op_type)) { + mode = Addressing_Value; + } else if (is_type_dynamic_array(op_type)) { + mode = Addressing_Value; + } else if (is_type_map(op_type)) { + mode = Addressing_Value; + } + + if (mode == Addressing_Invalid) { + String name = builtin_procs[id].name; + gbString t = type_to_string(operand->type); + error_node(call, "`%.*s` is not supported for `%s`", LIT(name), t); + return false; + } + + operand->mode = mode; + operand->value = value; + operand->type = type; + } break; + case BuiltinProc_new: { // new :: proc(Type) -> ^Type Operand op = {0}; @@ -3102,6 +3162,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id operand->mode = Addressing_Value; operand->type = make_type_pointer(c->allocator, type); } break; + #if 0 case BuiltinProc_new_slice: { // new_slice :: proc(Type, len: int) -> []Type // new_slice :: proc(Type, len, cap: int) -> []Type @@ -3139,6 +3200,62 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id operand->mode = Addressing_Value; operand->type = make_type_slice(c->allocator, type); } break; + #endif + case BuiltinProc_make: { + // make :: proc(Type, len: int) -> Type + // make :: proc(Type, len, cap: int) -> Type + Operand op = {0}; + check_expr_or_type(c, &op, ce->args.e[0]); + Type *type = op.type; + if ((op.mode != Addressing_Type && type == NULL) || type == t_invalid) { + error_node(ce->args.e[0], "Expected a type for `make`"); + return false; + } + + isize min_args = 0; + isize max_args = 1; + if (is_type_slice(type)) { + min_args = 2; + max_args = 3; + } else if (is_type_dynamic_map(type)) { + min_args = 1; + max_args = 2; + } else if (is_type_dynamic_array(type)) { + min_args = 1; + max_args = 3; + } else { + gbString str = type_to_string(type); + error_node(call, "Cannot `make` %s; type must be a slice, map, or dynamic array", str); + gb_string_free(str); + return false; + } + + isize arg_count = ce->args.count; + if (arg_count < min_args || max_args < arg_count) { + error_node(ce->args.e[0], "`make` expects %td or %d argument, found %td", min_args, max_args, arg_count); + return false; + } + + // If any are constant + i64 sizes[4] = {0}; + isize size_count = 0; + for (isize i = 1; i < arg_count; i++) { + i64 val = 0; + bool ok = check_index_value(c, ce->args.e[i], -1, &val); + if (ok && val >= 0) { + GB_ASSERT(size_count < gb_count_of(sizes)); + sizes[size_count++] = val; + } + } + + if (size_count == 2 && sizes[0] > sizes[1]) { + error_node(ce->args.e[1], "`make` count and capacity are swapped"); + // No need quit + } + + operand->mode = Addressing_Value; + operand->type = type; + } break; case BuiltinProc_free: { // free :: proc(^Type) @@ -3216,6 +3333,8 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id case BuiltinProc_append: { // append :: proc([dynamic]Type, item: ..Type) // append :: proc([]Type, item: ..Type) + Operand prev_operand = *operand; + Type *type = operand->type; bool is_pointer = is_type_pointer(type); type = base_type(type_deref(type)); diff --git a/src/check_stmt.c b/src/check_stmt.c index 6aec1beee..0ad48864a 100644 --- a/src/check_stmt.c +++ b/src/check_stmt.c @@ -1264,8 +1264,10 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { case Entity_TypeName: { Type *t = base_type(e->type); if (is_type_union(t)) { - for (isize i = 0; i < t->Record.variant_count; i++) { + TokenPos pos = ast_node_token(expr).pos; + for (isize i = 1; i < t->Record.variant_count; i++) { Entity *f = t->Record.variants[i]; + // gb_printf_err("%s\n", type_to_string(f->type)); Entity *found = scope_insert_entity(c->context.scope, f); if (found != NULL) { gbString expr_str = expr_to_string(expr); diff --git a/src/checker.c b/src/checker.c index 3a458d099..a4bf8364f 100644 --- a/src/checker.c +++ b/src/checker.c @@ -23,9 +23,13 @@ typedef struct BuiltinProc { typedef enum BuiltinProcId { BuiltinProc_Invalid, + BuiltinProc_len, + BuiltinProc_cap, + BuiltinProc_new, - BuiltinProc_new_slice, BuiltinProc_free, + // BuiltinProc_new_slice, + BuiltinProc_make, BuiltinProc_reserve, BuiltinProc_clear, @@ -75,9 +79,13 @@ typedef enum BuiltinProcId { gb_global BuiltinProc builtin_procs[BuiltinProc_Count] = { {STR_LIT(""), 0, false, Expr_Stmt}, + {STR_LIT("len"), 1, false, Expr_Expr}, + {STR_LIT("cap"), 1, false, Expr_Expr}, + {STR_LIT("new"), 1, false, Expr_Expr}, - {STR_LIT("new_slice"), 2, true, Expr_Expr}, {STR_LIT("free"), 1, false, Expr_Stmt}, + // {STR_LIT("new_slice"), 2, true, Expr_Expr}, + {STR_LIT("make"), 1, true, Expr_Expr}, {STR_LIT("reserve"), 2, false, Expr_Stmt}, {STR_LIT("clear"), 1, false, Expr_Stmt}, diff --git a/src/ir.c b/src/ir.c index bfe4f3781..13d1af22c 100644 --- a/src/ir.c +++ b/src/ir.c @@ -1470,6 +1470,7 @@ irValue *ir_gen_map_header(irProcedure *proc, irValue *map_val, Type *map_type) GB_ASSERT_MSG(is_type_pointer(ir_type(map_val)), "%s", type_to_string(ir_type(map_val))); gbAllocator a = proc->module->allocator; irValue *h = ir_add_local_generated(proc, t_map_header); + map_type = base_type(map_type); Type *key_type = map_type->Map.key; Type *val_type = map_type->Map.value; @@ -1962,12 +1963,74 @@ irValue *ir_emit_arith(irProcedure *proc, TokenKind op, irValue *left, irValue * return ir_emit(proc, ir_instr_binary_op(proc, op, left, right, type)); } +irValue *ir_emit_comp_against_nil(irProcedure *proc, TokenKind op_kind, irValue *x) { + Type *t = ir_type(x); + if (is_type_any(t)) { + irValue *ti = ir_emit_struct_ev(proc, x, 0); + irValue *data = ir_emit_struct_ev(proc, x, 1); + if (op_kind == Token_CmpEq) { + irValue *a = ir_emit_comp(proc, Token_CmpEq, ti, v_raw_nil); + irValue *b = ir_emit_comp(proc, Token_CmpEq, data, v_raw_nil); + return ir_emit_arith(proc, Token_Or, a, b, t_bool); + } else if (op_kind == Token_NotEq) { + irValue *a = ir_emit_comp(proc, Token_NotEq, ti, v_raw_nil); + irValue *b = ir_emit_comp(proc, Token_NotEq, data, v_raw_nil); + return ir_emit_arith(proc, Token_And, a, b, t_bool); + } + } else if (is_type_slice(t)) { + irValue *data = ir_emit_struct_ev(proc, x, 0); + irValue *cap = ir_emit_struct_ev(proc, x, 2); + if (op_kind == Token_CmpEq) { + irValue *a = ir_emit_comp(proc, Token_CmpEq, data, v_raw_nil); + irValue *b = ir_emit_comp(proc, Token_CmpEq, cap, v_zero); + return ir_emit_arith(proc, Token_Or, a, b, t_bool); + } else if (op_kind == Token_NotEq) { + irValue *a = ir_emit_comp(proc, Token_NotEq, data, v_raw_nil); + irValue *b = ir_emit_comp(proc, Token_NotEq, cap, v_zero); + return ir_emit_arith(proc, Token_And, a, b, t_bool); + } + } else if (is_type_dynamic_array(t)) { + irValue *data = ir_emit_struct_ev(proc, x, 0); + irValue *cap = ir_emit_struct_ev(proc, x, 2); + if (op_kind == Token_CmpEq) { + irValue *a = ir_emit_comp(proc, Token_CmpEq, data, v_raw_nil); + irValue *b = ir_emit_comp(proc, Token_CmpEq, cap, v_zero); + return ir_emit_arith(proc, Token_Or, a, b, t_bool); + } else if (op_kind == Token_NotEq) { + irValue *a = ir_emit_comp(proc, Token_NotEq, data, v_raw_nil); + irValue *b = ir_emit_comp(proc, Token_NotEq, cap, v_zero); + return ir_emit_arith(proc, Token_And, a, b, t_bool); + } + } else if (is_type_map(t)) { + irValue *hashes = ir_emit_struct_ev(proc, x, 0); + irValue *entries = ir_emit_struct_ev(proc, x, 1); + irValue *a = ir_emit_comp_against_nil(proc, op_kind, hashes); + irValue *b = ir_emit_comp_against_nil(proc, op_kind, entries); + if (op_kind == Token_CmpEq) { + return ir_emit_arith(proc, Token_Or, a, b, t_bool); + } else if (op_kind == Token_NotEq) { + return ir_emit_arith(proc, Token_And, a, b, t_bool); + } + } + return NULL; +} + irValue *ir_emit_comp(irProcedure *proc, TokenKind op_kind, irValue *left, irValue *right) { Type *a = base_type(ir_type(left)); Type *b = base_type(ir_type(right)); GB_ASSERT(gb_is_between(op_kind, Token__ComparisonBegin+1, Token__ComparisonEnd-1)); + irValue *nil_check = NULL; + if (left->kind == irValue_Nil) { + nil_check = ir_emit_comp_against_nil(proc, op_kind, right); + } else if (right->kind == irValue_Nil) { + nil_check = ir_emit_comp_against_nil(proc, op_kind, left); + } + if (nil_check != NULL) { + return nil_check; + } + if (are_types_identical(a, b)) { // NOTE(bill): No need for a conversion } else if (left->kind == irValue_Constant || left->kind == irValue_Nil) { @@ -3222,6 +3285,20 @@ void ir_build_defer_stmt(irProcedure *proc, irDefer d) { } +irValue *ir_emit_clamp(irProcedure *proc, Type *t, irValue *x, irValue *min, irValue *max) { + irValue *cond = NULL; + ir_emit_comment(proc, str_lit("clamp")); + x = ir_emit_conv(proc, x, t); + min = ir_emit_conv(proc, min, t); + max = ir_emit_conv(proc, max, t); + + cond = ir_emit_comp(proc, Token_Gt, min, x); + x = ir_emit_select(proc, cond, min, x); + cond = ir_emit_comp(proc, Token_Lt, max, x); + x = ir_emit_select(proc, cond, max, x); + return x; +} + irValue *ir_find_global_variable(irProcedure *proc, String name) { irValue **value = map_ir_value_get(&proc->module->members, hash_string(name)); @@ -3505,6 +3582,59 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { return ir_type_info(proc, t); } break; + case BuiltinProc_len: { + irValue *v = ir_build_expr(proc, ce->args.e[0]); + Type *t = base_type(ir_type(v)); + if (is_type_pointer(t)) { + // IMPORTANT TODO(bill): Should there be a nil pointer check? + v = ir_emit_load(proc, v); + t = type_deref(t); + } + if (is_type_string(t)) { + return ir_string_len(proc, v); + } else if (is_type_array(t)) { + GB_PANIC("Array lengths are constant"); + } else if (is_type_vector(t)) { + GB_PANIC("Vector lengths are constant"); + } else if (is_type_slice(t)) { + return ir_slice_count(proc, v); + } else if (is_type_dynamic_array(t)) { + return ir_dynamic_array_count(proc, v); + } else if (is_type_map(t)) { + irValue *entries = ir_emit_struct_ev(proc, v, 1); + return ir_dynamic_array_count(proc, entries); + } + + GB_PANIC("Unreachable"); + } break; + + case BuiltinProc_cap: { + irValue *v = ir_build_expr(proc, ce->args.e[0]); + Type *t = base_type(ir_type(v)); + if (is_type_pointer(t)) { + // IMPORTANT TODO(bill): Should there be a nil pointer check? + v = ir_emit_load(proc, v); + t = type_deref(t); + } + if (is_type_string(t)) { + GB_PANIC("Unreachable"); + } else if (is_type_array(t)) { + GB_PANIC("Array lengths are constant"); + } else if (is_type_vector(t)) { + GB_PANIC("Unreachable"); + } else if (is_type_slice(t)) { + return ir_slice_capacity(proc, v); + } else if (is_type_dynamic_array(t)) { + return ir_dynamic_array_capacity(proc, v); + } else if (is_type_map(t)) { + irValue *entries = ir_emit_struct_ev(proc, v, 1); + return ir_dynamic_array_capacity(proc, entries); + } + + GB_PANIC("Unreachable"); + + } break; + case BuiltinProc_new: { ir_emit_comment(proc, str_lit("new")); // new :: proc(Type) -> ^Type @@ -3524,6 +3654,7 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { return v; } break; + #if 0 case BuiltinProc_new_slice: { ir_emit_comment(proc, str_lit("new_slice")); // new_slice :: proc(Type, len: int) -> []Type @@ -3562,6 +3693,83 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { ir_fill_slice(proc, slice, ptr, count, capacity); return ir_emit_load(proc, slice); } break; + #endif + case BuiltinProc_make: { + ir_emit_comment(proc, str_lit("make")); + gbAllocator a = proc->module->allocator; + Type *type = type_of_expr(proc->module->info, ce->args.e[0]); + + if (is_type_slice(type)) { + Type *elem_type = core_type(type)->Slice.elem; + Type *elem_ptr_type = make_type_pointer(a, elem_type); + + irValue *elem_size = ir_const_int(a, type_size_of(a, elem_type)); + irValue *elem_align = ir_const_int(a, type_align_of(a, elem_type)); + + irValue *count = ir_emit_conv(proc, ir_build_expr(proc, ce->args.e[1]), t_int); + irValue *capacity = count; + + if (ce->args.count == 3) { + capacity = ir_emit_conv(proc, ir_build_expr(proc, ce->args.e[2]), t_int); + } + + ir_emit_slice_bounds_check(proc, ast_node_token(ce->args.e[1]), v_zero, count, capacity, false); + + irValue *slice_size = ir_emit_arith(proc, Token_Mul, elem_size, capacity, t_int); + + irValue **args = gb_alloc_array(a, irValue *, 2); + args[0] = slice_size; + args[1] = elem_align; + irValue *call = ir_emit_global_call(proc, "alloc_align", args, 2); + + irValue *ptr = ir_emit_conv(proc, call, elem_ptr_type); + irValue *slice = ir_add_local_generated(proc, type); + + ir_fill_slice(proc, slice, ptr, count, capacity); + return ir_emit_load(proc, slice); + } else if (is_type_dynamic_map(type)) { + irValue *int_16 = ir_const_int(a, 16); + irValue *cap = v_zero; + if (ce->args.count == 2) { + cap = ir_emit_conv(proc, ir_build_expr(proc, ce->args.e[1]), t_int); + } + + irValue *cond = ir_emit_comp(proc, Token_Gt, cap, v_zero); + cap = ir_emit_select(proc, cond, cap, int_16); + + irValue *map = ir_add_local_generated(proc, type); + irValue *header = ir_gen_map_header(proc, map, base_type(type)); + irValue **args = gb_alloc_array(a, irValue *, 2); + args[0] = header; + args[1] = cap; + ir_emit_global_call(proc, "__dynamic_map_reserve", args, 2); + + return ir_emit_load(proc, map); + } else if (is_type_dynamic_array(type)) { + Type *elem_type = base_type(type)->DynamicArray.elem; + irValue *len = v_zero; + if (ce->args.count > 1) { + len = ir_emit_conv(proc, ir_build_expr(proc, ce->args.e[1]), t_int); + } + irValue *cap = len; + if (ce->args.count > 2) { + cap = ir_emit_conv(proc, ir_build_expr(proc, ce->args.e[2]), t_int); + } + + ir_emit_slice_bounds_check(proc, ast_node_token(ce->args.e[0]), v_zero, len, cap, false); + + irValue *array = ir_add_local_generated(proc, type); + irValue **args = gb_alloc_array(a, irValue *, 5); + args[0] = array; + args[1] = ir_const_int(a, type_size_of(a, elem_type)); + args[2] = ir_const_int(a, type_align_of(a, elem_type));; + args[3] = len; + args[4] = cap; + ir_emit_global_call(proc, "__dynamic_array_make", args, 5); + + return ir_emit_load(proc, array); + } + } break; case BuiltinProc_free: { ir_emit_comment(proc, str_lit("free")); @@ -4055,8 +4263,10 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { irValue *ptr = ir_emit_conv(proc, ir_slice_elem(proc, s), t_u8_ptr); irValue *count = ir_slice_count(proc, s); + irValue *capacity = ir_slice_capacity(proc, s); count = ir_emit_arith(proc, Token_Mul, count, ir_const_int(proc->module->allocator, elem_size), t_int); - ir_fill_slice(proc, slice, ptr, count, count); + capacity = ir_emit_arith(proc, Token_Mul, capacity, ir_const_int(proc->module->allocator, elem_size), t_int); + ir_fill_slice(proc, slice, ptr, count, capacity); return ir_emit_load(proc, slice); } break; @@ -4112,15 +4322,10 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { case BuiltinProc_clamp: { ir_emit_comment(proc, str_lit("clamp")); Type *t = type_of_expr(proc->module->info, expr); - irValue *x = ir_emit_conv(proc, ir_build_expr(proc, ce->args.e[0]), t); - irValue *min = ir_emit_conv(proc, ir_build_expr(proc, ce->args.e[1]), t); - irValue *max = ir_emit_conv(proc, ir_build_expr(proc, ce->args.e[2]), t); - irValue *cond; - cond = ir_emit_comp(proc, Token_Gt, min, x); - x = ir_emit_select(proc, cond, min, x); - cond = ir_emit_comp(proc, Token_Lt, max, x); - x = ir_emit_select(proc, cond, max, x); - return x; + return ir_emit_clamp(proc, t, + ir_build_expr(proc, ce->args.e[0]), + ir_build_expr(proc, ce->args.e[1]), + ir_build_expr(proc, ce->args.e[2])); } break; } } @@ -4399,6 +4604,14 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) { ir_emit_store(proc, v, ir_emit_down_cast(proc, ir_build_expr(proc, ce->expr), type)); return ir_addr(v); } + case Token_union_cast: { + ir_emit_comment(proc, str_lit("Cast - union_cast")); + // NOTE(bill): Needed for dereference of pointer conversion + Type *type = type_of_expr(proc->module->info, expr); + irValue *v = ir_add_local_generated(proc, type); + ir_emit_store(proc, v, ir_emit_union_cast(proc, ir_build_expr(proc, ce->expr), type, ast_node_token(expr).pos)); + return ir_addr(v); + } default: GB_PANIC("Unknown cast expression"); } diff --git a/src/parser.c b/src/parser.c index 5169bd7bf..a9cae2710 100644 --- a/src/parser.c +++ b/src/parser.c @@ -2272,6 +2272,7 @@ AstNode *parse_value_decl(AstFile *f, AstNodeArray lhs) { } + AstNode *parse_simple_stmt(AstFile *f, bool in_stmt_ok) { AstNodeArray lhs = parse_lhs_expr_list(f); Token token = f->curr_token; @@ -3290,7 +3291,7 @@ AstNode *parse_stmt(AstFile *f) { return ast_using_stmt(f, token, list); } - AstNode *decl = parse_simple_stmt(f, false); + AstNode *decl = parse_value_decl(f, list); expect_semicolon(f, decl); if (decl->kind == AstNode_ValueDecl) { diff --git a/src/tokenizer.c b/src/tokenizer.c index 398f39f98..2ef1a7add 100644 --- a/src/tokenizer.c +++ b/src/tokenizer.c @@ -619,20 +619,22 @@ bool scan_escape(Tokenizer *t, Rune quote) { advance_to_next_rune(t); len = 8; base = 16; max = GB_RUNE_MAX; } else { - if (t->curr_rune < 0) + if (t->curr_rune < 0) { tokenizer_err(t, "Escape sequence was not terminated"); - else + } else { tokenizer_err(t, "Unknown escape sequence"); + } return false; } while (len --> 0) { u32 d = cast(u32)digit_value(t->curr_rune); if (d >= base) { - if (t->curr_rune < 0) + if (t->curr_rune < 0) { tokenizer_err(t, "Escape sequence was not terminated"); - else + } else { tokenizer_err(t, "Illegal character %d in escape sequence", t->curr_rune); + } return false; } diff --git a/src/types.c b/src/types.c index ebbce3e39..ecaa58871 100644 --- a/src/types.c +++ b/src/types.c @@ -834,9 +834,10 @@ bool type_has_nil(Type *t) { return false; } break; case Type_Slice: - case Type_DynamicArray: case Type_Proc: case Type_Pointer: + case Type_DynamicArray: + case Type_Map: return true; } return false; @@ -1231,6 +1232,9 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n if (type->kind == Type_Basic) { switch (type->Basic.kind) { case Basic_any: { + #if 1 + // IMPORTANT TODO(bill): Should these members be available to should I only allow them with + // `Raw_Any` type? String type_info_str = str_lit("type_info"); String data_str = str_lit("data"); if (entity__any_type_info == NULL) { @@ -1249,8 +1253,10 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n sel.entity = entity__any_data; return sel; } + #endif } break; case Basic_string: { + #if 0 String data_str = str_lit("data"); String count_str = str_lit("count"); if (entity__string_data == NULL) { @@ -1270,11 +1276,13 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n sel.entity = entity__string_count; return sel; } + #endif } break; } return sel; } else if (type->kind == Type_Array) { + #if 0 String count_str = str_lit("count"); // NOTE(bill): Underlying memory address cannot be changed if (str_eq(field_name, count_str)) { @@ -1282,7 +1290,9 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n sel.entity = make_entity_constant(a, NULL, make_token_ident(count_str), t_int, exact_value_integer(type->Array.count)); return sel; } + #endif } else if (type->kind == Type_Vector) { + #if 0 String count_str = str_lit("count"); // NOTE(bill): Vectors are not addressable if (str_eq(field_name, count_str)) { @@ -1290,7 +1300,7 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n sel.entity = make_entity_constant(a, NULL, make_token_ident(count_str), t_int, exact_value_integer(type->Vector.count)); return sel; } - + #endif if (type->Vector.count <= 4 && !is_type_boolean(type->Vector.elem)) { // HACK(bill): Memory leak switch (type->Vector.count) { @@ -1314,6 +1324,7 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n } } else if (type->kind == Type_Slice) { + #if 0 String data_str = str_lit("data"); String count_str = str_lit("count"); String capacity_str = str_lit("capacity"); @@ -1340,8 +1351,9 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n sel.entity = entity__slice_capacity; return sel; } - + #endif } else if (type->kind == Type_DynamicArray) { + #if 0 String data_str = str_lit("data"); String count_str = str_lit("count"); String capacity_str = str_lit("capacity"); @@ -1374,7 +1386,9 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n sel.entity = entity__dynamic_array_allocator; return sel; } + #endif } else if (type->kind == Type_Map) { + #if 0 String count_str = str_lit("count"); String capacity_str = str_lit("capacity"); String allocator_str = str_lit("allocator"); @@ -1404,6 +1418,7 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n sel.entity = entity__dynamic_map_allocator; return sel; } + #endif } if (is_type) {