Răsfoiți Sursa

Fix parsing for block/if expression within if/for/etc. statements

Ginger Bill 8 ani în urmă
părinte
comite
31aacd5bf4
10 a modificat fișierele cu 311 adăugiri și 281 ștergeri
  1. 1 1
      build.bat
  2. 16 13
      code/demo.odin
  3. 86 86
      code/old_demos/demo001.odin
  4. 166 158
      code/punity.odin
  5. 20 12
      core/fmt.odin
  6. 5 4
      src/check_decl.c
  7. 5 0
      src/check_expr.c
  8. 1 1
      src/main.c
  9. 8 5
      src/parser.c
  10. 3 1
      src/types.c

+ 1 - 1
build.bat

@@ -46,7 +46,7 @@ cl %compiler_settings% "src\main.c" ^
 	/link %linker_settings% -OUT:%exe_name% ^
 	&& odin run code/demo.odin
 	rem && odin build_dll code/example.odin ^
-	rem && odin run code/demo.odin
+	rem odin run code/punity.odin
 
 rem pushd src\asm
 rem 	nasm hellope.asm -fwin64 -o hellope.obj ^

+ 16 - 13
code/demo.odin

@@ -1,12 +1,13 @@
 #import "fmt.odin";
 #import "utf8.odin";
-#import "atomic.odin";
-#import "hash.odin";
-#import "math.odin";
-#import "mem.odin";
-#import "opengl.odin";
-#import "os.odin";
-#import "sync.odin";
+// #import "atomic.odin";
+// #import "hash.odin";
+// #import "math.odin";
+// #import "mem.odin";
+// #import "opengl.odin";
+// #import "os.odin";
+// #import "sync.odin";
+// #import win32 "sys/windows.odin";
 
 main :: proc() {
 	syntax();
@@ -15,8 +16,8 @@ main :: proc() {
 syntax :: proc() {
 	// Cyclic type checking
 	// Uncomment to see the error
-	// A :: struct { b: B };
-	// B :: struct { a: A };
+	// A :: struct {b: B};
+	// B :: struct {a: A};
 
 	x: int;
 	y := cast(f32)x;
@@ -40,10 +41,10 @@ syntax :: proc() {
 	};
 	Thing2 :: struct {x: f32, y: int, z: ^[]int};
 
-	// Slice interals are not just a `ptr+count`
+	// Slice interals are now just a `ptr+count`
 	slice: []int; compile_assert(size_of_val(slice) == 2*size_of(int));
 
-	// Helper type - Help the reader understand that it is quicker
+	// Helper type - Help the reader understand what it is quicker
 	My_Int  :: type int;
 	My_Proc :: type proc(int) -> f32;
 
@@ -62,6 +63,9 @@ syntax :: proc() {
 	// ++ and -- have been removed
 	// x++;
 	// x--;
+	// 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`
@@ -167,7 +171,6 @@ special_expressions :: proc() {
 }
 
 loops :: proc() {
-
 	// The C-style for loop
 	for i := 0; i < 123; i += 1 {
 		break;
@@ -259,7 +262,7 @@ procedure_overloading :: proc() {
 	}
 
 
-	a: i32 = #line;
+	a: i32 = 123;
 	b: f32;
 	c: rawptr;
 	fmt.println(foo(^a));

+ 86 - 86
code/old_demos/demo001.odin

@@ -1,9 +1,9 @@
-#import "fmt.odin"
-#import "os.odin"
-#import "mem.odin"
-// #import "http_test.odin" as ht
-// #import "game.odin" as game
-// #import "punity.odin" as pn
+#import "fmt.odin";
+#import "os.odin";
+#import "mem.odin";
+// #import "http_test.odin" as ht;
+// #import "game.odin" as game;
+// #import "punity.odin" as pn;
 
 main :: proc() {
 	// struct_padding()
@@ -26,58 +26,58 @@ main :: proc() {
 struct_padding :: proc() {
 	{
 		A :: struct {
-			a: u8
-			b: u32
-			c: u16
+			a: u8,
+			b: u32,
+			c: u16,
 		}
 
 		B :: struct {
-			a: [7]u8
-			b: [3]u16
-			c: u8
-			d: u16
+			a: [7]u8,
+			b: [3]u16,
+			c: u8,
+			d: u16,
 		}
 
-		fmt.println("size_of(A):", size_of(A))
-		fmt.println("size_of(B):", size_of(B))
+		fmt.println("size_of(A):", size_of(A));
+		fmt.println("size_of(B):", size_of(B));
 
 		// n.b. http://cbloomrants.blogspot.co.uk/2012/07/07-23-12-structs-are-not-what-you-want.html
 	}
 	{
 		A :: struct #ordered {
-			a: u8
-			b: u32
-			c: u16
+			a: u8,
+			b: u32,
+			c: u16,
 		}
 
 		B :: struct #ordered {
-			a: [7]u8
-			b: [3]u16
-			c: u8
-			d: u16
+			a: [7]u8,
+			b: [3]u16,
+			c: u8,
+			d: u16,
 		}
 
-		fmt.println("size_of(A):", size_of(A))
-		fmt.println("size_of(B):", size_of(B))
+		fmt.println("size_of(A):", size_of(A));
+		fmt.println("size_of(B):", size_of(B));
 
 		// C-style structure layout
 	}
 	{
 		A :: struct #packed {
-			a: u8
-			b: u32
-			c: u16
+			a: u8,
+			b: u32,
+			c: u16,
 		}
 
 		B :: struct #packed {
-			a: [7]u8
-			b: [3]u16
-			c: u8
-			d: u16
+			a: [7]u8,
+			b: [3]u16,
+			c: u8,
+			d: u16,
 		}
 
-		fmt.println("size_of(A):", size_of(A))
-		fmt.println("size_of(B):", size_of(B))
+		fmt.println("size_of(A):", size_of(A));
+		fmt.println("size_of(B):", size_of(B));
 
 		// Useful for explicit layout
 	}
@@ -119,7 +119,7 @@ struct_padding :: proc() {
 }
 
 bounds_checking :: proc() {
-	x: [4]int
+	x: [4]int;
 	// x[-1] = 0; // Compile Time
 	// x[4]  = 0; // Compile Time
 
@@ -132,9 +132,9 @@ bounds_checking :: proc() {
 	// Works for arrays, strings, slices, and related procedures & operations
 
 	{
-		base: [10]int
-		s := base[2:6]
-		a, b := -1, 6
+		base: [10]int;
+		s := base[2:6];
+		a, b := -1, 6;
 
 		#no_bounds_check {
 			s[a] = 0;
@@ -154,69 +154,69 @@ bounds_checking :: proc() {
 
 type_introspection :: proc() {
 	{
-		info: ^Type_Info
-		x: int
+		info: ^Type_Info;
+		x: int;
 
-		info = type_info(int) // by type
-		info = type_info_of_val(x) // by value
+		info = type_info(int); // by type
+		info = type_info_of_val(x); // by value
 		// See: runtime.odin
 
-		match type i : info {
+		match type i in info {
 		case Type_Info.Integer:
-			fmt.println("integer!")
+			fmt.println("integer!");
 		case Type_Info.Float:
-			fmt.println("float!")
+			fmt.println("float!");
 		default:
-			fmt.println("potato!")
+			fmt.println("potato!");
 		}
 
 		// Unsafe cast
-		integer_info := info as ^Type_Info.Integer
+		integer_info := cast(^Type_Info.Integer)info;
 	}
 
 	{
 		Vector2 :: struct { x, y: f32 }
 		Vector3 :: struct { x, y, z: f32 }
 
-		v1: Vector2
-		v2: Vector3
-		v3: Vector3
+		v1: Vector2;
+		v2: Vector3;
+		v3: Vector3;
 
-		t1 := type_info_of_val(v1)
-		t2 := type_info_of_val(v2)
-		t3 := type_info_of_val(v3)
+		t1 := type_info_of_val(v1);
+		t2 := type_info_of_val(v2);
+		t3 := type_info_of_val(v3);
 
-		fmt.println()
-		fmt.print("Type of v1 is:\n\t", t1)
+		fmt.println();
+		fmt.print("Type of v1 is:\n\t", t1);
 
-		fmt.println()
-		fmt.print("Type of v2 is:\n\t", t2)
+		fmt.println();
+		fmt.print("Type of v2 is:\n\t", t2);
 
-		fmt.println("\n")
-		fmt.println("t1 == t2:", t1 == t2)
-		fmt.println("t2 == t3:", t2 == t3)
+		fmt.println("\n");
+		fmt.println("t1 == t2:", t1 == t2);
+		fmt.println("t2 == t3:", t2 == t3);
 	}
 }
 
 any_type :: proc() {
-	a: any
+	a: any;
 
-	x: int = 123
-	y: f64 = 6.28
-	z: string = "Yo-Yo Ma"
+	x: int = 123;
+	y: f64 = 6.28;
+	z: string = "Yo-Yo Ma";
 	// All types can be implicit cast to `any`
-	a = x
-	a = y
-	a = z
-	a = a // This the "identity" type, it doesn't get converted
+	a = x;
+	a = y;
+	a = z;
+	a = a; // This the "identity" type, it doesn't get converted
 
-	a = 123 // Literals are copied onto the stack first
+	a = 123; // Literals are copied onto the stack first
 
 	// any has two members
 	// data      - rawptr to the data
 	// type_info - pointer to the type info
 
-	fmt.println(x, y, z)
+	fmt.println(x, y, z);
 	// See: fmt.odin
 	// For variadic any procedures in action
 }
@@ -232,15 +232,15 @@ crazy_introspection :: proc() {
 			TOMATO,
 		}
 
-		s: string
-		s = enum_to_string(Fruit.PEACH)
-		fmt.println(s)
+		s: string;
+		// s = enum_to_string(Fruit.PEACH);
+		fmt.println(s);
 
-		f := Fruit.GRAPE
-		s = enum_to_string(f)
-		fmt.println(s)
+		f := Fruit.GRAPE;
+		// s = enum_to_string(f);
+		fmt.println(s);
 
-		fmt.println(f)
+		fmt.println(f);
 		// See: runtime.odin
 	}
 
@@ -259,15 +259,15 @@ crazy_introspection :: proc() {
 			TOMATO,
 		}
 
-		fruit_ti := type_info(Fruit)
-		name := (fruit_ti as ^Type_Info.Named).name // Unsafe casts
-		info := type_info_base(fruit_ti) as ^Type_Info.Enum // Unsafe casts
+		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
 
 		fmt.printf("% :: enum % {\n", name, info.base);
-		for i := 0; i < info.values.count; i++ {
-			fmt.printf("\t%\t= %,\n", info.names[i], info.values[i])
+		for i := 0; i < info.values.count; i += 1 {
+			fmt.printf("\t%\t= %,\n", info.names[i], info.values[i]);
 		}
-		fmt.printf("}\n")
+		fmt.printf("}\n");
 
 		// NOTE(bill): look at that type-safe printf!
 	}
@@ -275,10 +275,10 @@ crazy_introspection :: proc() {
 	{
 		Vector3 :: struct {x, y, z: f32}
 
-		a := Vector3{x = 1, y = 4, z = 9}
-		fmt.println(a)
-		b := Vector3{x = 9, y = 3, z = 1}
-		fmt.println(b)
+		a := Vector3{x = 1, y = 4, z = 9};
+		fmt.println(a);
+		b := Vector3{x = 9, y = 3, z = 1};
+		fmt.println(b);
 
 		// NOTE(bill): See fmt.odin
 	}

+ 166 - 158
code/punity.odin

@@ -1,34 +1,35 @@
-#import "win32.odin"
-#import "fmt.odin"
-#import "os.odin"
+#import win32 "sys/windows.odin";
+#import "fmt.odin";
+#import "os.odin";
+#import "mem.odin";
 
-CANVAS_WIDTH  :: 128
-CANVAS_HEIGHT :: 128
-CANVAS_SCALE  :: 3
-FRAME_TIME    :: 1.0/30.0
-WINDOW_TITLE  :: "Punity\x00"
+CANVAS_WIDTH  :: 128;
+CANVAS_HEIGHT :: 128;
+CANVAS_SCALE  :: 3;
+FRAME_TIME    :: 1.0/30.0;
+WINDOW_TITLE  :: "Punity\x00";
 
-_ := compile_assert(CANVAS_WIDTH % 16 == 0)
+_ := compile_assert(CANVAS_WIDTH % 16 == 0);
 
-WINDOW_WIDTH  :: CANVAS_WIDTH  * CANVAS_SCALE
-WINDOW_HEIGHT :: CANVAS_HEIGHT * CANVAS_SCALE
+WINDOW_WIDTH  :: CANVAS_WIDTH  * CANVAS_SCALE;
+WINDOW_HEIGHT :: CANVAS_HEIGHT * CANVAS_SCALE;
 
 
-STACK_CAPACITY   :: 1<<20
-STORAGE_CAPACITY :: 1<<20
+STACK_CAPACITY   :: 1<<20;
+STORAGE_CAPACITY :: 1<<20;
 
-DRAW_LIST_RESERVE :: 128
+DRAW_LIST_RESERVE :: 128;
 
-MAX_KEYS :: 256
+MAX_KEYS :: 256;
 
 Core :: struct {
-	stack:   ^Bank
-	storage: ^Bank
+	stack:   ^Bank,
+	storage: ^Bank,
 
-	running:       bool
-	key_modifiers: u32
-	key_states:    [MAX_KEYS]byte
-	key_deltas:    [MAX_KEYS]byte
+	running:       bool,
+	key_modifiers: u32,
+	key_states:    [MAX_KEYS]byte,
+	key_deltas:    [MAX_KEYS]byte,
 
 	perf_frame,
 	perf_frame_inner,
@@ -36,70 +37,66 @@ Core :: struct {
 	perf_audio,
 	perf_blit,
 	perf_blit_cvt,
-	perf_blit_gdi: Perf_Span
+	perf_blit_gdi: Perf_Span,
 
-	frame: i64
+	frame: i64,
 
-	canvas:    Canvas
-	draw_list: ^Draw_List
+	canvas:    Canvas,
+	draw_list: ^Draw_List,
 }
 
 Perf_Span :: struct {
-	stamp: f64
-	delta: f32
+	stamp: f64,
+	delta: f32,
 }
 
 Bank :: struct {
-	memory: []byte
-	cursor: int
+	memory: []byte,
+	cursor: int,
 }
 
 Bank_State :: struct {
-	state: Bank
-	bank: ^Bank
+	state: Bank,
+	bank: ^Bank,
 }
 
 
 Color :: raw_union {
-	using channels: struct{ a, b, g, r: byte; }
-	rgba: u32
+	using channels: struct{a, b, g, r: byte},
+	rgba: u32,
 }
 
 Palette :: struct {
-	colors: [256]Color
-	colors_count: byte
+	colors: [256]Color,
+	colors_count: byte,
 }
 
 
 Rect :: raw_union {
-	using minmax: struct {
-		min_x, min_y, max_x, max_y: int
-	}
-	using pos: struct {
-		left, top, right, bottom: int
-	}
-	e: [4]int
+	using minmax: struct {min_x, min_y, max_x, max_y: int},
+	using pos: struct {left, top, right, bottom: int},
+	e: [4]int,
 }
 
 Bitmap :: struct {
-	pixels: []byte
-	width:  int
-	height: int
+	pixels: []byte,
+	width:  int,
+	height: int,
 }
 
 Font :: struct {
-	using bitmap: Bitmap
-	char_width:   int
-	char_height:  int
+	using bitmap: Bitmap,
+	char_width:   int,
+	char_height:  int,
 }
 
 Canvas :: struct {
-	using bitmap: ^Bitmap
-	palette:      Palette
-	translate_x:  int
-	translate_y:  int
-	clip:         Rect
-	font:         ^Font
+	using bitmap: ^Bitmap,
+	palette:      Palette,
+	translate_x:  int,
+	translate_y:  int,
+	clip:         Rect,
+	font:         ^Font,
 }
 
 DrawFlag :: enum {
@@ -109,12 +106,9 @@ DrawFlag :: enum {
 	MASK   = 1<<2,
 }
 
-
+Draw_Item :: struct {}
 Draw_List :: struct {
-	Item :: struct {
-
-	}
-	items: []Item
+	items: []Draw_Item,
 }
 
 Key :: enum {
@@ -268,112 +262,112 @@ Key :: enum {
 	BACKSLASH          = 92,  /* \ */
 	RIGHT_BRACKET      = 93,  /* ] */
 	GRAVE_ACCENT       = 96,  /* ` */
-}
+};
 
 
 key_down :: proc(k: Key) -> bool {
-	return _core.key_states[k] != 0
+	return _core.key_states[k] != 0;
 }
 
 key_pressed :: proc(k: Key) -> bool {
-	return (_core.key_deltas[k] != 0) && key_down(k)
+	return (_core.key_deltas[k] != 0) && key_down(k);
 }
 
 
 
 
-win32_perf_count_freq := win32.GetQueryPerformanceFrequency()
+win32_perf_count_freq := win32.GetQueryPerformanceFrequency();
 time_now :: proc() -> f64 {
-	assert(win32_perf_count_freq != 0)
+	assert(win32_perf_count_freq != 0);
 
-	counter: i64
-	win32.QueryPerformanceCounter(^counter)
-	result := counter as f64 / win32_perf_count_freq as f64
-	return result
+	counter: i64;
+	win32.QueryPerformanceCounter(^counter);
+	result := cast(f64)counter / cast(f64)win32_perf_count_freq;
+	return result;
 }
 
-_core: Core
+_core: Core;
 
 run :: proc(user_init, user_step: proc(c: ^Core)) {
-	using win32
+	using win32;
 
-	_core.running = true
+	_core.running = true;
 
-	win32_proc :: proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT #no_inline #stdcall {
+	win32_proc :: proc(hwnd: win32.HWND, msg: u32, wparam: win32.WPARAM, lparam: win32.LPARAM) -> win32.LRESULT #no_inline #cc_c {
 		win32_app_key_mods :: proc() -> u32 {
-			mods: u32 = 0
+			mods: u32 = 0;
 
 			if is_key_down(Key_Code.SHIFT) {
-				mods |= Key.MOD_SHIFT as u32
+				mods |= cast(u32)Key.MOD_SHIFT;
 			}
 			if is_key_down(Key_Code.CONTROL) {
-				mods |= Key.MOD_CONTROL as u32
+				mods |= cast(u32)Key.MOD_CONTROL;
 			}
 			if is_key_down(Key_Code.MENU) {
-				mods |= Key.MOD_ALT as u32
+				mods |= cast(u32)Key.MOD_ALT;
 			}
 			if is_key_down(Key_Code.LWIN) || is_key_down(Key_Code.RWIN) {
-				mods |= Key.MOD_SUPER as u32
+				mods |= cast(u32)Key.MOD_SUPER;
 			}
 
-			return mods
+			return mods;
 		}
 
 		match msg {
 		case WM_KEYDOWN:
-			_core.key_modifiers = win32_app_key_mods()
+			_core.key_modifiers = win32_app_key_mods();
 			if wparam < MAX_KEYS {
-				_core.key_states[wparam] = 1
-				_core.key_deltas[wparam] = 1
+				_core.key_states[wparam] = 1;
+				_core.key_deltas[wparam] = 1;
 			}
-			return 0
+			return 0;
 
 		case WM_KEYUP:
-			_core.key_modifiers = win32_app_key_mods()
+			_core.key_modifiers = win32_app_key_mods();
 			if wparam < MAX_KEYS {
-				_core.key_states[wparam] = 0
-				_core.key_deltas[wparam] = 1
+				_core.key_states[wparam] = 0;
+				_core.key_deltas[wparam] = 1;
 			}
-			return 0
+			return 0;
 
 		case WM_CLOSE:
-			PostQuitMessage(0)
-			_core.running = false
-			return 0
+			PostQuitMessage(0);
+			_core.running = false;
+			return 0;
 		}
 
-		return DefWindowProcA(hwnd, msg, wparam, lparam)
+		return DefWindowProcA(hwnd, msg, wparam, lparam);
 	}
 
 
 	window_class := WNDCLASSEXA{
-		class_name = ("Punity\x00" as string).data, // C-style string
-		size       = size_of(WNDCLASSEXA) as u32,
+		class_name = (cast(string)"Punity\x00").data, // C-style string
+		size       = size_of(WNDCLASSEXA),
 		style      = CS_HREDRAW | CS_VREDRAW | CS_OWNDC,
-		instance   = GetModuleHandleA(nil) as HINSTANCE,
+		instance   = cast(HINSTANCE)GetModuleHandleA(nil),
 		wnd_proc   = win32_proc,
 		// wnd_proc   = DefWindowProcA,
-		background = GetStockObject(BLACK_BRUSH) as HBRUSH,
-	}
+		background = cast(HBRUSH)GetStockObject(BLACK_BRUSH),
+	};
 
 	if RegisterClassExA(^window_class) == 0 {
-		fmt.fprintln(os.stderr, "RegisterClassExA failed")
-		return
+		fmt.fprintln(os.stderr, "RegisterClassExA failed");
+		return;
 	}
 
-	screen_width  := GetSystemMetrics(SM_CXSCREEN)
-	screen_height := GetSystemMetrics(SM_CYSCREEN)
+	screen_width  := GetSystemMetrics(SM_CXSCREEN);
+	screen_height := GetSystemMetrics(SM_CYSCREEN);
 
-	rc: RECT
-	rc.left   = (screen_width - WINDOW_WIDTH)   / 2
-	rc.top    = (screen_height - WINDOW_HEIGHT) / 2
-	rc.right  = rc.left + WINDOW_WIDTH
-	rc.bottom = rc.top + WINDOW_HEIGHT
+	rc: RECT;
+	rc.left   = (screen_width - WINDOW_WIDTH)   / 2;
+	rc.top    = (screen_height - WINDOW_HEIGHT) / 2;
+	rc.right  = rc.left + WINDOW_WIDTH;
+	rc.bottom = rc.top + WINDOW_HEIGHT;
 
-	style: u32 = WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX
-	assert(AdjustWindowRect(^rc, style, 0) != 0)
+	style: u32 = WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;
+	assert(AdjustWindowRect(^rc, style, 0) != 0);
 
-	wt := WINDOW_TITLE
+	wt := WINDOW_TITLE;
 
 	win32_window := CreateWindowExA(0,
 	                                window_class.class_name,
@@ -382,101 +376,115 @@ run :: proc(user_init, user_step: proc(c: ^Core)) {
 	                                rc.left, rc.top,
 	                                rc.right-rc.left, rc.bottom-rc.top,
 	                                nil, nil, window_class.instance,
-	                                nil)
+	                                nil);
 
 	if win32_window == nil {
-		fmt.fprintln(os.stderr, "CreateWindowExA failed")
-		return
+		fmt.fprintln(os.stderr, "CreateWindowExA failed");
+		return;
 	}
 
 
-	window_bmi: BITMAPINFO
-	window_bmi.size        = size_of(BITMAPINFO.HEADER) as u32
-	window_bmi.width       = CANVAS_WIDTH
-	window_bmi.height      = CANVAS_HEIGHT
-	window_bmi.planes      = 1
-	window_bmi.bit_count   = 32
-	window_bmi.compression = BI_RGB
+	window_bmi: BITMAPINFO;
+	window_bmi.size        = size_of(BITMAPINFOHEADER);
+	window_bmi.width       = CANVAS_WIDTH;
+	window_bmi.height      = CANVAS_HEIGHT;
+	window_bmi.planes      = 1;
+	window_bmi.bit_count   = 32;
+	window_bmi.compression = BI_RGB;
 
 
-	user_init(^_core)
+	user_init(^_core);
 
+	ShowWindow(win32_window, SW_SHOW);
 
-	ShowWindow(win32_window, SW_SHOW)
+	window_buffer := new_slice(u32, CANVAS_WIDTH * CANVAS_HEIGHT);
+	assert(window_buffer.data != nil);
+	defer free(window_buffer.data);
 
-	window_buffer := new_slice(u32, CANVAS_WIDTH * CANVAS_HEIGHT)
-	assert(window_buffer.data != nil)
-	defer free(window_buffer.data)
 
-	for i := 0; i < window_buffer.count; i++ {
-		window_buffer[i] = 0xff00ff
+	for i := 0; i < window_buffer.count; i += 1 {
+		window_buffer[i] = 0xff00ff;
 	}
 
 
-	prev_time, curr_time,dt: f64
-	prev_time = time_now()
-	curr_time = time_now()
-	total_time : f64 = 0
-	offset_x := 0
-	offset_y := 0
+	dt: f64;
+	prev_time := time_now();
+	curr_time := time_now();
+	total_time : f64 = 0;
+	offset_x := 0;
+	offset_y := 0;
 
-	message: MSG
+	message: MSG;
 	for _core.running {
-		curr_time = time_now()
-		dt = curr_time - prev_time
-		prev_time = curr_time
-		total_time += dt
+		curr_time = time_now();
+		dt = curr_time - prev_time;
+		prev_time = curr_time;
+		total_time += dt;
 
-		offset_x += 1
-		offset_y += 2
+		offset_x += 1;
+		offset_y += 2;
 
 		{
-			data: [128]byte
-			buf := data[:0]
-			fmt.bprintf(^buf, "Punity: % ms\x00", dt*1000)
-			win32.SetWindowTextA(win32_window, buf.data)
+			data: [128]byte;
+			buf: fmt.Buffer;
+			buf.data = data[:];
+			fmt.bprintf(^buf, "Punity: %.4f ms\x00", dt*1000);
+			win32.SetWindowTextA(win32_window, ^buf[0]);
 		}
 
 
-		for y := 0; y < CANVAS_HEIGHT; y++ {
-			for x := 0; x < CANVAS_WIDTH; x++ {
-				g := (x % 32) * 8
-				b := (y % 32) * 8
-				window_buffer[x + y*CANVAS_WIDTH] = (g << 8 | b) as u32
+		for y := 0; y < CANVAS_HEIGHT; y += 1 {
+			for x := 0; x < CANVAS_WIDTH; x += 1 {
+				g := (x % 32) * 8;
+				b := (y % 32) * 8;
+				window_buffer[x + y*CANVAS_WIDTH] = cast(u32)(g << 8 | b);
 			}
 		}
 
-		_core.key_deltas = nil
+		mem.zero(^_core.key_deltas[0], size_of_val(_core.key_deltas));
 
 		for PeekMessageA(^message, nil, 0, 0, PM_REMOVE) != 0 {
 			if message.message == WM_QUIT {
-				_core.running = false
+				_core.running = false;
 			}
-			TranslateMessage(^message)
-			DispatchMessageA(^message)
+			TranslateMessage(^message);
+			DispatchMessageA(^message);
 		}
 
-		user_step(^_core)
+		user_step(^_core);
 
-		dc := GetDC(win32_window)
+		dc := GetDC(win32_window);
 		StretchDIBits(dc,
 		              0, 0, CANVAS_WIDTH * CANVAS_SCALE, CANVAS_HEIGHT * CANVAS_SCALE,
 		              0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
 		              window_buffer.data,
 		              ^window_bmi,
 		              DIB_RGB_COLORS,
-		              SRCCOPY)
-		ReleaseDC(win32_window, dc)
+		              SRCCOPY);
+		ReleaseDC(win32_window, dc);
 
 
 		{
-			delta := time_now() - prev_time
-			ms := ((FRAME_TIME - delta) * 1000) as i32
+			delta := time_now() - prev_time;
+			ms := cast(i32)((FRAME_TIME - delta) * 1000);
 			if ms > 0 {
-				win32.Sleep(ms)
+				win32.Sleep(ms);
 			}
 		}
 
-		_core.frame++
+		_core.frame += 1;
+	}
+}
+
+
+main :: proc() {
+	user_init :: proc(c: ^Core) {
+
 	}
+
+	user_step :: proc(c: ^Core) {
+
+	}
+
+	run(user_init, user_step);
 }

+ 20 - 12
core/fmt.odin

@@ -421,9 +421,7 @@ fmt_write_padding :: proc(fi: ^Fmt_Info, width: int) {
 
 fmt_integer :: proc(fi: ^Fmt_Info, u: u64, base: int, signed: bool, digits: string) {
 	negative := signed && cast(i64)u < 0;
-	if negative {
-		u = -u;
-	}
+	u = abs(u);
 	buf: [256]byte;
 	if fi.width_set || fi.prec_set {
 		width := fi.width + fi.prec + 3;
@@ -504,14 +502,16 @@ fmt_integer :: proc(fi: ^Fmt_Info, u: u64, base: int, signed: bool, digits: stri
 		buffer_write(fi.buf, buf[i:]);
 	} else {
 		width := fi.width - utf8.rune_count(cast(string)buf[i:]);
-		if fi.minus {
-			// Right pad
-			buffer_write(fi.buf, buf[i:]);
-			fmt_write_padding(fi, width);
-		} else {
-			// Left pad
-			fmt_write_padding(fi, width);
-			buffer_write(fi.buf, buf[i:]);
+			if width > 0 {
+			if fi.minus {
+				// Right pad
+				buffer_write(fi.buf, buf[i:]);
+				fmt_write_padding(fi, width);
+			} else {
+				// Left pad
+				fmt_write_padding(fi, width);
+				buffer_write(fi.buf, buf[i:]);
+			}
 		}
 	}
 
@@ -574,8 +574,16 @@ fmt_float :: proc(fi: ^Fmt_Info, v: f64, bit_size: int, verb: rune) {
 			signed := v < 0;
 			v = abs(v);
 
+			if signed {
+				buffer_write_byte(fi.buf, '-');
+			}
+
 			val := cast(u64)v;
-			fmt_integer(fi, val, 10, signed, __DIGITS_LOWER);
+			fi.minus = false;
+			fi.width = 0;
+			fi.prec = 0;
+			// TODO(bill): Write integer to buffer than use this crap
+			fmt_integer(fi, val, 10, false, __DIGITS_LOWER);
 
 			if fi.hash || prec > 0 {
 				arg := v - cast(f64)val;

+ 5 - 4
src/check_decl.c

@@ -302,10 +302,11 @@ void check_proc_lit(Checker *c, Entity *e, DeclInfo *d) {
 			error_node(pd->body, "A procedure tagged as `#foreign` cannot have a body");
 		}
 
-		if (proc_type->Proc.calling_convention != ProcCC_Odin) {
-			error_node(d->proc_lit, "An internal procedure may only have the Odin calling convention");
-			proc_type->Proc.calling_convention = ProcCC_Odin;
-		}
+		// TODO(bill): Is this the best option? What about passing to external shit?!
+		// if (proc_type->Proc.calling_convention != ProcCC_Odin) {
+		// 	error_node(d->proc_lit, "An internal procedure may only have the Odin calling convention");
+		// 	proc_type->Proc.calling_convention = ProcCC_Odin;
+		// }
 
 		d->scope = c->context.scope;
 

+ 5 - 0
src/check_expr.c

@@ -203,6 +203,11 @@ i64 check_distance_between_types(Checker *c, Operand *operand, Type *type) {
 		}
 	}
 
+	// if (is_type_proc(dst)) {
+	// 	if (are_types_identical(src, dst)) {
+	// 		return 1;
+	// 	}
+	// }
 
 	if (is_type_any(dst)) {
 		// NOTE(bill): Anything can cast to `Any`

+ 1 - 1
src/main.c

@@ -240,7 +240,7 @@ int main(int argc, char **argv) {
 	char lib_str_buf[1024] = {0};
 	for_array(i, ir_gen.module.foreign_library_paths) {
 		String lib = ir_gen.module.foreign_library_paths.e[i];
-		gb_printf_err("Linking lib: %.*s\n", LIT(lib));
+		// gb_printf_err("Linking lib: %.*s\n", LIT(lib));
 		isize len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf),
 		                        " \"%.*s\"", LIT(lib));
 		lib_str = gb_string_appendc(lib_str, lib_str_buf);

+ 8 - 5
src/parser.c

@@ -1827,11 +1827,15 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
 	}
 
 	case Token_if:
-		if (lhs) goto error;
-		return parse_if_expr(f);
+		if (!lhs && f->expr_level >= 0) {
+			return parse_if_expr(f);
+		}
+		break;
 	case Token_OpenBrace:
-		if (lhs) goto error;
-		return parse_block_expr(f);
+		if (!lhs && f->expr_level >= 0) {
+			return parse_block_expr(f);
+		}
+		break;
 
 	default: {
 		AstNode *type = parse_identifier_or_type(f);
@@ -1846,7 +1850,6 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
 	}
 	}
 
-error:
 	Token begin = f->curr_token;
 	syntax_error(begin, "Expected an operand");
 	fix_advance_to_next_stmt(f);

+ 3 - 1
src/types.c

@@ -1194,7 +1194,9 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n
 	} else if (!is_type_union(type)) {
 		for (isize i = 0; i < type->Record.field_count; i++) {
 			Entity *f = type->Record.fields[i];
-			GB_ASSERT(f->kind == Entity_Variable && f->flags & EntityFlag_Field);
+			if (f->kind != Entity_Variable || (f->flags & EntityFlag_Field) == 0) {
+				continue;
+			}
 			String str = f->token.string;
 			if (str_eq(field_name, str)) {
 				selection_add_index(&sel, i);  // HACK(bill): Leaky memory