Przeglądaj źródła

Merge https://github.com/gingerBill/Odin

Zachary Pierson 8 lat temu
rodzic
commit
f952c7c747

+ 4 - 0
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
 

+ 13 - 5
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));
+
 }

+ 46 - 39
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();
+}

+ 8 - 8
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");
 

Plik diff jest za duży
+ 307 - 309
code/old_demos/demo002.odin


+ 17 - 17
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^);
 		}
 	}
 

+ 15 - 13
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);
 		}
 	}

+ 66 - 51
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);
+
+	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, capacity: int) -> bool {
+__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;

+ 6 - 6
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);
 }

+ 37 - 37
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, "<nil>");
 		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, "<nil>");
 			} 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);
 }

+ 9 - 8
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;

+ 6 - 6
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--;
 }
 

+ 3 - 3
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;
 }

+ 9 - 10
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)^);
 	}

+ 8 - 25
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);

+ 7 - 8
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);
 }

+ 1 - 0
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;

+ 4 - 4
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++;

+ 124 - 5
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));

+ 3 - 1
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);

+ 10 - 2
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},

+ 223 - 10
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");
 		}

+ 2 - 1
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) {

+ 6 - 4
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;
 		}
 

+ 18 - 3
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) {

Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików