Browse Source

Better `using`; foreign system libraries; optional semicolons

Ginger Bill 9 years ago
parent
commit
a06f70d5d9

+ 81 - 81
examples/basic.odin

@@ -3,166 +3,166 @@
 #load "file.odin"
 #load "file.odin"
 
 
 print_string :: proc(s: string) {
 print_string :: proc(s: string) {
-	file_write(file_get_standard(FileStandard.OUTPUT), s as []byte);
+	file_write(file_get_standard(FileStandard.OUTPUT), s as []byte)
 }
 }
 
 
 byte_reverse :: proc(b: []byte) {
 byte_reverse :: proc(b: []byte) {
-	n := len(b);
+	n := len(b)
 	for i := 0; i < n/2; i++ {
 	for i := 0; i < n/2; i++ {
-		b[i], b[n-1-i] = b[n-1-i], b[i];
+		b[i], b[n-1-i] = b[n-1-i], b[i]
 	}
 	}
 }
 }
 
 
 encode_rune :: proc(r: rune) -> ([4]byte, int) {
 encode_rune :: proc(r: rune) -> ([4]byte, int) {
-	buf: [4]byte;
-	i := r as u32;
-	mask: byte : 0x3f;
+	buf: [4]byte
+	i := r as u32
+	mask: byte : 0x3f
 	if i <= 1<<7-1 {
 	if i <= 1<<7-1 {
-		buf[0] = r as byte;
-		return buf, 1;
+		buf[0] = r as byte
+		return buf, 1
 	}
 	}
 	if i <= 1<<11-1 {
 	if i <= 1<<11-1 {
-		buf[0] = 0xc0 | (r>>6) as byte;
-		buf[1] = 0x80 | (r)    as byte & mask;
-		return buf, 2;
+		buf[0] = 0xc0 | (r>>6) as byte
+		buf[1] = 0x80 | (r)    as byte & mask
+		return buf, 2
 	}
 	}
 
 
 	// Invalid or Surrogate range
 	// Invalid or Surrogate range
 	if i > 0x0010ffff ||
 	if i > 0x0010ffff ||
 	   (i >= 0xd800 && i <= 0xdfff) {
 	   (i >= 0xd800 && i <= 0xdfff) {
-		r = 0xfffd;
+		r = 0xfffd
 	}
 	}
 
 
 	if i <= 1<<16-1 {
 	if i <= 1<<16-1 {
-		buf[0] = 0xe0 | (r>>12) as byte;
-		buf[1] = 0x80 | (r>>6)  as byte & mask;
-		buf[2] = 0x80 | (r)     as byte & mask;
-		return buf, 3;
+		buf[0] = 0xe0 | (r>>12) as byte
+		buf[1] = 0x80 | (r>>6)  as byte & mask
+		buf[2] = 0x80 | (r)     as byte & mask
+		return buf, 3
 	}
 	}
 
 
-	buf[0] = 0xf0 | (r>>18) as byte;
-	buf[1] = 0x80 | (r>>12) as byte & mask;
-	buf[2] = 0x80 | (r>>6)  as byte & mask;
-	buf[3] = 0x80 | (r)     as byte & mask;
-	return buf, 4;
+	buf[0] = 0xf0 | (r>>18) as byte
+	buf[1] = 0x80 | (r>>12) as byte & mask
+	buf[2] = 0x80 | (r>>6)  as byte & mask
+	buf[3] = 0x80 | (r)     as byte & mask
+	return buf, 4
 }
 }
 
 
 print_rune :: proc(r: rune) {
 print_rune :: proc(r: rune) {
-	buf, n := encode_rune(r);
-	str := buf[:n] as string;
-	print_string(str);
+	buf, n := encode_rune(r)
+	str := buf[:n] as string
+	print_string(str)
 }
 }
 
 
-print_space :: proc() { print_rune(#rune " "); }
-print_nl    :: proc() { print_rune(#rune "\n"); }
+print_space :: proc() { print_rune(#rune " ") }
+print_nl    :: proc() { print_rune(#rune "\n") }
 
 
 print_int :: proc(i: int) {
 print_int :: proc(i: int) {
 	print_int_base(i, 10);
 	print_int_base(i, 10);
 }
 }
 print_int_base :: proc(i, base: int) {
 print_int_base :: proc(i, base: int) {
-	NUM_TO_CHAR_TABLE :: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@$";
+	NUM_TO_CHAR_TABLE :: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@$"
 
 
-	buf: [65]byte;
-	len := 0;
-	negative := false;
+	buf: [65]byte
+	len := 0
+	negative := false
 	if i < 0 {
 	if i < 0 {
-		negative = true;
-		i = -i;
+		negative = true
+		i = -i
 	}
 	}
 	if i == 0 {
 	if i == 0 {
-		buf[len] = #rune "0";
-		len++;
+		buf[len] = #rune "0"
+		len++
 	}
 	}
 	for i > 0 {
 	for i > 0 {
-		buf[len] = NUM_TO_CHAR_TABLE[i % base];
+		buf[len] = NUM_TO_CHAR_TABLE[i % base]
 		len++;
 		len++;
-		i /= base;
+		i /= base
 	}
 	}
 
 
 	if negative {
 	if negative {
-		buf[len] = #rune "-";
-		len++;
+		buf[len] = #rune "-"
+		len++
 	}
 	}
 
 
-	byte_reverse(buf[:len]);
-	print_string(buf[:len] as string);
+	byte_reverse(buf[:len])
+	print_string(buf[:len] as string)
 }
 }
 
 
 print_uint :: proc(i: uint) {
 print_uint :: proc(i: uint) {
-	print__uint(i, 10, 0, #rune " ");
+	print__uint(i, 10, 0, #rune " ")
 }
 }
 print__uint :: proc(i, base: uint, min_width: int, pad_char: byte) {
 print__uint :: proc(i, base: uint, min_width: int, pad_char: byte) {
-	NUM_TO_CHAR_TABLE :: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@$";
+	NUM_TO_CHAR_TABLE :: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@$"
 
 
-	buf: [65]byte;
-	len := 0;
+	buf: [65]byte
+	len := 0
 	if i == 0 {
 	if i == 0 {
-		buf[len] = #rune "0";
-		len++;
+		buf[len] = #rune "0"
+		len++
 	}
 	}
 	for i > 0 {
 	for i > 0 {
-		buf[len] = NUM_TO_CHAR_TABLE[i % base];
-		len++;
-		i /= base;
+		buf[len] = NUM_TO_CHAR_TABLE[i % base]
+		len++
+		i /= base
 	}
 	}
 	for len < min_width {
 	for len < min_width {
-		buf[len] = pad_char;
-		len++;
+		buf[len] = pad_char
+		len++
 	}
 	}
 
 
-	byte_reverse(buf[:len]);
-	print_string(buf[:len] as string);
+	byte_reverse(buf[:len])
+	print_string(buf[:len] as string)
 }
 }
 
 
 print_bool :: proc(b : bool) {
 print_bool :: proc(b : bool) {
-	if b { print_string("true"); }
-	else { print_string("false"); }
+	if b { print_string("true") }
+	else { print_string("false") }
 }
 }
 
 
-print_pointer :: proc(p: rawptr) #inline { print__uint(p as uint, 16, 0, #rune " "); }
+print_pointer :: proc(p: rawptr) #inline { print__uint(p as uint, 16, 0, #rune " ") }
 
 
-print_f32     :: proc(f: f32) #inline { print__f64(f as f64, 7); }
-print_f64     :: proc(f: f64) #inline { print__f64(f, 10); }
+print_f32     :: proc(f: f32) #inline { print__f64(f as f64, 7) }
+print_f64     :: proc(f: f64) #inline { print__f64(f, 10) }
 
 
 print__f64 :: proc(f: f64, decimal_places: int) {
 print__f64 :: proc(f: f64, decimal_places: int) {
 	if f == 0 {
 	if f == 0 {
-		print_rune(#rune "0");
-		return;
+		print_rune(#rune "0")
+		return
 	}
 	}
 	if f < 0 {
 	if f < 0 {
-		print_rune(#rune "-");
-		f = -f;
+		print_rune(#rune "-")
+		f = -f
 	}
 	}
 
 
 	print_u64 :: proc(i: u64) {
 	print_u64 :: proc(i: u64) {
-		NUM_TO_CHAR_TABLE :: "0123456789";
+		NUM_TO_CHAR_TABLE :: "0123456789"
 
 
-		buf: [22]byte;
-		len := 0;
+		buf: [22]byte
+		len := 0
 		if i == 0 {
 		if i == 0 {
-			buf[len] = #rune "0";
-			len++;
+			buf[len] = #rune "0"
+			len++
 		}
 		}
 		for i > 0 {
 		for i > 0 {
-			buf[len] = NUM_TO_CHAR_TABLE[i % 10];
-			len++;
-			i /= 10;
+			buf[len] = NUM_TO_CHAR_TABLE[i % 10]
+			len++
+			i /= 10
 		}
 		}
-		byte_reverse(buf[:len]);
-		print_string(buf[:len] as string);
+		byte_reverse(buf[:len])
+		print_string(buf[:len] as string)
 	}
 	}
 
 
-	i := f as u64;
-	print_u64(i);
-	f -= i as f64;
+	i := f as u64
+	print_u64(i)
+	f -= i as f64
 
 
-	print_rune(#rune ".");
+	print_rune(#rune ".")
 
 
-	mult := 10.0;
+	mult := 10.0
 	for decimal_places := 6; decimal_places >= 0; decimal_places-- {
 	for decimal_places := 6; decimal_places >= 0; decimal_places-- {
-		i = (f * mult) as u64;
-		print_u64(i as u64);
-		f -= i as f64 / mult;
-		mult *= 10;
+		i = (f * mult) as u64
+		print_u64(i as u64)
+		f -= i as f64 / mult
+		mult *= 10
 	}
 	}
 }
 }

+ 13 - 745
examples/demo.odin

@@ -3,760 +3,28 @@
 #load "game.odin"
 #load "game.odin"
 
 
 main :: proc() {
 main :: proc() {
-	// _ = hellope();
-	// variables();
-	// procedures();
-	// constants();
-	// types();
-	// data_control();
-	// using_fields();
-
-	Entity :: type struct {
-		guid: u64;
-		name: string;
-	}
-
-	Frog :: type struct {
-		using entity: Entity;
-		jump_height: f32;
-	}
-
-
-	e: Entity;
-	frog : Frog;
-	frog.name = "Ribbit";
-
-	a: [16]u32;
-	x := ^a[1];
-	y := ^a[5];
-	d := ptr_sub(y, ptr_offset(x, 1));
-	print_int(d); nl();
 
 
 	Thing :: type struct {
 	Thing :: type struct {
-		CONSTANT :: 123;
-		Thing :: type struct {
-			y: f32;
-
-			z: int;
-			w: int;
-		}
-
-		x: Thing;
-	}
-
-	test :: proc() -> int {
-		t_outer: Thing;
-		t_outer.x = Thing.Thing{};
-		using Thing;
-		t_inner: Thing;
-		t_inner.y = 1;
-		print_int(CONSTANT); nl();
-		return CONSTANT;
-	}
-
-	test__ := test();
-
-
-
-	// run_game();
-}
-
-
-hellope :: proc() -> int {
-	print_string("Hellope, 世界\n");
-	return 1;
-}
-
-
-// Line comment
-/*
-	Block Comment
-*/
-/*
-	Nested /*
-		Block /*
-			Comment
-		*/
-	*/
-*/
-
-apple, banana, carrot: bool;
-box, carboard: bool = true, false;
-hellope_value: int = hellope(); // The procedure is ran just before `main`
-
-variables :: proc() {
-	i: int; // initialized with zero value
-	j: int = 1;
-	x, y: int = 1, 2;
-
-	// Type inference
-	apple, banana, 世界 := true, 123, "world";
-
-
-	// Basic Types of the Language
-	//
-	// bool
-	//
-	// i8 i16 i32 i64 i128
-	// u8 u16 u32 u64 u128
-	//
-	// f32 f64
-	//
-	// int uint (size_of(int) == size_of(uint) == size_of(rawptr))
-	//
-	// rawptr (equivalent to void * in C/C++)
-	//
-	// string
-	//
-	// byte - alias for u8
-	// rune - alias for i32 // Unicode Codepoint
-	//
-	// "untyped" types can implicitly convert to any of the "typed" types
-	//                      Default Type
-	// untyped bool      -  bool
-	// untyped integer   -  int
-	// untyped float     -  f64
-	// untyped pointer   -  rawptr
-	// untyped string    -  string
-	// untyped rune      -  rune/i32
-
-
-	// Zero values
-	zero_numeric := 0;
-	zero_boolean := false;
-	zero_pointer := null;
-	zero_string1 := ""; // Escaped string
-	zero_string2 := ``; // Raw string
-	// Compound types have a different kind of zero value
-
-	// Unary operators
-	// +a
-	// -a
-	// ~a
-	// !a
-
-	// Binary operators
-	// a + b    add
-	// a - b    sub
-	// a ~ b    xor
-	// a | b     or
-
-	// a * b    mul
-	// a / b    quo
-	// a % b    mod
-	// a & b    and
-	// a &~ b   bitclear == a & (~b)
-	// a << b   shl
-	// a >> b   shr
-
-	// a as Type         // Type cast
-	// a transmute Type  // Bit  cast
-
-	// a == b   eq
-	// a != b   ne
-	// a < b    lt
-	// a > b    gt
-	// a <= b   le
-	// a >= b   ge
-
-}
-
-procedures :: proc() {
-	add :: proc(x: int, y: int) -> int {
-		return x + y;
-	}
-	print_int(add(3, 4)); // 7
-	print_nl();
-
-	add_v2 :: proc(x, y: int) -> int {
-		return x + y;
-	}
-
-	fibonacci :: proc(n: int) -> int {
-		if n < 2 {
-			return n;
-		}
-		return fibonacci(n-1) + fibonacci(n-2);
-	}
-	print_int(fibonacci(12)); nl();
-
-
-	swap_strings :: proc(x, y: string) -> (string, string) {
-		return y, x;
+		using x: struct { a, b: int }
 	}
 	}
-	a, b := swap_strings("Hellope\n", "World\n");
-	print_string(a);
-	print_string(b);
-
-	a, b = b, a; // Quirk of grammar the of multiple assignments
-	             // Swap variables
-	print_string(a);
-	print_string(b);
-
-	// Not a hint like C/C++, it's mandatory (unless it cannot do it but it will warn)
-	proc1 :: proc(a, b: int) #inline {
-		print_int(a + b);
-	}
-	proc2 :: proc(a, b: int) #no_inline {
-		print_int(a + b);
-	}
-
-	print_int(3 ''add 4);     // Infix style
-	print_nl();
-	print_int(12 'fibonacci); // Postfix style
-	print_nl();
-}
-
-
-TAU :: 6.28318530718;
-
-constants :: proc() {
-	TAU :: 6.28318530718; // untyped float
-	WORLD_JAPANESE :: "世界"; // untyped string
-
-	TAU_32 : f32 : 6.28318530718;
-	TAU_AS_32 :: 6.28318530718 as f32;
-
-	PI :: TAU / 2;
-
-	CLOSE_TO_PI :: 3;
-
-	DIFF :: (PI - CLOSE_TO_PI) / PI; // Evaluated at compile time
-
-	a := TAU;         // the constant's value becomes typed as f64
-	b := CLOSE_TO_PI; // the constant's value becomes typed as int
-	c := DIFF;
-}
-
-nl :: proc() { print_nl(); }
-
-types :: proc() {
-
-	x: int = 123;
-	y := x; // y: int = x;
-	// z: f32 = x; // invalid
-	z: f32 = x as f32;
-
-
-	ptr_z := ^z;  // Pascal notation
-	ptr_z^ = 123; // Derefence Notation
-	w: f32 = ptr_z^;  // 123
-	print_f32(z); nl();
-
-	// ^z - pointer to z
-	// z^ - z from pointer
-
-	// Implicit conversion to and from rawptr
-	r_ptr: rawptr = ptr_z;
-	ptr_z = r_ptr;
-
-
-
-	f32_array: [12]f32; // Array of 12 f32
-	f32_array[0] = 2;
-	f32_array[1] = 3;
-	// f32_array[-1] = 2; // Error - compile time check
-	// f32_array[13]  = 2; // Error - compile time check
-	f32_array_len := len(f32_array); // builtin procedure
-	f32_array_cap := cap(f32_array); // == len(f32_array)
-
-
-	mda: [2][3][4]int; // Column-major
-	// mda[x][y][z]
-
-
-	api: [2]^f32;
-	papi: ^[2]^f32;
-
-
-
-
-	f32_slice: []f32; // Slice / Array reference
-	f32_slice = f32_array[0:5];
-	f32_slice = f32_array[:5];
-	f32_slice = f32_array[:]; // f32_array[0:len(f32_array)-1];
-
-	f32_slice = f32_array[1:5:7]; // low:1, high:5, max:7
-	                              // len: 5-1 == 4
-	                              // cap: 7-1 == 6
-
-
-
-	append_success := append(^f32_slice, 1);
-	_ = append(^f32_slice, 2);
-
-	_ = copy(f32_array[0:2], f32_array[2:4]); // You can use memcpy/memmove if you want
-
-
-
-
-
-	s := "Hellope World";
-	sub_string: string = s[5:10];
-
-
-
-
-
-	v0: {4}f32; // Vector of 4 f32
-	v0[0] = 1;
-	v0[1] = 3;
-	v0[2] = 6;
-	v0[3] = 10;
-
-	v1 := v0 + v0; // Simd Arithmetic
-	v1 = v1 - v0;
-	v1 *= v0; // i.e. hadamard product
-	v1 /= v0;
-
-	// builtin procedure
-	v2 := swizzle(v0, 3, 2, 1, 0); // {10, 6, 3, 1}
-
-	v3: {4}bool = v0 == v2;
-	// LLVM rant?
-
-
-
-
-
-
-
-	Vec4 :: type {4}f32;
-	Array3Int :: type [3]int;
-
-	Vec3 :: type struct {
-		x, y, z: f32;
-	}
-
-	BinaryNode :: type struct {
-		left, right: ^BinaryNode; // same format as procedure argument
-		data: rawptr;
-	}
-
-	AddProc :: type proc(a, b: int) -> int
-
-	Packed :: type struct #packed {
-		a: u8;
-		b: u16;
-		c: u32;
-	}
-	static_assert(size_of(Packed) == 7); // builtin procedure
-
 
 
 	{
 	{
-		MyInt :: type int;
-		x: int = 1;
-		y: MyInt = 2;
-		// z := x + y; // Failure - types cannot implicit convert*
-		z := x as MyInt + y; // Type cast using `as`
+		using t := new(Thing)
+		defer delete(t)
+		a = 321
+		print_int(a); nl()
 	}
 	}
 
 
+	// {
+	// 	using t := new(Thing)
+	// 	defer delete(t)
+	// 	a = 1337
+	// 	print_int(a); nl()
+	// }
 
 
-	{
-		// From: Quake III Arena
-		Q_rsqrt :: proc(number: f32) -> f32 {
-			i: i32;
-			x2, y: f32;
-			THREE_HALFS :: 1.5;
-
-			x2 = number * 0.5;
-			y = number;
-			i = (^y as ^i32)^;                      // evil floating point bit level hacking
-			i = 0x5f3759df - i>>1;                  // what the fuck?
-			y = (^i as ^f32)^;
-			y = y * (THREE_HALFS - (x2 * y *y));    // 1st iteration
-		//	y = y * (THREE_HALFS - (x2 * y *y));    // 2nd iteration, this can be removed
-			return y;
-		}
-
-		Q_rsqrt_v2 :: proc(number: f32) -> f32 {
-			THREE_HALFS :: 1.5;
-
-			x2 := number * 0.5;
-			y := number;
-			i := y transmute i32;                   // evil floating point bit level hacking
-			i = 0x5f3759df - i>>1;                  // what the fuck?
-			y = i transmute f32;
-			y = y * (THREE_HALFS - (x2 * y *y));    // 1st iteration
-		//	y = y * (THREE_HALFS - (x2 * y *y));    // 2nd iteration, this can be removed
-			return y;
-		}
-
-		// NOTE(bill): transmute only works if the size of the types are equal
-
-		/*
-			// in C
-			union {
-				i32 i;
-				f32 y;
-			};
-		 */
-	}
-
-	{ // Enumeration
-		Thing :: type enum {
-			APPLE,
-			FROG,
-			TREE,
-			TOMB,
-		}
-		a := Thing.APPLE;
-
-		Sized :: type enum u64 {
-			APPLE,
-			FROG,
-			TREE,
-			TOMB,
-		}
-		static_assert(size_of(Sized) == size_of(u64));
-
-		Certain :: type enum {
-			APPLE = 3,
-			FROG,
-			TREE = 7,
-			TOMB,
-		}
-		static_assert(Certain.TOMB == 8);
-	}
-
-	{ // Untagged union
-		BitHack :: type union {
-			i: i32;
-			f: f32;
-		}
-		b: BitHack;
-		b.f = 123;
-		print_int_base(b.i as int, 16); print_nl();
-
-
-
-		// Manually tagged union
-
-		EntityKind :: type enum {
-			Invalid,
-			Constant,
-			Variable,
-			TypeName,
-			Procedure,
-			Builtin,
-			Count,
-		}
-
-		Entity :: type struct {
-			kind: EntityKind;
-			guid: u64;
-
-			// Other data
-
-			/*using*/
-			data: union {
-				constant: struct{};
-				variable: struct{
-					visited, is_field, used, anonymous: bool;
-				};
-				procedure: struct { used: bool; };
-				buitlin: struct { id: i32; };
-			};
-		}
-
-
-		// NOTE(bill): Tagged unions are not added yet but are planned
-	}
-
-
-
-	{ // Compound Literals
-		a := [3]int{1, 2, 3};
-		b := [3]int{};
-		c := [..]int{1, 2, 3};
-
-		d := []int{1, 2, 3}; // slice
-
-		e := {4}f32{1, 2, 3, 4};
-		f := {4}f32{1}; // broadcasts to all
-		// g := {4}f32{1, 2}; // require either 1 or 4 elements
-
-		Vec2 :: type {2}f32;
-
-		h := Vec2{1, 2};
-
-		i := Vec2{5} * h; // For strong type safety
-		// FORENOTE: 5 * h was originally allowed but it was an edge case in the
-		// compiler I didn't think it was enough to justify have it it.
-
-		print_f32(i[0]); print_rune(#rune ",");
-		print_f32(i[1]); print_nl();
-	}
-
-
-
-	{ // First class procedures
-
-		do_thing :: proc(p: proc(a, b: int) -> int) {
-			print_int(p(3, 4)); nl();
-		}
-
-		add :: proc(a, b: int) -> int {
-			return a + b;
-		}
-
-
-		add_lambda := proc(a, b: int) -> int {
-			return a - b;
-		}; // note semicolon
-
-		do_thing(add);
-		do_thing(add_lambda);
-		do_thing(proc(a, b: int) -> int { // Anonymous
-			return a * b;
-		});
-	}
-
-
-
-	{ // strings and runes
-		escaped := "Hellope World\n";
-		raw     := `Hellope World\n`;
-		print_string(escaped);
-		print_string(raw); nl();
-
-		// Crap shader example
-		shader_string :=
-`#version 410
-
-layout (location = 0) in vec3 a_position;
-layout (location = 1) in vec3 a_normal;
-layout (location = 2) in vec2 a_tex_coord;
-
-out vec3 v_position;
-out vec3 v_normal;
-out vec2 v_tex_coord;
-
-uniform mat4 u_model_view;
-uniform mat3 u_normal;
-uniform mat4 u_proj;
-uniform mat4 u_mvp;
-
-void main() {
-    v_tex_coord = a_tex_coord;
-    v_normal = normalize(u_normal * a_normal);
-    v_position = vec3(u_model_view * vec4(a_position, 1.0));
-
-    gl_Position = u_mvp * vec4(a_position, 1.0);
-}`;
-
-
-		hearts1 := #rune "💕";
-		hearts2 := #rune "\U0001f495"; // 32 bit
-		hearts3 := #rune "\xf0\x9f\x92\x95";
-
-		㐒 := #rune "㐒";
-		㐒16 := #rune "\u4db5"; // 16 bit but will be `rune`
-		// String ideas "nicked" from Go, so far. I think I might change how some of it works later.
-	}
-
-
-	{ // size, align, offset
-		Thing :: type struct {
-			a: u8;
-			b: u16;
-			c, d, e: u32;
-		}
-
-		s := size_of(Thing);
-		a := align_of(Thing);
-		o := offset_of(Thing, b);
-
-		t: Thing;
-
-		sv := size_of_val(t);
-		av := align_of_val(t);
-		ov := offset_of_val(t.b);
-	}
+	// run_game()
 }
 }
 
 
-data_control :: proc() {
-	sum := 0;
-	for i := 0; i < 12; i++ {
-		sum += 1;
-	}
-	print_string("sum = "); print_int(sum); nl();
-
-	sum = 1;
-	for ; sum < 1000000; {
-		sum += sum;
-	}
-	print_string("sum = "); print_int(sum); nl();
-
-	sum = 1;
-	for sum < 1000000 {
-		sum += sum;
-	}
-	print_string("sum = "); print_int(sum); nl();
-
-	// loop
-	// for { } == for true {}
-
-	// Question: Should I separate all these concepts and rename it?
-	//
-	// range - iterable
-	// for   - c style
-	// while
-	// loop  - while true
-
-	// Notes:
-	// conditions _must_ a boolean expression
-	// i++ and i-- are statements, not expressions
-
-
-	x := 2;
-	if x < 3 {
-		print_string("x < 2\n");
-	}
-
-	// Unified initializer syntax - same as for statements
-	if x := 2; x < 3 {
-		print_string("x < 2\n");
-	}
-
-	if x := 4; x < 3 {
-		print_string("Never called\n");
-	} else {
-		print_string("This is called\n");
-	}
-
-	{ // String comparison
-		a := "Hellope";
-		b := "World";
-		if a < b {
-			print_string("a < b\n");
-		}
-		if a != b {
-			print_string("a != b\n");
-		}
-
-	}
-
-
-
 
 
-	{ // Defer statement
-		defer print_string("日本語\n");
-		print_string("Japanese\n");
-	}
-
-	{
-		defer print_string("1\n");
-		defer print_string("2\n");
-		defer print_string("3\n");
-	}
-
-	{
-		prev_allocator := context.allocator;
-		context.allocator = __default_allocator();
-		defer context.allocator = prev_allocator;
-
-		File :: type struct { filename: string; };
-		FileError :: type int;
-		open_file  :: proc(filename: string) -> (File, FileError) {
-			return File{}, 0;
-		}
-		close_file :: proc(f: ^File) {}
-		f, err := open_file("Test");
-		if err != 0 {
-			// handle error
-		}
-		defer close_file(^f);
-
-		// Rest of code!!!
-	}
-
-	for i := 0; i < 100; i++ {
-		blah := new(int);
-		defer {
-			defer print_string("!");
-			defer print_int(i);
-			defer print_string("dealloc");
-			delete(blah);
-		}
-
-		if i == 3 {
-			// defers called
-			continue;
-		}
-
-		if i == 5 {
-			// defers called
-			return; // End of procedure
-		}
-
-		if i == 8 {
-			// defers called
-			break; // never happens
-		}
-	}
-
-	defer print_string("It'll never happen, mate 1");
-	print_string("It'll never happen, mate 2");
-	print_string("It'll never happen, mate 3");
-}
-
-
-using_fields :: proc() {
-	{ // Everyday stuff
-		Vec3 :: type struct { x, y, z: f32; }
-
-		Entity :: type struct {
-			name: string;
-			using pos: Vec3;
-			vel: Vec3;
-		}
-		t: Entity;
-		t.y = 456;
-		print_f32(t.y);     print_nl();
-		print_f32(t.pos.y); print_nl();
-		print_f32(t.vel.y); print_nl();
-
-
-		Frog :: type struct { // Subtype (kind of)
-			using entity: Entity;
-			colour: u32;
-			jump_height: f32;
-		}
-
-		f: Frog;
-		f.y = 1337;
-		print_f32(f.y);     print_nl();
-		print_f32(f.pos.y); print_nl();
-		print_f32(f.vel.y); print_nl();
-
-
-		Buffalo :: type struct {
-			using entity: Entity;
-			speed: f32;
-			noise_level: f32;
-		}
-	}
-
-
-	{ // Crazy Shit
-		Vec2 :: type union {
-			using _xy: struct { x, y: f32; };
-			e: [2]f32;
-			v: {2}f32;
-		}
-
-		Entity :: type struct {
-			using pos: ^Vec2;
-			name: string;
-		}
-		t: Entity;
-		t.pos = new(Vec2);
-		defer delete(t.pos);
-		t.x = 123;
-		print_f32(t._xy.x);     print_nl();
-		print_f32(t.pos.x);     print_nl();
-		print_f32(t.pos._xy.x); print_nl();
-	}
-}
+nl :: proc() #inline { print_nl() }
 
 

+ 44 - 44
examples/file.odin

@@ -1,37 +1,37 @@
 #load "win32.odin"
 #load "win32.odin"
 
 
 File :: type struct {
 File :: type struct {
-	Handle :: type HANDLE;
-	handle: Handle;
+	Handle :: type HANDLE
+	handle: Handle
 }
 }
 
 
 file_open :: proc(name: string) -> (File, bool) {
 file_open :: proc(name: string) -> (File, bool) {
-	buf: [300]byte;
-	_ = copy(buf[:], name as []byte);
-	f := File{CreateFileA(^buf[0], FILE_GENERIC_READ, FILE_SHARE_READ, null, OPEN_EXISTING, 0, null)};
-	success := f.handle != INVALID_HANDLE_VALUE as File.Handle;
+	buf: [300]byte
+	_ = copy(buf[:], name as []byte)
+	f := File{CreateFileA(^buf[0], FILE_GENERIC_READ, FILE_SHARE_READ, null, OPEN_EXISTING, 0, null)}
+	success := f.handle != INVALID_HANDLE_VALUE as File.Handle
 
 
-	return f, success;
+	return f, success
 }
 }
 
 
 file_create :: proc(name: string) -> (File, bool) {
 file_create :: proc(name: string) -> (File, bool) {
-	buf: [300]byte;
-	_ = copy(buf[:], name as []byte);
+	buf: [300]byte
+	_ = copy(buf[:], name as []byte)
 	f := File{
 	f := File{
 		handle = CreateFileA(^buf[0], FILE_GENERIC_WRITE, FILE_SHARE_READ, null, CREATE_ALWAYS, 0, null),
 		handle = CreateFileA(^buf[0], FILE_GENERIC_WRITE, FILE_SHARE_READ, null, CREATE_ALWAYS, 0, null),
-	};
-	success := f.handle != INVALID_HANDLE_VALUE as File.Handle;
-	return f, success;
+	}
+	success := f.handle != INVALID_HANDLE_VALUE as File.Handle
+	return f, success
 }
 }
 
 
 
 
 file_close :: proc(f: ^File) {
 file_close :: proc(f: ^File) {
-	CloseHandle(f.handle);
+	CloseHandle(f.handle)
 }
 }
 
 
 file_write :: proc(f: ^File, buf: []byte) -> bool {
 file_write :: proc(f: ^File, buf: []byte) -> bool {
-	bytes_written: i32;
-	return WriteFile(f.handle, ^buf[0], len(buf) as i32, ^bytes_written, null) != 0;
+	bytes_written: i32
+	return WriteFile(f.handle, ^buf[0], len(buf) as i32, ^bytes_written, null) != 0
 }
 }
 
 
 FileStandard :: type enum {
 FileStandard :: type enum {
@@ -47,60 +47,60 @@ __std_files: [FileStandard.COUNT as int]File;
 file_get_standard :: proc(std: FileStandard) -> ^File {
 file_get_standard :: proc(std: FileStandard) -> ^File {
 	// using FileStandard;
 	// using FileStandard;
 	if (!__std_file_set) {
 	if (!__std_file_set) {
-		using FileStandard;
-		__std_files[INPUT] .handle = GetStdHandle(STD_INPUT_HANDLE);
-		__std_files[OUTPUT].handle = GetStdHandle(STD_OUTPUT_HANDLE);
-		__std_files[ERROR] .handle = GetStdHandle(STD_ERROR_HANDLE);
-		__std_file_set = true;
+		using FileStandard
+		__std_files[INPUT] .handle = GetStdHandle(STD_INPUT_HANDLE)
+		__std_files[OUTPUT].handle = GetStdHandle(STD_OUTPUT_HANDLE)
+		__std_files[ERROR] .handle = GetStdHandle(STD_ERROR_HANDLE)
+		__std_file_set = true
 	}
 	}
-	return ^__std_files[std];
+	return ^__std_files[std]
 }
 }
 
 
 
 
 read_entire_file :: proc(name: string) -> (string, bool) {
 read_entire_file :: proc(name: string) -> (string, bool) {
-	buf: [300]byte;
-	_ = copy(buf[:], name as []byte);
-	c_string := ^buf[0];
+	buf: [300]byte
+	_ = copy(buf[:], name as []byte)
+	c_string := ^buf[0]
 
 
 
 
-	f, file_ok := file_open(name);
+	f, file_ok := file_open(name)
 	if !file_ok {
 	if !file_ok {
-		return "", false;
+		return "", false
 	}
 	}
-	defer file_close(^f);
+	defer file_close(^f)
 
 
-	length: i64;
-	file_size_ok := GetFileSizeEx(f.handle as HANDLE, ^length) != 0;
+	length: i64
+	file_size_ok := GetFileSizeEx(f.handle as HANDLE, ^length) != 0
 	if !file_size_ok {
 	if !file_size_ok {
-		return "", false;
+		return "", false
 	}
 	}
 
 
-	data := new_slice(u8, length);
+	data := new_slice(u8, length)
 	if ^data[0] == null {
 	if ^data[0] == null {
-		return "", false;
+		return "", false
 	}
 	}
 
 
-	single_read_length: i32;
-	total_read: i64;
+	single_read_length: i32
+	total_read: i64
 
 
 	for total_read < length {
 	for total_read < length {
-		remaining := length - total_read;
-		to_read: u32;
-		MAX :: 0x7fffffff;
+		remaining := length - total_read
+		to_read: u32
+		MAX :: 0x7fffffff
 		if remaining <= MAX {
 		if remaining <= MAX {
-			to_read = remaining as u32;
+			to_read = remaining as u32
 		} else {
 		} else {
-			to_read = MAX;
+			to_read = MAX
 		}
 		}
 
 
-		ReadFile(f.handle as HANDLE, ^data[total_read], to_read, ^single_read_length, null);
+		ReadFile(f.handle as HANDLE, ^data[total_read], to_read, ^single_read_length, null)
 		if single_read_length <= 0 {
 		if single_read_length <= 0 {
-			delete(data);
-			return "", false;
+			delete(data)
+			return "", false
 		}
 		}
 
 
-		total_read += single_read_length as i64;
+		total_read += single_read_length as i64
 	}
 	}
 
 
-	return data as string, true;
+	return data as string, true
 }
 }

+ 90 - 90
examples/game.odin

@@ -2,55 +2,55 @@
 #load "opengl.odin"
 #load "opengl.odin"
 #load "math.odin"
 #load "math.odin"
 
 
-TWO_HEARTS :: #rune "💕";
+TWO_HEARTS :: #rune "💕"
 
 
-win32_perf_count_freq := GetQueryPerformanceFrequency();
+win32_perf_count_freq := GetQueryPerformanceFrequency()
 time_now :: proc() -> f64 {
 time_now :: proc() -> f64 {
 	if win32_perf_count_freq == 0 {
 	if win32_perf_count_freq == 0 {
-		debug_trap();
+		debug_trap()
 	}
 	}
 
 
-	counter: i64;
-	_ = QueryPerformanceCounter(^counter);
-	result := counter as f64 / win32_perf_count_freq as f64;
-	return result;
+	counter: i64
+	_ = QueryPerformanceCounter(^counter)
+	result := counter as f64 / win32_perf_count_freq as f64
+	return result
 }
 }
 win32_print_last_error :: proc() {
 win32_print_last_error :: proc() {
-	err_code := GetLastError() as int;
+	err_code := GetLastError() as int
 	if err_code != 0 {
 	if err_code != 0 {
-		print_string("GetLastError: ");
-		print_int(err_code);
-		print_string("\n");
+		print_string("GetLastError: ")
+		print_int(err_code)
+		print_string("\n")
 	}
 	}
 }
 }
 
 
 // Yuk!
 // Yuk!
 to_c_string :: proc(s: string) -> ^u8 {
 to_c_string :: proc(s: string) -> ^u8 {
-	c_str: ^u8 = alloc(len(s)+1);
-	memory_copy(c_str, ^s[0], len(s));
-	ptr_offset(c_str, len(s))^ = 0;
-	return c_str;
+	c_str: ^u8 = alloc(len(s)+1)
+	memory_copy(c_str, ^s[0], len(s))
+	ptr_offset(c_str, len(s))^ = 0
+	return c_str
 }
 }
 
 
 
 
 Window :: type struct {
 Window :: type struct {
-	width, height:      int;
-	wc:                 WNDCLASSEXA;
-	dc:                 HDC;
-	hwnd:               HWND;
-	opengl_context, rc: HGLRC;
-	c_title:            ^u8;
+	width, height:      int
+	wc:                 WNDCLASSEXA
+	dc:                 HDC
+	hwnd:               HWND
+	opengl_context, rc: HGLRC
+	c_title:            ^u8
 }
 }
 
 
 make_window :: proc(title: string, msg, height: int, window_proc: WNDPROC) -> (Window, bool) {
 make_window :: proc(title: string, msg, height: int, window_proc: WNDPROC) -> (Window, bool) {
-	w: Window;
-	w.width, w.height = msg, height;
+	w: Window
+	w.width, w.height = msg, height
 
 
-	class_name   := "Win32-Odin-Window\x00";
-	c_class_name := ^class_name[0];
-	w.c_title = to_c_string(title);
+	class_name   := "Win32-Odin-Window\x00"
+	c_class_name := ^class_name[0]
+	w.c_title = to_c_string(title)
 
 
-	instance := GetModuleHandleA(null);
+	instance := GetModuleHandleA(null)
 
 
 	w.wc = WNDCLASSEXA{
 	w.wc = WNDCLASSEXA{
 		size       = size_of(WNDCLASSEXA) as u32,
 		size       = size_of(WNDCLASSEXA) as u32,
@@ -61,7 +61,7 @@ make_window :: proc(title: string, msg, height: int, window_proc: WNDPROC) -> (W
 	};
 	};
 
 
 	if RegisterClassExA(^w.wc) == 0 {
 	if RegisterClassExA(^w.wc) == 0 {
-		return w, false;
+		return w, false
 	}
 	}
 
 
 	w.hwnd = CreateWindowExA(0,
 	w.hwnd = CreateWindowExA(0,
@@ -69,14 +69,14 @@ make_window :: proc(title: string, msg, height: int, window_proc: WNDPROC) -> (W
 	                         WS_VISIBLE | WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX,
 	                         WS_VISIBLE | WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX,
 	                         CW_USEDEFAULT, CW_USEDEFAULT,
 	                         CW_USEDEFAULT, CW_USEDEFAULT,
 	                         w.width as i32, w.height as i32,
 	                         w.width as i32, w.height as i32,
-	                         null, null, instance, null);
+	                         null, null, instance, null)
 
 
 	if w.hwnd == null {
 	if w.hwnd == null {
-		win32_print_last_error();
-		return w, false;
+		win32_print_last_error()
+		return w, false
 	}
 	}
 
 
-	w.dc = GetDC(w.hwnd);
+	w.dc = GetDC(w.hwnd)
 
 
 	{
 	{
 		pfd := PIXELFORMATDESCRIPTOR{
 		pfd := PIXELFORMATDESCRIPTOR{
@@ -89,126 +89,126 @@ make_window :: proc(title: string, msg, height: int, window_proc: WNDPROC) -> (W
 			depth_bits   = 24,
 			depth_bits   = 24,
 			stencil_bits = 8,
 			stencil_bits = 8,
 			layer_type   = PFD_MAIN_PLANE,
 			layer_type   = PFD_MAIN_PLANE,
-		};
+		}
 
 
-		SetPixelFormat(w.dc, ChoosePixelFormat(w.dc, ^pfd), null);
-		w.opengl_context = wglCreateContext(w.dc);
-		wglMakeCurrent(w.dc, w.opengl_context);
+		SetPixelFormat(w.dc, ChoosePixelFormat(w.dc, ^pfd), null)
+		w.opengl_context = wglCreateContext(w.dc)
+		wglMakeCurrent(w.dc, w.opengl_context)
 
 
 		attribs := [8]i32{
 		attribs := [8]i32{
 			WGL_CONTEXT_MAJOR_VERSION_ARB, 2,
 			WGL_CONTEXT_MAJOR_VERSION_ARB, 2,
 			WGL_CONTEXT_MINOR_VERSION_ARB, 1,
 			WGL_CONTEXT_MINOR_VERSION_ARB, 1,
 			WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
 			WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
 			0, // NOTE(bill): tells the proc that this is the end of attribs
 			0, // NOTE(bill): tells the proc that this is the end of attribs
-		};
-
-		wgl_string := "wglCreateContextAttribsARB\x00";
-		c_wgl_string := ^wgl_string[0];
-		wglCreateContextAttribsARB := wglGetProcAddress(c_wgl_string) as wglCreateContextAttribsARBType;
-		w.rc = wglCreateContextAttribsARB(w.dc, 0, ^attribs[0]);
-		wglMakeCurrent(w.dc, w.rc);
-		SwapBuffers(w.dc);
+		}
+
+		wgl_string := "wglCreateContextAttribsARB\x00"
+		c_wgl_string := ^wgl_string[0]
+		wglCreateContextAttribsARB := wglGetProcAddress(c_wgl_string) as wglCreateContextAttribsARBType
+		w.rc = wglCreateContextAttribsARB(w.dc, 0, ^attribs[0])
+		wglMakeCurrent(w.dc, w.rc)
+		SwapBuffers(w.dc)
 	}
 	}
 
 
-	return w, true;
+	return w, true
 }
 }
 
 
 destroy_window :: proc(w: ^Window) {
 destroy_window :: proc(w: ^Window) {
-	heap_free(w.c_title);
+	heap_free(w.c_title)
 }
 }
 
 
 display_window :: proc(w: ^Window) {
 display_window :: proc(w: ^Window) {
-	SwapBuffers(w.dc);
+	SwapBuffers(w.dc)
 }
 }
 
 
 
 
 Entity :: type struct {
 Entity :: type struct {
-	pos: Vec2;
-	dim: Vec2;
+	pos: Vec2
+	dim: Vec2
 }
 }
 
 
 
 
 run_game :: proc() {
 run_game :: proc() {
 	win32_proc :: proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT #no_inline {
 	win32_proc :: proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT #no_inline {
 		if msg == WM_DESTROY || msg == WM_CLOSE || msg == WM_QUIT {
 		if msg == WM_DESTROY || msg == WM_CLOSE || msg == WM_QUIT {
-			ExitProcess(0);
-			return 0;
+			ExitProcess(0)
+			return 0
 		}
 		}
-		return DefWindowProcA(hwnd, msg, wparam, lparam);
+		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, win32_proc)
 	if !window_success {
 	if !window_success {
-		return;
+		return
 	}
 	}
-	defer destroy_window(^window);
+	defer destroy_window(^window)
 
 
 
 
-	prev_time := time_now();
-	running := true;
+	prev_time := time_now()
+	running := true
 
 
-	pos := Vec2{100, 100};
+	pos := Vec2{100, 100}
 
 
 	for running {
 	for running {
-		curr_time := time_now();
-		dt := (curr_time - prev_time) as f32;
-		prev_time = curr_time;
+		curr_time := time_now()
+		dt := (curr_time - prev_time) as f32
+		prev_time = curr_time
 
 
-		msg: MSG;
+		msg: MSG
 		for PeekMessageA(^msg, null, 0, 0, PM_REMOVE) > 0 {
 		for PeekMessageA(^msg, null, 0, 0, PM_REMOVE) > 0 {
 			if msg.message == WM_QUIT {
 			if msg.message == WM_QUIT {
-				running = false;
+				running = false
 			}
 			}
-			_ = TranslateMessage(^msg);
-			_ = DispatchMessageA(^msg);
+			_ = TranslateMessage(^msg)
+			_ = DispatchMessageA(^msg)
 		}
 		}
 
 
 		if is_key_down(VK_ESCAPE) {
 		if is_key_down(VK_ESCAPE) {
-			running = false;
+			running = false
 		}
 		}
 
 
 		{
 		{
-			SPEED :: 500;
-			v: Vec2;
+			SPEED :: 500
+			v: Vec2
 
 
-			if is_key_down(VK_RIGHT) { v[0] += 1; }
-			if is_key_down(VK_LEFT)  { v[0] -= 1; }
-			if is_key_down(VK_UP)    { v[1] += 1; }
-			if is_key_down(VK_DOWN)  { v[1] -= 1; }
+			if is_key_down(VK_RIGHT) { v[0] += 1 }
+			if is_key_down(VK_LEFT)  { v[0] -= 1 }
+			if is_key_down(VK_UP)    { v[1] += 1 }
+			if is_key_down(VK_DOWN)  { v[1] -= 1 }
 
 
-			v = vec2_norm0(v);
+			v = vec2_norm0(v)
 
 
-			pos += v * Vec2{SPEED * dt};
+			pos += v * Vec2{SPEED * dt}
 		}
 		}
 
 
 
 
-		glClearColor(0.5, 0.7, 1.0, 1.0);
-		glClear(GL_COLOR_BUFFER_BIT);
+		glClearColor(0.5, 0.7, 1.0, 1.0)
+		glClear(GL_COLOR_BUFFER_BIT)
 
 
-		glLoadIdentity();
+		glLoadIdentity()
 		glOrtho(0, window.width as f64,
 		glOrtho(0, window.width as f64,
-		        0, window.height as f64, 0, 1);
+		        0, window.height as f64, 0, 1)
 
 
 		draw_rect :: proc(x, y, w, h: f32) {
 		draw_rect :: proc(x, y, w, h: f32) {
-			glBegin(GL_TRIANGLES);
+			glBegin(GL_TRIANGLES)
 
 
-			glColor3f(1, 0, 0); glVertex3f(x,   y,   0);
-			glColor3f(0, 1, 0); glVertex3f(x+w, y,   0);
-			glColor3f(0, 0, 1); glVertex3f(x+w, y+h, 0);
+			glColor3f(1, 0, 0); glVertex3f(x,   y,   0)
+			glColor3f(0, 1, 0); glVertex3f(x+w, y,   0)
+			glColor3f(0, 0, 1); glVertex3f(x+w, y+h, 0)
 
 
-			glColor3f(0, 0, 1); glVertex3f(x+w, y+h, 0);
-			glColor3f(1, 1, 0); glVertex3f(x,   y+h, 0);
-			glColor3f(1, 0, 0); glVertex3f(x,   y,   0);
+			glColor3f(0, 0, 1); glVertex3f(x+w, y+h, 0)
+			glColor3f(1, 1, 0); glVertex3f(x,   y+h, 0)
+			glColor3f(1, 0, 0); glVertex3f(x,   y,   0)
 
 
-			glEnd();
+			glEnd()
 		}
 		}
 
 
-		draw_rect(pos[0], pos[1], 50, 50);
+		draw_rect(pos[0], pos[1], 50, 50)
 
 
-		display_window(^window);
-		ms_to_sleep := (16 - 1000*dt) as i32;
+		display_window(^window)
+		ms_to_sleep := (16 - 1000*dt) as i32
 		if ms_to_sleep > 0 {
 		if ms_to_sleep > 0 {
-			sleep_ms(ms_to_sleep);
+			sleep_ms(ms_to_sleep)
 		}
 		}
 	}
 	}
 }
 }

+ 92 - 92
examples/math.odin

@@ -1,162 +1,162 @@
-MATH_TAU          :: 6.28318530717958647692528676655900576;
-MATH_PI           :: 3.14159265358979323846264338327950288;
-MATH_ONE_OVER_TAU :: 0.636619772367581343075535053490057448;
-MATH_ONE_OVER_PI  :: 0.159154943091895335768883763372514362;
+MATH_TAU          :: 6.28318530717958647692528676655900576
+MATH_PI           :: 3.14159265358979323846264338327950288
+MATH_ONE_OVER_TAU :: 0.636619772367581343075535053490057448
+MATH_ONE_OVER_PI  :: 0.159154943091895335768883763372514362
 
 
-MATH_E            :: 2.71828182845904523536;
-MATH_SQRT_TWO     :: 1.41421356237309504880168872420969808;
-MATH_SQRT_THREE   :: 1.73205080756887729352744634150587236;
-MATH_SQRT_FIVE    :: 2.23606797749978969640917366873127623;
+MATH_E            :: 2.71828182845904523536
+MATH_SQRT_TWO     :: 1.41421356237309504880168872420969808
+MATH_SQRT_THREE   :: 1.73205080756887729352744634150587236
+MATH_SQRT_FIVE    :: 2.23606797749978969640917366873127623
 
 
-MATH_LOG_TWO      :: 0.693147180559945309417232121458176568;
-MATH_LOG_TEN      :: 2.30258509299404568401799145468436421;
+MATH_LOG_TWO      :: 0.693147180559945309417232121458176568
+MATH_LOG_TEN      :: 2.30258509299404568401799145468436421
 
 
-MATH_EPSILON      :: 1.19209290e-7;
+MATH_EPSILON      :: 1.19209290e-7
 
 
-τ :: MATH_TAU;
-π :: MATH_PI;
+τ :: MATH_TAU
+π :: MATH_PI
 
 
-Vec2 :: type {2}f32;
-Vec3 :: type {3}f32;
-Vec4 :: type {4}f32;
+Vec2 :: type {2}f32
+Vec3 :: type {3}f32
+Vec4 :: type {4}f32
 
 
-Mat2 :: type  {4}f32;
-Mat3 :: type  {9}f32;
-Mat4 :: type {16}f32;
+Mat2 :: type  {4}f32
+Mat3 :: type  {9}f32
+Mat4 :: type {16}f32
 
 
 
 
 fsqrt    :: proc(x: f32) -> f32 #foreign "llvm.sqrt.f32"
 fsqrt    :: proc(x: f32) -> f32 #foreign "llvm.sqrt.f32"
 fsin     :: proc(x: f32) -> f32 #foreign "llvm.sin.f32"
 fsin     :: proc(x: f32) -> f32 #foreign "llvm.sin.f32"
 fcos     :: proc(x: f32) -> f32 #foreign "llvm.cos.f32"
 fcos     :: proc(x: f32) -> f32 #foreign "llvm.cos.f32"
-flerp    :: proc(a, b, t: f32) -> f32 { return a*(1-t) + b*t; }
-fclamp   :: proc(x, lower, upper: f32) -> f32 { return fmin(fmax(x, lower), upper); }
-fclamp01 :: proc(x: f32) -> f32 { return fclamp(x, 0, 1); }
-fabs     :: proc(x: f32) -> f32 { if x < 0 { x = -x; } return x; }
-fsign    :: proc(x: f32) -> f32 { if x >= 0 { return +1; } return -1; }
+flerp    :: proc(a, b, t: f32) -> f32 { return a*(1-t) + b*t }
+fclamp   :: proc(x, lower, upper: f32) -> f32 { return fmin(fmax(x, lower), upper) }
+fclamp01 :: proc(x: f32) -> f32 { return fclamp(x, 0, 1) }
+fabs     :: proc(x: f32) -> f32 { if x < 0 { x = -x } return x }
+fsign    :: proc(x: f32) -> f32 { if x >= 0 { return +1 } return -1 }
 
 
-fmin     :: proc(a, b: f32) -> f32 { if a < b { return a; } return b; }
-fmax     :: proc(a, b: f32) -> f32 { if a > b { return a; } return b; }
-fmin3    :: proc(a, b, c: f32) -> f32 { return fmin(fmin(a, b), c); }
-fmax3    :: proc(a, b, c: f32) -> f32 { return fmax(fmax(a, b), c); }
+fmin     :: proc(a, b: f32) -> f32 { if a < b { return a } return b }
+fmax     :: proc(a, b: f32) -> f32 { if a > b { return a } return b }
+fmin3    :: proc(a, b, c: f32) -> f32 { return fmin(fmin(a, b), c) }
+fmax3    :: proc(a, b, c: f32) -> f32 { return fmax(fmax(a, b), c) }
 
 
 
 
 copy_sign :: proc(x, y: f32) -> f32 {
 copy_sign :: proc(x, y: f32) -> f32 {
-	ix := x transmute u32;
-	iy := y transmute u32;
-	ix &= 0x7fffffff;
-	ix |= iy & 0x80000000;
-	return ix transmute f32;
+	ix := x transmute u32
+	iy := y transmute u32
+	ix &= 0x7fffffff
+	ix |= iy & 0x80000000
+	return ix transmute f32
 }
 }
 
 
 
 
 round :: proc(x: f32) -> f32 {
 round :: proc(x: f32) -> f32 {
 	if x >= 0 {
 	if x >= 0 {
-		return floor(x + 0.5);
+		return floor(x + 0.5)
 	}
 	}
-	return ceil(x - 0.5);
+	return ceil(x - 0.5)
 }
 }
 floor :: proc(x: f32) -> f32 {
 floor :: proc(x: f32) -> f32 {
 	if x >= 0 {
 	if x >= 0 {
-		return x as int as f32;
+		return x as int as f32
 	}
 	}
-	return (x-0.5) as int as f32;
+	return (x-0.5) as int as f32
 }
 }
 ceil :: proc(x: f32) -> f32 {
 ceil :: proc(x: f32) -> f32 {
 	if x < 0 {
 	if x < 0 {
-		return x as int as f32;
+		return x as int as f32
 	}
 	}
-	return ((x as int)+1) as f32;
+	return ((x as int)+1) as f32
 }
 }
 
 
 
 
 
 
 
 
 remainder :: proc(x, y: f32) -> f32 {
 remainder :: proc(x, y: f32) -> f32 {
-	return x - round(x/y) * y;
+	return x - round(x/y) * y
 }
 }
 
 
 fmod :: proc(x, y: f32) -> f32 {
 fmod :: proc(x, y: f32) -> f32 {
-	y = fabs(y);
-	result := remainder(fabs(x), y);
+	y = fabs(y)
+	result := remainder(fabs(x), y)
 	if fsign(result) < 0 {
 	if fsign(result) < 0 {
-		result += y;
+		result += y
 	}
 	}
-	return copy_sign(result, x);
+	return copy_sign(result, x)
 }
 }
 
 
 
 
-to_radians :: proc(degrees: f32) -> f32 { return degrees * MATH_TAU / 360; }
-to_degrees :: proc(radians: f32) -> f32 { return radians * 360 / MATH_TAU; }
+to_radians :: proc(degrees: f32) -> f32 { return degrees * MATH_TAU / 360 }
+to_degrees :: proc(radians: f32) -> f32 { return radians * 360 / MATH_TAU }
 
 
 
 
 
 
 
 
-dot2 :: proc(a, b: Vec2) -> f32 { c := a*b; return c[0] + c[1]; }
-dot3 :: proc(a, b: Vec3) -> f32 { c := a*b; return c[0] + c[1] + c[2]; }
-dot4 :: proc(a, b: Vec4) -> f32 { c := a*b; return c[0] + c[1] + c[2] + c[3]; }
+dot2 :: proc(a, b: Vec2) -> f32 { c := a*b; return c[0] + c[1] }
+dot3 :: proc(a, b: Vec3) -> f32 { c := a*b; return c[0] + c[1] + c[2] }
+dot4 :: proc(a, b: Vec4) -> f32 { c := a*b; return c[0] + c[1] + c[2] + c[3] }
 
 
 cross :: proc(x, y: Vec3) -> Vec3 {
 cross :: proc(x, y: Vec3) -> Vec3 {
-	a := swizzle(x, 1, 2, 0) * swizzle(y, 2, 0, 1);
-	b := swizzle(x, 2, 0, 1) * swizzle(y, 1, 2, 0);
-	return a - b;
+	a := swizzle(x, 1, 2, 0) * swizzle(y, 2, 0, 1)
+	b := swizzle(x, 2, 0, 1) * swizzle(y, 1, 2, 0)
+	return a - b
 }
 }
 
 
 
 
-vec2_mag :: proc(v: Vec2) -> f32 { return fsqrt(v ''dot2 v); }
-vec3_mag :: proc(v: Vec3) -> f32 { return fsqrt(v ''dot3 v); }
-vec4_mag :: proc(v: Vec4) -> f32 { return fsqrt(v ''dot4 v); }
+vec2_mag :: proc(v: Vec2) -> f32 { return fsqrt(v ''dot2 v) }
+vec3_mag :: proc(v: Vec3) -> f32 { return fsqrt(v ''dot3 v) }
+vec4_mag :: proc(v: Vec4) -> f32 { return fsqrt(v ''dot4 v) }
 
 
-vec2_norm :: proc(v: Vec2) -> Vec2 { return v / Vec2{vec2_mag(v)}; }
-vec3_norm :: proc(v: Vec3) -> Vec3 { return v / Vec3{vec3_mag(v)}; }
-vec4_norm :: proc(v: Vec4) -> Vec4 { return v / Vec4{vec4_mag(v)}; }
+vec2_norm :: proc(v: Vec2) -> Vec2 { return v / Vec2{vec2_mag(v)} }
+vec3_norm :: proc(v: Vec3) -> Vec3 { return v / Vec3{vec3_mag(v)} }
+vec4_norm :: proc(v: Vec4) -> Vec4 { return v / Vec4{vec4_mag(v)} }
 
 
 vec2_norm0 :: proc(v: Vec2) -> Vec2 {
 vec2_norm0 :: proc(v: Vec2) -> Vec2 {
-	m := vec2_mag(v);
+	m := vec2_mag(v)
 	if m == 0 {
 	if m == 0 {
-		return Vec2{0};
+		return Vec2{0}
 	}
 	}
-	return v / Vec2{m};
+	return v / Vec2{m}
 }
 }
 
 
 vec3_norm0 :: proc(v: Vec3) -> Vec3 {
 vec3_norm0 :: proc(v: Vec3) -> Vec3 {
-	m := vec3_mag(v);
+	m := vec3_mag(v)
 	if m == 0 {
 	if m == 0 {
-		return Vec3{0};
+		return Vec3{0}
 	}
 	}
-	return v / Vec3{m};
+	return v / Vec3{m}
 }
 }
 
 
 vec4_norm0 :: proc(v: Vec4) -> Vec4 {
 vec4_norm0 :: proc(v: Vec4) -> Vec4 {
-	m := vec4_mag(v);
+	m := vec4_mag(v)
 	if m == 0 {
 	if m == 0 {
-		return Vec4{0};
+		return Vec4{0}
 	}
 	}
-	return v / Vec4{m};
+	return v / Vec4{m}
 }
 }
 
 
 
 
-F32_DIG        :: 6;
-F32_EPSILON    :: 1.192092896e-07;
-F32_GUARD      :: 0;
-F32_MANT_DIG   :: 24;
-F32_MAX        :: 3.402823466e+38;
-F32_MAX_10_EXP :: 38;
-F32_MAX_EXP    :: 128;
-F32_MIN        :: 1.175494351e-38;
-F32_MIN_10_EXP :: -37;
-F32_MIN_EXP    :: -125;
-F32_NORMALIZE  :: 0;
-F32_RADIX      :: 2;
-F32_ROUNDS     :: 1;
-
-F64_DIG        :: 15;                      // # of decimal digits of precision
-F64_EPSILON    :: 2.2204460492503131e-016; // smallest such that 1.0+F64_EPSILON != 1.0
-F64_MANT_DIG   :: 53;                      // # of bits in mantissa
-F64_MAX        :: 1.7976931348623158e+308; // max value
-F64_MAX_10_EXP :: 308;                     // max decimal exponent
-F64_MAX_EXP    :: 1024;                    // max binary exponent
-F64_MIN        :: 2.2250738585072014e-308; // min positive value
-F64_MIN_10_EXP :: -307;                    // min decimal exponent
-F64_MIN_EXP    :: -1021;                   // min binary exponent
-F64_RADIX      :: 2;                       // exponent radix
-F64_ROUNDS     :: 1;                       // addition rounding: near
+F32_DIG        :: 6
+F32_EPSILON    :: 1.192092896e-07
+F32_GUARD      :: 0
+F32_MANT_DIG   :: 24
+F32_MAX        :: 3.402823466e+38
+F32_MAX_10_EXP :: 38
+F32_MAX_EXP    :: 128
+F32_MIN        :: 1.175494351e-38
+F32_MIN_10_EXP :: -37
+F32_MIN_EXP    :: -125
+F32_NORMALIZE  :: 0
+F32_RADIX      :: 2
+F32_ROUNDS     :: 1
+
+F64_DIG        :: 15                      // # of decimal digits of precision
+F64_EPSILON    :: 2.2204460492503131e-016 // smallest such that 1.0+F64_EPSILON != 1.0
+F64_MANT_DIG   :: 53                      // # of bits in mantissa
+F64_MAX        :: 1.7976931348623158e+308 // max value
+F64_MAX_10_EXP :: 308                     // max decimal exponent
+F64_MAX_EXP    :: 1024                    // max binary exponent
+F64_MIN        :: 2.2250738585072014e-308 // min positive value
+F64_MIN_10_EXP :: -307                    // min decimal exponent
+F64_MIN_EXP    :: -1021                   // min binary exponent
+F64_RADIX      :: 2                       // exponent radix
+F64_ROUNDS     :: 1                       // addition rounding: near

+ 24 - 22
examples/opengl.odin

@@ -1,29 +1,31 @@
-GL_ZERO                 :: 0x0000;
-GL_ONE                  :: 0x0001;
-GL_TRIANGLES            :: 0x0004;
-GL_BLEND                :: 0x0BE2;
-GL_SRC_ALPHA            :: 0x0302;
-GL_ONE_MINUS_SRC_ALPHA  :: 0x0303;
-GL_TEXTURE_2D           :: 0x0DE1;
-GL_RGBA8                :: 0x8058;
-GL_UNSIGNED_BYTE        :: 0x1401;
-GL_BGRA_EXT             :: 0x80E1;
-GL_TEXTURE_MAX_LEVEL    :: 0x813D;
-GL_RGBA                 :: 0x1908;
+#foreign_system_library "opengl32"
 
 
-GL_NEAREST :: 0x2600;
-GL_LINEAR  :: 0x2601;
+GL_ZERO                 :: 0x0000
+GL_ONE                  :: 0x0001
+GL_TRIANGLES            :: 0x0004
+GL_BLEND                :: 0x0be2
+GL_SRC_ALPHA            :: 0x0302
+GL_ONE_MINUS_SRC_ALPHA  :: 0x0303
+GL_TEXTURE_2D           :: 0x0de1
+GL_RGBA8                :: 0x8058
+GL_UNSIGNED_BYTE        :: 0x1401
+GL_BGRA_EXT             :: 0x80e1
+GL_TEXTURE_MAX_LEVEL    :: 0x813d
+GL_RGBA                 :: 0x1908
 
 
-GL_DEPTH_BUFFER_BIT   :: 0x00000100;
-GL_STENCIL_BUFFER_BIT :: 0x00000400;
-GL_COLOR_BUFFER_BIT   :: 0x00004000;
+GL_NEAREST :: 0x2600
+GL_LINEAR  :: 0x2601
 
 
-GL_TEXTURE_MAX_ANISOTROPY_EXT :: 0x84FE;
+GL_DEPTH_BUFFER_BIT   :: 0x00000100
+GL_STENCIL_BUFFER_BIT :: 0x00000400
+GL_COLOR_BUFFER_BIT   :: 0x00004000
 
 
-GL_TEXTURE_MAG_FILTER  :: 0x2800;
-GL_TEXTURE_MIN_FILTER  :: 0x2801;
-GL_TEXTURE_WRAP_S      :: 0x2802;
-GL_TEXTURE_WRAP_T      :: 0x2803;
+GL_TEXTURE_MAX_ANISOTROPY_EXT :: 0x84fe
+
+GL_TEXTURE_MAG_FILTER  :: 0x2800
+GL_TEXTURE_MIN_FILTER  :: 0x2801
+GL_TEXTURE_WRAP_S      :: 0x2802
+GL_TEXTURE_WRAP_T      :: 0x2803
 
 
 glClear         :: proc(mask: u32) #foreign
 glClear         :: proc(mask: u32) #foreign
 glClearColor    :: proc(r, g, b, a: f32) #foreign
 glClearColor    :: proc(r, g, b, a: f32) #foreign

+ 169 - 173
examples/runtime.odin

@@ -4,167 +4,167 @@ debug_trap :: proc() #foreign "llvm.debugtrap"
 
 
 // TODO(bill): make custom heap procedures
 // TODO(bill): make custom heap procedures
 heap_alloc :: proc(len: int) -> rawptr {
 heap_alloc :: proc(len: int) -> rawptr {
-	return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
+	return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len)
 }
 }
 heap_free :: proc(ptr: rawptr) {
 heap_free :: proc(ptr: rawptr) {
-	_ = HeapFree(GetProcessHeap(), 0, ptr);
+	_ = HeapFree(GetProcessHeap(), 0, ptr)
 }
 }
 
 
 
 
 memory_compare :: proc(dst, src: rawptr, len: int) -> int {
 memory_compare :: proc(dst, src: rawptr, len: int) -> int {
-	s1, s2: ^u8 = dst, src;
+	s1, s2: ^u8 = dst, src
 	for i := 0; i < len; i++ {
 	for i := 0; i < len; i++ {
-		a := ptr_offset(s1, i)^;
-		b := ptr_offset(s2, i)^;
+		a := ptr_offset(s1, i)^
+		b := ptr_offset(s2, i)^
 		if a != b {
 		if a != b {
-			return (a - b) as int;
+			return (a - b) as int
 		}
 		}
 	}
 	}
-	return 0;
+	return 0
 }
 }
 
 
 memory_copy :: proc(dst, src: rawptr, n: int) #inline {
 memory_copy :: proc(dst, src: rawptr, n: int) #inline {
 	if dst == src {
 	if dst == src {
-		return;
+		return
 	}
 	}
 
 
-	v128b :: type {4}u32;
-	static_assert(align_of(v128b) == 16);
+	v128b :: type {4}u32
+	static_assert(align_of(v128b) == 16)
 
 
-	d, s: ^u8 = dst, src;
+	d, s: ^u8 = dst, src
 
 
 	for ; s as uint % 16 != 0 && n != 0; n-- {
 	for ; s as uint % 16 != 0 && n != 0; n-- {
-		d^ = s^;
-		d, s = ptr_offset(d, 1), ptr_offset(s, 1);
+		d^ = s^
+		d, s = ptr_offset(d, 1), ptr_offset(s, 1)
 	}
 	}
 
 
 	if d as uint % 16 == 0 {
 	if d as uint % 16 == 0 {
 		for ; n >= 16; d, s, n = ptr_offset(d, 16), ptr_offset(s, 16), n-16 {
 		for ; n >= 16; d, s, n = ptr_offset(d, 16), ptr_offset(s, 16), n-16 {
-			(d as ^v128b)^ = (s as ^v128b)^;
+			(d as ^v128b)^ = (s as ^v128b)^
 		}
 		}
 
 
 		if n&8 != 0 {
 		if n&8 != 0 {
-			(d as ^u64)^ = (s as ^u64)^;
-			d, s = ptr_offset(d, 8), ptr_offset(s, 8);
+			(d as ^u64)^ = (s as ^u64)^
+			d, s = ptr_offset(d, 8), ptr_offset(s, 8)
 		}
 		}
 		if n&4 != 0 {
 		if n&4 != 0 {
 			(d as ^u32)^ = (s as ^u32)^;
 			(d as ^u32)^ = (s as ^u32)^;
-			d, s = ptr_offset(d, 4), ptr_offset(s, 4);
+			d, s = ptr_offset(d, 4), ptr_offset(s, 4)
 		}
 		}
 		if n&2 != 0 {
 		if n&2 != 0 {
-			(d as ^u16)^ = (s as ^u16)^;
-			d, s = ptr_offset(d, 2), ptr_offset(s, 2);
+			(d as ^u16)^ = (s as ^u16)^
+			d, s = ptr_offset(d, 2), ptr_offset(s, 2)
 		}
 		}
 		if n&1 != 0 {
 		if n&1 != 0 {
-			d^ = s^;
-			d, s = ptr_offset(d, 1), ptr_offset(s, 1);
+			d^ = s^
+			d, s = ptr_offset(d, 1), ptr_offset(s, 1)
 		}
 		}
 		return;
 		return;
 	}
 	}
 
 
 	// IMPORTANT NOTE(bill): Little endian only
 	// IMPORTANT NOTE(bill): Little endian only
-	LS :: proc(a, b: u32) -> u32 #inline { return a << b; }
-	RS :: proc(a, b: u32) -> u32 #inline { return a >> b; }
+	LS :: proc(a, b: u32) -> u32 #inline { return a << b }
+	RS :: proc(a, b: u32) -> u32 #inline { return a >> b }
 	/* NOTE(bill): Big endian version
 	/* NOTE(bill): Big endian version
 	LS :: proc(a, b: u32) -> u32 #inline { return a >> b; }
 	LS :: proc(a, b: u32) -> u32 #inline { return a >> b; }
 	RS :: proc(a, b: u32) -> u32 #inline { return a << b; }
 	RS :: proc(a, b: u32) -> u32 #inline { return a << b; }
 	*/
 	*/
 
 
-	w, x: u32;
+	w, x: u32
 
 
 	if d as uint % 4 == 1 {
 	if d as uint % 4 == 1 {
-		w = (s as ^u32)^;
-		d^ = s^; d = ptr_offset(d, 1); s = ptr_offset(s, 1);
-		d^ = s^; d = ptr_offset(d, 1); s = ptr_offset(s, 1);
-		d^ = s^; d = ptr_offset(d, 1); s = ptr_offset(s, 1);
-		n -= 3;
+		w = (s as ^u32)^
+		d^ = s^; d = ptr_offset(d, 1); s = ptr_offset(s, 1)
+		d^ = s^; d = ptr_offset(d, 1); s = ptr_offset(s, 1)
+		d^ = s^; d = ptr_offset(d, 1); s = ptr_offset(s, 1)
+		n -= 3
 
 
 		for n > 16 {
 		for n > 16 {
-			d32 := d as ^u32;
-			s32 := ptr_offset(s, 1) as ^u32;
-			x = s32^; d32^ = LS(w, 24) | RS(x, 8);
-			d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1);
-			w = s32^; d32^ = LS(x, 24) | RS(w, 8);
-			d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1);
-			x = s32^; d32^ = LS(w, 24) | RS(x, 8);
-			d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1);
-			w = s32^; d32^ = LS(x, 24) | RS(w, 8);
-			d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1);
-
-			d, s, n = ptr_offset(d, 16), ptr_offset(s, 16), n-16;
+			d32 := d as ^u32
+			s32 := ptr_offset(s, 1) as ^u32
+			x = s32^; d32^ = LS(w, 24) | RS(x, 8)
+			d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1)
+			w = s32^; d32^ = LS(x, 24) | RS(w, 8)
+			d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1)
+			x = s32^; d32^ = LS(w, 24) | RS(x, 8)
+			d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1)
+			w = s32^; d32^ = LS(x, 24) | RS(w, 8)
+			d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1)
+
+			d, s, n = ptr_offset(d, 16), ptr_offset(s, 16), n-16
 		}
 		}
 
 
 	} else if d as uint % 4 == 2 {
 	} else if d as uint % 4 == 2 {
-		w = (s as ^u32)^;
-		d^ = s^; d = ptr_offset(d, 1); s = ptr_offset(s, 1);
-		d^ = s^; d = ptr_offset(d, 1); s = ptr_offset(s, 1);
-		n -= 2;
+		w = (s as ^u32)^
+		d^ = s^; d = ptr_offset(d, 1); s = ptr_offset(s, 1)
+		d^ = s^; d = ptr_offset(d, 1); s = ptr_offset(s, 1)
+		n -= 2
 
 
 		for n > 17 {
 		for n > 17 {
-			d32 := d as ^u32;
-			s32 := ptr_offset(s, 2) as ^u32;
-			x = s32^; d32^ = LS(w, 16) | RS(x, 16);
-			d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1);
-			w = s32^; d32^ = LS(x, 16) | RS(w, 16);
-			d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1);
-			x = s32^; d32^ = LS(w, 16) | RS(x, 16);
-			d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1);
-			w = s32^; d32^ = LS(x, 16) | RS(w, 16);
-			d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1);
-
-			d, s, n = ptr_offset(d, 16), ptr_offset(s, 16), n-16;
+			d32 := d as ^u32
+			s32 := ptr_offset(s, 2) as ^u32
+			x = s32^; d32^ = LS(w, 16) | RS(x, 16)
+			d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1)
+			w = s32^; d32^ = LS(x, 16) | RS(w, 16)
+			d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1)
+			x = s32^; d32^ = LS(w, 16) | RS(x, 16)
+			d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1)
+			w = s32^; d32^ = LS(x, 16) | RS(w, 16)
+			d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1)
+
+			d, s, n = ptr_offset(d, 16), ptr_offset(s, 16), n-16
 		}
 		}
 
 
 	} else if d as uint % 4 == 3 {
 	} else if d as uint % 4 == 3 {
-		w = (s as ^u32)^;
-		d^ = s^;
-		n -= 1;
+		w = (s as ^u32)^
+		d^ = s^
+		n -= 1
 
 
 		for n > 18 {
 		for n > 18 {
-			d32 := d as ^u32;
-			s32 := ptr_offset(s, 3) as ^u32;
-			x = s32^; d32^ = LS(w, 8) | RS(x, 24);
-			d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1);
-			w = s32^; d32^ = LS(x, 8) | RS(w, 24);
-			d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1);
-			x = s32^; d32^ = LS(w, 8) | RS(x, 24);
-			d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1);
-			w = s32^; d32^ = LS(x, 8) | RS(w, 24);
-			d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1);
-
-			d, s, n = ptr_offset(d, 16), ptr_offset(s, 16), n-16;
+			d32 := d as ^u32
+			s32 := ptr_offset(s, 3) as ^u32
+			x = s32^; d32^ = LS(w, 8) | RS(x, 24)
+			d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1)
+			w = s32^; d32^ = LS(x, 8) | RS(w, 24)
+			d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1)
+			x = s32^; d32^ = LS(w, 8) | RS(x, 24)
+			d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1)
+			w = s32^; d32^ = LS(x, 8) | RS(w, 24)
+			d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1)
+
+			d, s, n = ptr_offset(d, 16), ptr_offset(s, 16), n-16
 		}
 		}
 	}
 	}
 
 
 	if n&16 != 0 {
 	if n&16 != 0 {
-		(d as ^v128b)^ = (s as ^v128b)^;
-		d, s = ptr_offset(d, 16), ptr_offset(s, 16);
+		(d as ^v128b)^ = (s as ^v128b)^
+		d, s = ptr_offset(d, 16), ptr_offset(s, 16)
 	}
 	}
 	if n&8 != 0 {
 	if n&8 != 0 {
-		(d as ^u64)^ = (s as ^u64)^;
-		d, s = ptr_offset(d, 8), ptr_offset(s, 8);
+		(d as ^u64)^ = (s as ^u64)^
+		d, s = ptr_offset(d, 8), ptr_offset(s, 8)
 	}
 	}
 	if n&4 != 0 {
 	if n&4 != 0 {
 		(d as ^u32)^ = (s as ^u32)^;
 		(d as ^u32)^ = (s as ^u32)^;
-		d, s = ptr_offset(d, 4), ptr_offset(s, 4);
+		d, s = ptr_offset(d, 4), ptr_offset(s, 4)
 	}
 	}
 	if n&2 != 0 {
 	if n&2 != 0 {
-		(d as ^u16)^ = (s as ^u16)^;
-		d, s = ptr_offset(d, 2), ptr_offset(s, 2);
+		(d as ^u16)^ = (s as ^u16)^
+		d, s = ptr_offset(d, 2), ptr_offset(s, 2)
 	}
 	}
 	if n&1 != 0 {
 	if n&1 != 0 {
-		d^  = s^;
+		d^  = s^
 	}
 	}
 }
 }
 
 
 memory_move :: proc(dst, src: rawptr, n: int) #inline {
 memory_move :: proc(dst, src: rawptr, n: int) #inline {
-	d, s: ^u8 = dst, src;
+	d, s: ^u8 = dst, src
 	if d == s {
 	if d == s {
-		return;
+		return
 	}
 	}
 	if d >= ptr_offset(s, n) || ptr_offset(d, n) <= s {
 	if d >= ptr_offset(s, n) || ptr_offset(d, n) <= s {
-		memory_copy(d, s, n);
-		return;
+		memory_copy(d, s, n)
+		return
 	}
 	}
 
 
 	// TODO(bill): Vectorize the shit out of this
 	// TODO(bill): Vectorize the shit out of this
@@ -172,94 +172,94 @@ memory_move :: proc(dst, src: rawptr, n: int) #inline {
 		if s as int % size_of(int) == d as int % size_of(int) {
 		if s as int % size_of(int) == d as int % size_of(int) {
 			for d as int % size_of(int) != 0 {
 			for d as int % size_of(int) != 0 {
 				if n == 0 {
 				if n == 0 {
-					return;
+					return
 				}
 				}
-				n--;
-				d^ = s^;
-				d, s = ptr_offset(d, 1), ptr_offset(s, 1);
+				n--
+				d^ = s^
+				d, s = ptr_offset(d, 1), ptr_offset(s, 1)
 			}
 			}
-			di, si := d as ^int, s as ^int;
+			di, si := d as ^int, s as ^int
 			for n >= size_of(int) {
 			for n >= size_of(int) {
-				di^ = si^;
-				di, si = ptr_offset(di, 1), ptr_offset(si, 1);
-				n -= size_of(int);
+				di^ = si^
+				di, si = ptr_offset(di, 1), ptr_offset(si, 1)
+				n -= size_of(int)
 			}
 			}
 		}
 		}
 		for ; n > 0; n-- {
 		for ; n > 0; n-- {
-			d^ = s^;
-			d, s = ptr_offset(d, 1), ptr_offset(s, 1);
+			d^ = s^
+			d, s = ptr_offset(d, 1), ptr_offset(s, 1)
 		}
 		}
 	} else {
 	} else {
 		if s as int % size_of(int) == d as int % size_of(int) {
 		if s as int % size_of(int) == d as int % size_of(int) {
 			for ptr_offset(d, n) as int % size_of(int) != 0 {
 			for ptr_offset(d, n) as int % size_of(int) != 0 {
 				if n == 0 {
 				if n == 0 {
-					return;
+					return
 				}
 				}
-				n--;
-				d^ = s^;
-				d, s = ptr_offset(d, 1), ptr_offset(s, 1);
+				n--
+				d^ = s^
+				d, s = ptr_offset(d, 1), ptr_offset(s, 1)
 			}
 			}
 			for n >= size_of(int) {
 			for n >= size_of(int) {
-				n -= size_of(int);
-				di := ptr_offset(d, n) as ^int;
-				si := ptr_offset(s, n) as ^int;
-				di^ = si^;
+				n -= size_of(int)
+				di := ptr_offset(d, n) as ^int
+				si := ptr_offset(s, n) as ^int
+				di^ = si^
 			}
 			}
 			for ; n > 0; n-- {
 			for ; n > 0; n-- {
-				d^ = s^;
-				d, s = ptr_offset(d, 1), ptr_offset(s, 1);
+				d^ = s^
+				d, s = ptr_offset(d, 1), ptr_offset(s, 1)
 			}
 			}
 		}
 		}
 		for n > 0 {
 		for n > 0 {
-			n--;
-			dn := ptr_offset(d, n);
-			sn := ptr_offset(s, n);
-			dn^ = sn^;
+			n--
+			dn := ptr_offset(d, n)
+			sn := ptr_offset(s, n)
+			dn^ = sn^
 		}
 		}
 	}
 	}
 }
 }
 
 
-__string_eq :: proc(a, b : string) -> bool {
+__string_eq :: proc(a, b: string) -> bool {
 	if len(a) != len(b) {
 	if len(a) != len(b) {
-		return false;
+		return false
 	}
 	}
 	if ^a[0] == ^b[0] {
 	if ^a[0] == ^b[0] {
-		return true;
+		return true
 	}
 	}
-	return memory_compare(^a[0], ^b[0], len(a)) == 0;
+	return memory_compare(^a[0], ^b[0], len(a)) == 0
 }
 }
 
 
 __string_ne :: proc(a, b : string) -> bool #inline {
 __string_ne :: proc(a, b : string) -> bool #inline {
-	return !__string_eq(a, b);
+	return !__string_eq(a, b)
 }
 }
 
 
 __string_cmp :: proc(a, b : string) -> int {
 __string_cmp :: proc(a, b : string) -> int {
-	min_len := len(a);
+	min_len := len(a)
 	if len(b) < min_len {
 	if len(b) < min_len {
-		min_len = len(b);
+		min_len = len(b)
 	}
 	}
 	for i := 0; i < min_len; i++ {
 	for i := 0; i < min_len; i++ {
-		x := a[i];
-		y := b[i];
+		x := a[i]
+		y := b[i]
 		if x < y {
 		if x < y {
-			return -1;
+			return -1
 		} else if x > y {
 		} else if x > y {
-			return +1;
+			return +1
 		}
 		}
 	}
 	}
 
 
 	if len(a) < len(b) {
 	if len(a) < len(b) {
-		return -1;
+		return -1
 	} else if len(a) > len(b) {
 	} else if len(a) > len(b) {
-		return +1;
+		return +1
 	}
 	}
-	return 0;
+	return 0
 }
 }
 
 
-__string_lt :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) < 0; }
-__string_gt :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) > 0; }
-__string_le :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) <= 0; }
-__string_ge :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) >= 0; }
+__string_lt :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) < 0 }
+__string_gt :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) > 0 }
+__string_le :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) <= 0 }
+__string_ge :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) >= 0 }
 
 
 
 
 
 
@@ -275,117 +275,113 @@ AllocationMode :: type enum {
 
 
 AllocatorProc :: type proc(allocator_data: rawptr, mode: AllocationMode,
 AllocatorProc :: type proc(allocator_data: rawptr, mode: AllocationMode,
                            size, alignment: int,
                            size, alignment: int,
-                           old_memory: rawptr, old_size: int, flags: u64) -> rawptr;
+                           old_memory: rawptr, old_size: int, flags: u64) -> rawptr
 
 
 Allocator :: type struct {
 Allocator :: type struct {
 	procedure: AllocatorProc;
 	procedure: AllocatorProc;
-	data:      rawptr;
+	data:      rawptr
 }
 }
 
 
 
 
 Context :: type struct {
 Context :: type struct {
-	thread_id: i32;
+	thread_id: i32
 
 
-	user_index: i32;
-	user_data:  rawptr;
+	user_index: i32
+	user_data:  rawptr
 
 
-	allocator: Allocator;
+	allocator: Allocator
 }
 }
 
 
-#thread_local context: Context;
+#thread_local context: Context
 
 
-DEFAULT_ALIGNMENT :: 2*size_of(int);
+DEFAULT_ALIGNMENT :: 2*size_of(int)
 
 
 
 
 __check_context :: proc() {
 __check_context :: proc() {
-	static_assert(AllocationMode.ALLOC == 0);
-	static_assert(AllocationMode.DEALLOC == 1);
-	static_assert(AllocationMode.DEALLOC_ALL == 2);
-	static_assert(AllocationMode.RESIZE == 3);
-
 	if context.allocator.procedure == null {
 	if context.allocator.procedure == null {
-		context.allocator = __default_allocator();
+		context.allocator = __default_allocator()
 	}
 	}
 }
 }
 
 
 
 
-alloc :: proc(size: int) -> rawptr #inline { return alloc_align(size, DEFAULT_ALIGNMENT); }
+alloc :: proc(size: int) -> rawptr #inline { return alloc_align(size, DEFAULT_ALIGNMENT) }
 
 
 alloc_align :: proc(size, alignment: int) -> rawptr #inline {
 alloc_align :: proc(size, alignment: int) -> rawptr #inline {
-	__check_context();
-	a := context.allocator;
-	return a.procedure(a.data, AllocationMode.ALLOC, size, alignment, null, 0, 0);
+	__check_context()
+	a := context.allocator
+	return a.procedure(a.data, AllocationMode.ALLOC, size, alignment, null, 0, 0)
 }
 }
 
 
 dealloc :: proc(ptr: rawptr) #inline {
 dealloc :: proc(ptr: rawptr) #inline {
-	__check_context();
-	a := context.allocator;
-	_ = a.procedure(a.data, AllocationMode.DEALLOC, 0, 0, ptr, 0, 0);
+	__check_context()
+	a := context.allocator
+	_ = a.procedure(a.data, AllocationMode.DEALLOC, 0, 0, ptr, 0, 0)
 }
 }
 dealloc_all :: proc(ptr: rawptr) #inline {
 dealloc_all :: proc(ptr: rawptr) #inline {
-	__check_context();
-	a := context.allocator;
-	_ = a.procedure(a.data, AllocationMode.DEALLOC_ALL, 0, 0, ptr, 0, 0);
+	__check_context()
+	a := context.allocator
+	_ = a.procedure(a.data, AllocationMode.DEALLOC_ALL, 0, 0, ptr, 0, 0)
 }
 }
 
 
 
 
-resize       :: proc(ptr: rawptr, old_size, new_size: int) -> rawptr #inline { return resize_align(ptr, old_size, new_size, DEFAULT_ALIGNMENT); }
+resize       :: proc(ptr: rawptr, old_size, new_size: int) -> rawptr #inline { return resize_align(ptr, old_size, new_size, DEFAULT_ALIGNMENT) }
 resize_align :: proc(ptr: rawptr, old_size, new_size, alignment: int) -> rawptr #inline {
 resize_align :: proc(ptr: rawptr, old_size, new_size, alignment: int) -> rawptr #inline {
-	__check_context();
-	a := context.allocator;
-	return a.procedure(a.data, AllocationMode.RESIZE, new_size, alignment, ptr, old_size, 0);
+	__check_context()
+	a := context.allocator
+	return a.procedure(a.data, AllocationMode.RESIZE, new_size, alignment, ptr, old_size, 0)
 }
 }
 
 
 
 
 
 
 default_resize_align :: proc(old_memory: rawptr, old_size, new_size, alignment: int) -> rawptr {
 default_resize_align :: proc(old_memory: rawptr, old_size, new_size, alignment: int) -> rawptr {
 	if old_memory == null {
 	if old_memory == null {
-		return alloc_align(new_size, alignment);
+		return alloc_align(new_size, alignment)
 	}
 	}
 
 
 	if new_size == 0 {
 	if new_size == 0 {
-		dealloc(old_memory);
-		return null;
+		dealloc(old_memory)
+		return null
 	}
 	}
 
 
 	if new_size < old_size {
 	if new_size < old_size {
-		new_size = old_size;
+		new_size = old_size
 	}
 	}
 
 
 	if old_size == new_size {
 	if old_size == new_size {
-		return old_memory;
+		return old_memory
 	}
 	}
 
 
-	new_memory := alloc_align(new_size, alignment);
+	new_memory := alloc_align(new_size, alignment)
 	if new_memory == null {
 	if new_memory == null {
-		return null;
+		return null
 	}
 	}
-	_ = copy(slice_ptr(new_memory as ^u8, new_size), slice_ptr(old_memory as ^u8, old_size));
-	dealloc(old_memory);
-	return new_memory;
+	_ = copy(slice_ptr(new_memory as ^u8, new_size), slice_ptr(old_memory as ^u8, old_size))
+	dealloc(old_memory)
+	return new_memory
 }
 }
 
 
 
 
 __default_allocator_proc :: proc(allocator_data: rawptr, mode: AllocationMode,
 __default_allocator_proc :: proc(allocator_data: rawptr, mode: AllocationMode,
                                  size, alignment: int,
                                  size, alignment: int,
                                  old_memory: rawptr, old_size: int, flags: u64) -> rawptr {
                                  old_memory: rawptr, old_size: int, flags: u64) -> rawptr {
-	if mode == AllocationMode.ALLOC {
-		return heap_alloc(size);
-	} else if mode == AllocationMode.RESIZE {
-		return default_resize_align(old_memory, old_size, size, alignment);
-	} else if mode == AllocationMode.DEALLOC {
-		heap_free(old_memory);
-	} else if mode == AllocationMode.DEALLOC_ALL {
+	using AllocationMode
+	if mode == ALLOC {
+		return heap_alloc(size)
+	} else if mode == RESIZE {
+		return default_resize_align(old_memory, old_size, size, alignment)
+	} else if mode == DEALLOC {
+		heap_free(old_memory)
+	} else if mode == DEALLOC_ALL {
 		// NOTE(bill): Does nothing
 		// NOTE(bill): Does nothing
 	}
 	}
 
 
-	return null;
+	return null
 }
 }
 
 
 __default_allocator :: proc() -> Allocator {
 __default_allocator :: proc() -> Allocator {
 	return Allocator{
 	return Allocator{
 		__default_allocator_proc,
 		__default_allocator_proc,
 		null,
 		null,
-	};
+	}
 }
 }
 
 

+ 13 - 13
examples/stb_image.odin

@@ -7,24 +7,24 @@ type Bitmap: struct {
 make_bitmap :: proc(filename: string) -> Bitmap {
 make_bitmap :: proc(filename: string) -> Bitmap {
 	stbi_load :: proc(filename: ^u8, x, y, comp: ^i32, req_comp: i32) -> ^u8 #foreign
 	stbi_load :: proc(filename: ^u8, x, y, comp: ^i32, req_comp: i32) -> ^u8 #foreign
 
 
-	c_buf: [1024]u8;
-	bytes :=  filename as []byte;
-	str_len := copy(c_buf[:], bytes);
+	c_buf: [1024]u8
+	bytes :=  filename as []byte
+	str_len := copy(c_buf[:], bytes)
 
 
-	b: Bitmap;
-	pixels := stbi_load(^c_buf[0], ^b.width, ^b.height, ^b.comp, 4);
-	len := (b.width*b.height*b.comp) as int;
-	b.data = pixels[:len];
+	b: Bitmap
+	pixels := stbi_load(^c_buf[0], ^b.width, ^b.height, ^b.comp, 4)
+	len := (b.width*b.height*b.comp) as int
+	b.data = slice_ptr(pixels, len)
 
 
-	return b;
+	return b
 }
 }
 
 
 destroy_bitmap :: proc(b: ^Bitmap) {
 destroy_bitmap :: proc(b: ^Bitmap) {
 	stbi_image_free :: proc(retval_from_stbi_load: rawptr) #foreign
 	stbi_image_free :: proc(retval_from_stbi_load: rawptr) #foreign
 
 
-	stbi_image_free(^b.data[0]);
-	b.data   = b.data[:0];
-	b.width  = 0;
-	b.height = 0;
-	b.comp   = 0;
+	stbi_image_free(^b.data[0])
+	b.data   = b.data[:0]
+	b.width  = 0
+	b.height = 0
+	b.comp   = 0
 }
 }

+ 260 - 257
examples/win32.odin

@@ -1,63 +1,66 @@
-CS_VREDRAW    :: 1;
-CS_HREDRAW    :: 2;
-CW_USEDEFAULT :: 0x80000000;
-
-WS_OVERLAPPED       :: 0;
-WS_MAXIMIZEBOX      :: 0x00010000;
-WS_MINIMIZEBOX      :: 0x00020000;
-WS_THICKFRAME       :: 0x00040000;
-WS_SYSMENU          :: 0x00080000;
-WS_CAPTION          :: 0x00C00000;
-WS_VISIBLE          :: 0x10000000;
-WS_OVERLAPPEDWINDOW :: WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|WS_MAXIMIZEBOX;
-
-WM_DESTROY :: 0x02;
-WM_CLOSE   :: 0x10;
-WM_QUIT    :: 0x12;
-
-PM_REMOVE :: 1;
-
-COLOR_BACKGROUND :: 1 as HBRUSH;
-
-
-HANDLE    :: type rawptr;
-HWND      :: type HANDLE;
-HDC       :: type HANDLE;
-HINSTANCE :: type HANDLE;
-HICON     :: type HANDLE;
-HCURSOR   :: type HANDLE;
-HMENU     :: type HANDLE;
-HBRUSH    :: type HANDLE;
-WPARAM    :: type uint;
-LPARAM    :: type int;
-LRESULT   :: type int;
-ATOM      :: type i16;
-BOOL      :: type i32;
-POINT     :: type struct { x, y: i32; };
-
-INVALID_HANDLE_VALUE :: (-1 as int) as HANDLE;
+#foreign_system_library "user32"
+#foreign_system_library "gdi32"
+
+CS_VREDRAW    :: 1
+CS_HREDRAW    :: 2
+CW_USEDEFAULT :: 0x80000000
+
+WS_OVERLAPPED       :: 0
+WS_MAXIMIZEBOX      :: 0x00010000
+WS_MINIMIZEBOX      :: 0x00020000
+WS_THICKFRAME       :: 0x00040000
+WS_SYSMENU          :: 0x00080000
+WS_CAPTION          :: 0x00C00000
+WS_VISIBLE          :: 0x10000000
+WS_OVERLAPPEDWINDOW :: WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|WS_MAXIMIZEBOX
+
+WM_DESTROY :: 0x02
+WM_CLOSE   :: 0x10
+WM_QUIT    :: 0x12
+
+PM_REMOVE :: 1
+
+COLOR_BACKGROUND :: 1 as HBRUSH
+
+
+HANDLE    :: type rawptr
+HWND      :: type HANDLE
+HDC       :: type HANDLE
+HINSTANCE :: type HANDLE
+HICON     :: type HANDLE
+HCURSOR   :: type HANDLE
+HMENU     :: type HANDLE
+HBRUSH    :: type HANDLE
+WPARAM    :: type uint
+LPARAM    :: type int
+LRESULT   :: type int
+ATOM      :: type i16
+BOOL      :: type i32
+POINT     :: type struct { x, y: i32 }
+
+INVALID_HANDLE_VALUE :: (-1 as int) as HANDLE
 
 
 WNDPROC :: type proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT
 WNDPROC :: type proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT
 
 
 WNDCLASSEXA :: type struct {
 WNDCLASSEXA :: type struct {
-	size, style:           u32;
-	wnd_proc:              WNDPROC;
-	cls_extra, wnd_extra:  i32;
-	instance:              HINSTANCE;
-	icon:                  HICON;
-	cursor:                HCURSOR;
-	background:            HBRUSH;
-	menu_name, class_name: ^u8;
-	sm:                    HICON;
+	size, style:           u32
+	wnd_proc:              WNDPROC
+	cls_extra, wnd_extra:  i32
+	instance:              HINSTANCE
+	icon:                  HICON
+	cursor:                HCURSOR
+	background:            HBRUSH
+	menu_name, class_name: ^u8
+	sm:                    HICON
 }
 }
 
 
 MSG :: type struct {
 MSG :: type struct {
-	hwnd:    HWND;
-	message: u32;
-	wparam:  WPARAM;
-	lparam:  LPARAM;
-	time:    u32;
-	pt:      POINT;
+	hwnd:    HWND
+	message: u32
+	wparam:  WPARAM
+	lparam:  LPARAM
+	time:    u32
+	pt:      POINT
 }
 }
 
 
 
 
@@ -75,7 +78,7 @@ QueryPerformanceCounter   :: proc(result: ^i64) -> i32 #foreign
 
 
 sleep_ms :: proc(ms: i32) {
 sleep_ms :: proc(ms: i32) {
 	Sleep :: proc(ms: i32) -> i32 #foreign
 	Sleep :: proc(ms: i32) -> i32 #foreign
-	Sleep(ms);
+	Sleep(ms)
 }
 }
 
 
 OutputDebugStringA :: proc(c_str: ^u8) #foreign
 OutputDebugStringA :: proc(c_str: ^u8) #foreign
@@ -102,9 +105,9 @@ DefWindowProcA   :: proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -
 
 
 
 
 GetQueryPerformanceFrequency :: proc() -> i64 {
 GetQueryPerformanceFrequency :: proc() -> i64 {
-	r: i64;
-	_ = QueryPerformanceFrequency(^r);
-	return r;
+	r: i64
+	_ = QueryPerformanceFrequency(^r)
+	return r
 }
 }
 
 
 
 
@@ -121,30 +124,30 @@ WriteFile    :: proc(h: HANDLE, buf: rawptr, len: i32, written_result: ^i32, ove
 
 
 GetFileSizeEx :: proc(file_handle: HANDLE, file_size: ^i64) -> BOOL #foreign
 GetFileSizeEx :: proc(file_handle: HANDLE, file_size: ^i64) -> BOOL #foreign
 
 
-FILE_SHARE_READ      :: 0x00000001;
-FILE_SHARE_WRITE     :: 0x00000002;
-FILE_SHARE_DELETE    :: 0x00000004;
-FILE_GENERIC_ALL     :: 0x10000000;
-FILE_GENERIC_EXECUTE :: 0x20000000;
-FILE_GENERIC_WRITE   :: 0x40000000;
-FILE_GENERIC_READ    :: 0x80000000;
+FILE_SHARE_READ      :: 0x00000001
+FILE_SHARE_WRITE     :: 0x00000002
+FILE_SHARE_DELETE    :: 0x00000004
+FILE_GENERIC_ALL     :: 0x10000000
+FILE_GENERIC_EXECUTE :: 0x20000000
+FILE_GENERIC_WRITE   :: 0x40000000
+FILE_GENERIC_READ    :: 0x80000000
 
 
-STD_INPUT_HANDLE  :: -10;
-STD_OUTPUT_HANDLE :: -11;
-STD_ERROR_HANDLE  :: -12;
+STD_INPUT_HANDLE  :: -10
+STD_OUTPUT_HANDLE :: -11
+STD_ERROR_HANDLE  :: -12
 
 
-CREATE_NEW        :: 1;
-CREATE_ALWAYS     :: 2;
-OPEN_EXISTING     :: 3;
-OPEN_ALWAYS       :: 4;
-TRUNCATE_EXISTING :: 5;
+CREATE_NEW        :: 1
+CREATE_ALWAYS     :: 2
+OPEN_EXISTING     :: 3
+OPEN_ALWAYS       :: 4
+TRUNCATE_EXISTING :: 5
 
 
 
 
 HeapAlloc :: proc(h: HANDLE, flags: u32, bytes: int) -> rawptr #foreign
 HeapAlloc :: proc(h: HANDLE, flags: u32, bytes: int) -> rawptr #foreign
 HeapFree  :: proc(h: HANDLE, flags: u32, memory: rawptr) -> BOOL #foreign
 HeapFree  :: proc(h: HANDLE, flags: u32, memory: rawptr) -> BOOL #foreign
 GetProcessHeap :: proc() -> HANDLE #foreign
 GetProcessHeap :: proc() -> HANDLE #foreign
 
 
-HEAP_ZERO_MEMORY :: 0x00000008;
+HEAP_ZERO_MEMORY :: 0x00000008
 
 
 
 
 
 
@@ -159,37 +162,37 @@ HEAP_ZERO_MEMORY :: 0x00000008;
 
 
 // Windows OpenGL
 // Windows OpenGL
 
 
-PFD_TYPE_RGBA             :: 0;
-PFD_TYPE_COLORINDEX       :: 1;
-PFD_MAIN_PLANE            :: 0;
-PFD_OVERLAY_PLANE         :: 1;
-PFD_UNDERLAY_PLANE        :: -1;
-PFD_DOUBLEBUFFER          :: 1;
-PFD_STEREO                :: 2;
-PFD_DRAW_TO_WINDOW        :: 4;
-PFD_DRAW_TO_BITMAP        :: 8;
-PFD_SUPPORT_GDI           :: 16;
-PFD_SUPPORT_OPENGL        :: 32;
-PFD_GENERIC_FORMAT        :: 64;
-PFD_NEED_PALETTE          :: 128;
-PFD_NEED_SYSTEM_PALETTE   :: 0x00000100;
-PFD_SWAP_EXCHANGE         :: 0x00000200;
-PFD_SWAP_COPY             :: 0x00000400;
-PFD_SWAP_LAYER_BUFFERS    :: 0x00000800;
-PFD_GENERIC_ACCELERATED   :: 0x00001000;
-PFD_DEPTH_DONTCARE        :: 0x20000000;
-PFD_DOUBLEBUFFER_DONTCARE :: 0x40000000;
-PFD_STEREO_DONTCARE       :: 0x80000000;
-
-HGLRC :: type HANDLE;
-PROC  :: type proc();
-wglCreateContextAttribsARBType :: type proc(hdc: HDC, hshareContext: rawptr, attribList: ^i32) -> HGLRC;
+PFD_TYPE_RGBA             :: 0
+PFD_TYPE_COLORINDEX       :: 1
+PFD_MAIN_PLANE            :: 0
+PFD_OVERLAY_PLANE         :: 1
+PFD_UNDERLAY_PLANE        :: -1
+PFD_DOUBLEBUFFER          :: 1
+PFD_STEREO                :: 2
+PFD_DRAW_TO_WINDOW        :: 4
+PFD_DRAW_TO_BITMAP        :: 8
+PFD_SUPPORT_GDI           :: 16
+PFD_SUPPORT_OPENGL        :: 32
+PFD_GENERIC_FORMAT        :: 64
+PFD_NEED_PALETTE          :: 128
+PFD_NEED_SYSTEM_PALETTE   :: 0x00000100
+PFD_SWAP_EXCHANGE         :: 0x00000200
+PFD_SWAP_COPY             :: 0x00000400
+PFD_SWAP_LAYER_BUFFERS    :: 0x00000800
+PFD_GENERIC_ACCELERATED   :: 0x00001000
+PFD_DEPTH_DONTCARE        :: 0x20000000
+PFD_DOUBLEBUFFER_DONTCARE :: 0x40000000
+PFD_STEREO_DONTCARE       :: 0x80000000
+
+HGLRC :: type HANDLE
+PROC  :: type proc()
+wglCreateContextAttribsARBType :: type proc(hdc: HDC, hshareContext: rawptr, attribList: ^i32) -> HGLRC
 
 
 
 
 PIXELFORMATDESCRIPTOR :: type struct  {
 PIXELFORMATDESCRIPTOR :: type struct  {
 	size,
 	size,
 	version,
 	version,
-	flags: u32;
+	flags: u32
 
 
 	pixel_type,
 	pixel_type,
 	color_bits,
 	color_bits,
@@ -210,11 +213,11 @@ PIXELFORMATDESCRIPTOR :: type struct  {
 	stencil_bits,
 	stencil_bits,
 	aux_buffers,
 	aux_buffers,
 	layer_type,
 	layer_type,
-	reserved: byte;
+	reserved: byte
 
 
 	layer_mask,
 	layer_mask,
 	visible_mask,
 	visible_mask,
-	damage_mask: u32;
+	damage_mask: u32
 }
 }
 
 
 GetDC             :: proc(h: HANDLE) -> HDC #foreign
 GetDC             :: proc(h: HANDLE) -> HDC #foreign
@@ -223,10 +226,10 @@ ChoosePixelFormat :: proc(hdc: HDC, pfd: ^PIXELFORMATDESCRIPTOR) -> i32 #foreign
 SwapBuffers       :: proc(hdc: HDC) -> BOOL #foreign
 SwapBuffers       :: proc(hdc: HDC) -> BOOL #foreign
 
 
 
 
-WGL_CONTEXT_MAJOR_VERSION_ARB             :: 0x2091;
-WGL_CONTEXT_MINOR_VERSION_ARB             :: 0x2092;
-WGL_CONTEXT_PROFILE_MASK_ARB              :: 0x9126;
-WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB :: 0x0002;
+WGL_CONTEXT_MAJOR_VERSION_ARB             :: 0x2091
+WGL_CONTEXT_MINOR_VERSION_ARB             :: 0x2092
+WGL_CONTEXT_PROFILE_MASK_ARB              :: 0x9126
+WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB :: 0x0002
 
 
 wglCreateContext  :: proc(hdc: HDC) -> HGLRC #foreign
 wglCreateContext  :: proc(hdc: HDC) -> HGLRC #foreign
 wglMakeCurrent    :: proc(hdc: HDC, hglrc: HGLRC) -> BOOL #foreign
 wglMakeCurrent    :: proc(hdc: HDC, hglrc: HGLRC) -> BOOL #foreign
@@ -238,159 +241,159 @@ wglDeleteContext  :: proc(hglrc: HGLRC) -> BOOL #foreign
 GetAsyncKeyState :: proc(v_key: i32) -> i16 #foreign
 GetAsyncKeyState :: proc(v_key: i32) -> i16 #foreign
 
 
 is_key_down :: proc(key: int) -> bool {
 is_key_down :: proc(key: int) -> bool {
-	return GetAsyncKeyState(key as i32) < 0;
+	return GetAsyncKeyState(key as i32) < 0
 }
 }
 
 
 
 
-VK_LBUTTON    :: 0x01;
-VK_RBUTTON    :: 0x02;
-VK_CANCEL     :: 0x03;
-VK_MBUTTON    :: 0x04;
-
-VK_BACK       :: 0x08;
-VK_TAB        :: 0x09;
-
-VK_CLEAR      :: 0x0C;
-VK_RETURN     :: 0x0D;
-
-VK_SHIFT      :: 0x10;
-VK_CONTROL    :: 0x11;
-VK_MENU       :: 0x12;
-VK_PAUSE      :: 0x13;
-VK_CAPITAL    :: 0x14;
-
-VK_KANA       :: 0x15;
-VK_HANGEUL    :: 0x15;
-VK_HANGUL     :: 0x15;
-VK_JUNJA      :: 0x17;
-VK_FINAL      :: 0x18;
-VK_HANJA      :: 0x19;
-VK_KANJI      :: 0x19;
-
-VK_ESCAPE     :: 0x1B;
-
-VK_CONVERT    :: 0x1C;
-VK_NONCONVERT :: 0x1D;
-VK_ACCEPT     :: 0x1E;
-VK_MODECHANGE :: 0x1F;
-
-VK_SPACE      :: 0x20;
-VK_PRIOR      :: 0x21;
-VK_NEXT       :: 0x22;
-VK_END        :: 0x23;
-VK_HOME       :: 0x24;
-VK_LEFT       :: 0x25;
-VK_UP         :: 0x26;
-VK_RIGHT      :: 0x27;
-VK_DOWN       :: 0x28;
-VK_SELECT     :: 0x29;
-VK_PRINT      :: 0x2A;
-VK_EXECUTE    :: 0x2B;
-VK_SNAPSHOT   :: 0x2C;
-VK_INSERT     :: 0x2D;
-VK_DELETE     :: 0x2E;
-VK_HELP       :: 0x2F;
-
-VK_0 :: #rune "0";
-VK_1 :: #rune "1";
-VK_2 :: #rune "2";
-VK_3 :: #rune "3";
-VK_4 :: #rune "4";
-VK_5 :: #rune "5";
-VK_6 :: #rune "6";
-VK_7 :: #rune "7";
-VK_8 :: #rune "8";
-VK_9 :: #rune "9";
-
-VK_A :: #rune "A";
-VK_B :: #rune "B";
-VK_C :: #rune "C";
-VK_D :: #rune "D";
-VK_E :: #rune "E";
-VK_F :: #rune "F";
-VK_G :: #rune "G";
-VK_H :: #rune "H";
-VK_I :: #rune "I";
-VK_J :: #rune "J";
-VK_K :: #rune "K";
-VK_L :: #rune "L";
-VK_M :: #rune "M";
-VK_N :: #rune "N";
-VK_O :: #rune "O";
-VK_P :: #rune "P";
-VK_Q :: #rune "Q";
-VK_R :: #rune "R";
-VK_S :: #rune "S";
-VK_T :: #rune "T";
-VK_U :: #rune "U";
-VK_V :: #rune "V";
-VK_W :: #rune "W";
-VK_X :: #rune "X";
-VK_Y :: #rune "Y";
-VK_Z :: #rune "Z";
-
-VK_LWIN       :: 0x5B;
-VK_RWIN       :: 0x5C;
-VK_APPS       :: 0x5D;
-
-VK_NUMPAD0    :: 0x60;
-VK_NUMPAD1    :: 0x61;
-VK_NUMPAD2    :: 0x62;
-VK_NUMPAD3    :: 0x63;
-VK_NUMPAD4    :: 0x64;
-VK_NUMPAD5    :: 0x65;
-VK_NUMPAD6    :: 0x66;
-VK_NUMPAD7    :: 0x67;
-VK_NUMPAD8    :: 0x68;
-VK_NUMPAD9    :: 0x69;
-VK_MULTIPLY   :: 0x6A;
-VK_ADD        :: 0x6B;
-VK_SEPARATOR  :: 0x6C;
-VK_SUBTRACT   :: 0x6D;
-VK_DECIMAL    :: 0x6E;
-VK_DIVIDE     :: 0x6F;
-VK_F1         :: 0x70;
-VK_F2         :: 0x71;
-VK_F3         :: 0x72;
-VK_F4         :: 0x73;
-VK_F5         :: 0x74;
-VK_F6         :: 0x75;
-VK_F7         :: 0x76;
-VK_F8         :: 0x77;
-VK_F9         :: 0x78;
-VK_F10        :: 0x79;
-VK_F11        :: 0x7A;
-VK_F12        :: 0x7B;
-VK_F13        :: 0x7C;
-VK_F14        :: 0x7D;
-VK_F15        :: 0x7E;
-VK_F16        :: 0x7F;
-VK_F17        :: 0x80;
-VK_F18        :: 0x81;
-VK_F19        :: 0x82;
-VK_F20        :: 0x83;
-VK_F21        :: 0x84;
-VK_F22        :: 0x85;
-VK_F23        :: 0x86;
-VK_F24        :: 0x87;
-
-VK_NUMLOCK    :: 0x90;
-VK_SCROLL     :: 0x91;
-
-VK_LSHIFT     :: 0xA0;
-VK_RSHIFT     :: 0xA1;
-VK_LCONTROL   :: 0xA2;
-VK_RCONTROL   :: 0xA3;
-VK_LMENU      :: 0xA4;
-VK_RMENU      :: 0xA5;
-VK_PROCESSKEY :: 0xE5;
-VK_ATTN       :: 0xF6;
-VK_CRSEL      :: 0xF7;
-VK_EXSEL      :: 0xF8;
-VK_EREOF      :: 0xF9;
-VK_PLAY       :: 0xFA;
-VK_ZOOM       :: 0xFB;
-VK_NONAME     :: 0xFC;
-VK_PA1        :: 0xFD;
-VK_OEM_CLEAR  :: 0xFE;
+VK_LBUTTON    :: 0x01
+VK_RBUTTON    :: 0x02
+VK_CANCEL     :: 0x03
+VK_MBUTTON    :: 0x04
+
+VK_BACK       :: 0x08
+VK_TAB        :: 0x09
+
+VK_CLEAR      :: 0x0C
+VK_RETURN     :: 0x0D
+
+VK_SHIFT      :: 0x10
+VK_CONTROL    :: 0x11
+VK_MENU       :: 0x12
+VK_PAUSE      :: 0x13
+VK_CAPITAL    :: 0x14
+
+VK_KANA       :: 0x15
+VK_HANGEUL    :: 0x15
+VK_HANGUL     :: 0x15
+VK_JUNJA      :: 0x17
+VK_FINAL      :: 0x18
+VK_HANJA      :: 0x19
+VK_KANJI      :: 0x19
+
+VK_ESCAPE     :: 0x1B
+
+VK_CONVERT    :: 0x1C
+VK_NONCONVERT :: 0x1D
+VK_ACCEPT     :: 0x1E
+VK_MODECHANGE :: 0x1F
+
+VK_SPACE      :: 0x20
+VK_PRIOR      :: 0x21
+VK_NEXT       :: 0x22
+VK_END        :: 0x23
+VK_HOME       :: 0x24
+VK_LEFT       :: 0x25
+VK_UP         :: 0x26
+VK_RIGHT      :: 0x27
+VK_DOWN       :: 0x28
+VK_SELECT     :: 0x29
+VK_PRINT      :: 0x2A
+VK_EXECUTE    :: 0x2B
+VK_SNAPSHOT   :: 0x2C
+VK_INSERT     :: 0x2D
+VK_DELETE     :: 0x2E
+VK_HELP       :: 0x2F
+
+VK_0 :: #rune "0"
+VK_1 :: #rune "1"
+VK_2 :: #rune "2"
+VK_3 :: #rune "3"
+VK_4 :: #rune "4"
+VK_5 :: #rune "5"
+VK_6 :: #rune "6"
+VK_7 :: #rune "7"
+VK_8 :: #rune "8"
+VK_9 :: #rune "9"
+
+VK_A :: #rune "A"
+VK_B :: #rune "B"
+VK_C :: #rune "C"
+VK_D :: #rune "D"
+VK_E :: #rune "E"
+VK_F :: #rune "F"
+VK_G :: #rune "G"
+VK_H :: #rune "H"
+VK_I :: #rune "I"
+VK_J :: #rune "J"
+VK_K :: #rune "K"
+VK_L :: #rune "L"
+VK_M :: #rune "M"
+VK_N :: #rune "N"
+VK_O :: #rune "O"
+VK_P :: #rune "P"
+VK_Q :: #rune "Q"
+VK_R :: #rune "R"
+VK_S :: #rune "S"
+VK_T :: #rune "T"
+VK_U :: #rune "U"
+VK_V :: #rune "V"
+VK_W :: #rune "W"
+VK_X :: #rune "X"
+VK_Y :: #rune "Y"
+VK_Z :: #rune "Z"
+
+VK_LWIN       :: 0x5B
+VK_RWIN       :: 0x5C
+VK_APPS       :: 0x5D
+
+VK_NUMPAD0    :: 0x60
+VK_NUMPAD1    :: 0x61
+VK_NUMPAD2    :: 0x62
+VK_NUMPAD3    :: 0x63
+VK_NUMPAD4    :: 0x64
+VK_NUMPAD5    :: 0x65
+VK_NUMPAD6    :: 0x66
+VK_NUMPAD7    :: 0x67
+VK_NUMPAD8    :: 0x68
+VK_NUMPAD9    :: 0x69
+VK_MULTIPLY   :: 0x6A
+VK_ADD        :: 0x6B
+VK_SEPARATOR  :: 0x6C
+VK_SUBTRACT   :: 0x6D
+VK_DECIMAL    :: 0x6E
+VK_DIVIDE     :: 0x6F
+VK_F1         :: 0x70
+VK_F2         :: 0x71
+VK_F3         :: 0x72
+VK_F4         :: 0x73
+VK_F5         :: 0x74
+VK_F6         :: 0x75
+VK_F7         :: 0x76
+VK_F8         :: 0x77
+VK_F9         :: 0x78
+VK_F10        :: 0x79
+VK_F11        :: 0x7A
+VK_F12        :: 0x7B
+VK_F13        :: 0x7C
+VK_F14        :: 0x7D
+VK_F15        :: 0x7E
+VK_F16        :: 0x7F
+VK_F17        :: 0x80
+VK_F18        :: 0x81
+VK_F19        :: 0x82
+VK_F20        :: 0x83
+VK_F21        :: 0x84
+VK_F22        :: 0x85
+VK_F23        :: 0x86
+VK_F24        :: 0x87
+
+VK_NUMLOCK    :: 0x90
+VK_SCROLL     :: 0x91
+
+VK_LSHIFT     :: 0xA0
+VK_RSHIFT     :: 0xA1
+VK_LCONTROL   :: 0xA2
+VK_RCONTROL   :: 0xA3
+VK_LMENU      :: 0xA4
+VK_RMENU      :: 0xA5
+VK_PROCESSKEY :: 0xE5
+VK_ATTN       :: 0xF6
+VK_CRSEL      :: 0xF7
+VK_EXSEL      :: 0xF8
+VK_EREOF      :: 0xF9
+VK_PLAY       :: 0xFA
+VK_ZOOM       :: 0xFB
+VK_NONAME     :: 0xFC
+VK_PA1        :: 0xFD
+VK_OEM_CLEAR  :: 0xFE
 
 

+ 8 - 2
src/checker/checker.cpp

@@ -530,7 +530,7 @@ void add_entity_definition(CheckerInfo *i, AstNode *identifier, Entity *entity)
 	map_set(&i->definitions, key, entity);
 	map_set(&i->definitions, key, entity);
 }
 }
 
 
-void add_entity(Checker *c, Scope *scope, AstNode *identifier, Entity *entity) {
+b32 add_entity(Checker *c, Scope *scope, AstNode *identifier, Entity *entity) {
 	if (!are_strings_equal(entity->token.string, make_string("_"))) {
 	if (!are_strings_equal(entity->token.string, make_string("_"))) {
 		Entity *insert_entity = scope_insert_entity(scope, entity);
 		Entity *insert_entity = scope_insert_entity(scope, entity);
 		if (insert_entity) {
 		if (insert_entity) {
@@ -541,18 +541,20 @@ void add_entity(Checker *c, Scope *scope, AstNode *identifier, Entity *entity) {
 				      "\tat %.*s(%td:%td)",
 				      "\tat %.*s(%td:%td)",
 				      LIT(entity->token.string),
 				      LIT(entity->token.string),
 				      LIT(up->token.pos.file), up->token.pos.line, up->token.pos.column);
 				      LIT(up->token.pos.file), up->token.pos.line, up->token.pos.column);
+				return false;
 			} else {
 			} else {
 				error(&c->error_collector, entity->token,
 				error(&c->error_collector, entity->token,
 				      "Redeclararation of `%.*s` in this scope\n"
 				      "Redeclararation of `%.*s` in this scope\n"
 				      "\tat %.*s(%td:%td)",
 				      "\tat %.*s(%td:%td)",
 				      LIT(entity->token.string),
 				      LIT(entity->token.string),
 				      LIT(entity->token.pos.file), entity->token.pos.line, entity->token.pos.column);
 				      LIT(entity->token.pos.file), entity->token.pos.line, entity->token.pos.column);
+				return false;
 			}
 			}
-			return;
 		}
 		}
 	}
 	}
 	if (identifier != NULL)
 	if (identifier != NULL)
 		add_entity_definition(&c->info, identifier, entity);
 		add_entity_definition(&c->info, identifier, entity);
+	return true;
 }
 }
 
 
 void add_entity_use(CheckerInfo *i, AstNode *identifier, Entity *entity) {
 void add_entity_use(CheckerInfo *i, AstNode *identifier, Entity *entity) {
@@ -733,6 +735,10 @@ void check_parsed_files(Checker *c) {
 			case_ast_node(ld, LoadDecl, decl);
 			case_ast_node(ld, LoadDecl, decl);
 				// NOTE(bill): ignore
 				// NOTE(bill): ignore
 			case_end;
 			case_end;
+			case_ast_node(fsl, ForeignSystemLibrary, decl);
+				// NOTE(bill): ignore
+			case_end;
+
 
 
 			default:
 			default:
 				error(&c->error_collector, ast_node_token(decl), "Only declarations are allowed at file scope");
 				error(&c->error_collector, ast_node_token(decl), "Only declarations are allowed at file scope");

+ 13 - 3
src/checker/entity.cpp

@@ -6,6 +6,7 @@ enum BuiltinProcId;
 	ENTITY_KIND(Invalid), \
 	ENTITY_KIND(Invalid), \
 	ENTITY_KIND(Constant), \
 	ENTITY_KIND(Constant), \
 	ENTITY_KIND(Variable), \
 	ENTITY_KIND(Variable), \
+	ENTITY_KIND(UsingVariable), \
 	ENTITY_KIND(TypeName), \
 	ENTITY_KIND(TypeName), \
 	ENTITY_KIND(Procedure), \
 	ENTITY_KIND(Procedure), \
 	ENTITY_KIND(Builtin), \
 	ENTITY_KIND(Builtin), \
@@ -35,6 +36,7 @@ struct Entity {
 	Token token;
 	Token token;
 	Type *type;
 	Type *type;
 	Entity *using_parent;
 	Entity *using_parent;
+	AstNode *using_expr;
 
 
 	union {
 	union {
 		struct { ExactValue value; } Constant;
 		struct { ExactValue value; } Constant;
@@ -44,9 +46,9 @@ struct Entity {
 			b8 is_field;  // Is struct field
 			b8 is_field;  // Is struct field
 			b8 anonymous; // Variable is an anonymous
 			b8 anonymous; // Variable is an anonymous
 		} Variable;
 		} Variable;
-		struct {
-			b8 used;
-		} Procedure;
+		struct {} UsingVariable;
+		struct {} TypeName;
+		struct { b8 used; } Procedure;
 		struct { BuiltinProcId id; } Builtin;
 		struct { BuiltinProcId id; } Builtin;
 	};
 	};
 };
 };
@@ -72,6 +74,14 @@ Entity *make_entity_variable(gbAllocator a, Scope *scope, Token token, Type *typ
 	return entity;
 	return entity;
 }
 }
 
 
+Entity *make_entity_using_variable(gbAllocator a, Entity *parent, Token token, Type *type) {
+	GB_ASSERT(parent != NULL);
+	Entity *entity = alloc_entity(a, Entity_UsingVariable, parent->scope, token, type);
+	entity->using_parent = parent;
+	return entity;
+}
+
+
 Entity *make_entity_constant(gbAllocator a, Scope *scope, Token token, Type *type, ExactValue value) {
 Entity *make_entity_constant(gbAllocator a, Scope *scope, Token token, Type *type, ExactValue value) {
 	Entity *entity = alloc_entity(a, Entity_Constant, scope, token, type);
 	Entity *entity = alloc_entity(a, Entity_Constant, scope, token, type);
 	entity->Constant.value = value;
 	entity->Constant.value = value;

+ 23 - 5
src/checker/expr.cpp

@@ -4,7 +4,7 @@ void     check_expr_or_type        (Checker *c, Operand *operand, AstNode *expre
 ExprKind check_expr_base           (Checker *c, Operand *operand, AstNode *expression, Type *type_hint = NULL);
 ExprKind check_expr_base           (Checker *c, Operand *operand, AstNode *expression, Type *type_hint = NULL);
 Type *   check_type                (Checker *c, AstNode *expression, Type *named_type = NULL, CycleChecker *cycle_checker = NULL);
 Type *   check_type                (Checker *c, AstNode *expression, Type *named_type = NULL, CycleChecker *cycle_checker = NULL);
 void     check_type_decl           (Checker *c, Entity *e, AstNode *type_expr, Type *def, CycleChecker *cycle_checker);
 void     check_type_decl           (Checker *c, Entity *e, AstNode *type_expr, Type *def, CycleChecker *cycle_checker);
-void     check_selector            (Checker *c, Operand *operand, AstNode *node);
+Entity * check_selector            (Checker *c, Operand *operand, AstNode *node);
 void     check_not_tuple           (Checker *c, Operand *operand);
 void     check_not_tuple           (Checker *c, Operand *operand);
 b32      check_value_is_expressible(Checker *c, ExactValue in_value, Type *type, ExactValue *out_value);
 b32      check_value_is_expressible(Checker *c, ExactValue in_value, Type *type, ExactValue *out_value);
 void     convert_to_typed          (Checker *c, Operand *operand, Type *target_type);
 void     convert_to_typed          (Checker *c, Operand *operand, Type *target_type);
@@ -143,6 +143,7 @@ void populate_using_entity_map(Checker *c, AstNode *node, Type *t, Map<Entity *>
 				error(&c->error_collector, e->token, "`%.*s` is already declared in `%s`", LIT(name), str);
 				error(&c->error_collector, e->token, "`%.*s` is already declared in `%s`", LIT(name), str);
 			} else {
 			} else {
 				map_set(entity_map, key, f);
 				map_set(entity_map, key, f);
+				add_entity(c, c->context.scope, NULL, f);
 				if (f->Variable.anonymous) {
 				if (f->Variable.anonymous) {
 					populate_using_entity_map(c, node, f->type, entity_map);
 					populate_using_entity_map(c, node, f->type, entity_map);
 				}
 				}
@@ -338,6 +339,7 @@ void check_struct_type(Checker *c, Type *struct_type, AstNode *node, CycleChecke
 			} else {
 			} else {
 				map_set(&entity_map, key, e);
 				map_set(&entity_map, key, e);
 				fields[field_index++] = e;
 				fields[field_index++] = e;
+				add_entity(c, c->context.scope, name, e);
 			}
 			}
 			add_entity_use(&c->info, name, e);
 			add_entity_use(&c->info, name, e);
 		}
 		}
@@ -610,6 +612,11 @@ void check_identifier(Checker *c, Operand *o, AstNode *n, Type *named_type, Cycl
 		o->mode = Addressing_Builtin;
 		o->mode = Addressing_Builtin;
 		break;
 		break;
 
 
+	case Entity_UsingVariable:
+		// TODO(bill): Entity_UsingVariable: is this correct?
+		o->mode = Addressing_Variable;
+		break;
+
 	default:
 	default:
 		GB_PANIC("Compiler error: Unknown EntityKind");
 		GB_PANIC("Compiler error: Unknown EntityKind");
 		break;
 		break;
@@ -727,6 +734,7 @@ Type *check_type(Checker *c, AstNode *e, Type *named_type, CycleChecker *cycle_c
 		check_open_scope(c, e);
 		check_open_scope(c, e);
 		check_struct_type(c, type, e, cycle_checker);
 		check_struct_type(c, type, e, cycle_checker);
 		check_close_scope(c);
 		check_close_scope(c);
+		type->Struct.node = e;
 		goto end;
 		goto end;
 	case_end;
 	case_end;
 
 
@@ -736,6 +744,7 @@ Type *check_type(Checker *c, AstNode *e, Type *named_type, CycleChecker *cycle_c
 		check_open_scope(c, e);
 		check_open_scope(c, e);
 		check_union_type(c, type, e, cycle_checker);
 		check_union_type(c, type, e, cycle_checker);
 		check_close_scope(c);
 		check_close_scope(c);
+		type->Union.node = e;
 		goto end;
 		goto end;
 	case_end;
 	case_end;
 
 
@@ -1746,7 +1755,7 @@ Selection lookup_field(Type *type_, String field_name, AddressingMode mode, Sele
 	return sel;
 	return sel;
 }
 }
 
 
-void check_selector(Checker *c, Operand *operand, AstNode *node) {
+Entity *check_selector(Checker *c, Operand *operand, AstNode *node) {
 	GB_ASSERT(node->kind == AstNode_SelectorExpr);
 	GB_ASSERT(node->kind == AstNode_SelectorExpr);
 
 
 	ast_node(se, SelectorExpr, node);
 	ast_node(se, SelectorExpr, node);
@@ -1764,7 +1773,7 @@ void check_selector(Checker *c, Operand *operand, AstNode *node) {
 			error(&c->error_collector, ast_node_token(op_expr), "`%s` (`%s`) has no field `%s`", op_str, type_str, sel_str);
 			error(&c->error_collector, ast_node_token(op_expr), "`%s` (`%s`) has no field `%s`", op_str, type_str, sel_str);
 			operand->mode = Addressing_Invalid;
 			operand->mode = Addressing_Invalid;
 			operand->expr = node;
 			operand->expr = node;
-			return;
+			return NULL;
 		}
 		}
 		add_entity_use(&c->info, selector, entity);
 		add_entity_use(&c->info, selector, entity);
 
 
@@ -1779,11 +1788,12 @@ void check_selector(Checker *c, Operand *operand, AstNode *node) {
 			if (operand->mode != Addressing_Variable)
 			if (operand->mode != Addressing_Variable)
 				operand->mode = Addressing_Value;
 				operand->mode = Addressing_Value;
 		}
 		}
+		return entity;
 	} else {
 	} else {
 		operand->mode = Addressing_Invalid;
 		operand->mode = Addressing_Invalid;
 		operand->expr = node;
 		operand->expr = node;
 	}
 	}
-
+	return NULL;
 }
 }
 
 
 b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) {
 b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) {
@@ -1886,7 +1896,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
 			return false;
 			return false;
 		}
 		}
 
 
-		operand->mode = Addressing_Value;
+		operand->mode = Addressing_NoValue;
 		operand->type = NULL;
 		operand->type = NULL;
 	} break;
 	} break;
 
 
@@ -2967,6 +2977,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
 	case AstNode_ArrayType:
 	case AstNode_ArrayType:
 	case AstNode_VectorType:
 	case AstNode_VectorType:
 	case AstNode_StructType:
 	case AstNode_StructType:
+	case AstNode_UnionType:
 		o->mode = Addressing_Type;
 		o->mode = Addressing_Type;
 		o->type = check_type(c, node);
 		o->type = check_type(c, node);
 		break;
 		break;
@@ -3240,6 +3251,13 @@ gbString write_expr_to_string(gbString str, AstNode *node) {
 		str = gb_string_appendc(str, "}");
 		str = gb_string_appendc(str, "}");
 	case_end;
 	case_end;
 
 
+	case_ast_node(st, UnionType, node);
+		str = gb_string_appendc(str, "union{");
+		// str = write_field_list_to_string(str, st->decl_list, ", ");
+		str = gb_string_appendc(str, "}");
+	case_end;
+
+
 	case_ast_node(et, EnumType, node);
 	case_ast_node(et, EnumType, node);
 		str = gb_string_appendc(str, "enum ");
 		str = gb_string_appendc(str, "enum ");
 		if (et->base_type != NULL) {
 		if (et->base_type != NULL) {

+ 198 - 110
src/checker/stmt.cpp

@@ -436,6 +436,107 @@ void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type, Cyc
 
 
 
 
 
 
+void check_var_decl(Checker *c, AstNode *node) {
+	ast_node(vd, VarDecl, node);
+	isize entity_count = vd->name_count;
+	isize entity_index = 0;
+	Entity **entities = gb_alloc_array(c->allocator, Entity *, entity_count);
+	switch (vd->kind) {
+	case Declaration_Mutable: {
+		Entity **new_entities = gb_alloc_array(c->allocator, Entity *, entity_count);
+		isize new_entity_count = 0;
+
+		for (AstNode *name = vd->name_list; name != NULL; name = name->next) {
+			Entity *entity = NULL;
+			Token token = name->Ident.token;
+			if (name->kind == AstNode_Ident) {
+				String str = token.string;
+				Entity *found = NULL;
+				// NOTE(bill): Ignore assignments to `_`
+				b32 can_be_ignored = are_strings_equal(str, make_string("_"));
+				if (!can_be_ignored) {
+					found = current_scope_lookup_entity(c->context.scope, str);
+				}
+				if (found == NULL) {
+					entity = make_entity_variable(c->allocator, c->context.scope, token, NULL);
+					if (!can_be_ignored) {
+						new_entities[new_entity_count++] = entity;
+					}
+					add_entity_definition(&c->info, name, entity);
+				} else {
+					entity = found;
+				}
+			} else {
+				error(&c->error_collector, token, "A variable declaration must be an identifier");
+			}
+			if (entity == NULL)
+				entity = make_entity_dummy_variable(c->allocator, c->global_scope, token);
+			entities[entity_index++] = entity;
+		}
+
+		Type *init_type = NULL;
+		if (vd->type) {
+			init_type = check_type(c, vd->type, NULL);
+			if (init_type == NULL)
+				init_type = t_invalid;
+		}
+
+		for (isize i = 0; i < entity_count; i++) {
+			Entity *e = entities[i];
+			GB_ASSERT(e != NULL);
+			if (e->Variable.visited) {
+				e->type = t_invalid;
+				continue;
+			}
+			e->Variable.visited = true;
+
+			if (e->type == NULL)
+				e->type = init_type;
+		}
+
+		check_init_variables(c, entities, entity_count, vd->value_list, vd->value_count, make_string("variable declaration"));
+
+		AstNode *name = vd->name_list;
+		for (isize i = 0; i < new_entity_count; i++, name = name->next) {
+			add_entity(c, c->context.scope, name, new_entities[i]);
+		}
+
+	} break;
+
+	case Declaration_Immutable: {
+		for (AstNode *name = vd->name_list, *value = vd->value_list;
+		     name != NULL && value != NULL;
+		     name = name->next, value = value->next) {
+			GB_ASSERT(name->kind == AstNode_Ident);
+			ExactValue v = {ExactValue_Invalid};
+			ast_node(i, Ident, name);
+			Entity *e = make_entity_constant(c->allocator, c->context.scope, i->token, NULL, v);
+			entities[entity_index++] = e;
+			check_const_decl(c, e, vd->type, value);
+		}
+
+		isize lhs_count = vd->name_count;
+		isize rhs_count = vd->value_count;
+
+		// TODO(bill): Better error messages or is this good enough?
+		if (rhs_count == 0 && vd->type == NULL) {
+			error(&c->error_collector, ast_node_token(node), "Missing type or initial expression");
+		} else if (lhs_count < rhs_count) {
+			error(&c->error_collector, ast_node_token(node), "Extra initial expression");
+		}
+
+		AstNode *name = vd->name_list;
+		for (isize i = 0; i < entity_count; i++, name = name->next) {
+			add_entity(c, c->context.scope, name, entities[i]);
+		}
+	} break;
+
+	default:
+		error(&c->error_collector, ast_node_token(node), "Unknown variable declaration kind. Probably an invalid AST.");
+		return;
+	}
+}
+
 
 
 void check_stmt(Checker *c, AstNode *node, u32 flags) {
 void check_stmt(Checker *c, AstNode *node, u32 flags) {
 	switch (node->kind) {
 	switch (node->kind) {
@@ -688,16 +789,28 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
 	case_ast_node(us, UsingStmt, node);
 	case_ast_node(us, UsingStmt, node);
 		switch (us->node->kind) {
 		switch (us->node->kind) {
 		case_ast_node(es, ExprStmt, us->node);
 		case_ast_node(es, ExprStmt, us->node);
-			AstNode *ident = es->expr;
-			GB_ASSERT(ident->kind == AstNode_Ident);
-			String name = ident->Ident.token.string;
+			Entity *e = NULL;
+
+			b32 is_selector = false;
+			AstNode *expr = unparen_expr(es->expr);
+			if (expr->kind == AstNode_Ident) {
+				String name = expr->Ident.token.string;
+				e = scope_lookup_entity(c, c->context.scope, name);
+			} else if (expr->kind == AstNode_SelectorExpr) {
+				Operand o = {};
+				check_expr_base(c, &o, expr->SelectorExpr.expr);
+				e = check_selector(c, &o, expr);
+				is_selector = true;
+			}
 
 
-			Entity *e = scope_lookup_entity(c, c->context.scope, name);
 			if (e == NULL) {
 			if (e == NULL) {
 				error(&c->error_collector, us->token, "`using` applied to an unknown entity");
 				error(&c->error_collector, us->token, "`using` applied to an unknown entity");
 				return;
 				return;
 			}
 			}
 
 
+			gbString expr_str = expr_to_string(expr);
+			defer (gb_string_free(expr_str));
+
 			switch (e->kind) {
 			switch (e->kind) {
 			case Entity_TypeName: {
 			case Entity_TypeName: {
 				Type *t = get_base_type(e->type);
 				Type *t = get_base_type(e->type);
@@ -706,20 +819,34 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
 						Entity *f = t->Enum.fields[i];
 						Entity *f = t->Enum.fields[i];
 						Entity *found = scope_insert_entity(c->context.scope, f);
 						Entity *found = scope_insert_entity(c->context.scope, f);
 						if (found != NULL) {
 						if (found != NULL) {
-							error(&c->error_collector, us->token, "Namespace collision while `using` `%.*s` of the constant: %.*s", LIT(name), LIT(found->token.string));
+							error(&c->error_collector, us->token, "Namespace collision while `using` `%s` of the constant: %.*s", expr_str, LIT(found->token.string));
 							return;
 							return;
 						}
 						}
 						f->using_parent = e;
 						f->using_parent = e;
 					}
 					}
 				} else if (t->kind == Type_Struct) {
 				} else if (t->kind == Type_Struct) {
-					for (isize i = 0; i < t->Struct.other_field_count; i++) {
-						Entity *f = t->Struct.other_fields[i];
-						Entity *found = scope_insert_entity(c->context.scope, f);
-						if (found != NULL) {
-							error(&c->error_collector, us->token, "Namespace collision while `using` `%.*s` of: %.*s", LIT(name), LIT(found->token.string));
-							return;
+					Scope **found = map_get(&c->info.scopes, hash_pointer(t->Struct.node));
+					if (found != NULL) {
+						gb_for_array(i, (*found)->elements.entries) {
+							Entity *f = (*found)->elements.entries[i].value;
+							Entity *found = scope_insert_entity(c->context.scope, f);
+							if (found != NULL) {
+								error(&c->error_collector, us->token, "Namespace collision while `using` `%s` of: %.*s", expr_str, LIT(found->token.string));
+								return;
+							}
+							f->using_parent = e;
+						}
+					} else {
+						for (isize i = 0; i < t->Struct.other_field_count; i++) {
+							// TODO(bill): using field types too
+							Entity *f = t->Struct.other_fields[i];
+							Entity *found = scope_insert_entity(c->context.scope, f);
+							if (found != NULL) {
+								error(&c->error_collector, us->token, "Namespace collision while `using` `%s` of: %.*s", expr_str, LIT(found->token.string));
+								return;
+							}
+							f->using_parent = e;
 						}
 						}
-						f->using_parent = e;
 					}
 					}
 				}
 				}
 			} break;
 			} break;
@@ -733,13 +860,70 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
 				error(&c->error_collector, us->token, "`using` cannot be applied to a procedure");
 				error(&c->error_collector, us->token, "`using` cannot be applied to a procedure");
 				break;
 				break;
 
 
+			case Entity_Variable:
+			case Entity_UsingVariable: {
+				Type *t = get_base_type(type_deref(e->type));
+				if (t->kind == Type_Struct || t->kind == Type_Union) {
+					// IMPORTANT HACK(bill): Entity_(Struct|Union) overlap in some memory allowing
+					// for some variables to accessed to same
+					Scope **found = map_get(&c->info.scopes, hash_pointer(t->Struct.node));
+					GB_ASSERT(found != NULL);
+					gb_for_array(i, (*found)->elements.entries) {
+						Entity *f = (*found)->elements.entries[i].value;
+						if (f->kind == Entity_Variable) {
+							Entity *uvar = make_entity_using_variable(c->allocator, e, f->token, f->type);
+							if (is_selector) {
+								uvar->using_expr = expr;
+							}
+							Entity *prev = scope_insert_entity(c->context.scope, uvar);
+							if (prev != NULL) {
+								error(&c->error_collector, us->token, "Namespace collision while `using` `%s` of: %.*s", expr_str, LIT(prev->token.string));
+								return;
+							}
+						}
+					}
+				} else {
+					error(&c->error_collector, us->token, "`using` can only be applied to variables of type struct or union");
+					return;
+				}
+			} break;
+
 			default:
 			default:
 				GB_PANIC("TODO(bill): using Ident");
 				GB_PANIC("TODO(bill): using Ident");
 			}
 			}
 		case_end;
 		case_end;
 
 
 		case_ast_node(vd, VarDecl, us->node);
 		case_ast_node(vd, VarDecl, us->node);
-			GB_PANIC("TODO(bill): using VarDecl");
+			if (vd->name_count > 1) {
+				error(&c->error_collector, us->token, "`using` can only be applied to one variable of the same type");
+			}
+			check_var_decl(c, us->node);
+			ast_node(i, Ident, vd->name_list);
+
+			String name = i->token.string;
+			Entity *e = scope_lookup_entity(c, c->context.scope, name);
+
+			Type *t = get_base_type(type_deref(e->type));
+			if (t->kind == Type_Struct || t->kind == Type_Union) {
+				// IMPORTANT HACK(bill): Entity_(Struct|Union) overlap in some memory allowing
+				// for some variables to accessed to same
+				Scope **found = map_get(&c->info.scopes, hash_pointer(t->Struct.node));
+				GB_ASSERT(found != NULL);
+				gb_for_array(i, (*found)->elements.entries) {
+					Entity *f = (*found)->elements.entries[i].value;
+					if (f->kind == Entity_Variable) {
+						Entity *uvar = make_entity_using_variable(c->allocator, e, f->token, f->type);
+						Entity *prev = scope_insert_entity(c->context.scope, uvar);
+						if (prev != NULL) {
+							error(&c->error_collector, us->token, "Namespace collision while `using` `%.*s` of: %.*s", LIT(name), LIT(prev->token.string));
+							return;
+						}
+					}
+				}
+			} else {
+				error(&c->error_collector, us->token, "`using` can only be applied to variables of type struct or union");
+				return;
+			}
 		case_end;
 		case_end;
 
 
 
 
@@ -755,103 +939,7 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
 
 
 
 
 	case_ast_node(vd, VarDecl, node);
 	case_ast_node(vd, VarDecl, node);
-		isize entity_count = vd->name_count;
-		isize entity_index = 0;
-		Entity **entities = gb_alloc_array(c->allocator, Entity *, entity_count);
-		switch (vd->kind) {
-		case Declaration_Mutable: {
-			Entity **new_entities = gb_alloc_array(c->allocator, Entity *, entity_count);
-			isize new_entity_count = 0;
-
-			for (AstNode *name = vd->name_list; name != NULL; name = name->next) {
-				Entity *entity = NULL;
-				Token token = name->Ident.token;
-				if (name->kind == AstNode_Ident) {
-					String str = token.string;
-					Entity *found = NULL;
-					// NOTE(bill): Ignore assignments to `_`
-					b32 can_be_ignored = are_strings_equal(str, make_string("_"));
-					if (!can_be_ignored) {
-						found = current_scope_lookup_entity(c->context.scope, str);
-					}
-					if (found == NULL) {
-						entity = make_entity_variable(c->allocator, c->context.scope, token, NULL);
-						if (!can_be_ignored) {
-							new_entities[new_entity_count++] = entity;
-						}
-						add_entity_definition(&c->info, name, entity);
-					} else {
-						entity = found;
-					}
-				} else {
-					error(&c->error_collector, token, "A variable declaration must be an identifier");
-				}
-				if (entity == NULL)
-					entity = make_entity_dummy_variable(c->allocator, c->global_scope, token);
-				entities[entity_index++] = entity;
-			}
-
-			Type *init_type = NULL;
-			if (vd->type) {
-				init_type = check_type(c, vd->type, NULL);
-				if (init_type == NULL)
-					init_type = t_invalid;
-			}
-
-			for (isize i = 0; i < entity_count; i++) {
-				Entity *e = entities[i];
-				GB_ASSERT(e != NULL);
-				if (e->Variable.visited) {
-					e->type = t_invalid;
-					continue;
-				}
-				e->Variable.visited = true;
-
-				if (e->type == NULL)
-					e->type = init_type;
-			}
-
-			check_init_variables(c, entities, entity_count, vd->value_list, vd->value_count, make_string("variable declaration"));
-
-			AstNode *name = vd->name_list;
-			for (isize i = 0; i < new_entity_count; i++, name = name->next) {
-				add_entity(c, c->context.scope, name, new_entities[i]);
-			}
-
-		} break;
-
-		case Declaration_Immutable: {
-			for (AstNode *name = vd->name_list, *value = vd->value_list;
-			     name != NULL && value != NULL;
-			     name = name->next, value = value->next) {
-				GB_ASSERT(name->kind == AstNode_Ident);
-				ExactValue v = {ExactValue_Invalid};
-				ast_node(i, Ident, name);
-				Entity *e = make_entity_constant(c->allocator, c->context.scope, i->token, NULL, v);
-				entities[entity_index++] = e;
-				check_const_decl(c, e, vd->type, value);
-			}
-
-			isize lhs_count = vd->name_count;
-			isize rhs_count = vd->value_count;
-
-			// TODO(bill): Better error messages or is this good enough?
-			if (rhs_count == 0 && vd->type == NULL) {
-				error(&c->error_collector, ast_node_token(node), "Missing type or initial expression");
-			} else if (lhs_count < rhs_count) {
-				error(&c->error_collector, ast_node_token(node), "Extra initial expression");
-			}
-
-			AstNode *name = vd->name_list;
-			for (isize i = 0; i < entity_count; i++, name = name->next) {
-				add_entity(c, c->context.scope, name, entities[i]);
-			}
-		} break;
-
-		default:
-			error(&c->error_collector, ast_node_token(node), "Unknown variable declaration kind. Probably an invalid AST.");
-			return;
-		}
+		check_var_decl(c, node);
 	case_end;
 	case_end;
 
 
 	case_ast_node(pd, ProcDecl, node);
 	case_ast_node(pd, ProcDecl, node);

+ 5 - 1
src/checker/type.cpp

@@ -107,18 +107,22 @@ struct Type {
 			// Theses are arrays
 			// Theses are arrays
 			Entity **fields; // Entity_Variable
 			Entity **fields; // Entity_Variable
 			isize    field_count; // == offset_count
 			isize    field_count; // == offset_count
+			AstNode *node;
+
 			i64 *    offsets;
 			i64 *    offsets;
 			b32      are_offsets_set;
 			b32      are_offsets_set;
 			b32      is_packed;
 			b32      is_packed;
 
 
 			Entity **other_fields; // Entity_Constant or Entity_TypeName
 			Entity **other_fields; // Entity_Constant or Entity_TypeName
 			isize    other_field_count;
 			isize    other_field_count;
+
 		} Struct;
 		} Struct;
 		struct {
 		struct {
-			// IMPORTANT HACK(bill): The positions of fields and field_count
+			// IMPORTANT HACK(bill): The positions of fields, field_count, and node
 			// must be same for Struct and Union
 			// must be same for Struct and Union
 			Entity **fields; // Entity_Variable
 			Entity **fields; // Entity_Variable
 			isize    field_count;
 			isize    field_count;
+			AstNode *node;
 		} Union;
 		} Union;
 		struct { Type *elem; } Pointer;
 		struct { Type *elem; } Pointer;
 		struct {
 		struct {

+ 36 - 1
src/codegen/ssa.cpp

@@ -2034,6 +2034,30 @@ ssaValue *ssa_emit_deep_field_gep(ssaProcedure *proc, Type *type, ssaValue *e, S
 }
 }
 
 
 
 
+ssaValue *ssa_add_using_variable(ssaProcedure *proc, Entity *e) {
+	GB_ASSERT(e->kind == Entity_UsingVariable);
+	String name = e->token.string;
+	Entity *parent = e->using_parent;
+	ssaValue *p = NULL;
+	if (parent->kind == Entity_UsingVariable) {
+		p = ssa_add_using_variable(proc, parent);
+	}
+
+	Selection sel = lookup_field(parent->type, name, Addressing_Variable);
+	GB_ASSERT(sel.entity != NULL);
+	ssaValue **pv = map_get(&proc->module->values, hash_pointer(parent));
+	ssaValue *v = NULL;
+	if (pv != NULL) {
+		v = *pv;
+	} else {
+		v = ssa_build_addr(proc, e->using_expr).addr;
+	}
+	GB_ASSERT(v != NULL);
+	ssaValue *var = ssa_emit_deep_field_gep(proc, parent->type, v, sel);
+	map_set(&proc->module->values, hash_pointer(e), var);
+	return var;
+}
+
 ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
 ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
 	switch (expr->kind) {
 	switch (expr->kind) {
 	case_ast_node(i, Ident, expr);
 	case_ast_node(i, Ident, expr);
@@ -2047,9 +2071,13 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
 		ssaValue **found = map_get(&proc->module->values, hash_pointer(e));
 		ssaValue **found = map_get(&proc->module->values, hash_pointer(e));
 		if (found) {
 		if (found) {
 			v = *found;
 			v = *found;
-		} else {
+		} else if (e->kind == Entity_UsingVariable) {
+			v = ssa_add_using_variable(proc, e);
+		}
+		if (v == NULL) {
 			GB_PANIC("Unknown value: %s, entity: %p\n", expr_to_string(expr), e);
 			GB_PANIC("Unknown value: %s, entity: %p\n", expr_to_string(expr), e);
 		}
 		}
+
 		return ssa_make_addr(v, expr);
 		return ssa_make_addr(v, expr);
 	case_end;
 	case_end;
 
 
@@ -2286,6 +2314,13 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
 	case_ast_node(bs, EmptyStmt, node);
 	case_ast_node(bs, EmptyStmt, node);
 	case_end;
 	case_end;
 
 
+	case_ast_node(us, UsingStmt, node);
+		AstNode *decl = unparen_expr(us->node);
+		if (decl->kind == AstNode_VarDecl) {
+			ssa_build_stmt(proc, decl);
+		}
+	case_end;
+
 	case_ast_node(vd, VarDecl, node);
 	case_ast_node(vd, VarDecl, node);
 		if (vd->kind == Declaration_Mutable) {
 		if (vd->kind == Declaration_Mutable) {
 			if (vd->name_count == vd->value_count) { // 1:1 assigment
 			if (vd->name_count == vd->value_count) { // 1:1 assigment

+ 14 - 2
src/main.cpp

@@ -93,14 +93,26 @@ int main(int argc, char **argv) {
 #if 1
 #if 1
 #endif
 #endif
 
 
+	gbString lib_str = gb_string_make(gb_heap_allocator(), "-lKernel32.lib");
+	char lib_str_buf[1024] = {};
+	gb_for_array(i, parser.system_libraries) {
+		String lib = parser.system_libraries[i];
+		isize len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf),
+		                        " -l%.*s.lib", LIT(lib));
+		lib_str = gb_string_appendc(lib_str, lib_str_buf);
+	}
+
+
 	exit_code = win32_exec_command_line_app(
 	exit_code = win32_exec_command_line_app(
 		"clang -o %.*s.exe %.*s.bc "
 		"clang -o %.*s.exe %.*s.bc "
 		"-Wno-override-module "
 		"-Wno-override-module "
 		// "-nostartfiles "
 		// "-nostartfiles "
-		"-lKernel32.lib -lUser32.lib -lGdi32.lib -lOpengl32.lib "
+		"%s "
 		,
 		,
 		cast(int)base_name_len, output_name,
 		cast(int)base_name_len, output_name,
-		cast(int)base_name_len, output_name);
+		cast(int)base_name_len, output_name,
+		lib_str);
+	gb_string_free(lib_str);
 	if (exit_code != 0)
 	if (exit_code != 0)
 		return exit_code;
 		return exit_code;
 
 

+ 79 - 14
src/parser.cpp

@@ -32,6 +32,7 @@ struct AstFile {
 
 
 	AstScope *file_scope;
 	AstScope *file_scope;
 	AstScope *curr_scope;
 	AstScope *curr_scope;
+	AstNode *curr_proc;
 	isize scope_level;
 	isize scope_level;
 
 
 	ErrorCollector error_collector;
 	ErrorCollector error_collector;
@@ -60,6 +61,8 @@ struct Parser {
 	String init_fullpath;
 	String init_fullpath;
 	gbArray(AstFile) files;
 	gbArray(AstFile) files;
 	gbArray(String) loads;
 	gbArray(String) loads;
+	gbArray(String) libraries;
+	gbArray(String) system_libraries;
 	isize load_index;
 	isize load_index;
 	isize total_token_count;
 	isize total_token_count;
 };
 };
@@ -193,6 +196,7 @@ AST_NODE_KIND(_DeclBegin,      struct{}) \
 		}) \
 		}) \
 	AST_NODE_KIND(TypeDecl, struct { Token token; AstNode *name, *type; }) \
 	AST_NODE_KIND(TypeDecl, struct { Token token; AstNode *name, *type; }) \
 	AST_NODE_KIND(LoadDecl, struct { Token token, filepath; }) \
 	AST_NODE_KIND(LoadDecl, struct { Token token, filepath; }) \
+	AST_NODE_KIND(ForeignSystemLibrary, struct { Token token, filepath; }) \
 AST_NODE_KIND(_DeclEnd, struct{}) \
 AST_NODE_KIND(_DeclEnd, struct{}) \
 AST_NODE_KIND(_TypeBegin, struct{}) \
 AST_NODE_KIND(_TypeBegin, struct{}) \
 	AST_NODE_KIND(Field, struct { \
 	AST_NODE_KIND(Field, struct { \
@@ -368,6 +372,8 @@ Token ast_node_token(AstNode *node) {
 		return node->TypeDecl.token;
 		return node->TypeDecl.token;
 	case AstNode_LoadDecl:
 	case AstNode_LoadDecl:
 		return node->LoadDecl.token;
 		return node->LoadDecl.token;
+	case AstNode_ForeignSystemLibrary:
+		return node->ForeignSystemLibrary.token;
 	case AstNode_Field: {
 	case AstNode_Field: {
 		if (node->Field.name_list)
 		if (node->Field.name_list)
 			return ast_node_token(node->Field.name_list);
 			return ast_node_token(node->Field.name_list);
@@ -831,6 +837,12 @@ gb_inline AstNode *make_load_decl(AstFile *f, Token token, Token filepath) {
 	return result;
 	return result;
 }
 }
 
 
+gb_inline AstNode *make_foreign_system_library(AstFile *f, Token token, Token filepath) {
+	AstNode *result = make_node(f, AstNode_ForeignSystemLibrary);
+	result->ForeignSystemLibrary.token = token;
+	result->ForeignSystemLibrary.filepath = filepath;
+	return result;
+}
 
 
 gb_inline b32 next_token(AstFile *f) {
 gb_inline b32 next_token(AstFile *f) {
 	if (f->cursor+1 < f->tokens + gb_array_count(f->tokens)) {
 	if (f->cursor+1 < f->tokens + gb_array_count(f->tokens)) {
@@ -967,11 +979,15 @@ b32 expect_semicolon_after_stmt(AstFile *f, AstNode *s) {
 	}
 	}
 
 
 	if (!allow_token(f, Token_Semicolon)) {
 	if (!allow_token(f, Token_Semicolon)) {
-		// CLEANUP(bill): Semicolon handling in parser
-		ast_file_err(f, f->cursor[0],
-		             "Expected `;` after %.*s, got `%.*s`",
-		             LIT(ast_node_strings[s->kind]), LIT(token_strings[f->cursor[0].kind]));
-		return false;
+		if (f->cursor[0].pos.line == f->cursor[-1].pos.line) {
+			if (f->cursor[0].kind != Token_CloseBrace) {
+				// CLEANUP(bill): Semicolon handling in parser
+				ast_file_err(f, f->cursor[0],
+				             "Expected `;` after %.*s, got `%.*s`",
+				             LIT(ast_node_strings[s->kind]), LIT(token_strings[f->cursor[0].kind]));
+				return false;
+			}
+		}
 	}
 	}
 	return true;
 	return true;
 }
 }
@@ -1203,7 +1219,10 @@ AstNode *parse_operand(AstFile *f, b32 lhs) {
 	// Parse Procedure Type or Literal
 	// Parse Procedure Type or Literal
 	case Token_proc: {
 	case Token_proc: {
 		AstScope *scope = NULL;
 		AstScope *scope = NULL;
+		AstNode *curr_proc = f->curr_proc;
 		AstNode *type = parse_proc_type(f, &scope);
 		AstNode *type = parse_proc_type(f, &scope);
+		f->curr_proc = type;
+		defer (f->curr_proc = curr_proc);
 
 
 		u64 tags = 0;
 		u64 tags = 0;
 		String foreign_name = {};
 		String foreign_name = {};
@@ -1862,8 +1881,13 @@ AstNode *parse_identifier_or_type(AstFile *f) {
 		return make_enum_type(f, token, base_type, root, field_count);
 		return make_enum_type(f, token, base_type, root, field_count);
 	}
 	}
 
 
-	case Token_proc:
-		return parse_proc_type(f, NULL);
+	case Token_proc: {
+		AstNode *curr_proc = f->curr_proc;
+		AstNode *type = parse_proc_type(f, NULL);
+		f->curr_proc = type;
+		f->curr_proc = curr_proc;
+		return type;
+	}
 
 
 
 
 	case Token_OpenParen: {
 	case Token_OpenParen: {
@@ -2126,10 +2150,14 @@ AstNode *parse_return_stmt(AstFile *f) {
 	Token token = expect_token(f, Token_return);
 	Token token = expect_token(f, Token_return);
 	AstNode *result = NULL;
 	AstNode *result = NULL;
 	isize result_count = 0;
 	isize result_count = 0;
-	if (f->cursor[0].kind != Token_Semicolon)
+
+	if (f->cursor[0].kind != Token_Semicolon && f->cursor[0].kind != Token_CloseBrace &&
+	    f->cursor[0].pos.line == token.pos.line) {
 		result = parse_rhs_expr_list(f, &result_count);
 		result = parse_rhs_expr_list(f, &result_count);
-	if (f->cursor[0].kind != Token_CloseBrace)
-		expect_token(f, Token_Semicolon);
+	}
+	if (f->cursor[0].kind != Token_CloseBrace) {
+		expect_semicolon_after_stmt(f, result);
+	}
 
 
 	return make_return_stmt(f, token, result, result_count);
 	return make_return_stmt(f, token, result, result_count);
 }
 }
@@ -2248,11 +2276,15 @@ AstNode *parse_stmt(AstFile *f) {
 		b32 valid = false;
 		b32 valid = false;
 
 
 		switch (node->kind) {
 		switch (node->kind) {
-		case AstNode_ExprStmt:
-			if (node->ExprStmt.expr->kind == AstNode_Ident) {
+		case AstNode_ExprStmt: {
+			AstNode *e = unparen_expr(node->ExprStmt.expr);
+			while (e->kind == AstNode_SelectorExpr) {
+				e = unparen_expr(e->SelectorExpr.selector);
+			}
+			if (e->kind == AstNode_Ident) {
 				valid = true;
 				valid = true;
 			}
 			}
-			break;
+		} break;
 		case AstNode_VarDecl:
 		case AstNode_VarDecl:
 			if (node->VarDecl.kind == Declaration_Mutable) {
 			if (node->VarDecl.kind == Declaration_Mutable) {
 				valid = true;
 				valid = true;
@@ -2279,6 +2311,13 @@ AstNode *parse_stmt(AstFile *f) {
 			}
 			}
 			ast_file_err(f, token, "You cannot `load` within a procedure. This must be done at the file scope.");
 			ast_file_err(f, token, "You cannot `load` within a procedure. This must be done at the file scope.");
 			return make_bad_decl(f, token, file_path);
 			return make_bad_decl(f, token, file_path);
+		} else if (are_strings_equal(s->TagStmt.name.string, make_string("foreign_system_library"))) {
+			Token file_path = expect_token(f, Token_String);
+			if (f->curr_scope == f->file_scope) {
+				return make_foreign_system_library(f, s->TagStmt.token, file_path);
+			}
+			ast_file_err(f, token, "You cannot using `foreign_system_library` within a procedure. This must be done at the file scope.");
+			return make_bad_decl(f, token, file_path);
 		} else if (are_strings_equal(s->TagStmt.name.string, make_string("thread_local"))) {
 		} else if (are_strings_equal(s->TagStmt.name.string, make_string("thread_local"))) {
 			AstNode *var_decl = parse_simple_stmt(f);
 			AstNode *var_decl = parse_simple_stmt(f);
 			if (var_decl->kind != AstNode_VarDecl ||
 			if (var_decl->kind != AstNode_VarDecl ||
@@ -2387,6 +2426,8 @@ void destroy_ast_file(AstFile *f) {
 b32 init_parser(Parser *p) {
 b32 init_parser(Parser *p) {
 	gb_array_init(p->files, gb_heap_allocator());
 	gb_array_init(p->files, gb_heap_allocator());
 	gb_array_init(p->loads, gb_heap_allocator());
 	gb_array_init(p->loads, gb_heap_allocator());
+	gb_array_init(p->libraries, gb_heap_allocator());
+	gb_array_init(p->system_libraries, gb_heap_allocator());
 	return true;
 	return true;
 }
 }
 
 
@@ -2402,6 +2443,8 @@ void destroy_parser(Parser *p) {
 #endif
 #endif
 	gb_array_free(p->files);
 	gb_array_free(p->files);
 	gb_array_free(p->loads);
 	gb_array_free(p->loads);
+	gb_array_free(p->libraries);
+	gb_array_free(p->system_libraries);
 }
 }
 
 
 // NOTE(bill): Returns true if it's added
 // NOTE(bill): Returns true if it's added
@@ -2417,6 +2460,18 @@ b32 try_add_load_path(Parser *p, String import_file) {
 	return true;
 	return true;
 }
 }
 
 
+// NOTE(bill): Returns true if it's added
+b32 try_add_foreign_system_library_path(Parser *p, String import_file) {
+	gb_for_array(i, p->system_libraries) {
+		String import = p->system_libraries[i];
+		if (are_strings_equal(import, import_file)) {
+			return false;
+		}
+	}
+	gb_array_append(p->system_libraries, import_file);
+	return true;
+}
+
 gb_global Rune illegal_import_runes[] = {
 gb_global Rune illegal_import_runes[] = {
 	'"', '\'', '`', ' ',
 	'"', '\'', '`', ' ',
 	'\\', // NOTE(bill): Disallow windows style filepaths
 	'\\', // NOTE(bill): Disallow windows style filepaths
@@ -2480,7 +2535,7 @@ void parse_file(Parser *p, AstFile *f) {
 				String file_str = id->filepath.string;
 				String file_str = id->filepath.string;
 
 
 				if (!is_load_path_valid(file_str)) {
 				if (!is_load_path_valid(file_str)) {
-					ast_file_err(f, ast_node_token(node), "Invalid import path");
+					ast_file_err(f, ast_node_token(node), "Invalid `load` path");
 					continue;
 					continue;
 				}
 				}
 
 
@@ -2498,6 +2553,16 @@ void parse_file(Parser *p, AstFile *f) {
 				if (!try_add_load_path(p, import_file)) {
 				if (!try_add_load_path(p, import_file)) {
 					gb_free(gb_heap_allocator(), import_file.text);
 					gb_free(gb_heap_allocator(), import_file.text);
 				}
 				}
+			} else if (node->kind == AstNode_ForeignSystemLibrary) {
+				auto *id = &node->ForeignSystemLibrary;
+				String file_str = id->filepath.string;
+
+				if (!is_load_path_valid(file_str)) {
+					ast_file_err(f, ast_node_token(node), "Invalid `foreign_system_library` path");
+					continue;
+				}
+
+				try_add_foreign_system_library_path(p, file_str);
 			}
 			}
 		}
 		}
 	}
 	}