Forráskód Böngészése

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

Zac Pierson 8 éve
szülő
commit
aaa4dd5c36
21 módosított fájl, 656 hozzáadás és 806 törlés
  1. 19 12
      code/demo.odin
  2. 15 12
      core/_preload.odin
  3. 15 8
      core/fmt.odin
  4. 4 4
      core/hash.odin
  5. 99 99
      core/opengl.odin
  6. 8 5
      core/sys/windows.odin
  7. 1 1
      core/types.odin
  8. 2 2
      core/utf8.odin
  9. 6 2
      src/build_settings.c
  10. 0 11
      src/check_decl.c
  11. 157 320
      src/check_expr.c
  12. 67 67
      src/check_stmt.c
  13. 41 32
      src/checker.c
  14. 3 0
      src/common.c
  15. 6 3
      src/entity.c
  16. 61 64
      src/ir.c
  17. 3 0
      src/map.c
  18. 136 156
      src/parser.c
  19. 1 0
      src/string.c
  20. 3 0
      src/tokenizer.c
  21. 9 8
      src/types.c

+ 19 - 12
code/demo.odin

@@ -1,18 +1,22 @@
 #import "fmt.odin";
+#import "atomic.odin";
+#import "hash.odin";
+#import "math.odin";
+#import "mem.odin";
+#import "opengl.odin";
+#import "os.odin";
+#import "utf8.odin";
 
-main :: proc() {
-
-	{
-		Vec2 :: [vector 2]f32;
-		i: f32 = 1;
-		b := Vec2{i, i};
-	}
 
+main :: proc() {
+	x: f32 = false ? 123 : 55;
+	fmt.println("Ternary:", x);
+/*
 /*
-	Version 0.1.0
+	Version 0.1.1
 
 	Added:
-	 * Dynamic Arrays `[...]Type`
+	 * Dynamic Arrays [dynamic]Type`
 	 * Dynamic Maps   `map[Key]Value`
 	 * Dynamic array and map literals
 	 * Custom struct alignemnt `struct #align 8 { bar: i8 }`
@@ -22,10 +26,12 @@ main :: proc() {
 	 * Entities prefixes with an underscore do not get exported on imports
 	 * Overloaded `free` for pointers, slices, strings, dynamic arrays, and dynamic maps
 	 * enum types have an implict `names` field, a []string of all the names in that enum
+	 * immutable variables are "completely immutable" - rules need a full explanation
+	 * `slice_to_bytes` - convert any slice to a slice of bytes
+	 * `union_cast` allows for optional ok check
 
 	Removed:
 	 * Maybe/option types
-	 * immutable variables
 	 * Remove `type` keyword and other "reserved" keywords
 	 * `compile_assert` and `assert`return the value of the condition for semantic reasons
 
@@ -92,7 +98,7 @@ main :: proc() {
 	}
 
 	{
-		x: [...]f64;
+		x: [dynamic]f64;
 		reserve(x, 16);
 		defer free(x);
 		append(x, 2_000_000.500_000, 3, 5, 7);
@@ -105,7 +111,7 @@ main :: proc() {
 	}
 
 	{
-		x := [...]f64{2_000_000.500_000, 3, 5, 7};
+		x := [dynamic]f64{2_000_000.500_000, 3, 5, 7};
 		defer free(x);
 		fmt.println(x);
 	}
@@ -130,5 +136,6 @@ main :: proc() {
 		compile_assert(size_of([vector 7]i32) == size_of([7]i32));
 		// align_of([vector 7]i32) != align_of([7]i32) // this may be the case
 	}
+*/
 }
 

+ 15 - 12
core/_preload.odin

@@ -315,7 +315,11 @@ __assert :: proc(file: string, line, column: int, msg: string) #inline {
 	            file, line, column, msg);
 	__debug_trap();
 }
-
+__panic :: proc(file: string, line, column: int, msg: string) #inline {
+	fmt.fprintf(os.stderr, "%s(%d:%d) Panic: %s\n",
+	            file, line, column, msg);
+	__debug_trap();
+}
 __bounds_check_error :: proc(file: string, line, column: int, index, count: int) {
 	if 0 <= index && index < count {
 		return;
@@ -341,6 +345,13 @@ __substring_expr_error :: proc(file: string, line, column: int, low, high: int)
 	            file, line, column, low, high);
 	__debug_trap();
 }
+__union_cast_check :: proc(ok: bool, file: string, line, column: int, from, to: ^Type_Info) {
+	if !ok {
+		fmt.fprintf(os.stderr, "%s(%d:%d) Invalid `union_cast` from %T to %T\n",
+		            file, line, column, from, to);
+		__debug_trap();
+	}
+}
 
 __string_decode_rune :: proc(s: string) -> (rune, int) #inline {
 	return utf8.decode_rune(s);
@@ -370,7 +381,7 @@ Raw_Dynamic_Array :: struct #ordered {
 };
 
 Raw_Dynamic_Map :: struct #ordered {
-	hashes:  [...]int,
+	hashes:  [dynamic]int,
 	entries: Raw_Dynamic_Array,
 };
 
@@ -449,6 +460,8 @@ __dynamic_array_append_nothing :: proc(array_: rawptr, elem_size, elem_align: in
 }
 
 
+// Map stuff
+
 __default_hash :: proc(data: []byte) -> u64 {
 	return hash.fnv64a(data);
 }
@@ -650,13 +663,3 @@ __dynamic_map_erase :: proc(using h: __Map_Header, fr: __Map_Find_Result) {
 		m.hashes[last.hash_index] = fr.entry_index;
 	}
 }
-
-
-__print_ti_ptr :: proc(ti: ^Type_Info) {
-	fmt.println(ti);
-	match e in ti {
-	case Type_Info.Enum:
-		fmt.println(e.names);
-	}
-}
-

+ 15 - 8
core/fmt.odin

@@ -116,7 +116,11 @@ buffer_write_type :: proc(buf: ^Buffer, ti: ^Type_Info) {
 		case ti == type_info(int):  buffer_write_string(buf, "int");
 		case ti == type_info(uint): buffer_write_string(buf, "uint");
 		default:
-			buffer_write_string(buf, if info.signed { give "i" } else { give "u"});
+			if info.signed {
+				buffer_write_string(buf, "i");
+			} else {
+				buffer_write_string(buf, "u");
+			}
 			fi := Fmt_Info{buf = buf};
 			fmt_int(^fi, cast(u64)(8*info.size), false, 'd');
 		}
@@ -140,7 +144,7 @@ buffer_write_type :: proc(buf: ^Buffer, ti: ^Type_Info) {
 		if info.params == nil {
 			buffer_write_string(buf, "()");
 		} else {
-			t := cast(^Tuple)info.params;
+			t := union_cast(^Tuple)info.params;
 			buffer_write_string(buf, "(");
 			for type, i in t.types {
 				if i > 0 { buffer_write_string(buf, ", "); }
@@ -155,10 +159,9 @@ buffer_write_type :: proc(buf: ^Buffer, ti: ^Type_Info) {
 	case Tuple:
 		count := info.names.count;
 		if count != 1 { buffer_write_string(buf, "("); }
-		for i in 0..<count {
+		for name, i in info.names {
 			if i > 0 { buffer_write_string(buf, ", "); }
 
-			name := info.names[i];
 			type := info.types[i];
 
 			if name.count > 0 {
@@ -393,7 +396,11 @@ fmt_bad_verb :: proc(using fi: ^Fmt_Info, verb: rune) {
 fmt_bool :: proc(using fi: ^Fmt_Info, b: bool, verb: rune) {
 	match verb {
 	case 't', 'v':
-		buffer_write_string(buf, if b { give "true" } else { give "false" });
+		if b {
+			buffer_write_string(buf, "true");
+		} else {
+			buffer_write_string(buf, "false");
+		}
 	default:
 		fmt_bad_verb(fi, verb);
 	}
@@ -790,10 +797,10 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
 		buffer_write_string(fi.buf, "map[");
 		defer buffer_write_byte(fi.buf, ']');
 		entries := ^(cast(^Raw_Dynamic_Map)v.data).entries;
-		gs, gs_ok := union_cast(^Struct)type_info_base(info.generated_struct); assert(gs_ok);
-		ed, ed_ok := union_cast(^Dynamic_Array)type_info_base(gs.types[1]);    assert(ed_ok);
+		gs := union_cast(^Struct)type_info_base(info.generated_struct);
+		ed := union_cast(^Dynamic_Array)type_info_base(gs.types[1]);
 
-		entry_type, et_ok := union_cast(^Struct)ed.elem; assert(et_ok);
+		entry_type := union_cast(^Struct)ed.elem;
 		entry_size := ed.elem_size;
 		for i in 0..<entries.count {
 			if i > 0 {

+ 4 - 4
core/hash.odin

@@ -1,14 +1,14 @@
 crc32 :: proc(data: []byte) -> u32 {
 	result := ~cast(u32)0;
 	for b in data {
-		result = result>>8 ~ __CRC32_TABLE[(result ~ cast(u32)b) & 0xff];
+		result = result>>8 ~ _crc32_table[(result ~ cast(u32)b) & 0xff];
 	}
 	return ~result;
 }
 crc64 :: proc(data: []byte) -> u64 {
 	result := ~cast(u64)0;
 	for b in data {
-		result = result>>8 ~ __CRC64_TABLE[(result ~ cast(u64)b) & 0xff];
+		result = result>>8 ~ _crc64_table[(result ~ cast(u64)b) & 0xff];
 	}
 	return ~result;
 }
@@ -202,7 +202,7 @@ murmur64 :: proc(data: []byte) -> u64 {
 }
 
 
-__CRC32_TABLE := [256]u32{
+immutable _crc32_table := [256]u32{
 	0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
 	0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
 	0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
@@ -268,7 +268,7 @@ __CRC32_TABLE := [256]u32{
 	0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
 	0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
 };
-__CRC64_TABLE := [256]u64{
+immutable _crc64_table := [256]u64{
 	0x0000000000000000, 0x42f0e1eba9ea3693, 0x85e1c3d753d46d26, 0xc711223cfa3e5bb5,
 	0x493366450e42ecdf, 0x0bc387aea7a8da4c, 0xccd2a5925d9681f9, 0x8e224479f47cb76a,
 	0x9266cc8a1c85d9be, 0xd0962d61b56fef2d, 0x17870f5d4f51b498, 0x5577eeb6e6bb820b,

+ 99 - 99
core/opengl.odin

@@ -20,13 +20,13 @@ Viewport      :: proc(x, y, width, height: i32)                 #foreign lib "gl
 Ortho         :: proc(left, right, bottom, top, near, far: f64) #foreign lib "glOrtho";
 Color3f       :: proc(r, g, b: f32)                             #foreign lib "glColor3f";
 Vertex3f      :: proc(x, y, z: f32)                             #foreign lib "glVertex3f";
+GetError      :: proc() -> i32                                  #foreign lib "glGetError";
+GetString     :: proc(name: i32) -> ^byte                       #foreign lib "glGetString";
+GetIntegerv   :: proc(name: i32, v: ^i32)                       #foreign lib "glGetIntegerv";
+TexCoord2f    :: proc(x, y: f32)                                #foreign lib "glTexCoord2f";
 TexImage2D    :: proc(target, level, internal_format,
                       width, height, border,
-                      format, _type: i32, pixels: rawptr) #foreign lib "glTexImage2D";
-
-GetError    :: proc() -> i32            #foreign lib "glGetError";
-GetString   :: proc(name: i32) -> ^byte #foreign lib "glGetString";
-GetIntegerv :: proc(name: i32, v: ^i32) #foreign lib "glGetIntegerv";
+                      format, type: i32, pixels: rawptr)        #foreign lib "glTexImage2D";
 
 
 string_data :: proc(s: string) -> ^u8 #inline { return ^s[0]; }
@@ -42,114 +42,114 @@ GetProcAddress :: proc(name: string) -> proc() #cc_c {
 	return res;
 }
 
-GenBuffers:       proc(count: i32, buffers: ^u32) #cc_c;
-GenVertexArrays:  proc(count: i32, buffers: ^u32) #cc_c;
-GenSamplers:      proc(count: i32, buffers: ^u32) #cc_c;
-BindBuffer:       proc(target: i32, buffer: u32) #cc_c;
-BindVertexArray:  proc(buffer: u32) #cc_c;
-BindSampler:      proc(position: i32, sampler: u32) #cc_c;
-BufferData:       proc(target: i32, size: int, data: rawptr, usage: i32) #cc_c;
-BufferSubData:    proc(target: i32, offset, size: int, data: rawptr) #cc_c;
+GenBuffers:               proc(count: i32, buffers: ^u32) #cc_c;
+GenVertexArrays:          proc(count: i32, buffers: ^u32) #cc_c;
+GenSamplers:              proc(count: i32, buffers: ^u32) #cc_c;
+BindBuffer:               proc(target: i32, buffer: u32) #cc_c;
+BindVertexArray:          proc(buffer: u32) #cc_c;
+BindSampler:              proc(position: i32, sampler: u32) #cc_c;
+BufferData:               proc(target: i32, size: int, data: rawptr, usage: i32) #cc_c;
+BufferSubData:            proc(target: i32, offset, size: int, data: rawptr) #cc_c;
 
-DrawArrays:       proc(mode, first: i32, count: u32) #cc_c;
-DrawElements:     proc(mode: i32, count: u32, type_: i32, indices: rawptr) #cc_c;
+DrawArrays:               proc(mode, first: i32, count: u32) #cc_c;
+DrawElements:             proc(mode: i32, count: u32, type_: i32, indices: rawptr) #cc_c;
 
-MapBuffer:        proc(target, access: i32) -> rawptr #cc_c;
-UnmapBuffer:      proc(target: i32) #cc_c;
+MapBuffer:                proc(target, access: i32) -> rawptr #cc_c;
+UnmapBuffer:              proc(target: i32) #cc_c;
 
-VertexAttribPointer:  proc(index: u32, size, type_: i32, normalized: i32, stride: u32, pointer: rawptr) #cc_c;
+VertexAttribPointer:      proc(index: u32, size, type_: i32, normalized: i32, stride: u32, pointer: rawptr) #cc_c;
 EnableVertexAttribArray:  proc(index: u32) #cc_c;
 
-CreateShader:   proc(shader_type: i32) -> u32 #cc_c;
-ShaderSource:   proc(shader: u32, count: u32, str: ^^byte, length: ^i32) #cc_c;
-CompileShader:  proc(shader: u32) #cc_c;
-CreateProgram:  proc() -> u32 #cc_c;
-AttachShader:   proc(program, shader: u32) #cc_c;
-DetachShader:   proc(program, shader: u32) #cc_c;
-DeleteShader:   proc(shader:  u32) #cc_c;
-LinkProgram:    proc(program: u32) #cc_c;
-UseProgram:     proc(program: u32) #cc_c;
-DeleteProgram:  proc(program: u32) #cc_c;
-
-
-GetShaderiv:        proc(shader:  u32, pname: i32, params: ^i32) #cc_c;
-GetProgramiv:       proc(program: u32, pname: i32, params: ^i32) #cc_c;
-GetShaderInfoLog:   proc(shader:  u32, max_length: u32, length: ^u32, info_long: ^byte) #cc_c;
-GetProgramInfoLog:  proc(program: u32, max_length: u32, length: ^u32, info_long: ^byte) #cc_c;
-
-ActiveTexture:   proc(texture: i32) #cc_c;
-GenerateMipmap:  proc(target:  i32) #cc_c;
-
-SamplerParameteri:     proc(sampler: u32, pname: i32, param: i32) #cc_c;
-SamplerParameterf:     proc(sampler: u32, pname: i32, param: f32) #cc_c;
-SamplerParameteriv:    proc(sampler: u32, pname: i32, params: ^i32) #cc_c;
-SamplerParameterfv:    proc(sampler: u32, pname: i32, params: ^f32) #cc_c;
-SamplerParameterIiv:   proc(sampler: u32, pname: i32, params: ^i32) #cc_c;
-SamplerParameterIuiv:  proc(sampler: u32, pname: i32, params: ^u32) #cc_c;
-
-
-Uniform1i:         proc(loc: i32, v0: i32) #cc_c;
-Uniform2i:         proc(loc: i32, v0, v1: i32) #cc_c;
-Uniform3i:         proc(loc: i32, v0, v1, v2: i32) #cc_c;
-Uniform4i:         proc(loc: i32, v0, v1, v2, v3: i32) #cc_c;
-Uniform1f:         proc(loc: i32, v0: f32) #cc_c;
-Uniform2f:         proc(loc: i32, v0, v1: f32) #cc_c;
-Uniform3f:         proc(loc: i32, v0, v1, v2: f32) #cc_c;
-Uniform4f:         proc(loc: i32, v0, v1, v2, v3: f32) #cc_c;
-UniformMatrix4fv:  proc(loc: i32, count: u32, transpose: i32, value: ^f32) #cc_c;
-
-GetUniformLocation:  proc(program: u32, name: ^byte) -> i32 #cc_c;
+CreateShader:             proc(shader_type: i32) -> u32 #cc_c;
+ShaderSource:             proc(shader: u32, count: u32, str: ^^byte, length: ^i32) #cc_c;
+CompileShader:            proc(shader: u32) #cc_c;
+CreateProgram:            proc() -> u32 #cc_c;
+AttachShader:             proc(program, shader: u32) #cc_c;
+DetachShader:             proc(program, shader: u32) #cc_c;
+DeleteShader:             proc(shader:  u32) #cc_c;
+LinkProgram:              proc(program: u32) #cc_c;
+UseProgram:               proc(program: u32) #cc_c;
+DeleteProgram:            proc(program: u32) #cc_c;
+
+
+GetShaderiv:              proc(shader:  u32, pname: i32, params: ^i32) #cc_c;
+GetProgramiv:             proc(program: u32, pname: i32, params: ^i32) #cc_c;
+GetShaderInfoLog:         proc(shader:  u32, max_length: u32, length: ^u32, info_long: ^byte) #cc_c;
+GetProgramInfoLog:        proc(program: u32, max_length: u32, length: ^u32, info_long: ^byte) #cc_c;
+
+ActiveTexture:            proc(texture: i32) #cc_c;
+GenerateMipmap:           proc(target:  i32) #cc_c;
+
+SamplerParameteri:        proc(sampler: u32, pname: i32, param: i32) #cc_c;
+SamplerParameterf:        proc(sampler: u32, pname: i32, param: f32) #cc_c;
+SamplerParameteriv:       proc(sampler: u32, pname: i32, params: ^i32) #cc_c;
+SamplerParameterfv:       proc(sampler: u32, pname: i32, params: ^f32) #cc_c;
+SamplerParameterIiv:      proc(sampler: u32, pname: i32, params: ^i32) #cc_c;
+SamplerParameterIuiv:     proc(sampler: u32, pname: i32, params: ^u32) #cc_c;
+
+
+Uniform1i:                proc(loc: i32, v0: i32) #cc_c;
+Uniform2i:                proc(loc: i32, v0, v1: i32) #cc_c;
+Uniform3i:                proc(loc: i32, v0, v1, v2: i32) #cc_c;
+Uniform4i:                proc(loc: i32, v0, v1, v2, v3: i32) #cc_c;
+Uniform1f:                proc(loc: i32, v0: f32) #cc_c;
+Uniform2f:                proc(loc: i32, v0, v1: f32) #cc_c;
+Uniform3f:                proc(loc: i32, v0, v1, v2: f32) #cc_c;
+Uniform4f:                proc(loc: i32, v0, v1, v2, v3: f32) #cc_c;
+UniformMatrix4fv:         proc(loc: i32, count: u32, transpose: i32, value: ^f32) #cc_c;
+
+GetUniformLocation:       proc(program: u32, name: ^byte) -> i32 #cc_c;
 
 init :: proc() {
 	set_proc_address :: proc(p: rawptr, name: string) #inline { (cast(^(proc() #cc_c))p)^ = GetProcAddress(name); }
 
-	set_proc_address(^GenBuffers,      "glGenBuffers\x00");
-	set_proc_address(^GenVertexArrays, "glGenVertexArrays\x00");
-	set_proc_address(^GenSamplers,     "glGenSamplers\x00");
-	set_proc_address(^BindBuffer,      "glBindBuffer\x00");
-	set_proc_address(^BindSampler,     "glBindSampler\x00");
-	set_proc_address(^BindVertexArray, "glBindVertexArray\x00");
-	set_proc_address(^BufferData,      "glBufferData\x00");
-	set_proc_address(^BufferSubData,   "glBufferSubData\x00");
+	set_proc_address(^GenBuffers,              "glGenBuffers\x00");
+	set_proc_address(^GenVertexArrays,         "glGenVertexArrays\x00");
+	set_proc_address(^GenSamplers,             "glGenSamplers\x00");
+	set_proc_address(^BindBuffer,              "glBindBuffer\x00");
+	set_proc_address(^BindSampler,             "glBindSampler\x00");
+	set_proc_address(^BindVertexArray,         "glBindVertexArray\x00");
+	set_proc_address(^BufferData,              "glBufferData\x00");
+	set_proc_address(^BufferSubData,           "glBufferSubData\x00");
 
-	set_proc_address(^DrawArrays,      "glDrawArrays\x00");
-	set_proc_address(^DrawElements,    "glDrawElements\x00");
+	set_proc_address(^DrawArrays,              "glDrawArrays\x00");
+	set_proc_address(^DrawElements,            "glDrawElements\x00");
 
-	set_proc_address(^MapBuffer,   "glMapBuffer\x00");
-	set_proc_address(^UnmapBuffer, "glUnmapBuffer\x00");
+	set_proc_address(^MapBuffer,               "glMapBuffer\x00");
+	set_proc_address(^UnmapBuffer,             "glUnmapBuffer\x00");
 
 	set_proc_address(^VertexAttribPointer,     "glVertexAttribPointer\x00");
 	set_proc_address(^EnableVertexAttribArray, "glEnableVertexAttribArray\x00");
 
-	set_proc_address(^CreateShader,  "glCreateShader\x00");
-	set_proc_address(^ShaderSource,  "glShaderSource\x00");
-	set_proc_address(^CompileShader, "glCompileShader\x00");
-	set_proc_address(^CreateProgram, "glCreateProgram\x00");
-	set_proc_address(^AttachShader,  "glAttachShader\x00");
-	set_proc_address(^DetachShader,  "glDetachShader\x00");
-	set_proc_address(^DeleteShader,  "glDeleteShader\x00");
-	set_proc_address(^LinkProgram,   "glLinkProgram\x00");
-	set_proc_address(^UseProgram,    "glUseProgram\x00");
-	set_proc_address(^DeleteProgram, "glDeleteProgram\x00");
-
-	set_proc_address(^GetShaderiv,       "glGetShaderiv\x00");
-	set_proc_address(^GetProgramiv,      "glGetProgramiv\x00");
-	set_proc_address(^GetShaderInfoLog,  "glGetShaderInfoLog\x00");
-	set_proc_address(^GetProgramInfoLog, "glGetProgramInfoLog\x00");
-
-	set_proc_address(^ActiveTexture,  "glActiveTexture\x00");
-	set_proc_address(^GenerateMipmap, "glGenerateMipmap\x00");
-
-	set_proc_address(^Uniform1i,        "glUniform1i\x00");
-	set_proc_address(^UniformMatrix4fv, "glUniformMatrix4fv\x00");
-
-	set_proc_address(^GetUniformLocation, "glGetUniformLocation\x00");
-
-	set_proc_address(^SamplerParameteri,    "glSamplerParameteri\x00");
-	set_proc_address(^SamplerParameterf,    "glSamplerParameterf\x00");
-	set_proc_address(^SamplerParameteriv,   "glSamplerParameteriv\x00");
-	set_proc_address(^SamplerParameterfv,   "glSamplerParameterfv\x00");
-	set_proc_address(^SamplerParameterIiv,  "glSamplerParameterIiv\x00");
-	set_proc_address(^SamplerParameterIuiv, "glSamplerParameterIuiv\x00");
+	set_proc_address(^CreateShader,            "glCreateShader\x00");
+	set_proc_address(^ShaderSource,            "glShaderSource\x00");
+	set_proc_address(^CompileShader,           "glCompileShader\x00");
+	set_proc_address(^CreateProgram,           "glCreateProgram\x00");
+	set_proc_address(^AttachShader,            "glAttachShader\x00");
+	set_proc_address(^DetachShader,            "glDetachShader\x00");
+	set_proc_address(^DeleteShader,            "glDeleteShader\x00");
+	set_proc_address(^LinkProgram,             "glLinkProgram\x00");
+	set_proc_address(^UseProgram,              "glUseProgram\x00");
+	set_proc_address(^DeleteProgram,           "glDeleteProgram\x00");
+
+	set_proc_address(^GetShaderiv,             "glGetShaderiv\x00");
+	set_proc_address(^GetProgramiv,            "glGetProgramiv\x00");
+	set_proc_address(^GetShaderInfoLog,        "glGetShaderInfoLog\x00");
+	set_proc_address(^GetProgramInfoLog,       "glGetProgramInfoLog\x00");
+
+	set_proc_address(^ActiveTexture,           "glActiveTexture\x00");
+	set_proc_address(^GenerateMipmap,          "glGenerateMipmap\x00");
+
+	set_proc_address(^Uniform1i,               "glUniform1i\x00");
+	set_proc_address(^UniformMatrix4fv,        "glUniformMatrix4fv\x00");
+
+	set_proc_address(^GetUniformLocation,      "glGetUniformLocation\x00");
+
+	set_proc_address(^SamplerParameteri,       "glSamplerParameteri\x00");
+	set_proc_address(^SamplerParameterf,       "glSamplerParameterf\x00");
+	set_proc_address(^SamplerParameteriv,      "glSamplerParameteriv\x00");
+	set_proc_address(^SamplerParameterfv,      "glSamplerParameterfv\x00");
+	set_proc_address(^SamplerParameterIiv,     "glSamplerParameterIiv\x00");
+	set_proc_address(^SamplerParameterIuiv,    "glSamplerParameterIuiv\x00");
 }
 

+ 8 - 5
core/sys/windows.odin

@@ -41,11 +41,14 @@ WS_CAPTION          :: 0x00C00000;
 WS_VISIBLE          :: 0x10000000;
 WS_OVERLAPPEDWINDOW :: WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|WS_MAXIMIZEBOX;
 
-WM_DESTROY :: 0x0002;
-WM_CLOSE   :: 0x0010;
-WM_QUIT    :: 0x0012;
-WM_KEYDOWN :: 0x0100;
-WM_KEYUP   :: 0x0101;
+WM_DESTROY     :: 0x0002;
+WM_SIZE	       :: 0x0005;
+WM_CLOSE       :: 0x0010;
+WM_ACTIVATEAPP :: 0x001C;
+WM_QUIT        :: 0x0012;
+WM_KEYDOWN     :: 0x0100;
+WM_KEYUP       :: 0x0101;
+WM_SIZING      :: 0x0214;
 
 PM_REMOVE :: 1;
 

+ 1 - 1
core/types.odin

@@ -1,6 +1,6 @@
 is_signed :: proc(info: ^Type_Info) -> bool {
 	if is_integer(info) {
-		i := cast(^Type_Info.Integer)info;
+		i := union_cast(^Type_Info.Integer)info;
 		return i.signed;
 	}
 	if is_float(info) {

+ 2 - 2
core/utf8.odin

@@ -30,7 +30,7 @@ HICB :: 0b1011_1111;
 
 Accept_Range :: struct { lo, hi: u8 }
 
-accept_ranges := [5]Accept_Range{
+immutable accept_ranges := [5]Accept_Range{
 	{0x80, 0xbf},
 	{0xa0, 0xbf},
 	{0x80, 0x9f},
@@ -38,7 +38,7 @@ accept_ranges := [5]Accept_Range{
 	{0x80, 0x8f},
 };
 
-accept_sizes := [256]byte{
+immutable accept_sizes := [256]byte{
 	0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x00-0x0f
 	0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x10-0x1f
 	0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x20-0x2f

+ 6 - 2
src/build_settings.c

@@ -1,4 +1,6 @@
+// This stores the information for the specify architecture of this build
 typedef struct BuildContext {
+	// Constants
 	String ODIN_OS;      // target operating system
 	String ODIN_ARCH;    // target architecture
 	String ODIN_ENDIAN;  // target endian
@@ -6,8 +8,10 @@ typedef struct BuildContext {
 	String ODIN_VERSION; // compiler version
 	String ODIN_ROOT;    // Odin ROOT
 
-	i64    word_size;
-	i64    max_align;
+	// In bytes
+	i64    word_size; // Size of a pointer, must be >= 4
+	i64    max_align; // max alignment, must be >= 1 (and typically >= word_size)
+
 	String llc_flags;
 	String link_flags;
 	bool   is_dll;

+ 0 - 11
src/check_decl.c

@@ -72,25 +72,14 @@ void check_init_variables(Checker *c, Entity **lhs, isize lhs_count, AstNodeArra
 		}
 	}
 
-
 	isize max = gb_min(lhs_count, rhs_count);
 	for (isize i = 0; i < max; i++) {
 		check_init_variable(c, lhs[i], &operands.e[i], context_name);
 	}
-
 	if (rhs_count > 0 && lhs_count != rhs_count) {
 		error(lhs[0]->token, "Assignment count mismatch `%td` = `%td`", lhs_count, rhs_count);
 	}
 
-#if 0
-	if (lhs[0]->kind == Entity_Variable &&
-	    lhs[0]->Variable.is_let) {
-		if (lhs_count != rhs_count) {
-			error(lhs[0]->token, "`let` variables must be initialized, `%td` = `%td`", lhs_count, rhs_count);
-		}
-	}
-#endif
-
 	gb_temp_arena_memory_end(tmp);
 }
 

+ 157 - 320
src/check_expr.c

@@ -265,8 +265,6 @@ void check_assignment(Checker *c, Operand *operand, Type *type, String context_n
 	}
 
 
-
-
 	if (type == NULL) {
 		return;
 	}
@@ -1030,7 +1028,7 @@ void check_ident(Checker *c, Operand *o, AstNode *n, Type *named_type, Type *typ
 		}
 		o->mode = Addressing_Variable;
 		if (e->Variable.is_immutable) {
-			o->mode = Addressing_Value;
+			o->mode = Addressing_Immutable;
 		}
 		break;
 
@@ -1073,7 +1071,7 @@ i64 check_array_or_map_count(Checker *c, AstNode *e, bool is_map) {
 	}
 	Operand o = {0};
 	if (e->kind == AstNode_UnaryExpr &&
-	    e->UnaryExpr.op.kind == Token_Question) {
+	    e->UnaryExpr.op.kind == Token_Ellipsis) {
 		return -1;
 	}
 
@@ -1115,12 +1113,13 @@ i64 check_array_or_map_count(Checker *c, AstNode *e, bool is_map) {
 	return 0;
 }
 
-Type *make_map_tuple_type(gbAllocator a, Type *value) {
+Type *make_optional_ok_type(gbAllocator a, Type *value) {
+	bool typed = true;
 	Type *t = make_type_tuple(a);
 	t->Tuple.variables = gb_alloc_array(a, Entity *, 2);
 	t->Tuple.variable_count = 2;
 	t->Tuple.variables[0] = make_entity_field(a, NULL, blank_token, value,  false, 0);
-	t->Tuple.variables[1] = make_entity_field(a, NULL, blank_token, t_bool, false, 1);
+	t->Tuple.variables[1] = make_entity_field(a, NULL, blank_token, typed ? t_bool : t_untyped_bool, false, 1);
 	return t;
 }
 
@@ -1221,7 +1220,7 @@ void check_map_type(Checker *c, Type *type, AstNode *node) {
 		type->Map.generated_struct_type = generated_struct_type;
 	}
 
-	type->Map.lookup_result_type = make_map_tuple_type(a, value);
+	type->Map.lookup_result_type = make_optional_ok_type(a, value);
 
 	// error_node(node, "`map` types are not yet implemented");
 }
@@ -1929,6 +1928,76 @@ void check_shift(Checker *c, Operand *x, Operand *y, AstNode *node) {
 	x->mode = Addressing_Value;
 }
 
+
+String check_down_cast_name(Type *dst_, Type *src_) {
+	String result = {0};
+	Type *dst = type_deref(dst_);
+	Type *src = type_deref(src_);
+	Type *dst_s = base_type(dst);
+	GB_ASSERT(is_type_struct(dst_s) || is_type_raw_union(dst_s));
+	for (isize i = 0; i < dst_s->Record.field_count; i++) {
+		Entity *f = dst_s->Record.fields[i];
+		GB_ASSERT(f->kind == Entity_Variable && f->flags & EntityFlag_Field);
+		if (f->flags & EntityFlag_Anonymous) {
+			if (are_types_identical(f->type, src_)) {
+				return f->token.string;
+			}
+			if (are_types_identical(type_deref(f->type), src_)) {
+				return f->token.string;
+			}
+
+			if (!is_type_pointer(f->type)) {
+				result = check_down_cast_name(f->type, src_);
+				if (result.len > 0) {
+					return result;
+				}
+			}
+		}
+	}
+
+	return result;
+}
+
+Operand check_ptr_addition(Checker *c, TokenKind op, Operand *ptr, Operand *offset, AstNode *node) {
+	GB_ASSERT(node->kind == AstNode_BinaryExpr);
+	ast_node(be, BinaryExpr, node);
+	GB_ASSERT(is_type_pointer(ptr->type));
+	GB_ASSERT(is_type_integer(offset->type));
+	GB_ASSERT(op == Token_Add || op == Token_Sub);
+
+	Operand operand = {0};
+	operand.mode = Addressing_Value;
+	operand.type = ptr->type;
+	operand.expr = node;
+
+	if (base_type(ptr->type) == t_rawptr) {
+		gbString str = type_to_string(ptr->type);
+		error_node(node, "Invalid pointer type for pointer arithmetic: `%s`", str);
+		gb_string_free(str);
+		operand.mode = Addressing_Invalid;
+		return operand;
+	}
+
+
+	if (ptr->mode == Addressing_Constant && offset->mode == Addressing_Constant) {
+		i64 elem_size = type_size_of(c->allocator, ptr->type);
+		i64 ptr_val = ptr->value.value_pointer;
+		i64 offset_val = exact_value_to_integer(offset->value).value_integer;
+		i64 new_ptr_val = ptr_val;
+		if (op == Token_Add) {
+			new_ptr_val += elem_size*offset_val;
+		} else {
+			new_ptr_val -= elem_size*offset_val;
+		}
+		operand.mode = Addressing_Constant;
+		operand.value = make_exact_value_pointer(new_ptr_val);
+	}
+
+	return operand;
+}
+
+
+
 bool check_is_castable_to(Checker *c, Operand *operand, Type *y) {
 	if (check_is_assignable_to(c, operand, y)) {
 		return true;
@@ -1968,10 +2037,21 @@ bool check_is_castable_to(Checker *c, Operand *operand, Type *y) {
 
 	// Cast between pointers
 	if (is_type_pointer(src) && is_type_pointer(dst)) {
+		Type *s = base_type(type_deref(src));
+		if (is_type_union(s)) {
+			// NOTE(bill): Should the error be here?!
+			// NOTE(bill): This error should suppress the next casting error as it's at the same position
+			gbString xs = type_to_string(x);
+			gbString ys = type_to_string(y);
+			error_node(operand->expr, "Cannot cast from a union pointer `%s` to `%s`, try using `union_cast` or cast to a `rawptr`", xs, ys);
+			gb_string_free(ys);
+			gb_string_free(xs);
+			return false;
+		}
 		return true;
 	}
 
-	// (u)int <-> pointer
+	// (u)int <-> rawptr
 	if (is_type_int_or_uint(src) && is_type_rawptr(dst)) {
 		return true;
 	}
@@ -2006,75 +2086,7 @@ bool check_is_castable_to(Checker *c, Operand *operand, Type *y) {
 	return false;
 }
 
-String check_down_cast_name(Type *dst_, Type *src_) {
-	String result = {0};
-	Type *dst = type_deref(dst_);
-	Type *src = type_deref(src_);
-	Type *dst_s = base_type(dst);
-	GB_ASSERT(is_type_struct(dst_s) || is_type_raw_union(dst_s));
-	for (isize i = 0; i < dst_s->Record.field_count; i++) {
-		Entity *f = dst_s->Record.fields[i];
-		GB_ASSERT(f->kind == Entity_Variable && f->flags & EntityFlag_Field);
-		if (f->flags & EntityFlag_Anonymous) {
-			if (are_types_identical(f->type, src_)) {
-				return f->token.string;
-			}
-			if (are_types_identical(type_deref(f->type), src_)) {
-				return f->token.string;
-			}
-
-			if (!is_type_pointer(f->type)) {
-				result = check_down_cast_name(f->type, src_);
-				if (result.len > 0) {
-					return result;
-				}
-			}
-		}
-	}
-
-	return result;
-}
-
-Operand check_ptr_addition(Checker *c, TokenKind op, Operand *ptr, Operand *offset, AstNode *node) {
-	GB_ASSERT(node->kind == AstNode_BinaryExpr);
-	ast_node(be, BinaryExpr, node);
-	GB_ASSERT(is_type_pointer(ptr->type));
-	GB_ASSERT(is_type_integer(offset->type));
-	GB_ASSERT(op == Token_Add || op == Token_Sub);
-
-	Operand operand = {0};
-	operand.mode = Addressing_Value;
-	operand.type = ptr->type;
-	operand.expr = node;
-
-	if (base_type(ptr->type) == t_rawptr) {
-		gbString str = type_to_string(ptr->type);
-		error_node(node, "Invalid pointer type for pointer arithmetic: `%s`", str);
-		gb_string_free(str);
-		operand.mode = Addressing_Invalid;
-		return operand;
-	}
-
-
-	if (ptr->mode == Addressing_Constant && offset->mode == Addressing_Constant) {
-		i64 elem_size = type_size_of(c->allocator, ptr->type);
-		i64 ptr_val = ptr->value.value_pointer;
-		i64 offset_val = exact_value_to_integer(offset->value).value_integer;
-		i64 new_ptr_val = ptr_val;
-		if (op == Token_Add) {
-			new_ptr_val += elem_size*offset_val;
-		} else {
-			new_ptr_val -= elem_size*offset_val;
-		}
-		operand.mode = Addressing_Constant;
-		operand.value = make_exact_value_pointer(new_ptr_val);
-	}
-
-	return operand;
-}
-
-
-void check_conversion(Checker *c, Operand *x, Type *type) {
+void check_cast(Checker *c, Operand *x, Type *type) {
 	bool is_const_expr = x->mode == Addressing_Constant;
 	bool can_convert = false;
 
@@ -2714,7 +2726,9 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h
 		break;
 	case Entity_Variable:
 		// TODO(bill): This is the rule I need?
-		if (sel.indirect || operand->mode != Addressing_Value) {
+		if (operand->mode == Addressing_Immutable) {
+			// Okay
+		} else if (sel.indirect || operand->mode != Addressing_Value) {
 			operand->mode = Addressing_Variable;
 		} else {
 			operand->mode = Addressing_Value;
@@ -3819,17 +3833,16 @@ int valid_proc_and_score_cmp(void const *a, void const *b) {
 
 typedef Array(Operand) ArrayOperand;
 
-void check_unpack_arguments(Checker *c, isize lhs_count, ArrayOperand *operands, AstNodeArray args, bool allow_map_ok) {
-	for_array(i, args) {
+bool check_unpack_arguments(Checker *c, isize lhs_count, ArrayOperand *operands, AstNodeArray rhs, bool allow_ok) {
+	bool optional_ok = false;
+	for_array(i, rhs) {
 		Operand o = {0};
-		check_multi_expr(c, &o, args.e[i]);
+		check_multi_expr(c, &o, rhs.e[i]);
 
 		if (o.type == NULL || o.type->kind != Type_Tuple) {
-			if (o.mode == Addressing_MapIndex &&
-			    allow_map_ok &&
-			    lhs_count == 2 &&
-			    args.count == 1) {
-				Type *tuple = make_map_tuple_type(c->allocator, o.type);
+			if (allow_ok && lhs_count == 2 && rhs.count == 1 &&
+			    (o.mode == Addressing_MapIndex || o.mode == Addressing_OptionalOk)) {
+				Type *tuple = make_optional_ok_type(c->allocator, o.type);
 				add_type_and_value(&c->info, o.expr, o.mode, tuple, o.value);
 
 				Operand val = o;
@@ -3839,9 +3852,11 @@ void check_unpack_arguments(Checker *c, isize lhs_count, ArrayOperand *operands,
 				ok.type  = t_bool;
 				array_add(operands, val);
 				array_add(operands, ok);
-				continue;
+
+				optional_ok = true;
+			} else {
+				array_add(operands, o);
 			}
-			array_add(operands, o);
 		} else {
 			TypeTuple *tuple = &o.type->Tuple;
 			for (isize j = 0; j < tuple->variable_count; j++) {
@@ -3850,6 +3865,8 @@ void check_unpack_arguments(Checker *c, isize lhs_count, ArrayOperand *operands,
 			}
 		}
 	}
+
+	return optional_ok;
 }
 
 Type *check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNode *call) {
@@ -3998,7 +4015,7 @@ ExprKind check_call_expr(Checker *c, Operand *operand, AstNode *call) {
 		case 1:
 			check_expr(c, operand, ce->args.e[0]);
 			if (operand->mode != Addressing_Invalid) {
-				check_conversion(c, operand, t);
+				check_cast(c, operand, t);
 			}
 			break;
 		}
@@ -4097,8 +4114,19 @@ void check_expr_with_type_hint(Checker *c, Operand *o, AstNode *e, Type *t) {
 	}
 }
 
-bool check_set_index_data(Operand *o, Type *t, i64 *max_count) {
-	t = base_type(type_deref(t));
+void check_set_mode_with_indirection(Operand *o, bool indirection) {
+	if (o->mode != Addressing_Immutable) {
+		if (indirection) {
+			o->mode = Addressing_Variable;
+		} else if (o->mode != Addressing_Variable &&
+		           o->mode != Addressing_Constant) {
+			o->mode = Addressing_Value;
+		}
+	}
+}
+
+bool check_set_index_data(Operand *o, Type *type, bool indirection, i64 *max_count) {
+	Type *t = base_type(type_deref(type));
 
 	switch (t->kind) {
 	case Type_Basic:
@@ -4106,9 +4134,7 @@ bool check_set_index_data(Operand *o, Type *t, i64 *max_count) {
 			if (o->mode == Addressing_Constant) {
 				*max_count = o->value.value_string.len;
 			}
-			if (o->mode != Addressing_Variable) {
-				o->mode = Addressing_Value;
-			}
+			check_set_mode_with_indirection(o, indirection);
 			o->type = t_u8;
 			return true;
 		}
@@ -4116,69 +4142,33 @@ bool check_set_index_data(Operand *o, Type *t, i64 *max_count) {
 
 	case Type_Array:
 		*max_count = t->Array.count;
-		if (o->mode != Addressing_Variable) {
-			o->mode = Addressing_Value;
-		}
+		check_set_mode_with_indirection(o, indirection);
 		o->type = t->Array.elem;
 		return true;
 
 	case Type_Vector:
 		*max_count = t->Vector.count;
-		if (o->mode != Addressing_Variable) {
-			o->mode = Addressing_Value;
-		}
+		check_set_mode_with_indirection(o, indirection);
 		o->type = t->Vector.elem;
 		return true;
 
 
 	case Type_Slice:
 		o->type = t->Slice.elem;
-		o->mode = Addressing_Variable;
+		if (o->mode != Addressing_Immutable) {
+			o->mode = Addressing_Variable;
+		}
 		return true;
 
 	case Type_DynamicArray:
 		o->type = t->DynamicArray.elem;
-		o->mode = Addressing_Variable;
+		check_set_mode_with_indirection(o, indirection);
 		return true;
 	}
 
 	return false;
 }
 
-
-bool check_is_giving(AstNode *node, AstNode **give_expr) {
-	switch (node->kind) {
-	case_ast_node(es, ExprStmt, node);
-		if (es->expr->kind == AstNode_GiveExpr) {
-			if (give_expr) *give_expr = es->expr;
-			return true;
-		}
-	case_end;
-
-	case_ast_node(ge, GiveExpr, node);
-		if (give_expr) *give_expr = node;
-		return true;
-	case_end;
-
-	case_ast_node(be, BlockExpr, node);
-		// Iterate backwards
-		for (isize n = be->stmts.count-1; n >= 0; n--) {
-			AstNode *stmt = be->stmts.e[n];
-			if (stmt->kind == AstNode_EmptyStmt) {
-				continue;
-			}
-			if (stmt->kind == AstNode_ExprStmt && stmt->ExprStmt.expr->kind == AstNode_GiveExpr) {
-				if (give_expr) *give_expr = stmt->ExprStmt.expr;
-				return true;
-			}
-		}
-	case_end;
-	}
-
-	if (give_expr) *give_expr = NULL;
-	return false;
-}
-
 ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint) {
 	ExprKind kind = Expr_Stmt;
 
@@ -4280,177 +4270,30 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
 		o->type = type;
 	case_end;
 
-	case_ast_node(ge, GiveExpr, node);
-		if (c->proc_stack.count == 0) {
-			error_node(node, "A give expression is only allowed within a procedure");
-			goto error;
-		}
-
-		if (ge->results.count == 0) {
-			error_node(node, "`give` has no results");
-			goto error;
-		}
-
-		gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena);
-
-		Array(Operand) operands;
-		array_init_reserve(&operands, c->tmp_allocator, 2*ge->results.count);
-
-		for_array(i, ge->results) {
-			AstNode *rhs = ge->results.e[i];
-			Operand o = {0};
-			check_multi_expr(c, &o, rhs);
-			if (!is_operand_value(o)) {
-				error_node(rhs, "Expected a value for a `give`");
-				continue;
-			}
-			if (o.type->kind != Type_Tuple) {
-				array_add(&operands, o);
-			} else {
-				TypeTuple *tuple = &o.type->Tuple;
-				for (isize j = 0; j < tuple->variable_count; j++) {
-					o.type = tuple->variables[j]->type;
-					array_add(&operands, o);
-				}
-			}
-		}
-
-		if (operands.count == 0) {
-			error_node(node, "`give` has no value");
-			gb_temp_arena_memory_end(tmp);
-			goto error;
-		} else if (operands.count == 1) {
-			Operand operand = operands.e[0];
-			Type *th = type_hint != NULL ? type_hint : c->context.type_hint;
-			if (th != NULL) {
-				convert_to_typed(c, &operand, th, 0);
-			}
-			// IMPORTANT NOTE(bill): This type could be untyped!!!
-			o->type = default_type(operand.type);
-			o->mode = Addressing_Value;
-		} else {
-			Type *tuple = make_type_tuple(c->allocator);
-
-			Entity **variables = gb_alloc_array(c->allocator, Entity *, operands.count);
-			isize variable_index = 0;
-			for_array(i, operands) {
-				Operand operand = operands.e[i];
-				// Type *type = default_type(operand.type);
-				Type *type = operand.type;
-				switch (operand.mode) {
-				case Addressing_Constant:
-					variables[variable_index++] = make_entity_constant(c->allocator, NULL, empty_token, type, operand.value);
-					break;
-				default:
-					variables[variable_index++] = make_entity_param(c->allocator, NULL, empty_token, type, false, true);
-					break;
-				}
-			}
-			tuple->Tuple.variables = variables;
-			tuple->Tuple.variable_count = operands.count;
-
-			o->type = tuple;
-			o->mode = Addressing_Value;
-		}
-		gb_temp_arena_memory_end(tmp);
-	case_end;
-
-	case_ast_node(be, BlockExpr, node);
+	case_ast_node(te, TernaryExpr, node);
 		if (c->proc_stack.count == 0) {
-			error_node(node, "A block expression is only allowed within a procedure");
+			error_node(node, "A ternary expression is only allowed within a procedure");
 			goto error;
 		}
-
-		for (isize i = be->stmts.count-1; i >= 0; i--) {
-			if (be->stmts.e[i]->kind != AstNode_EmptyStmt) {
-				break;
-			}
-			be->stmts.count--;
-		}
-
-		if (be->stmts.count == 0) {
-			error_node(node, "Empty block expression");
-			goto error;
-		}
-
-		CheckerContext prev_context = c->context;
-		c->context.type_hint = type_hint;
-		check_open_scope(c, node);
-		check_stmt_list(c, be->stmts, Stmt_GiveAllowed);
-		check_close_scope(c);
-
-		c->context = prev_context;
-
-		AstNode *give_node = NULL;
-		if (!check_is_giving(node, &give_node) || give_node == NULL) {
-			error_node(node, "Missing give statement at end of block expression");
-			goto error;
-		}
-
-		GB_ASSERT(give_node != NULL && give_node->kind == AstNode_GiveExpr);
-		be->give_node = give_node;
-
-		Type *type = type_of_expr(&c->info, give_node);
-		if (type == NULL) {
-			goto error;
-		} else if (type == t_invalid) {
-			o->type = t_invalid;
-			o->mode = Addressing_Invalid;
-		} else {
-			o->type = type;
-			o->mode = Addressing_Value;
-		}
-	case_end;
-
-	case_ast_node(ie, IfExpr, node);
-		if (c->proc_stack.count == 0) {
-			error_node(node, "An if expression is only allowed within a procedure");
-			goto error;
-		}
-
-		check_open_scope(c, node);
-
-		if (ie->init != NULL) {
-			check_stmt(c, ie->init, 0);
-		}
-
 		Operand operand = {Addressing_Invalid};
-		check_expr(c, &operand, ie->cond);
+		check_expr(c, &operand, te->cond);
 		if (operand.mode != Addressing_Invalid && !is_type_boolean(operand.type)) {
-			error_node(ie->cond, "Non-boolean condition in if expression");
+			error_node(te->cond, "Non-boolean condition in if expression");
 		}
 
 		Operand x = {Addressing_Invalid};
 		Operand y = {Addressing_Invalid};
-		Type *if_type = NULL;
-		Type *else_type = NULL;
-		if (type_hint) {
-			gb_printf_err("here\n");
-		}
-		check_expr_with_type_hint(c, &x, ie->body, type_hint);
-		if_type = x.type;
-
-		if (ie->else_expr != NULL) {
-			switch (ie->else_expr->kind) {
-			case AstNode_IfExpr:
-			case AstNode_BlockExpr:
-				check_expr_with_type_hint(c, &y, ie->else_expr, if_type);
-				else_type = y.type;
-				break;
-			default:
-				error_node(ie->else_expr, "Invalid else expression in if expression");
-				break;
-			}
+		check_expr_with_type_hint(c, &x, te->x, type_hint);
+
+		if (te->y != NULL) {
+			check_expr_with_type_hint(c, &y, te->y, type_hint);
 		} else {
-			error_node(ie->else_expr, "An if expression must have an else expression");
-			check_close_scope(c);
+			error_node(node, "A ternary expression must have an else clause");
 			goto error;
 		}
 
-		check_close_scope(c);
-
-		if (if_type == NULL || if_type == t_invalid ||
-		    else_type == NULL || else_type == t_invalid) {
+		if (x.type == NULL || x.type == t_invalid ||
+		    y.type == NULL || y.type == t_invalid) {
 			goto error;
 		}
 
@@ -4465,16 +4308,16 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
 		}
 
 
-		if (!are_types_identical(if_type, else_type)) {
-			gbString its = type_to_string(if_type);
-			gbString ets = type_to_string(else_type);
-			error_node(node, "Mismatched types in if expression, %s vs %s", its, ets);
+		if (!are_types_identical(x.type, y.type)) {
+			gbString its = type_to_string(x.type);
+			gbString ets = type_to_string(y.type);
+			error_node(node, "Mismatched types in ternary expression, %s vs %s", its, ets);
 			gb_string_free(ets);
 			gb_string_free(its);
 			goto error;
 		}
 
-		o->type = if_type;
+		o->type = x.type;
 		o->mode = Addressing_Value;
 	case_end;
 
@@ -4489,7 +4332,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
 			if (cl->type->kind == AstNode_ArrayType && cl->type->ArrayType.count != NULL) {
 				AstNode *count = cl->type->ArrayType.count;
 				if (count->kind == AstNode_UnaryExpr &&
-				    count->UnaryExpr.op.kind == Token_Question) {
+				    count->UnaryExpr.op.kind == Token_Ellipsis) {
 					type = make_type_array(c->allocator, check_type(c, cl->type->ArrayType.elem), -1);
 					is_to_be_determined_array_count = true;
 				}
@@ -4820,7 +4663,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
 		}
 		switch (ce->token.kind) {
 		case Token_cast:
-			check_conversion(c, o, t);
+			check_cast(c, o, t);
 			break;
 		case Token_transmute: {
 			if (o->mode == Addressing_Constant) {
@@ -4913,16 +4756,11 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
 				goto error;
 			}
 
-			Entity **variables = gb_alloc_array(c->allocator, Entity *, 2);
-			variables[0] = make_entity_param(c->allocator, NULL, empty_token, t, false, true);
-			variables[1] = make_entity_param(c->allocator, NULL, empty_token, t_bool, false, true);
-
-			Type *tuple = make_type_tuple(c->allocator);
-			tuple->Tuple.variables = variables;
-			tuple->Tuple.variable_count = 2;
+			add_type_info_type(c, o->type);
+			add_type_info_type(c, t);
 
-			o->type = tuple;
-			o->mode = Addressing_Value;
+			o->type = t;
+			o->mode = Addressing_OptionalOk;
 		} break;
 		case Token_down_cast: {
 			if (o->mode == Addressing_Constant) {
@@ -5023,6 +4861,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
 		}
 
 		Type *t = base_type(type_deref(o->type));
+		bool is_ptr = is_type_pointer(o->type);
 		bool is_const = o->mode == Addressing_Constant;
 
 		if (is_type_map(t)) {
@@ -5039,7 +4878,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
 		}
 
 		i64 max_count = -1;
-		bool valid = check_set_index_data(o, t, &max_count);
+		bool valid = check_set_index_data(o, t, is_ptr, &max_count);
 
 		if (is_const) {
 			valid = false;
@@ -5048,7 +4887,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
 		if (!valid && (is_type_struct(t) || is_type_raw_union(t))) {
 			Entity *found = find_using_index_expr(t);
 			if (found != NULL) {
-				valid = check_set_index_data(o, found->type, &max_count);
+				valid = check_set_index_data(o, found->type, is_type_pointer(found->type), &max_count);
 			}
 		}
 
@@ -5125,7 +4964,9 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
 			goto error;
 		}
 
-		o->mode = Addressing_Value;
+		if (o->mode != Addressing_Immutable) {
+			o->mode = Addressing_Value;
+		}
 
 		i64 indices[2] = {0};
 		AstNode *nodes[2] = {se->low, se->high};
@@ -5173,7 +5014,9 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
 		} else {
 			Type *t = base_type(o->type);
 			if (t->kind == Type_Pointer) {
-				o->mode = Addressing_Variable;
+				if (o->mode != Addressing_Immutable) {
+					o->mode = Addressing_Variable;
+				}
 				o->type = t->Pointer.elem;
  			} else {
  				gbString str = expr_to_string(o->expr);
@@ -5354,12 +5197,6 @@ gbString write_expr_to_string(gbString str, AstNode *node) {
 		str = gb_string_appendc(str, "}");
 	case_end;
 
-	case_ast_node(be, BlockExpr, node);
-		str = gb_string_appendc(str, "block expression");
-	case_end;
-	case_ast_node(ie, IfExpr, node);
-		str = gb_string_appendc(str, "if expression");
-	case_end;
 
 	case_ast_node(te, TagExpr, node);
 		str = gb_string_appendc(str, "#");

+ 67 - 67
src/check_stmt.c

@@ -30,11 +30,6 @@ void check_stmt_list(Checker *c, AstNodeArray stmts, u32 flags) {
 			case AstNode_ReturnStmt:
 				error_node(n, "Statements after this `return` are never executed");
 				break;
-			case AstNode_ExprStmt:
-				if (n->ExprStmt.expr->kind == AstNode_GiveExpr) {
-					error_node(n, "A `give` must be the last statement in a block");
-				}
-				break;
 			}
 		}
 
@@ -182,40 +177,40 @@ bool check_is_terminating(AstNode *node) {
 	return false;
 }
 
-Type *check_assignment_variable(Checker *c, Operand *op_a, AstNode *lhs) {
-	if (op_a->mode == Addressing_Invalid ||
-	    (op_a->type == t_invalid && op_a->mode != Addressing_Overload)) {
+Type *check_assignment_variable(Checker *c, Operand *rhs, AstNode *lhs_node) {
+	if (rhs->mode == Addressing_Invalid ||
+	    (rhs->type == t_invalid && rhs->mode != Addressing_Overload)) {
 		return NULL;
 	}
 
-	AstNode *node = unparen_expr(lhs);
+	AstNode *node = unparen_expr(lhs_node);
 
 	// NOTE(bill): Ignore assignments to `_`
 	if (node->kind == AstNode_Ident &&
 	    str_eq(node->Ident.string, str_lit("_"))) {
 		add_entity_definition(&c->info, node, NULL);
-		check_assignment(c, op_a, NULL, str_lit("assignment to `_` identifier"));
-		if (op_a->mode == Addressing_Invalid) {
+		check_assignment(c, rhs, NULL, str_lit("assignment to `_` identifier"));
+		if (rhs->mode == Addressing_Invalid) {
 			return NULL;
 		}
-		return op_a->type;
+		return rhs->type;
 	}
 
 	Entity *e = NULL;
 	bool used = false;
-	Operand op_b = {Addressing_Invalid};
+	Operand lhs = {Addressing_Invalid};
 
 
-	check_expr(c, &op_b, lhs);
-	if (op_b.mode == Addressing_Invalid ||
-	    op_b.type == t_invalid) {
+	check_expr(c, &lhs, lhs_node);
+	if (lhs.mode == Addressing_Invalid ||
+	    lhs.type == t_invalid) {
 		return NULL;
 	}
 
 
-	if (op_a->mode == Addressing_Overload) {
-		isize overload_count = op_a->overload_count;
-		Entity **procs = op_a->overload_entities;
+	if (rhs->mode == Addressing_Overload) {
+		isize overload_count = rhs->overload_count;
+		Entity **procs = rhs->overload_entities;
 		GB_ASSERT(procs != NULL && overload_count > 0);
 
 		// NOTE(bill): These should be done
@@ -227,19 +222,19 @@ Type *check_assignment_variable(Checker *c, Operand *op_a, AstNode *lhs) {
 			Operand x = {0};
 			x.mode = Addressing_Value;
 			x.type = t;
-			if (check_is_assignable_to(c, &x, op_b.type)) {
+			if (check_is_assignable_to(c, &x, lhs.type)) {
 				e = procs[i];
-				add_entity_use(c, op_a->expr, e);
+				add_entity_use(c, rhs->expr, e);
 				break;
 			}
 		}
 
 		if (e != NULL) {
 			// HACK TODO(bill): Should the entities be freed as it's technically a leak
-			op_a->mode = Addressing_Value;
-			op_a->type = e->type;
-			op_a->overload_count = 0;
-			op_a->overload_entities = NULL;
+			rhs->mode = Addressing_Value;
+			rhs->type = e->type;
+			rhs->overload_count = 0;
+			rhs->overload_entities = NULL;
 		}
 	} else {
 		if (node->kind == AstNode_Ident) {
@@ -256,43 +251,60 @@ Type *check_assignment_variable(Checker *c, Operand *op_a, AstNode *lhs) {
 		e->flags |= EntityFlag_Used;
 	}
 
-	Type *assignment_type = op_b.type;
-	switch (op_b.mode) {
+	Type *assignment_type = lhs.type;
+	switch (lhs.mode) {
 	case Addressing_Invalid:
 		return NULL;
+
 	case Addressing_Variable:
-	case Addressing_MapIndex:
 		break;
+	case Addressing_MapIndex: {
+		AstNode *ln = unparen_expr(lhs_node);
+		if (ln->kind == AstNode_IndexExpr) {
+			AstNode *x = ln->IndexExpr.expr;
+			TypeAndValue *tav = type_and_value_of_expression(&c->info, x);
+			GB_ASSERT(tav != NULL);
+			if (tav->mode != Addressing_Variable) {
+				if (!is_type_pointer(tav->type)) {
+					gbString str = expr_to_string(lhs.expr);
+					error_node(lhs.expr, "Cannot assign to the value of a map `%s`", str);
+					gb_string_free(str);
+					return NULL;
+				}
+			}
+		}
+	} break;
+
 	default: {
-		if (op_b.expr->kind == AstNode_SelectorExpr) {
+		if (lhs.expr->kind == AstNode_SelectorExpr) {
 			// NOTE(bill): Extra error checks
 			Operand op_c = {Addressing_Invalid};
-			ast_node(se, SelectorExpr, op_b.expr);
+			ast_node(se, SelectorExpr, lhs.expr);
 			check_expr(c, &op_c, se->expr);
 			if (op_c.mode == Addressing_MapIndex) {
-				gbString str = expr_to_string(op_b.expr);
-				error_node(op_b.expr, "Cannot assign to record field `%s` in map", str);
+				gbString str = expr_to_string(lhs.expr);
+				error_node(lhs.expr, "Cannot assign to record field `%s` in map", str);
 				gb_string_free(str);
 				return NULL;
 			}
 		}
 
-		gbString str = expr_to_string(op_b.expr);
-		if (e != NULL && e->kind == Entity_Variable && e->Variable.is_immutable) {
-			error_node(op_b.expr, "Cannot assign to an immutable: `%s`", str);
+		gbString str = expr_to_string(lhs.expr);
+		if (lhs.mode == Addressing_Immutable) {
+			error_node(lhs.expr, "Cannot assign to an immutable: `%s`", str);
 		} else {
-			error_node(op_b.expr, "Cannot assign to `%s`", str);
+			error_node(lhs.expr, "Cannot assign to `%s`", str);
 		}
 		gb_string_free(str);
 	} break;
 	}
 
-	check_assignment(c, op_a, assignment_type, str_lit("assignment"));
-	if (op_a->mode == Addressing_Invalid) {
+	check_assignment(c, rhs, assignment_type, str_lit("assignment"));
+	if (rhs->mode == Addressing_Invalid) {
 		return NULL;
 	}
 
-	return op_a->type;
+	return rhs->type;
 }
 
 bool check_valid_type_match_type(Type *type, bool *is_union_ptr, bool *is_any) {
@@ -396,12 +408,6 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
 			if (operand.expr->kind == AstNode_CallExpr) {
 				return;
 			}
-			if (operand.expr->kind == AstNode_GiveExpr) {
-				if ((flags&Stmt_GiveAllowed) != 0) {
-					return;
-				}
-				error_node(node, "Illegal use of `give`");
-			}
 			gbString expr_str = expr_to_string(operand.expr);
 			error_node(node, "Expression is not used: `%s`", expr_str);
 			gb_string_free(expr_str);
@@ -419,40 +425,34 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
 		switch (as->op.kind) {
 		case Token_Eq: {
 			// a, b, c = 1, 2, 3;  // Multisided
-			if (as->lhs.count == 0) {
+
+			isize lhs_count = as->lhs.count;
+			if (lhs_count == 0) {
 				error(as->op, "Missing lhs in assignment statement");
 				return;
 			}
 
+			// TODO(bill): This is a very similar to check_init_variables, should I merge the two some how or just
+			// leave it?
+
 			gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena);
 
 			// NOTE(bill): If there is a bad syntax error, rhs > lhs which would mean there would need to be
 			// an extra allocation
-			Array(Operand) operands;
-			array_init_reserve(&operands, c->tmp_allocator, 2 * as->lhs.count);
+			ArrayOperand operands = {0};
+			array_init_reserve(&operands, c->tmp_allocator, 2 * lhs_count);
+			check_unpack_arguments(c, lhs_count, &operands, as->rhs, true);
 
-			for_array(i, as->rhs) {
-				AstNode *rhs = as->rhs.e[i];
-				Operand o = {0};
-				check_multi_expr(c, &o, rhs);
-				if (o.type->kind != Type_Tuple) {
-					array_add(&operands, o);
-				} else {
-					TypeTuple *tuple = &o.type->Tuple;
-					for (isize j = 0; j < tuple->variable_count; j++) {
-						o.type = tuple->variables[j]->type;
-						array_add(&operands, o);
-					}
+			isize rhs_count = operands.count;
+			for_array(i, operands) {
+				if (operands.e[i].mode == Addressing_Invalid) {
+					rhs_count--;
 				}
 			}
 
-			isize lhs_count = as->lhs.count;
-			isize rhs_count = operands.count;
-
-			isize operand_count = gb_min(as->lhs.count, operands.count);
-			for (isize i = 0; i < operand_count; i++) {
-				AstNode *lhs = as->lhs.e[i];
-				check_assignment_variable(c, &operands.e[i], lhs);
+			isize max = gb_min(lhs_count, rhs_count);
+			for (isize i = 0; i < max; i++) {
+				check_assignment_variable(c, &operands.e[i], as->lhs.e[i]);
 			}
 			if (lhs_count != rhs_count) {
 				error_node(as->lhs.e[0], "Assignment count mismatch `%td` = `%td`", lhs_count, rhs_count);

+ 41 - 32
src/checker.c

@@ -106,29 +106,29 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_Count] = {
 };
 
 
+#include "types.c"
 
 typedef enum AddressingMode {
-	Addressing_Invalid,
-
-	Addressing_NoValue,
-	Addressing_Value,
-	Addressing_Variable,
-	Addressing_Constant,
-	Addressing_Type,
-	Addressing_Builtin,
-	Addressing_Overload,
-	Addressing_MapIndex,
-
-	Addressing_Count,
+	Addressing_Invalid,    // invalid addressing mode
+	Addressing_NoValue,    // no value (void in C)
+	Addressing_Value,      // computed value (rvalue)
+	Addressing_Immutable,  // immutable computed value (const rvalue)
+	Addressing_Variable,   // addressable variable (lvalue)
+	Addressing_Constant,   // constant & type will be a of Type_Basic (stripping Type_Named)
+	Addressing_Type,       // type
+	Addressing_Builtin,    // built in procedure
+	Addressing_Overload,   // overloaded procedure
+	Addressing_MapIndex,   // map index expression -
+	                       // 	lhs: acts like a Variable
+	                       // 	rhs: acts like OptionalOk
+	Addressing_OptionalOk, // rhs: acts like a value with an optional boolean part (for existence check)
 } AddressingMode;
 
-#include "types.c"
-
-#define MAP_TYPE Entity *
-#define MAP_PROC map_entity_
-#define MAP_NAME MapEntity
-#include "map.c"
-
+// Operand is used as an intermediate value whilst checking
+// Operands store an addressing mode, the expression being evaluated,
+// its type and node, and other specific information for certain
+// addressing modes
+// Its zero-value is a valid "invalid operand"
 typedef struct Operand {
 	AddressingMode mode;
 	Type *         type;
@@ -149,7 +149,9 @@ bool is_operand_value(Operand o) {
 	switch (o.mode) {
 	case Addressing_Value:
 	case Addressing_Variable:
+	case Addressing_Immutable:
 	case Addressing_Constant:
+	case Addressing_MapIndex:
 		return true;
 	}
 	return false;
@@ -159,7 +161,7 @@ bool is_operand_nil(Operand o) {
 }
 
 
-
+// DeclInfo is used to store information of certain declarations to allow for "any order" usage
 typedef struct DeclInfo {
 	Scope *scope;
 
@@ -173,6 +175,17 @@ typedef struct DeclInfo {
 	MapBool deps; // Key: Entity *
 } DeclInfo;
 
+// ProcedureInfo stores the information needed for checking a procedure
+typedef struct ProcedureInfo {
+	AstFile * file;
+	Token     token;
+	DeclInfo *decl;
+	Type *    type; // Type_Procedure
+	AstNode * body; // AstNode_BlockStmt
+	u32       tags;
+} ProcedureInfo;
+
+// ExprInfo stores information used for "untyped" expressions
 typedef struct ExprInfo {
 	bool           is_lhs; // Debug info
 	AddressingMode mode;
@@ -185,14 +198,12 @@ ExprInfo make_expr_info(bool is_lhs, AddressingMode mode, Type *type, ExactValue
 	return ei;
 }
 
-typedef struct ProcedureInfo {
-	AstFile * file;
-	Token     token;
-	DeclInfo *decl;
-	Type *    type; // Type_Procedure
-	AstNode * body; // AstNode_BlockStmt
-	u32       tags;
-} ProcedureInfo;
+
+
+#define MAP_TYPE Entity *
+#define MAP_PROC map_entity_
+#define MAP_NAME MapEntity
+#include "map.c"
 
 typedef struct Scope {
 	Scope *        parent;
@@ -256,7 +267,7 @@ typedef struct CheckerContext {
 	Type *     type_hint;
 } CheckerContext;
 
-// NOTE(bill): Symbol tables
+// CheckerInfo stores all the symbol information for a type-checked program
 typedef struct CheckerInfo {
 	MapTypeAndValue      types;           // Key: AstNode * | Expression -> Type (and value)
 	MapEntity            definitions;     // Key: AstNode * | Identifier -> Entity
@@ -389,9 +400,7 @@ void check_open_scope(Checker *c, AstNode *node) {
 	node = unparen_expr(node);
 	GB_ASSERT(node->kind == AstNode_Invalid ||
 	          is_ast_node_stmt(node) ||
-	          is_ast_node_type(node) ||
-	          node->kind == AstNode_BlockExpr ||
-	          node->kind == AstNode_IfExpr );
+	          is_ast_node_type(node));
 	Scope *scope = make_scope(c->context.scope, c->allocator);
 	add_scope(c, node, scope);
 	if (node->kind == AstNode_ProcType) {

+ 3 - 0
src/common.c

@@ -131,6 +131,9 @@ i16 f32_to_f16(f32 value) {
 //
 ////////////////////////////////////////////////////////////////
 
+typedef Array(i32)   Array_i32;
+typedef Array(isize) Array_isize;
+
 
 #define MAP_TYPE String
 #define MAP_PROC map_string_

+ 6 - 3
src/entity.c

@@ -40,12 +40,15 @@ typedef enum EntityFlag {
 	EntityFlag_TypeField  = 1<<8,
 } EntityFlag;
 
+// Zero value means the overloading process is not yet done
 typedef enum OverloadKind {
-	Overload_No      = -1,
-	Overload_Unknown = 0,
-	Overload_Yes     = +1,
+	Overload_Unknown,
+	Overload_No,
+	Overload_Yes,
 } OverloadKind;
 
+
+// An Entity is a named "thing" in the language
 typedef struct Entity Entity;
 struct Entity {
 	EntityKind kind;

+ 61 - 64
src/ir.c

@@ -2462,13 +2462,19 @@ irValue *ir_emit_down_cast(irProcedure *proc, irValue *value, Type *t) {
 	return ir_emit_conv(proc, head, t);
 }
 
-irValue *ir_emit_union_cast(irProcedure *proc, irValue *value, Type *tuple) {
-	GB_ASSERT(tuple->kind == Type_Tuple);
+irValue *ir_emit_union_cast(irProcedure *proc, irValue *value, Type *type, TokenPos pos) {
 	gbAllocator a = proc->module->allocator;
 
 	Type *src_type = ir_type(value);
 	bool is_ptr = is_type_pointer(src_type);
 
+	bool is_tuple = true;
+	Type *tuple = type;
+	if (type->kind != Type_Tuple) {
+		is_tuple = false;
+		tuple = make_optional_ok_type(a, type);
+	}
+
 	irValue *v = ir_add_local_generated(proc, tuple);
 
 	if (is_ptr) {
@@ -2541,6 +2547,25 @@ irValue *ir_emit_union_cast(irProcedure *proc, irValue *value, Type *tuple) {
 		ir_start_block(proc, end_block);
 
 	}
+
+	if (!is_tuple) {
+		// NOTE(bill): Panic on invalid conversion
+		Type *dst_type = tuple->Tuple.variables[0]->type;
+
+		irValue *ok = ir_emit_load(proc, ir_emit_struct_ep(proc, v, 1));
+		irValue **args = gb_alloc_array(a, irValue *, 6);
+		args[0] = ok;
+
+		args[1] = ir_make_const_string(a, pos.file);
+		args[2] = ir_make_const_int(a, pos.line);
+		args[3] = ir_make_const_int(a, pos.column);
+
+		args[4] = ir_type_info(proc, src_type);
+		args[5] = ir_type_info(proc, dst_type);
+		ir_emit_global_call(proc, "__union_cast_check", args, 6);
+
+		return ir_emit_load(proc, ir_emit_struct_ep(proc, v, 0));
+	}
 	return ir_emit_load(proc, v);
 }
 
@@ -2826,25 +2851,40 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
 		return ir_addr_load(proc, ir_build_addr(proc, expr));
 	case_end;
 
-	case_ast_node(be, BlockExpr, expr);
-		ir_emit_comment(proc, str_lit("BlockExpr"));
-		ir_open_scope(proc);
+	case_ast_node(te, TernaryExpr, expr);
+		ir_emit_comment(proc, str_lit("TernaryExpr"));
+
+		irValueArray edges = {0};
+		array_init_reserve(&edges, proc->module->allocator, 2);
 
-		AstNodeArray stmts = be->stmts;
-		stmts.count--;
-		ir_build_stmt_list(proc, stmts);
+		GB_ASSERT(te->y != NULL);
+		irBlock *then  = ir_new_block(proc, NULL, "if.then");
+		irBlock *done  = ir_new_block(proc, NULL, "if.done"); // NOTE(bill): Append later
+		irBlock *else_ = ir_new_block(proc, NULL, "if.else");
 
-		AstNode *give_stmt = be->stmts.e[be->stmts.count-1];
-		GB_ASSERT(give_stmt->kind == AstNode_ExprStmt);
-		AstNode *give_expr = give_stmt->ExprStmt.expr;
-		GB_ASSERT(give_expr->kind == AstNode_GiveExpr);
-		irValue *value = ir_build_expr(proc, give_expr);
+		irValue *cond = ir_build_cond(proc, te->cond, then, else_);
+		ir_start_block(proc, then);
 
+		ir_open_scope(proc);
+		array_add(&edges, ir_build_expr(proc, te->x));
 		ir_close_scope(proc, irDeferExit_Default, NULL);
 
-		return value;
+		ir_emit_jump(proc, done);
+		ir_start_block(proc, else_);
+
+		ir_open_scope(proc);
+		array_add(&edges, ir_build_expr(proc, te->y));
+		ir_close_scope(proc, irDeferExit_Default, NULL);
+
+		ir_emit_jump(proc, done);
+		ir_start_block(proc, done);
+
+		Type *type = type_of_expr(proc->module->info, expr);
+
+		return ir_emit(proc, ir_make_instr_phi(proc, edges, type));
 	case_end;
 
+#if 0
 	case_ast_node(ie, IfExpr, expr);
 		ir_emit_comment(proc, str_lit("IfExpr"));
 		if (ie->init != NULL) {
@@ -2883,70 +2923,27 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
 
 		return ir_emit(proc, ir_make_instr_phi(proc, edges, type));
 	case_end;
-
-	case_ast_node(ge, GiveExpr, expr);
-		ir_emit_comment(proc, str_lit("GiveExpr"));
-
-		irValue *v = NULL;
-		Type *give_type = type_of_expr(proc->module->info, expr);
-		GB_ASSERT(give_type != NULL);
-		if (give_type->kind != Type_Tuple) {
-			v = ir_emit_conv(proc, ir_build_expr(proc, ge->results.e[0]), give_type);
-		} else {
-			TypeTuple *tuple = &give_type->Tuple;
-			gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&proc->module->tmp_arena);
-
-			irValueArray results;
-			array_init_reserve(&results, proc->module->tmp_allocator, tuple->variable_count);
-
-			for_array(res_index, ge->results) {
-				irValue *res = ir_build_expr(proc, ge->results.e[res_index]);
-				Type *t = ir_type(res);
-				if (t->kind == Type_Tuple) {
-					for (isize i = 0; i < t->Tuple.variable_count; i++) {
-						Entity *e = t->Tuple.variables[i];
-						irValue *v = ir_emit_struct_ev(proc, res, i);
-						array_add(&results, v);
-					}
-				} else {
-					array_add(&results, res);
-				}
-			}
-
-			v = ir_add_local_generated(proc, give_type);
-			for_array(i, results) {
-				Entity *e = tuple->variables[i];
-				irValue *res = ir_emit_conv(proc, results.e[i], e->type);
-				irValue *field = ir_emit_struct_ep(proc, v, i);
-				ir_emit_store(proc, field, res);
-			}
-			v = ir_emit_load(proc, v);
-
-			gb_temp_arena_memory_end(tmp);
-		}
-
-		return v;
-	case_end;
+#endif
 
 	case_ast_node(ce, CastExpr, expr);
 		Type *type = tv->type;
-		irValue *expr = ir_build_expr(proc, ce->expr);
+		irValue *e = ir_build_expr(proc, ce->expr);
 		switch (ce->token.kind) {
 		case Token_cast:
 			ir_emit_comment(proc, str_lit("cast - cast"));
-			return ir_emit_conv(proc, expr, type);
+			return ir_emit_conv(proc, e, type);
 
 		case Token_transmute:
 			ir_emit_comment(proc, str_lit("cast - transmute"));
-			return ir_emit_transmute(proc, expr, type);
+			return ir_emit_transmute(proc, e, type);
 
 		case Token_down_cast:
 			ir_emit_comment(proc, str_lit("cast - down_cast"));
-			return ir_emit_down_cast(proc, expr, type);
+			return ir_emit_down_cast(proc, e, type);
 
 		case Token_union_cast:
 			ir_emit_comment(proc, str_lit("cast - union_cast"));
-			return ir_emit_union_cast(proc, expr, type);
+			return ir_emit_union_cast(proc, e, type, ast_node_token(expr).pos);
 
 		default:
 			GB_PANIC("Unknown cast expression");
@@ -3384,7 +3381,7 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
 					args[1] = ir_make_const_int(proc->module->allocator, pos.line);
 					args[2] = ir_make_const_int(proc->module->allocator, pos.column);
 					args[3] = msg;
-					ir_emit_global_call(proc, "__assert", args, 4);
+					ir_emit_global_call(proc, "__panic", args, 4);
 
 					return NULL;
 				} break;

+ 3 - 0
src/map.c

@@ -6,6 +6,9 @@
 	#define MAP_NAME MapString
 	#include "map.c"
 */
+// A `Map` is an unordered hash table which can allow for a key to point to multiple values
+// with the use of the `multi_*` procedures.
+// TODO(bill): I should probably allow the `multi_*` stuff to be #ifdefed out
 
 #ifndef MAP_UTIL_STUFF
 #define MAP_UTIL_STUFF

+ 136 - 156
src/parser.c

@@ -111,7 +111,9 @@ AstNodeArray make_ast_node_array(AstFile *f) {
 }
 
 
-
+// NOTE(bill): This massive define is so it is possible to create a discriminated union (and extra debug info)
+// for the AstNode. I personally prefer discriminated unions over subtype polymorphism as I can preallocate
+// all the nodes and even memcpy in a different kind of node
 #define AST_NODE_KINDS \
 	AST_NODE_KIND(Ident,          "identifier",      Token) \
 	AST_NODE_KIND(Implicit,       "implicit",        Token) \
@@ -166,24 +168,9 @@ AST_NODE_KIND(_ExprBegin,  "",  i32) \
 		Token        open; \
 		Token        close; \
 	}) \
-	AST_NODE_KIND(CastExpr, "cast expression", struct { Token token; AstNode *type, *expr; Token open, close; }) \
-	AST_NODE_KIND(FieldValue, "field value", struct { Token eq; AstNode *field, *value; }) \
-	AST_NODE_KIND(BlockExpr, "block expr", struct { \
-		AstNodeArray stmts; \
-		Token open, close; \
-		AstNode *give_node; \
-	}) \
-	AST_NODE_KIND(GiveExpr, "give expression", struct { \
-		Token token; \
-		AstNodeArray results; \
-	}) \
-	AST_NODE_KIND(IfExpr, "if expression", struct { \
-		Token token; \
-		AstNode *init; \
-		AstNode *cond; \
-		AstNode *body; \
-		AstNode *else_expr; \
-	}) \
+	AST_NODE_KIND(CastExpr,     "cast expression",     struct { Token token; AstNode *type, *expr; Token open, close; }) \
+	AST_NODE_KIND(FieldValue,   "field value",         struct { Token eq; AstNode *field, *value; }) \
+	AST_NODE_KIND(TernaryExpr,  "ternary expression",  struct { AstNode *cond, *x, *y; }) \
 	AST_NODE_KIND(IntervalExpr, "interval expression", struct { Token op; AstNode *left, *right; }) \
 AST_NODE_KIND(_ExprEnd,       "", i32) \
 AST_NODE_KIND(_StmtBegin,     "", i32) \
@@ -463,9 +450,7 @@ Token ast_node_token(AstNode *node) {
 	case AstNode_CastExpr:     return node->CastExpr.token;
 	case AstNode_FieldValue:   return node->FieldValue.eq;
 	case AstNode_DerefExpr:    return node->DerefExpr.op;
-	case AstNode_BlockExpr:    return node->BlockExpr.open;
-	case AstNode_GiveExpr:     return node->GiveExpr.token;
-	case AstNode_IfExpr:       return node->IfExpr.token;
+	case AstNode_TernaryExpr:  return ast_node_token(node->TernaryExpr.cond);
 	case AstNode_IntervalExpr: return ast_node_token(node->IntervalExpr.left);
 
 	case AstNode_BadStmt:       return node->BadStmt.begin;
@@ -766,29 +751,11 @@ AstNode *ast_compound_lit(AstFile *f, AstNode *type, AstNodeArray elems, Token o
 	return result;
 }
 
-
-AstNode *ast_block_expr(AstFile *f, AstNodeArray stmts, Token open, Token close) {
-	AstNode *result = make_ast_node(f, AstNode_BlockExpr);
-	result->BlockExpr.stmts = stmts;
-	result->BlockExpr.open = open;
-	result->BlockExpr.close = close;
-	return result;
-}
-
-AstNode *ast_give_expr(AstFile *f, Token token, AstNodeArray results) {
-	AstNode *result = make_ast_node(f, AstNode_GiveExpr);
-	result->GiveExpr.token = token;
-	result->GiveExpr.results = results;
-	return result;
-}
-
-AstNode *ast_if_expr(AstFile *f, Token token, AstNode *init, AstNode *cond, AstNode *body, AstNode *else_expr) {
-	AstNode *result = make_ast_node(f, AstNode_IfExpr);
-	result->IfExpr.token = token;
-	result->IfExpr.init = init;
-	result->IfExpr.cond = cond;
-	result->IfExpr.body = body;
-	result->IfExpr.else_expr = else_expr;
+AstNode *ast_ternary_expr(AstFile *f, AstNode *cond, AstNode *x, AstNode *y) {
+	AstNode *result = make_ast_node(f, AstNode_TernaryExpr);
+	result->TernaryExpr.cond = cond;
+	result->TernaryExpr.x = x;
+	result->TernaryExpr.y = y;
 	return result;
 }
 
@@ -1319,13 +1286,13 @@ void expect_semicolon(AstFile *f, AstNode *s) {
 				return;
 			}
 		} else {
-			switch (s->kind) {
-			case AstNode_GiveExpr:
-				if (f->curr_token.kind == Token_CloseBrace) {
-					return;
-				}
-				break;
-			}
+			// switch (s->kind) {
+			// case AstNode_GiveExpr:
+			// 	if (f->curr_token.kind == Token_CloseBrace) {
+			// 		return;
+			// 	}
+			// 	break;
+			// }
 		}
 		syntax_error(prev_token, "Expected `;` after %.*s, got %.*s",
 		             LIT(ast_node_strings[s->kind]), LIT(token_strings[prev_token.kind]));
@@ -1610,72 +1577,72 @@ AstNode *convert_stmt_to_expr(AstFile *f, AstNode *statement, String kind) {
 
 
 
-AstNode *parse_block_expr(AstFile *f) {
-	AstNodeArray stmts = {0};
-	Token open, close;
-	open = expect_token(f, Token_OpenBrace);
-	f->expr_level++;
-	stmts = parse_stmt_list(f);
-	f->expr_level--;
-	close = expect_token(f, Token_CloseBrace);
-	return ast_block_expr(f, stmts, open, close);
-}
-
-AstNode *parse_if_expr(AstFile *f) {
-	if (f->curr_proc == NULL) {
-		syntax_error(f->curr_token, "You cannot use an if expression in the file scope");
-		return ast_bad_stmt(f, f->curr_token, f->curr_token);
-	}
-
-	Token token = expect_token(f, Token_if);
-	AstNode *init = NULL;
-	AstNode *cond = NULL;
-	AstNode *body = NULL;
-	AstNode *else_expr = NULL;
-
-	isize prev_level = f->expr_level;
-	f->expr_level = -1;
-
-	if (allow_token(f, Token_Semicolon)) {
-		cond = parse_expr(f, false);
-	} else {
-		init = parse_simple_stmt(f, false);
-		if (allow_token(f, Token_Semicolon)) {
-			cond = parse_expr(f, false);
-		} else {
-			cond = convert_stmt_to_expr(f, init, str_lit("boolean expression"));
-			init = NULL;
-		}
-	}
-
-	f->expr_level = prev_level;
-
-	if (cond == NULL) {
-		syntax_error(f->curr_token, "Expected condition for if statement");
-	}
-
-	body = parse_block_expr(f);
-
-	if (allow_token(f, Token_else)) {
-		switch (f->curr_token.kind) {
-		case Token_if:
-			else_expr = parse_if_expr(f);
-			break;
-		case Token_OpenBrace:
-			else_expr = parse_block_expr(f);
-			break;
-		default:
-			syntax_error(f->curr_token, "Expected if expression block statement");
-			else_expr = ast_bad_expr(f, f->curr_token, f->tokens.e[f->curr_token_index+1]);
-			break;
-		}
-	} else {
-		syntax_error(f->curr_token, "An if expression must have an else clause");
-		return ast_bad_stmt(f, f->curr_token, f->tokens.e[f->curr_token_index+1]);
-	}
-
-	return ast_if_expr(f, token, init, cond, body, else_expr);
-}
+// AstNode *parse_block_expr(AstFile *f) {
+// 	AstNodeArray stmts = {0};
+// 	Token open, close;
+// 	open = expect_token(f, Token_OpenBrace);
+// 	f->expr_level++;
+// 	stmts = parse_stmt_list(f);
+// 	f->expr_level--;
+// 	close = expect_token(f, Token_CloseBrace);
+// 	return ast_block_expr(f, stmts, open, close);
+// }
+
+// AstNode *parse_if_expr(AstFile *f) {
+// 	if (f->curr_proc == NULL) {
+// 		syntax_error(f->curr_token, "You cannot use an if expression in the file scope");
+// 		return ast_bad_stmt(f, f->curr_token, f->curr_token);
+// 	}
+
+// 	Token token = expect_token(f, Token_if);
+// 	AstNode *init = NULL;
+// 	AstNode *cond = NULL;
+// 	AstNode *body = NULL;
+// 	AstNode *else_expr = NULL;
+
+// 	isize prev_level = f->expr_level;
+// 	f->expr_level = -1;
+
+// 	if (allow_token(f, Token_Semicolon)) {
+// 		cond = parse_expr(f, false);
+// 	} else {
+// 		init = parse_simple_stmt(f, false);
+// 		if (allow_token(f, Token_Semicolon)) {
+// 			cond = parse_expr(f, false);
+// 		} else {
+// 			cond = convert_stmt_to_expr(f, init, str_lit("boolean expression"));
+// 			init = NULL;
+// 		}
+// 	}
+
+// 	f->expr_level = prev_level;
+
+// 	if (cond == NULL) {
+// 		syntax_error(f->curr_token, "Expected condition for if statement");
+// 	}
+
+// 	body = parse_block_expr(f);
+
+// 	if (allow_token(f, Token_else)) {
+// 		switch (f->curr_token.kind) {
+// 		case Token_if:
+// 			else_expr = parse_if_expr(f);
+// 			break;
+// 		case Token_OpenBrace:
+// 			else_expr = parse_block_expr(f);
+// 			break;
+// 		default:
+// 			syntax_error(f->curr_token, "Expected if expression block statement");
+// 			else_expr = ast_bad_expr(f, f->curr_token, f->tokens.e[f->curr_token_index+1]);
+// 			break;
+// 		}
+// 	} else {
+// 		syntax_error(f->curr_token, "An if expression must have an else clause");
+// 		return ast_bad_stmt(f, f->curr_token, f->tokens.e[f->curr_token_index+1]);
+// 	}
+
+// 	return ast_if_expr(f, token, init, cond, body, else_expr);
+// }
 
 AstNode *parse_operand(AstFile *f, bool lhs) {
 	AstNode *operand = NULL; // Operand
@@ -1789,16 +1756,16 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
 		return type;
 	}
 
-	case Token_if:
-		if (!lhs && f->expr_level >= 0) {
-			return parse_if_expr(f);
-		}
-		break;
-	case Token_OpenBrace:
-		if (!lhs && f->expr_level >= 0) {
-			return parse_block_expr(f);
-		}
-		break;
+	// case Token_if:
+	// 	if (!lhs && f->expr_level >= 0) {
+	// 		return parse_if_expr(f);
+	// 	}
+	// 	break;
+	// case Token_OpenBrace:
+	// 	if (!lhs && f->expr_level >= 0) {
+	// 		return parse_block_expr(f);
+	// 	}
+	// 	break;
 
 	default: {
 		AstNode *type = parse_type_or_ident(f);
@@ -1982,6 +1949,19 @@ AstNode *parse_atom_expr(AstFile *f, bool lhs) {
 			}
 			break;
 
+		case Token_Question:
+			if (!lhs && operand != NULL && f->expr_level >= 0) {
+				AstNode *cond = operand;
+				Token token_q = expect_token(f, Token_Question);
+				AstNode *x = parse_expr(f, false);
+				Token token_c = expect_token(f, Token_Colon);
+				AstNode *y = parse_expr(f, false);
+				operand = ast_ternary_expr(f, cond, x, y);
+			} else {
+				loop = false;
+			}
+			break;
+
 		default:
 			loop = false;
 			break;
@@ -2358,7 +2338,7 @@ bool is_token_field_prefix(TokenKind kind) {
 	switch (kind) {
 	case Token_using:
 	case Token_no_alias:
-	// case Token_immutable:
+	case Token_immutable:
 		return true;
 	}
 	return false;
@@ -2374,7 +2354,7 @@ u32 parse_field_prefixes(AstFile *f) {
 		switch (f->curr_token.kind) {
 		case Token_using:     using_count     += 1; next_token(f); break;
 		case Token_no_alias:  no_alias_count  += 1; next_token(f); break;
-		// case Token_immutable: immutable_count += 1; next_token(f); break;
+		case Token_immutable: immutable_count += 1; next_token(f); break;
 		}
 	}
 	if (using_count     > 1) syntax_error(f->curr_token, "Multiple `using` in this field list");
@@ -2572,8 +2552,8 @@ AstNode *parse_type_or_ident(AstFile *f) {
 		AstNode *count_expr = NULL;
 		bool is_vector = false;
 
-		if (f->curr_token.kind == Token_Question) {
-			count_expr = ast_unary_expr(f, expect_token(f, Token_Question), NULL);
+		if (f->curr_token.kind == Token_Ellipsis) {
+			count_expr = ast_unary_expr(f, expect_token(f, Token_Ellipsis), NULL);
 		} else if (f->curr_token.kind == Token_vector) {
 			next_token(f);
 			if (f->curr_token.kind != Token_CloseBracket) {
@@ -2584,7 +2564,7 @@ AstNode *parse_type_or_ident(AstFile *f) {
 				syntax_error(f->curr_token, "Vector type missing count");
 			}
 			is_vector = true;
-		} else if (f->curr_token.kind == Token_Ellipsis) {
+		} else if (f->curr_token.kind == Token_dynamic) {
 			next_token(f);
 			expect_token(f, Token_CloseBracket);
 			return ast_dynamic_array_type(f, token, parse_type(f));
@@ -2923,27 +2903,27 @@ AstNode *parse_return_stmt(AstFile *f) {
 }
 
 
-AstNode *parse_give_stmt(AstFile *f) {
-	if (f->curr_proc == NULL) {
-		syntax_error(f->curr_token, "You cannot use a give statement in the file scope");
-		return ast_bad_stmt(f, f->curr_token, f->curr_token);
-	}
-	if (f->expr_level == 0) {
-		syntax_error(f->curr_token, "A give statement must be used within an expression");
-		return ast_bad_stmt(f, f->curr_token, f->curr_token);
-	}
-
-	Token token = expect_token(f, Token_give);
-	AstNodeArray results;
-	if (f->curr_token.kind != Token_Semicolon && f->curr_token.kind != Token_CloseBrace) {
-		results = parse_rhs_expr_list(f);
-	} else {
-		results = make_ast_node_array(f);
-	}
-	AstNode *ge = ast_give_expr(f, token, results);
-	expect_semicolon(f, ge);
-	return ast_expr_stmt(f, ge);
-}
+// AstNode *parse_give_stmt(AstFile *f) {
+// 	if (f->curr_proc == NULL) {
+// 		syntax_error(f->curr_token, "You cannot use a give statement in the file scope");
+// 		return ast_bad_stmt(f, f->curr_token, f->curr_token);
+// 	}
+// 	if (f->expr_level == 0) {
+// 		syntax_error(f->curr_token, "A give statement must be used within an expression");
+// 		return ast_bad_stmt(f, f->curr_token, f->curr_token);
+// 	}
+
+// 	Token token = expect_token(f, Token_give);
+// 	AstNodeArray results;
+// 	if (f->curr_token.kind != Token_Semicolon && f->curr_token.kind != Token_CloseBrace) {
+// 		results = parse_rhs_expr_list(f);
+// 	} else {
+// 		results = make_ast_node_array(f);
+// 	}
+// 	AstNode *ge = ast_give_expr(f, token, results);
+// 	expect_semicolon(f, ge);
+// 	return ast_expr_stmt(f, ge);
+// }
 
 AstNode *parse_for_stmt(AstFile *f) {
 	if (f->curr_proc == NULL) {
@@ -3225,7 +3205,7 @@ AstNode *parse_stmt(AstFile *f) {
 	case Token_defer:  return parse_defer_stmt(f);
 	case Token_asm:    return parse_asm_stmt(f);
 	case Token_return: return parse_return_stmt(f);
-	case Token_give:   return parse_give_stmt(f);
+	// case Token_give:   return parse_give_stmt(f);
 
 	case Token_break:
 	case Token_continue:
@@ -3272,7 +3252,7 @@ AstNode *parse_stmt(AstFile *f) {
 		return ast_bad_stmt(f, token, f->curr_token);
 	} break;
 
-#if 0
+#if 1
 	case Token_immutable: {
 		Token token = expect_token(f, Token_immutable);
 		AstNode *node = parse_stmt(f);

+ 1 - 0
src/string.c

@@ -19,6 +19,7 @@ typedef struct String {
 #define str_lit(c_str) (String){cast(u8 *)c_str, gb_size_of(c_str)-1}
 
 
+// NOTE(bill): String16 is only used for Windows due to its file directories
 typedef struct String16 {
 	wchar_t *text;
 	isize    len;

+ 3 - 0
src/tokenizer.c

@@ -99,9 +99,12 @@ TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
 	TOKEN_KIND(Token_raw_union,      "raw_union"),           \
 	TOKEN_KIND(Token_enum,           "enum"),                \
 	TOKEN_KIND(Token_vector,         "vector"),              \
+	TOKEN_KIND(Token_static,         "static"),              \
+	TOKEN_KIND(Token_dynamic,        "dynamic"),             \
 	TOKEN_KIND(Token_map,            "map"),                 \
 	TOKEN_KIND(Token_using,          "using"),               \
 	TOKEN_KIND(Token_no_alias,       "no_alias"),            \
+	TOKEN_KIND(Token_immutable,      "immutable"),           \
 	TOKEN_KIND(Token_cast,           "cast"),                \
 	TOKEN_KIND(Token_transmute,      "transmute"),           \
 	TOKEN_KIND(Token_down_cast,      "down_cast"),           \

+ 9 - 8
src/types.c

@@ -178,8 +178,9 @@ typedef struct Type {
 	bool failure;
 } Type;
 
-typedef Array(i32) Array_i32;
 
+// TODO(bill): Should I add extra information here specifying the kind of selection?
+// e.g. field, constant, vector field, type field, etc.
 typedef struct Selection {
 	Entity *  entity;
 	Array_i32 index;
@@ -195,6 +196,7 @@ Selection make_selection(Entity *entity, Array_i32 index, bool indirect) {
 void selection_add_index(Selection *s, isize index) {
 	// IMPORTANT NOTE(bill): this requires a stretchy buffer/dynamic array so it requires some form
 	// of heap allocation
+	// TODO(bill): Find a way to use a backing buffer for initial use as the general case is probably .count<3
 	if (s->index.e == NULL) {
 		array_init(&s->index, heap_allocator());
 	}
@@ -277,6 +279,7 @@ gb_global Type *t_byte_slice = NULL;
 gb_global Type *t_string_slice = NULL;
 
 
+// Type generated for the "preload" file
 gb_global Type *t_type_info                = NULL;
 gb_global Type *t_type_info_record         = NULL;
 gb_global Type *t_type_info_enum_value     = NULL;
@@ -303,7 +306,6 @@ gb_global Type *t_type_info_raw_union     = NULL;
 gb_global Type *t_type_info_enum          = NULL;
 gb_global Type *t_type_info_map           = NULL;
 
-
 gb_global Type *t_type_info_named_ptr         = NULL;
 gb_global Type *t_type_info_integer_ptr       = NULL;
 gb_global Type *t_type_info_float_ptr         = NULL;
@@ -323,8 +325,6 @@ gb_global Type *t_type_info_raw_union_ptr     = NULL;
 gb_global Type *t_type_info_enum_ptr          = NULL;
 gb_global Type *t_type_info_map_ptr           = NULL;
 
-
-
 gb_global Type *t_allocator            = NULL;
 gb_global Type *t_allocator_ptr        = NULL;
 gb_global Type *t_context              = NULL;
@@ -337,14 +337,15 @@ gb_global Type *t_map_header            = NULL;
 
 
 
-i64 type_size_of  (gbAllocator allocator, Type *t);
-i64 type_align_of (gbAllocator allocator, Type *t);
-i64 type_offset_of(gbAllocator allocator, Type *t, i32 index);
-
 
 
+i64     type_size_of   (gbAllocator allocator, Type *t);
+i64     type_align_of  (gbAllocator allocator, Type *t);
+i64     type_offset_of (gbAllocator allocator, Type *t, i32 index);
 gbString type_to_string(Type *type);
 
+
+
 Type *base_type(Type *t) {
 	for (;;) {
 		if (t == NULL) {