Browse Source

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

Zachary Pierson 8 years ago
parent
commit
cad46ae51c
17 changed files with 486 additions and 572 deletions
  1. 38 39
      code/demo.odin
  2. 1 1
      code/http_test.odin
  3. 24 21
      core/_preload.odin
  4. 16 26
      core/fmt.odin
  5. 0 4
      core/math.odin
  6. 36 37
      core/mem.odin
  7. 4 3
      core/sys/windows.odin
  8. 24 24
      core/types.odin
  9. 12 9
      src/check_expr.c
  10. 25 5
      src/check_stmt.c
  11. 53 46
      src/checker.c
  12. 1 0
      src/entity.c
  13. 98 72
      src/ir.c
  14. 0 21
      src/ir_print.c
  15. 38 80
      src/parser.c
  16. 85 124
      src/tokenizer.c
  17. 31 60
      src/types.c

+ 38 - 39
code/demo.odin

@@ -10,17 +10,28 @@
 #import ht "http_test.odin";
 
 main :: proc() {
+	{
+		Fruit :: enum {
+			APPLE,
+			BANANA,
+			COCONUT,
+		}
+
+		fmt.println(Fruit.names);
+	}
+
+when false {
 	{
 		m: map[f32]int;
-		reserve(^m, 16);
+		reserve(m, 16);
 		defer free(m);
 
 		m[1.0] = 1278;
 		m[2.0] = 7643;
 		m[3.0] = 564;
-		c := m[3.0];
 		_, ok := m[3.0];
-		// assert(ok && c == 564);
+		c := m[3.0];
+		assert(ok && c == 564);
 
 		fmt.print("map[");
 		i := 0;
@@ -28,7 +39,7 @@ main :: proc() {
 			if i > 0 {
 				fmt.print(", ");
 			}
-			fmt.printf("%f=%v", key, val);
+			fmt.printf("%v=%v", key, val);
 			i += 1;
 		}
 		fmt.println("]");
@@ -48,48 +59,36 @@ main :: proc() {
 		fmt.println(m);
 	}
 
-
-
-	// fm: map[128, int]f32;
-
-/*
 	{
-		sig: u32;
-		x := __cpuid(0, ^sig);
-		fmt.println(sig, x);
-	}
-
-
-
-	i: int;
-
-	fmt.println("Hellope!");
+		fmt.println("Hellope!");
 
-	x: [dynamic]f64;
-	defer free(x);
-	append(^x, 2_000_000.500_000, 3, 5, 7);
+		x: [dynamic]f64;
+		reserve(x, 16);
+		defer free(x);
+		append(x, 2_000_000.500_000, 3, 5, 7);
 
-	for p, i in x {
-		if i > 0 { fmt.print(", "); }
-		fmt.print(p);
-	}
-	fmt.println();
+		for p, i in x {
+			if i > 0 { fmt.print(", "); }
+			fmt.print(p);
+		}
+		fmt.println();
 
-	{
-		Vec3 :: [vector 3]f32;
+		{
+			Vec3 :: [vector 3]f32;
 
-		x := Vec3{1, 2, 3};
-		y := Vec3{4, 5, 6};
-		fmt.println(x < y);
-		fmt.println(x + y);
-		fmt.println(x - y);
-		fmt.println(x * y);
-		fmt.println(x / y);
+			x := Vec3{1, 2, 3};
+			y := Vec3{4, 5, 6};
+			fmt.println(x < y);
+			fmt.println(x + y);
+			fmt.println(x - y);
+			fmt.println(x * y);
+			fmt.println(x / y);
 
-		for i in x {
-			fmt.println(i);
+			for i in x {
+				fmt.println(i);
+			}
 		}
 	}
-*/
+}
 }
 

+ 1 - 1
code/http_test.odin

@@ -3,7 +3,7 @@
 #foreign_system_library ws2 "Ws2_32.lib" when ODIN_OS == "windows";
 
 
-SOCKET :: type uint;
+SOCKET :: #type uint;
 INVALID_SOCKET :: ~(cast(SOCKET)0);
 
 AF :: enum i32 {

+ 24 - 21
core/_preload.odin

@@ -52,15 +52,12 @@ Type_Info :: union {
 	Float: struct #ordered {
 		size: int, // in bytes
 	},
-	Any:     struct #ordered {},
 	String:  struct #ordered {},
 	Boolean: struct #ordered {},
+	Any:     struct #ordered {},
 	Pointer: struct #ordered {
 		elem: ^Type_Info, // nil -> rawptr
 	},
-	Maybe: struct #ordered {
-		elem: ^Type_Info,
-	},
 	Procedure: struct #ordered {
 		params:     ^Type_Info, // Type_Info.Tuple
 		results:    ^Type_Info, // Type_Info.Tuple
@@ -112,7 +109,7 @@ type_info_base :: proc(info: ^Type_Info) -> ^Type_Info {
 		return nil;
 	}
 	base := info;
-	match type i in base {
+	match i in base {
 	case Type_Info.Named:
 		base = i.base;
 	}
@@ -125,7 +122,7 @@ type_info_base_without_enum :: proc(info: ^Type_Info) -> ^Type_Info {
 		return nil;
 	}
 	base := info;
-	match type i in base {
+	match i in base {
 	case Type_Info.Named:
 		base = i.base;
 	case Type_Info.Enum:
@@ -146,6 +143,8 @@ __cpuid :: proc(level: u32, sig: ^u32) -> i32 #foreign __llvm_core "__get_cpuid"
 
 
 
+
+
 // IMPORTANT NOTE(bill): Must be in this order (as the compiler relies upon it)
 Allocator_Mode :: enum u8 {
 	ALLOC,
@@ -153,9 +152,9 @@ Allocator_Mode :: enum u8 {
 	FREE_ALL,
 	RESIZE,
 }
-Allocator_Proc :: type proc(allocator_data: rawptr, mode: Allocator_Mode,
-                            size, alignment: int,
-                            old_memory: rawptr, old_size: int, flags: u64) -> rawptr;
+Allocator_Proc :: #type proc(allocator_data: rawptr, mode: Allocator_Mode,
+                             size, alignment: int,
+                             old_memory: rawptr, old_size: int, flags: u64) -> rawptr;
 Allocator :: struct #ordered {
 	procedure: Allocator_Proc,
 	data:      rawptr,
@@ -199,23 +198,17 @@ free_ptr_with_allocator :: proc(a: Allocator, ptr: rawptr) #inline {
 	if ptr == nil {
 		return;
 	}
-	a.procedure(a.data, Allocator_Mode.FREE, 0, 0, ptr, 0, 0);
-}
-
-__free_raw_dynamic_array :: proc(a: ^Raw_Dynamic_Array) {
-	if a.allocator.procedure == nil {
-		return;
-	}
-	if a.data == nil {
+	if a.procedure == nil {
 		return;
 	}
-	free_ptr_with_allocator(a.allocator, a.data);
+	a.procedure(a.data, Allocator_Mode.FREE, 0, 0, ptr, 0, 0);
 }
 
 free_ptr :: proc(ptr: rawptr) #inline {
 	__check_context();
 	free_ptr_with_allocator(context.allocator, ptr);
 }
+
 free_all :: proc() #inline {
 	__check_context();
 	a := context.allocator;
@@ -306,11 +299,11 @@ __string_eq :: proc(a, b: string) -> bool {
 	if a.data == b.data {
 		return true;
 	}
-	return mem.compare(cast(rawptr)a.data, cast(rawptr)b.data, a.count) == 0;
+	return __string_cmp(a, b) == 0;
 }
 
 __string_cmp :: proc(a, b: string) -> int {
-	return mem.compare(cast(rawptr)a.data, cast(rawptr)b.data, min(a.count, b.count));
+	return mem.compare(cast([]byte)a, cast([]byte)b);
 }
 
 __string_ne :: proc(a, b: string) -> bool #inline { return !__string_eq(a, b); }
@@ -504,7 +497,7 @@ __dynamic_map_rehash :: proc(using header: __Map_Header, new_count: int) {
 	nm: Raw_Dynamic_Map;
 	new_header.m = ^nm;
 
-	reserve(^nm.hashes, new_count);
+	reserve(nm.hashes, new_count);
 	nm.hashes.count = nm.hashes.capacity;
 	__dynamic_array_reserve(^nm.entries, entry_size, entry_align, m.entries.count);
 	for _, i in nm.hashes {
@@ -660,3 +653,13 @@ __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);
+	}
+}
+

+ 16 - 26
core/fmt.odin

@@ -107,7 +107,7 @@ buffer_write_type :: proc(buf: ^Buffer, ti: ^Type_Info) {
 	}
 
 	using Type_Info;
-	match type info in ti {
+	match info in ti {
 	case Named:
 		buffer_write_string(buf, info.name);
 	case Integer:
@@ -134,9 +134,6 @@ buffer_write_type :: proc(buf: ^Buffer, ti: ^Type_Info) {
 			buffer_write_string(buf, "^");
 			buffer_write_type(buf, info.elem);
 		}
-	case Maybe:
-		buffer_write_string(buf, "?");
-		buffer_write_type(buf, info.elem);
 	case Procedure:
 		buffer_write_string(buf, "proc");
 		if info.params == nil {
@@ -358,7 +355,7 @@ int_from_arg :: proc(args: []any, arg_index: int) -> (int, int, bool) {
 	if arg_index < args.count {
 		arg := args[arg_index];
 		arg.type_info = type_info_base(arg.type_info);
-		match type i in arg {
+		match i in arg {
 		case int:  num = i;
 		case i8:   num = cast(int)i;
 		case i16:  num = cast(int)i;
@@ -420,8 +417,9 @@ fmt_write_padding :: proc(fi: ^Fmt_Info, width: int) {
 }
 
 fmt_integer :: proc(fi: ^Fmt_Info, u: u64, base: int, signed: bool, digits: string) {
-	negative := signed && cast(i64)u < 0;
-	u = abs(u);
+	s := cast(i64)u;
+	negative := signed && s < 0;
+	u = cast(u64)abs(s);
 	buf: [256]byte;
 	if fi.width_set || fi.prec_set {
 		width := fi.width + fi.prec + 3;
@@ -628,6 +626,7 @@ fmt_string :: proc(fi: ^Fmt_Info, s: string, verb: rune) {
 fmt_pointer :: proc(fi: ^Fmt_Info, p: rawptr, verb: rune) {
 	match verb {
 	case 'p', 'v':
+		// Okay
 	default:
 		fmt_bad_verb(fi, verb);
 		return;
@@ -646,7 +645,7 @@ fmt_enum :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
 	}
 
 	using Type_Info;
-	match type e in v.type_info {
+	match e in v.type_info {
 	default:
 		fmt_bad_verb(fi, verb);
 		return;
@@ -659,7 +658,7 @@ fmt_enum :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
 			f: f64;
 			ok := false;
 			a := any{type_info_base(e.base), v.data};
-			match type v in a {
+			match v in a {
 			case i8:   i = cast(i64)v;
 			case i16:  i = cast(i64)v;
 			case i32:  i = cast(i64)v;
@@ -710,9 +709,9 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
 	}
 
 	using Type_Info;
-	match type info in v.type_info {
+	match info in v.type_info {
 	case Named:
-		match type b in info.base {
+		match b in info.base {
 		case Struct:
 			if verb != 'v' {
 				fmt_bad_verb(fi, verb);
@@ -747,16 +746,6 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
 			fmt_pointer(fi, (cast(^rawptr)v.data)^, verb);
 		}
 
-	case Maybe:
-		// TODO(bill): Correct verbs for Maybe types?
-		size := mem.size_of_type_info(info.elem);
-		data := slice_ptr(cast(^byte)v.data, size+1);
-		if data[size] != 0 {
-			fmt_arg(fi, any{info.elem, v.data}, verb);
-		} else {
-			buffer_write_string(fi.buf, "nil");
-		}
-
 	case Array:
 		if verb != 'v' {
 			fmt_bad_verb(fi, verb);
@@ -799,9 +788,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, _ := union_cast(^Struct)info.generated_struct;
-		ed, _ := union_cast(^Dynamic_Array)gs.fields[1].type_info;
-		entry_type, _ := union_cast(^Struct)ed.elem;
+		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.fields[1].type_info); assert(ed_ok);
+
+		entry_type, et_ok := union_cast(^Struct)ed.elem; assert(et_ok);
 		entry_size := ed.elem_size;
 		for i in 0..<entries.count {
 			if i > 0 {
@@ -892,7 +882,7 @@ fmt_arg :: proc(fi: ^Fmt_Info, arg: any, verb: rune) {
 
 	if verb == 'T' {
 		ti := arg.type_info;
-		match type a in arg {
+		match a in arg {
 		case ^Type_Info: ti = a;
 		}
 		buffer_write_type(fi.buf, ti);
@@ -902,7 +892,7 @@ fmt_arg :: proc(fi: ^Fmt_Info, arg: any, verb: rune) {
 
 	base_arg := arg;
 	base_arg.type_info = type_info_base(base_arg.type_info);
-	match type a in base_arg {
+	match a in base_arg {
 	case bool:    fmt_bool(fi, a, verb);
 	case f32:     fmt_float(fi, cast(f64)a, 32, verb);
 	case f64:     fmt_float(fi, a, 64, verb);

+ 0 - 4
core/math.odin

@@ -46,10 +46,6 @@ bit_reverse :: proc(b: u16) -> u16 #foreign __llvm_core "llvm.bitreverse.i16";
 bit_reverse :: proc(b: u32) -> u32 #foreign __llvm_core "llvm.bitreverse.i32";
 bit_reverse :: proc(b: u64) -> u64 #foreign __llvm_core "llvm.bitreverse.i64";
 
-byte_swap :: proc(b: u16) -> u16 #foreign __llvm_core "llvm.bswap.i16";
-byte_swap :: proc(b: u32) -> u32 #foreign __llvm_core "llvm.bswap.i32";
-byte_swap :: proc(b: u64) -> u64 #foreign __llvm_core "llvm.bswap.i64";
-
 fmuladd :: proc(a, b, c: f32) -> f32 #foreign __llvm_core "llvm.fmuladd.f32";
 fmuladd :: proc(a, b, c: f64) -> f64 #foreign __llvm_core "llvm.fmuladd.f64";
 

+ 36 - 37
core/mem.odin

@@ -1,6 +1,11 @@
 #import "fmt.odin";
 #import "os.odin";
 
+swap :: proc(b: u16) -> u16 #foreign __llvm_core "llvm.bswap.i16";
+swap :: proc(b: u32) -> u32 #foreign __llvm_core "llvm.bswap.i32";
+swap :: proc(b: u64) -> u64 #foreign __llvm_core "llvm.bswap.i64";
+
+
 set :: proc(data: rawptr, value: i32, len: int) -> rawptr #link_name "__mem_set" {
 	llvm_memset_64bit :: proc(dst: rawptr, val: byte, len: int, align: i32, is_volatile: bool) #foreign __llvm_core "llvm.memset.p0i8.i64";
 	llvm_memset_64bit(data, cast(byte)value, len, 1, false);
@@ -12,22 +17,21 @@ zero :: proc(data: rawptr, len: int) -> rawptr #link_name "__mem_zero" {
 }
 
 copy :: proc(dst, src: rawptr, len: int) -> rawptr #link_name "__mem_copy" {
-	// NOTE(bill): This _must_ implemented like C's memmove
+	// NOTE(bill): This _must_ be implemented like C's memmove
 	llvm_memmove_64bit :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) #foreign __llvm_core "llvm.memmove.p0i8.p0i8.i64";
 	llvm_memmove_64bit(dst, src, len, 1, false);
 	return dst;
 }
 
 copy_non_overlapping :: proc(dst, src: rawptr, len: int) -> rawptr #link_name "__mem_copy_non_overlapping" {
-	// NOTE(bill): This _must_ implemented like C's memcpy
+	// NOTE(bill): This _must_ be implemented like C's memcpy
 	llvm_memcpy_64bit :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) #foreign __llvm_core "llvm.memcpy.p0i8.p0i8.i64";
 	llvm_memcpy_64bit(dst, src, len, 1, false);
 	return dst;
 }
 
-compare :: proc(dst, src: rawptr, n: int) -> int #link_name "__mem_compare" {
-	a := slice_ptr(cast(^byte)dst, n);
-	b := slice_ptr(cast(^byte)src, n);
+compare :: proc(a, b: []byte) -> int #link_name "__mem_compare" {
+	n := min(a.count, b.count);
 	for i in 0..<n {
 		match {
 		case a[i] < b[i]:
@@ -43,8 +47,8 @@ compare :: proc(dst, src: rawptr, n: int) -> int #link_name "__mem_compare" {
 
 kilobytes :: proc(x: int) -> int #inline { return          (x) * 1024; }
 megabytes :: proc(x: int) -> int #inline { return kilobytes(x) * 1024; }
-gigabytes :: proc(x: int) -> int #inline { return gigabytes(x) * 1024; }
-terabytes :: proc(x: int) -> int #inline { return terabytes(x) * 1024; }
+gigabytes :: proc(x: int) -> int #inline { return megabytes(x) * 1024; }
+terabytes :: proc(x: int) -> int #inline { return gigabytes(x) * 1024; }
 
 is_power_of_two :: proc(x: int) -> bool {
 	if x <= 0 {
@@ -213,8 +217,7 @@ align_of_type_info :: proc(type_info: ^Type_Info) -> int {
 	WORD_SIZE :: size_of(int);
 	MAX_ALIGN :: size_of([vector 64]f64); // TODO(bill): Should these constants be builtin constants?
 	using Type_Info;
-
-	match type info in type_info {
+	match info in type_info {
 	case Named:
 		return align_of_type_info(info.base);
 	case Integer:
@@ -225,14 +228,16 @@ align_of_type_info :: proc(type_info: ^Type_Info) -> int {
 		return WORD_SIZE;
 	case Boolean:
 		return 1;
+	case Any:
+		return WORD_SIZE;
 	case Pointer:
 		return WORD_SIZE;
-	case Maybe:
-		return max(align_of_type_info(info.elem), 1);
 	case Procedure:
 		return WORD_SIZE;
 	case Array:
 		return align_of_type_info(info.elem);
+	case Dynamic_Array:
+		return WORD_SIZE;
 	case Slice:
 		return WORD_SIZE;
 	case Vector:
@@ -240,12 +245,18 @@ align_of_type_info :: proc(type_info: ^Type_Info) -> int {
 		count := cast(int)max(prev_pow2(cast(i64)info.count), 1);
 		total := size * count;
 		return clamp(total, 1, MAX_ALIGN);
+	case Tuple:
+		return info.align;
 	case Struct:
 		return info.align;
 	case Union:
 		return info.align;
 	case Raw_Union:
 		return info.align;
+	case Enum:
+		return align_of_type_info(info.base);
+	case Map:
+		return align_of_type_info(info.generated_struct);
 	}
 
 	return 0;
@@ -259,23 +270,21 @@ align_formula :: proc(size, align: int) -> int {
 size_of_type_info :: proc(type_info: ^Type_Info) -> int {
 	WORD_SIZE :: size_of(int);
 	using Type_Info;
-	match type info in type_info {
+	match info in type_info {
 	case Named:
 		return size_of_type_info(info.base);
 	case Integer:
 		return info.size;
 	case Float:
 		return info.size;
-	case Any:
-		return 2*WORD_SIZE;
 	case String:
 		return 2*WORD_SIZE;
 	case Boolean:
 		return 1;
+	case Any:
+		return 2*WORD_SIZE;
 	case Pointer:
 		return WORD_SIZE;
-	case Maybe:
-		return size_of_type_info(info.elem) + 1;
 	case Procedure:
 		return WORD_SIZE;
 	case Array:
@@ -287,39 +296,29 @@ size_of_type_info :: proc(type_info: ^Type_Info) -> int {
 		align     := align_of_type_info(info.elem);
 		alignment := align_formula(size, align);
 		return alignment*(count-1) + size;
+	case Dynamic_Array:
+		return size_of(rawptr) + 2*size_of(int) + size_of(Allocator);
 	case Slice:
-		return 3*WORD_SIZE;
+		return 2*WORD_SIZE;
 	case Vector:
-		is_bool :: proc(type_info: ^Type_Info) -> bool {
-			match type info in type_info {
-			case Named:
-				return is_bool(info.base);
-			case Boolean:
-				return true;
-			}
-			return false;
-		}
-
 		count := info.count;
 		if count == 0 {
 			return 0;
 		}
-		bit_size := 8*size_of_type_info(info.elem);
-		if is_bool(info.elem) {
-			// NOTE(bill): LLVM can store booleans as 1 bit because a boolean _is_ an `i1`
-			// Silly LLVM spec
-			bit_size = 1;
-		}
-		total_size_in_bits := bit_size * count;
-		total_size := (total_size_in_bits+7)/8;
-		return total_size;
-
+		size      := size_of_type_info(info.elem);
+		align     := align_of_type_info(info.elem);
+		alignment := align_formula(size, align);
+		return alignment*(count-1) + size;
 	case Struct:
 		return info.size;
 	case Union:
 		return info.size;
 	case Raw_Union:
 		return info.size;
+	case Enum:
+		return size_of_type_info(info.base);
+	case Map:
+		return size_of_type_info(info.generated_struct);
 	}
 
 	return 0;

+ 4 - 3
core/sys/windows.odin

@@ -1,3 +1,4 @@
+_ := compile_assert(ODIN_OS == "windows");
 #foreign_system_library "kernel32.lib";
 #foreign_system_library "user32.lib";
 #foreign_system_library "gdi32.lib";
@@ -19,7 +20,7 @@ LPARAM    :: int;
 LRESULT   :: int;
 ATOM      :: i16;
 BOOL      :: i32;
-WNDPROC   :: type proc(HWND, u32, WPARAM, LPARAM) -> LRESULT #cc_c;
+WNDPROC   :: #type proc(HWND, u32, WPARAM, LPARAM) -> LRESULT #cc_c;
 
 
 INVALID_HANDLE_VALUE :: cast(HANDLE)(~cast(int)0);
@@ -358,8 +359,8 @@ PFD_DOUBLEBUFFER_DONTCARE :: 0x40000000;
 PFD_STEREO_DONTCARE       :: 0x80000000;
 
 HGLRC :: HANDLE;
-PROC  :: type proc() #cc_c;
-wglCreateContextAttribsARBType :: type proc(hdc: HDC, hshareContext: rawptr, attribList: ^i32) -> HGLRC;
+PROC  :: #type proc() #cc_c;
+wglCreateContextAttribsARBType :: #type proc(hdc: HDC, hshareContext: rawptr, attribList: ^i32) -> HGLRC;
 
 
 PIXELFORMATDESCRIPTOR :: struct #ordered {

+ 24 - 24
core/types.odin

@@ -11,7 +11,7 @@ is_signed :: proc(info: ^Type_Info) -> bool {
 is_integer :: proc(info: ^Type_Info) -> bool {
 	if info == nil { return false; }
 
-	match type i in type_info_base(info) {
+	match i in type_info_base(info) {
 	case Type_Info.Integer: return true;
 	}
 	return false;
@@ -19,7 +19,7 @@ is_integer :: proc(info: ^Type_Info) -> bool {
 is_float :: proc(info: ^Type_Info) -> bool {
 	if info == nil { return false; }
 
-	match type i in type_info_base(info) {
+	match i in type_info_base(info) {
 	case Type_Info.Float: return true;
 	}
 	return false;
@@ -27,7 +27,7 @@ is_float :: proc(info: ^Type_Info) -> bool {
 is_any :: proc(info: ^Type_Info) -> bool {
 	if info == nil { return false; }
 
-	match type i in type_info_base(info) {
+	match i in type_info_base(info) {
 	case Type_Info.Any: return true;
 	}
 	return false;
@@ -35,7 +35,7 @@ is_any :: proc(info: ^Type_Info) -> bool {
 is_string :: proc(info: ^Type_Info) -> bool {
 	if info == nil { return false; }
 
-	match type i in type_info_base(info) {
+	match i in type_info_base(info) {
 	case Type_Info.String: return true;
 	}
 	return false;
@@ -43,7 +43,7 @@ is_string :: proc(info: ^Type_Info) -> bool {
 is_boolean :: proc(info: ^Type_Info) -> bool {
 	if info == nil { return false; }
 
-	match type i in type_info_base(info) {
+	match i in type_info_base(info) {
 	case Type_Info.Boolean: return true;
 	}
 	return false;
@@ -51,23 +51,15 @@ is_boolean :: proc(info: ^Type_Info) -> bool {
 is_pointer :: proc(info: ^Type_Info) -> bool {
 	if info == nil { return false; }
 
-	match type i in type_info_base(info) {
+	match i in type_info_base(info) {
 	case Type_Info.Pointer: return true;
 	}
 	return false;
 }
-is_maybe :: proc(info: ^Type_Info) -> bool {
-	if info == nil { return false; }
-
-	match type i in type_info_base(info) {
-	case Type_Info.Maybe: return true;
-	}
-	return false;
-}
 is_procedure :: proc(info: ^Type_Info) -> bool {
 	if info == nil { return false; }
 
-	match type i in type_info_base(info) {
+	match i in type_info_base(info) {
 	case Type_Info.Procedure: return true;
 	}
 	return false;
@@ -75,7 +67,7 @@ is_procedure :: proc(info: ^Type_Info) -> bool {
 is_array :: proc(info: ^Type_Info) -> bool {
 	if info == nil { return false; }
 
-	match type i in type_info_base(info) {
+	match i in type_info_base(info) {
 	case Type_Info.Array: return true;
 	}
 	return false;
@@ -83,15 +75,23 @@ is_array :: proc(info: ^Type_Info) -> bool {
 is_dynamic_array :: proc(info: ^Type_Info) -> bool {
 	if info == nil { return false; }
 
-	match type i in type_info_base(info) {
+	match i in type_info_base(info) {
 	case Type_Info.Dynamic_Array: return true;
 	}
 	return false;
 }
+is_dynamic_map :: proc(info: ^Type_Info) -> bool {
+	if info == nil { return false; }
+
+	match i in type_info_base(info) {
+	case Type_Info.Map: return i.count == 0;
+	}
+	return false;
+}
 is_slice :: proc(info: ^Type_Info) -> bool {
 	if info == nil { return false; }
 
-	match type i in type_info_base(info) {
+	match i in type_info_base(info) {
 	case Type_Info.Slice: return true;
 	}
 	return false;
@@ -99,7 +99,7 @@ is_slice :: proc(info: ^Type_Info) -> bool {
 is_vector :: proc(info: ^Type_Info) -> bool {
 	if info == nil { return false; }
 
-	match type i in type_info_base(info) {
+	match i in type_info_base(info) {
 	case Type_Info.Vector: return true;
 	}
 	return false;
@@ -107,7 +107,7 @@ is_vector :: proc(info: ^Type_Info) -> bool {
 is_tuple :: proc(info: ^Type_Info) -> bool {
 	if info == nil { return false; }
 
-	match type i in type_info_base(info) {
+	match i in type_info_base(info) {
 	case Type_Info.Tuple: return true;
 	}
 	return false;
@@ -115,7 +115,7 @@ is_tuple :: proc(info: ^Type_Info) -> bool {
 is_struct :: proc(info: ^Type_Info) -> bool {
 	if info == nil { return false; }
 
-	match type i in type_info_base(info) {
+	match i in type_info_base(info) {
 	case Type_Info.Struct: return true;
 	}
 	return false;
@@ -123,7 +123,7 @@ is_struct :: proc(info: ^Type_Info) -> bool {
 is_union :: proc(info: ^Type_Info) -> bool {
 	if info == nil { return false; }
 
-	match type i in type_info_base(info) {
+	match i in type_info_base(info) {
 	case Type_Info.Union: return true;
 	}
 	return false;
@@ -131,7 +131,7 @@ is_union :: proc(info: ^Type_Info) -> bool {
 is_raw_union :: proc(info: ^Type_Info) -> bool {
 	if info == nil { return false; }
 
-	match type i in type_info_base(info) {
+	match i in type_info_base(info) {
 	case Type_Info.Raw_Union: return true;
 	}
 	return false;
@@ -139,7 +139,7 @@ is_raw_union :: proc(info: ^Type_Info) -> bool {
 is_enum :: proc(info: ^Type_Info) -> bool {
 	if info == nil { return false; }
 
-	match type i in type_info_base(info) {
+	match i in type_info_base(info) {
 	case Type_Info.Enum: return true;
 	}
 	return false;

File diff suppressed because it is too large
+ 12 - 9
src/check_expr.c


+ 25 - 5
src/check_stmt.c

@@ -942,7 +942,25 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
 		bool is_union_ptr = false;
 		bool is_any = false;
 
-		check_expr(c, &x, ms->tag);
+		if (ms->tag->kind != AstNode_AssignStmt) {
+			error_node(ms->tag, "Expected an `in` assignment for this type match statement");
+			break;
+		}
+
+		ast_node(as, AssignStmt, ms->tag);
+		Token as_token = ast_node_token(ms->tag);
+		if (as->lhs.count != 1) {
+			syntax_error(as_token, "Expected 1 name before `in`");
+			break;
+		}
+		if (as->rhs.count != 1) {
+			syntax_error(as_token, "Expected 1 expression after `in`");
+			break;
+		}
+		AstNode *lhs = as->lhs.e[0];
+		AstNode *rhs = as->rhs.e[0];
+
+		check_expr(c, &x, rhs);
 		check_assignment(c, &x, NULL, str_lit("type match expression"));
 		if (!check_valid_type_match_type(x.type, &is_union_ptr, &is_any)) {
 			gbString str = type_to_string(x.type);
@@ -980,7 +998,9 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
 			}
 		}
 
-		if (ms->var->kind != AstNode_Ident) {
+
+		if (unparen_expr(lhs)->kind != AstNode_Ident) {
+			error_node(rhs, "Expected an identifier, got `%.*s`", LIT(ast_node_strings[rhs->kind]));
 			break;
 		}
 
@@ -1056,10 +1076,10 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
 					tt = make_type_pointer(c->allocator, case_type);
 					add_type_info_type(c, tt);
 				}
-				Entity *tag_var = make_entity_variable(c->allocator, c->context.scope, ms->var->Ident, tt, true);
+				Entity *tag_var = make_entity_variable(c->allocator, c->context.scope, lhs->Ident, tt, true);
 				tag_var->flags |= EntityFlag_Used;
-				add_entity(c, c->context.scope, ms->var, tag_var);
-				add_entity_use(c, ms->var, tag_var);
+				add_entity(c, c->context.scope, lhs, tag_var);
+				add_entity_use(c, lhs, tag_var);
 			}
 			check_stmt_list(c, cc->stmts, mod_flags);
 			check_close_scope(c);

+ 53 - 46
src/checker.c

@@ -630,11 +630,12 @@ void init_universal_scope(BuildContext *bc) {
 	}
 
 
-	t_u8_ptr  = make_type_pointer(a, t_u8);
-	t_int_ptr = make_type_pointer(a, t_int);
-	t_i64_ptr = make_type_pointer(a, t_i64);
-	t_f64_ptr = make_type_pointer(a, t_f64);
-	t_byte_slice = make_type_slice(a, t_byte);
+	t_u8_ptr       = make_type_pointer(a, t_u8);
+	t_int_ptr      = make_type_pointer(a, t_int);
+	t_i64_ptr      = make_type_pointer(a, t_i64);
+	t_f64_ptr      = make_type_pointer(a, t_f64);
+	t_byte_slice   = make_type_slice(a, t_byte);
+	t_string_slice = make_type_slice(a, t_string);
 }
 
 
@@ -911,11 +912,6 @@ void add_type_info_type(Checker *c, Type *t) {
 		}
 	} break;
 
-	case Type_Maybe:
-		add_type_info_type(c, bt->Maybe.elem);
-		add_type_info_type(c, t_bool);
-		break;
-
 	case Type_Pointer:
 		add_type_info_type(c, bt->Pointer.elem);
 		break;
@@ -1099,48 +1095,46 @@ void init_preload(Checker *c) {
 
 
 
-		if (record->field_count != 20) {
+		if (record->field_count != 19) {
 			compiler_error("Invalid `Type_Info` layout");
 		}
 		t_type_info_named         = record->fields[ 1]->type;
 		t_type_info_integer       = record->fields[ 2]->type;
 		t_type_info_float         = record->fields[ 3]->type;
-		t_type_info_any           = record->fields[ 4]->type;
-		t_type_info_string        = record->fields[ 5]->type;
-		t_type_info_boolean       = record->fields[ 6]->type;
+		t_type_info_string        = record->fields[ 4]->type;
+		t_type_info_boolean       = record->fields[ 5]->type;
+		t_type_info_any           = record->fields[ 6]->type;
 		t_type_info_pointer       = record->fields[ 7]->type;
-		t_type_info_maybe         = record->fields[ 8]->type;
-		t_type_info_procedure     = record->fields[ 9]->type;
-		t_type_info_array         = record->fields[10]->type;
-		t_type_info_dynamic_array = record->fields[11]->type;
-		t_type_info_slice         = record->fields[12]->type;
-		t_type_info_vector        = record->fields[13]->type;
-		t_type_info_tuple         = record->fields[14]->type;
-		t_type_info_struct        = record->fields[15]->type;
-		t_type_info_union         = record->fields[16]->type;
-		t_type_info_raw_union     = record->fields[17]->type;
-		t_type_info_enum          = record->fields[18]->type;
-		t_type_info_map           = record->fields[19]->type;
-
-		t_type_info_named_ptr         = make_type_pointer(heap_allocator(), t_type_info_named);
-		t_type_info_integer_ptr       = make_type_pointer(heap_allocator(), t_type_info_integer);
-		t_type_info_float_ptr         = make_type_pointer(heap_allocator(), t_type_info_float);
-		t_type_info_any_ptr           = make_type_pointer(heap_allocator(), t_type_info_any);
-		t_type_info_string_ptr        = make_type_pointer(heap_allocator(), t_type_info_string);
-		t_type_info_boolean_ptr       = make_type_pointer(heap_allocator(), t_type_info_boolean);
-		t_type_info_pointer_ptr       = make_type_pointer(heap_allocator(), t_type_info_pointer);
-		t_type_info_maybe_ptr         = make_type_pointer(heap_allocator(), t_type_info_maybe);
-		t_type_info_procedure_ptr     = make_type_pointer(heap_allocator(), t_type_info_procedure);
-		t_type_info_array_ptr         = make_type_pointer(heap_allocator(), t_type_info_array);
-		t_type_info_dynamic_array_ptr = make_type_pointer(heap_allocator(), t_type_info_dynamic_array);
-		t_type_info_slice_ptr         = make_type_pointer(heap_allocator(), t_type_info_slice);
-		t_type_info_vector_ptr        = make_type_pointer(heap_allocator(), t_type_info_vector);
-		t_type_info_tuple_ptr         = make_type_pointer(heap_allocator(), t_type_info_tuple);
-		t_type_info_struct_ptr        = make_type_pointer(heap_allocator(), t_type_info_struct);
-		t_type_info_union_ptr         = make_type_pointer(heap_allocator(), t_type_info_union);
-		t_type_info_raw_union_ptr     = make_type_pointer(heap_allocator(), t_type_info_raw_union);
-		t_type_info_enum_ptr          = make_type_pointer(heap_allocator(), t_type_info_enum);
-		t_type_info_map_ptr           = make_type_pointer(heap_allocator(), t_type_info_map);
+		t_type_info_procedure     = record->fields[ 8]->type;
+		t_type_info_array         = record->fields[ 9]->type;
+		t_type_info_dynamic_array = record->fields[10]->type;
+		t_type_info_slice         = record->fields[11]->type;
+		t_type_info_vector        = record->fields[12]->type;
+		t_type_info_tuple         = record->fields[13]->type;
+		t_type_info_struct        = record->fields[14]->type;
+		t_type_info_union         = record->fields[15]->type;
+		t_type_info_raw_union     = record->fields[16]->type;
+		t_type_info_enum          = record->fields[17]->type;
+		t_type_info_map           = record->fields[18]->type;
+
+		t_type_info_named_ptr         = make_type_pointer(c->allocator, t_type_info_named);
+		t_type_info_integer_ptr       = make_type_pointer(c->allocator, t_type_info_integer);
+		t_type_info_float_ptr         = make_type_pointer(c->allocator, t_type_info_float);
+		t_type_info_string_ptr        = make_type_pointer(c->allocator, t_type_info_string);
+		t_type_info_boolean_ptr       = make_type_pointer(c->allocator, t_type_info_boolean);
+		t_type_info_any_ptr           = make_type_pointer(c->allocator, t_type_info_any);
+		t_type_info_pointer_ptr       = make_type_pointer(c->allocator, t_type_info_pointer);
+		t_type_info_procedure_ptr     = make_type_pointer(c->allocator, t_type_info_procedure);
+		t_type_info_array_ptr         = make_type_pointer(c->allocator, t_type_info_array);
+		t_type_info_dynamic_array_ptr = make_type_pointer(c->allocator, t_type_info_dynamic_array);
+		t_type_info_slice_ptr         = make_type_pointer(c->allocator, t_type_info_slice);
+		t_type_info_vector_ptr        = make_type_pointer(c->allocator, t_type_info_vector);
+		t_type_info_tuple_ptr         = make_type_pointer(c->allocator, t_type_info_tuple);
+		t_type_info_struct_ptr        = make_type_pointer(c->allocator, t_type_info_struct);
+		t_type_info_union_ptr         = make_type_pointer(c->allocator, t_type_info_union);
+		t_type_info_raw_union_ptr     = make_type_pointer(c->allocator, t_type_info_raw_union);
+		t_type_info_enum_ptr          = make_type_pointer(c->allocator, t_type_info_enum);
+		t_type_info_map_ptr           = make_type_pointer(c->allocator, t_type_info_map);
 	}
 
 	if (t_allocator == NULL) {
@@ -1727,6 +1721,19 @@ void check_import_entities(Checker *c, MapScope *file_scopes) {
 			file_str = import_file;
 		}
 
+		if (fl->cond != NULL) {
+			Operand operand = {Addressing_Invalid};
+			check_expr(c, &operand, fl->cond);
+			if (operand.mode != Addressing_Constant || !is_type_boolean(operand.type)) {
+				error_node(fl->cond, "Non-constant boolean `when` condition");
+				continue;
+			}
+			if (operand.value.kind == ExactValue_Bool &&
+			    !operand.value.value_bool) {
+				continue;
+			}
+		}
+
 		String library_name = path_to_entity_name(fl->library_name.string, file_str);
 		if (str_eq(library_name, str_lit("_"))) {
 			error(fl->token, "File name, %.*s, cannot be as a library name as it is not a valid identifier", LIT(fl->library_name.string));

+ 1 - 0
src/entity.c

@@ -37,6 +37,7 @@ typedef enum EntityFlag {
 	EntityFlag_VectorElem = 1<<5,
 	EntityFlag_Ellipsis   = 1<<6,
 	EntityFlag_NoAlias    = 1<<7,
+	EntityFlag_EnumField  = 1<<8,
 } EntityFlag;
 
 typedef enum OverloadKind {

+ 98 - 72
src/ir.c

@@ -1788,11 +1788,6 @@ irValue *ir_emit_struct_ep(irProcedure *proc, irValue *s, i32 index) {
 		case 0: result_type = make_type_pointer(a, t_type_info_ptr); break;
 		case 1: result_type = make_type_pointer(a, t_rawptr);        break;
 		}
-	} else if (is_type_maybe(t)) {
-		switch (index) {
-		case 0: result_type = make_type_pointer(a, t->Maybe.elem); break;
-		case 1: result_type = make_type_pointer(a, t_bool);        break;
-		}
 	} else if (is_type_dynamic_array(t)) {
 		switch (index) {
 		case 0: result_type = make_type_pointer(a, make_type_pointer(a, t->DynamicArray.elem)); break;
@@ -1848,11 +1843,6 @@ irValue *ir_emit_struct_ev(irProcedure *proc, irValue *s, i32 index) {
 		case 0: result_type = t_type_info_ptr; break;
 		case 1: result_type = t_rawptr;        break;
 		}
-	} else if (is_type_maybe(t)) {
-		switch (index) {
-		case 0: result_type = t->Maybe.elem; break;
-		case 1: result_type = t_bool;        break;
-		}
 	} else if (is_type_dynamic_array(t)) {
 		switch (index) {
 		case 0: result_type = make_type_pointer(a, t->DynamicArray.elem); break;
@@ -2165,15 +2155,6 @@ irValue *ir_emit_conv(irProcedure *proc, irValue *value, Type *t) {
 		return value;
 	}
 
-	if (is_type_maybe(dst)) {
-		irValue *maybe = ir_add_local_generated(proc, dst);
-		irValue *val = ir_emit_struct_ep(proc, maybe, 0);
-		irValue *set = ir_emit_struct_ep(proc, maybe, 1);
-		ir_emit_store(proc, val, value);
-		ir_emit_store(proc, set, v_true);
-		return ir_emit_load(proc, maybe);
-	}
-
 	// integer -> integer
 	if (is_type_integer(src) && is_type_integer(dst)) {
 		GB_ASSERT(src->kind == Type_Basic &&
@@ -2396,7 +2377,6 @@ bool ir_is_type_aggregate(Type *t) {
 
 	case Type_Array:
 	case Type_Slice:
-	case Type_Maybe:
 	case Type_Record:
 	case Type_Tuple:
 		return true;
@@ -3130,22 +3110,33 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
 						args[1] = ptr;
 						return ir_emit_global_call(proc, "free_ptr_with_allocator", args, 2);
 					} else if (is_type_dynamic_map(type)) {
-						// irValue *val = ir_build_expr(proc, node);
-						// irValue *map_ptr = ir_address_from_load_or_generate_local(proc, val);
-
-						// {
-						// 	irValue *array = ir_emit_conv(proc, ir_emit_struct_ep(proc, map_ptr, 0), t_raw_dynamic_array_ptr);
-						// 	irValue **args = gb_alloc_array(a, irValue *, 1);
-						// 	args[0] = array;
-						// 	ir_emit_global_call(proc, "__free_raw_dynamic_array", args, 1);
-						// }
-						// {
-						// 	irValue *array = ir_emit_conv(proc, ir_emit_struct_ep(proc, map_ptr, 1), t_raw_dynamic_array_ptr);
-						// 	irValue **args = gb_alloc_array(a, irValue *, 1);
-						// 	args[0] = array;
-						// 	ir_emit_global_call(proc, "__free_raw_dynamic_array", args, 1);
-						// }
+						irValue *map = ir_build_expr(proc, node);
+						irValue *map_ptr = ir_address_from_load_or_generate_local(proc, map);
+
+						{
+							irValue *array = ir_emit_struct_ep(proc, map_ptr, 0);
 
+							irValue *da_allocator = ir_emit_load(proc, ir_emit_struct_ep(proc, array, 3));
+							irValue *da_ptr = ir_emit_load(proc, ir_emit_struct_ep(proc, array, 0));
+							da_ptr = ir_emit_conv(proc, da_ptr, t_rawptr);
+
+							irValue **args = gb_alloc_array(a, irValue *, 1);
+							args[0] = da_allocator;
+							args[1] = da_ptr;
+							ir_emit_global_call(proc, "free_ptr_with_allocator", args, 2);
+						}
+						{
+							irValue *array = ir_emit_struct_ep(proc, map_ptr, 1);
+
+							irValue *da_allocator = ir_emit_load(proc, ir_emit_struct_ep(proc, array, 3));
+							irValue *da_ptr = ir_emit_load(proc, ir_emit_struct_ep(proc, array, 0));
+							da_ptr = ir_emit_conv(proc, da_ptr, t_rawptr);
+
+							irValue **args = gb_alloc_array(a, irValue *, 1);
+							args[0] = da_allocator;
+							args[1] = da_ptr;
+							ir_emit_global_call(proc, "free_ptr_with_allocator", args, 2);
+						}
 						return NULL;
 					}
 
@@ -3176,7 +3167,7 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
 					ir_emit_comment(proc, str_lit("reserve"));
 					gbAllocator a = proc->module->allocator;
 
-					irValue *ptr = ir_build_expr(proc, ce->args.e[0]);
+					irValue *ptr = ir_build_addr(proc, ce->args.e[0]).addr;
 					Type *type = ir_type(ptr);
 					GB_ASSERT(is_type_pointer(type));
 					type = base_type(type_deref(type));
@@ -3208,8 +3199,8 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
 				} break;
 
 				case BuiltinProc_clear: {
-					ir_emit_comment(proc, str_lit("reserve"));
-					irValue *ptr = ir_build_expr(proc, ce->args.e[0]);
+					ir_emit_comment(proc, str_lit("clear"));
+					irValue *ptr = ir_build_addr(proc, ce->args.e[0]).addr;
 					Type *t = base_type(type_deref(ir_type(ptr)));
 					if (is_type_dynamic_array(t)) {
 						irValue *count_ptr = ir_emit_struct_ep(proc, ptr, 1);
@@ -3229,7 +3220,7 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
 					ir_emit_comment(proc, str_lit("append"));
 					gbAllocator a = proc->module->allocator;
 
-					irValue *array_ptr = ir_build_expr(proc, ce->args.e[0]);
+					irValue *array_ptr = ir_build_addr(proc, ce->args.e[0]).addr;
 					Type *type = ir_type(array_ptr);
 					GB_ASSERT(is_type_pointer(type));
 					type = base_type(type_deref(type));
@@ -3348,7 +3339,7 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
 					ir_emit_jump(proc, done);
 					ir_start_block(proc, done);
 
-					return NULL;
+					return cond;
 				} break;
 
 				case BuiltinProc_panic: {
@@ -3596,10 +3587,6 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
 		return ir_emit_call(proc, value, args, arg_count);
 	case_end;
 
-	case_ast_node(de, DemaybeExpr, expr);
-		return ir_addr_load(proc, ir_build_addr(proc, expr));
-	case_end;
-
 	case_ast_node(se, SliceExpr, expr);
 		return ir_addr_load(proc, ir_build_addr(proc, expr));
 	case_end;
@@ -3722,7 +3709,34 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
 		AstNode *sel = unparen_expr(se->selector);
 		if (sel->kind == AstNode_Ident) {
 			String selector = sel->Ident.string;
-			Type *type = base_type(type_of_expr(proc->module->info, se->expr));
+			Type *type = type_of_expr(proc->module->info, se->expr);
+
+			if (is_type_enum(type)) {
+				Selection sel = lookup_field(proc->module->allocator, type, selector, true);
+				Entity *e = sel.entity;
+				GB_ASSERT(e->kind == Entity_Variable);
+				i32 index = e->Variable.field_index;
+				switch (index) {
+				case 0: {
+					irValue *ti_ptr = ir_type_info(proc, type);
+					{
+						irValue **args = gb_alloc_array(proc->module->allocator, irValue *, 1);
+						args[0] = ti_ptr;
+						ti_ptr = ir_emit_global_call(proc, "type_info_base", args, 1);
+					}
+
+
+					irValue *enum_info = ir_emit_conv(proc, ti_ptr, t_type_info_enum_ptr);
+					irValue *names_ptr = ir_emit_struct_ep(proc, enum_info, 1);
+					return ir_make_addr(names_ptr);
+				} break;
+				default:
+					GB_PANIC("Unhandled enum index %d %.*s", index, LIT(selector));
+					break;
+				}
+			}
+
+			type = base_type(type);
 
 			if (type == t_invalid) {
 				// NOTE(bill): Imports
@@ -4056,18 +4070,6 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
 		return ir_make_addr(addr);
 	case_end;
 
-	case_ast_node(de, DemaybeExpr, expr);
-		ir_emit_comment(proc, str_lit("DemaybeExpr"));
-		irValue *maybe = ir_build_expr(proc, de->expr);
-		Type *t = default_type(type_of_expr(proc->module->info, expr));
-		GB_ASSERT(is_type_tuple(t));
-
-		irValue *result = ir_add_local_generated(proc, t);
-		ir_emit_store(proc, result, maybe);
-
-		return ir_make_addr(result);
-	case_end;
-
 	case_ast_node(ce, CallExpr, expr);
 		// NOTE(bill): This is make sure you never need to have an `array_ev`
 		irValue *e = ir_build_expr(proc, expr);
@@ -5253,7 +5255,13 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
 		ir_emit_comment(proc, str_lit("TypeMatchStmt"));
 		gbAllocator allocator = proc->module->allocator;
 
-		irValue *parent = ir_build_expr(proc, ms->tag);
+		ast_node(as, AssignStmt, ms->tag);
+		GB_ASSERT(as->lhs.count == 1);
+		GB_ASSERT(as->rhs.count == 1);
+		AstNode *lhs = as->lhs.e[0];
+		AstNode *rhs = as->rhs.e[0];
+
+		irValue *parent = ir_build_expr(proc, rhs);
 		bool is_union_ptr = false;
 		bool is_any = false;
 		GB_ASSERT(check_valid_type_match_type(ir_type(parent), &is_union_ptr, &is_any));
@@ -5274,7 +5282,8 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
 
 		ast_node(body, BlockStmt, ms->body);
 
-		String tag_var_name = ms->var->Ident.string;
+		String tag_var_name = lhs->Ident.string;
+
 
 		AstNodeArray default_stmts = {0};
 		irBlock *default_block = NULL;
@@ -5291,19 +5300,32 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
 				default_block = ir_new_block(proc, clause, "type-match.dflt.body");
 				continue;
 			}
+			GB_ASSERT(cc->list.count == 1);
 
 
 			irBlock *body = ir_new_block(proc, clause, "type-match.case.body");
 
-			Scope *scope = *map_scope_get(&proc->module->info->scopes, hash_pointer(clause));
-			Entity *tag_var_entity = current_scope_lookup_entity(scope, tag_var_name);
-			GB_ASSERT_MSG(tag_var_entity != NULL, "%.*s", LIT(tag_var_name));
+			Entity *tag_var_entity = NULL;
+			Type *tag_var_type = NULL;
+			if (str_eq(tag_var_name, str_lit("_"))) {
+				Type *t = type_of_expr(proc->module->info, cc->list.e[0]);
+				if (is_union_ptr) {
+					t = make_type_pointer(proc->module->allocator, t);
+				}
+				tag_var_type = t;
+			} else {
+				Scope *scope = *map_scope_get(&proc->module->info->scopes, hash_pointer(clause));
+				tag_var_entity = current_scope_lookup_entity(scope, tag_var_name);
+				GB_ASSERT_MSG(tag_var_entity != NULL, "%.*s", LIT(tag_var_name));
+				tag_var_type = tag_var_entity->type;
+			}
+			GB_ASSERT(tag_var_type != NULL);
 
 			irBlock *next_cond = NULL;
 			irValue *cond = NULL;
 
 			if (is_union_ptr) {
-				Type *bt = type_deref(tag_var_entity->type);
+				Type *bt = type_deref(tag_var_type);
 				irValue *index = NULL;
 				Type *ut = base_type(type_deref(ir_type(parent)));
 				GB_ASSERT(ut->Record.kind == TypeRecord_Union);
@@ -5316,16 +5338,25 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
 				}
 				GB_ASSERT(index != NULL);
 
-				irValue *tag_var = ir_add_local(proc, tag_var_entity);
-				irValue *data_ptr = ir_emit_conv(proc, union_data, tag_var_entity->type);
+				irValue *tag_var = NULL;
+				if (tag_var_entity != NULL) {
+					tag_var = ir_add_local(proc, tag_var_entity);
+				} else {
+					tag_var = ir_add_local_generated(proc, tag_var_type);
+				}
+
+
+				irValue *data_ptr = ir_emit_conv(proc, union_data, tag_var_type);
 				ir_emit_store(proc, tag_var, data_ptr);
 
 				cond = ir_emit_comp(proc, Token_CmpEq, tag_index, index);
 			} else if (is_any) {
-				Type *type = tag_var_entity->type;
+				Type *type = tag_var_type;
 				irValue *any_data = ir_emit_struct_ev(proc, parent, 1);
 				irValue *data = ir_emit_conv(proc, any_data, make_type_pointer(proc->module->allocator, type));
-				ir_module_add_value(proc->module, tag_var_entity, data);
+				if (tag_var_entity != NULL) {
+					ir_module_add_value(proc->module, tag_var_entity, data);
+				}
 
 				irValue *any_ti  = ir_emit_struct_ev(proc, parent, 0);
 				irValue *case_ti = ir_type_info(proc, type);
@@ -6228,11 +6259,6 @@ void ir_gen_tree(irGen *s) {
 					irValue *gep = ir_get_type_info_ptr(proc, type_info_data, t->Pointer.elem);
 					ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 0), gep);
 				} break;
-				case Type_Maybe: {
-					tag = ir_emit_conv(proc, ti_ptr, t_type_info_maybe_ptr);
-					irValue *gep = ir_get_type_info_ptr(proc, type_info_data, t->Maybe.elem);
-					ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 0), gep);
-				} break;
 				case Type_Array: {
 					tag = ir_emit_conv(proc, ti_ptr, t_type_info_array_ptr);
 					irValue *gep = ir_get_type_info_ptr(proc, type_info_data, t->Array.elem);

+ 0 - 21
src/ir_print.c

@@ -172,13 +172,6 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t) {
 		ir_print_type(f, m, t->Pointer.elem);
 		ir_fprintf(f, "*");
 		return;
-	case Type_Maybe:
-		ir_fprintf(f, "{");
-		ir_print_type(f, m, t->Maybe.elem);
-		ir_fprintf(f, ", ");
-		ir_print_type(f, m, t_bool);
-		ir_fprintf(f, "}");
-		return;
 	case Type_Array:
 		ir_fprintf(f, "[%lld x ", t->Array.count);
 		ir_print_type(f, m, t->Array.elem);
@@ -306,25 +299,11 @@ void ir_print_compound_element(irFileBuffer *f, irModule *m, ExactValue v, Type
 	ir_print_type(f, m, elem_type);
 	ir_fprintf(f, " ");
 
-	if (v.kind != ExactValue_Invalid && is_type_maybe(elem_type)) {
-		Type *t = base_type(elem_type)->Maybe.elem;
-		ir_fprintf(f, "{");
-		ir_print_type(f, m, t);
-		ir_fprintf(f, " ");
-	}
-
 	if (v.kind == ExactValue_Invalid || base_type(elem_type) == t_any) {
 		ir_fprintf(f, "zeroinitializer");
 	} else {
 		ir_print_exact_value(f, m, v, elem_type);
 	}
-
-	if (v.kind != ExactValue_Invalid && is_type_maybe(elem_type)) {
-		ir_fprintf(f, ", ");
-		ir_print_type(f, m, t_bool);
-		ir_fprintf(f, " ");
-		ir_fprintf(f, "true}");
-	}
 }
 
 void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *type) {

+ 38 - 80
src/parser.c

@@ -147,7 +147,6 @@ AST_NODE_KIND(_ExprBegin,  "",  i32) \
 	AST_NODE_KIND(SelectorExpr, "selector expression",    struct { Token token; AstNode *expr, *selector; }) \
 	AST_NODE_KIND(IndexExpr,    "index expression",       struct { AstNode *expr, *index; Token open, close; }) \
 	AST_NODE_KIND(DerefExpr,    "dereference expression", struct { Token op; AstNode *expr; }) \
-	AST_NODE_KIND(DemaybeExpr,  "demaybe expression",     struct { Token op; AstNode *expr; }) \
 	AST_NODE_KIND(SliceExpr, "slice expression", struct { \
 		AstNode *expr; \
 		Token open, close, interval; \
@@ -251,7 +250,6 @@ AST_NODE_KIND(_ComplexStmtBegin, "", i32) \
 	AST_NODE_KIND(TypeMatchStmt, "type match statement", struct { \
 		Token    token; \
 		AstNode *tag;   \
- 		AstNode *var;   \
 		AstNode *body;  \
 	}) \
 	AST_NODE_KIND(DeferStmt,  "defer statement",  struct { Token token; AstNode *stmt; }) \
@@ -333,10 +331,6 @@ AST_NODE_KIND(_TypeBegin, "", i32) \
 		Token token; \
 		AstNode *type; \
 	}) \
-	AST_NODE_KIND(MaybeType, "maybe type", struct { \
-		Token token; \
-		AstNode *type; \
-	}) \
 	AST_NODE_KIND(ArrayType, "array type", struct { \
 		Token token; \
 		AstNode *count; \
@@ -469,7 +463,6 @@ 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_DemaybeExpr:  return node->DemaybeExpr.op;
 	case AstNode_BlockExpr:    return node->BlockExpr.open;
 	case AstNode_GiveExpr:     return node->GiveExpr.token;
 	case AstNode_IfExpr:       return node->IfExpr.token;
@@ -513,7 +506,6 @@ Token ast_node_token(AstNode *node) {
 	case AstNode_HelperType:       return node->HelperType.token;
 	case AstNode_ProcType:         return node->ProcType.token;
 	case AstNode_PointerType:      return node->PointerType.token;
-	case AstNode_MaybeType:        return node->MaybeType.token;
 	case AstNode_ArrayType:        return node->ArrayType.token;
 	case AstNode_DynamicArrayType: return node->DynamicArrayType.token;
 	case AstNode_VectorType:       return node->VectorType.token;
@@ -693,13 +685,6 @@ AstNode *ast_deref_expr(AstFile *f, AstNode *expr, Token op) {
 	return result;
 }
 
-AstNode *ast_demaybe_expr(AstFile *f, AstNode *expr, Token op) {
-	AstNode *result = make_ast_node(f, AstNode_DemaybeExpr);
-	result->DemaybeExpr.expr = expr;
-	result->DemaybeExpr.op = op;
-	return result;
-}
-
 AstNode *ast_interval_expr(AstFile *f, Token op, AstNode *left, AstNode *right) {
 	AstNode *result = make_ast_node(f, AstNode_IntervalExpr);
 
@@ -907,11 +892,10 @@ AstNode *ast_match_stmt(AstFile *f, Token token, AstNode *init, AstNode *tag, As
 }
 
 
-AstNode *ast_type_match_stmt(AstFile *f, Token token, AstNode *tag, AstNode *var, AstNode *body) {
+AstNode *ast_type_match_stmt(AstFile *f, Token token, AstNode *tag, AstNode *body) {
 	AstNode *result = make_ast_node(f, AstNode_TypeMatchStmt);
 	result->TypeMatchStmt.token = token;
 	result->TypeMatchStmt.tag   = tag;
-	result->TypeMatchStmt.var   = var;
 	result->TypeMatchStmt.body  = body;
 	return result;
 }
@@ -1031,13 +1015,6 @@ AstNode *ast_pointer_type(AstFile *f, Token token, AstNode *type) {
 	return result;
 }
 
-AstNode *ast_maybe_type(AstFile *f, Token token, AstNode *type) {
-	AstNode *result = make_ast_node(f, AstNode_MaybeType);
-	result->MaybeType.token = token;
-	result->MaybeType.type = type;
-	return result;
-}
-
 AstNode *ast_array_type(AstFile *f, Token token, AstNode *count, AstNode *elem) {
 	AstNode *result = make_ast_node(f, AstNode_ArrayType);
 	result->ArrayType.token = token;
@@ -1777,6 +1754,7 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
 		} else if (str_eq(name.string, str_lit("file"))) { return ast_basic_directive(f, token, name.string);
 		} else if (str_eq(name.string, str_lit("line"))) { return ast_basic_directive(f, token, name.string);
 		} else if (str_eq(name.string, str_lit("procedure"))) { return ast_basic_directive(f, token, name.string);
+		} else if (str_eq(name.string, str_lit("type"))) { return ast_helper_type(f, token, parse_type(f));
 		} else {
 			operand = ast_tag_expr(f, token, name, parse_expr(f, false));
 		}
@@ -1999,10 +1977,6 @@ AstNode *parse_atom_expr(AstFile *f, bool lhs) {
 			operand = ast_deref_expr(f, operand, expect_token(f, Token_Pointer));
 			break;
 
-		case Token_Maybe: // Demaybe
-			operand = ast_demaybe_expr(f, operand, expect_token(f, Token_Maybe));
-			break;
-
 		case Token_OpenBrace:
 			if (!lhs && is_literal_type(operand) && f->expr_level >= 0) {
 				operand = parse_literal_value(f, operand);
@@ -2205,9 +2179,7 @@ AstNode *parse_value_decl(AstFile *f, AstNodeArray lhs) {
 	bool is_mutable = true;
 
 	if (allow_token(f, Token_Colon)) {
-		if (!allow_token(f, Token_type)) {
-			type = parse_type_attempt(f);
-		}
+		type = parse_type_attempt(f);
 	} else if (f->curr_token.kind != Token_Eq &&
 	           f->curr_token.kind != Token_Semicolon) {
 		syntax_error(f->curr_token, "Expected a type separator `:` or `=`");
@@ -2553,10 +2525,16 @@ AstNode *parse_type_or_ident(AstFile *f) {
 		return e;
 	}
 
-	case Token_type: {
-		Token token = expect_token(f, Token_type);
-		AstNode *type = parse_type(f);
-		return ast_helper_type(f, token, type);
+	case Token_Hash: {
+		Token hash_token = expect_token(f, Token_Hash);
+		Token name = expect_token(f, Token_Ident);
+		String tag = name.string;
+		if (str_eq(tag, str_lit("type"))) {
+			AstNode *type = parse_type(f);
+			return ast_helper_type(f, hash_token, type);
+		}
+		syntax_error(name, "Expected `type` after #");
+		return ast_bad_expr(f, hash_token, f->curr_token);
 	}
 
 	case Token_Pointer: {
@@ -2565,12 +2543,6 @@ AstNode *parse_type_or_ident(AstFile *f) {
 		return ast_pointer_type(f, token, elem);
 	}
 
-	case Token_Maybe: {
-		Token token = expect_token(f, Token_Maybe);
-		AstNode *elem = parse_type(f);
-		return ast_maybe_type(f, token, elem);
-	}
-
 	case Token_OpenBracket: {
 		Token token = expect_token(f, Token_OpenBracket);
 		AstNode *count_expr = NULL;
@@ -2972,8 +2944,7 @@ AstNode *parse_for_stmt(AstFile *f) {
 		f->expr_level = -1;
 		if (f->curr_token.kind != Token_Semicolon) {
 			cond = parse_simple_stmt(f, true);
-			if (cond->kind == AstNode_AssignStmt &&
-			    cond->AssignStmt.op.kind == Token_in) {
+			if (cond->kind == AstNode_AssignStmt && cond->AssignStmt.op.kind == Token_in) {
 				is_range = true;
 			}
 		}
@@ -3065,6 +3036,7 @@ AstNode *parse_for_stmt(AstFile *f) {
 #endif
 }
 
+
 AstNode *parse_case_clause(AstFile *f) {
 	Token token = f->curr_token;
 	AstNodeArray list = make_ast_node_array(f);
@@ -3097,6 +3069,7 @@ AstNode *parse_type_case_clause(AstFile *f) {
 }
 
 
+
 AstNode *parse_match_stmt(AstFile *f) {
 	if (f->curr_proc == NULL) {
 		syntax_error(f->curr_token, "You cannot use a match statement in the file scope");
@@ -3108,37 +3081,16 @@ AstNode *parse_match_stmt(AstFile *f) {
 	AstNode *tag  = NULL;
 	AstNode *body = NULL;
 	Token open, close;
+	bool is_type_match = false;
 
-	if (allow_token(f, Token_type)) {
+	if (f->curr_token.kind != Token_OpenBrace) {
 		isize prev_level = f->expr_level;
 		f->expr_level = -1;
 
-		AstNode *var = parse_ident(f);
-		expect_token_after(f, Token_in, "match type name");
-		tag = parse_simple_stmt(f, false);
-
-		f->expr_level = prev_level;
-
-		open = expect_token(f, Token_OpenBrace);
-		AstNodeArray list = make_ast_node_array(f);
-
-		while (f->curr_token.kind == Token_case ||
-		       f->curr_token.kind == Token_default) {
-			array_add(&list, parse_type_case_clause(f));
-		}
-
-		close = expect_token(f, Token_CloseBrace);
-		body = ast_block_stmt(f, list, open, close);
-
-		tag = convert_stmt_to_expr(f, tag, str_lit("type match expression"));
-		return ast_type_match_stmt(f, token, tag, var, body);
-	} else {
-		if (f->curr_token.kind != Token_OpenBrace) {
-			isize prev_level = f->expr_level;
-			f->expr_level = -1;
-			if (f->curr_token.kind != Token_Semicolon) {
-				tag = parse_simple_stmt(f, false);
-			}
+		tag = parse_simple_stmt(f, true);
+		if (tag->kind == AstNode_AssignStmt && tag->AssignStmt.op.kind == Token_in) {
+			is_type_match = true;
+		} else {
 			if (allow_token(f, Token_Semicolon)) {
 				init = tag;
 				tag = NULL;
@@ -3146,28 +3098,33 @@ AstNode *parse_match_stmt(AstFile *f) {
 					tag = parse_simple_stmt(f, false);
 				}
 			}
-
-			f->expr_level = prev_level;
 		}
+		f->expr_level = prev_level;
+	}
+	open = expect_token(f, Token_OpenBrace);
+	AstNodeArray list = make_ast_node_array(f);
 
-		open = expect_token(f, Token_OpenBrace);
-		AstNodeArray list = make_ast_node_array(f);
-
-		while (f->curr_token.kind == Token_case ||
-		       f->curr_token.kind == Token_default) {
+	while (f->curr_token.kind == Token_case ||
+	       f->curr_token.kind == Token_default) {
+		if (is_type_match) {
+			array_add(&list, parse_type_case_clause(f));
+		} else {
 			array_add(&list, parse_case_clause(f));
 		}
+	}
 
-		close = expect_token(f, Token_CloseBrace);
+	close = expect_token(f, Token_CloseBrace);
 
-		body = ast_block_stmt(f, list, open, close);
+	body = ast_block_stmt(f, list, open, close);
 
+	if (!is_type_match) {
 		tag = convert_stmt_to_expr(f, tag, str_lit("match expression"));
 		return ast_match_stmt(f, token, init, tag, body);
+	} else {
+		return ast_type_match_stmt(f, token, tag, body);
 	}
 }
 
-
 AstNode *parse_defer_stmt(AstFile *f) {
 	if (f->curr_proc == NULL) {
 		syntax_error(f->curr_token, "You cannot use a defer statement in the file scope");
@@ -3359,6 +3316,7 @@ AstNode *parse_stmt(AstFile *f) {
 		Token hash_token = expect_token(f, Token_Hash);
 		Token name = expect_token(f, Token_Ident);
 		String tag = name.string;
+
 		if (str_eq(tag, str_lit("import"))) {
 			AstNode *cond = NULL;
 			Token import_name = {0};

+ 85 - 124
src/tokenizer.c

@@ -12,23 +12,24 @@ TOKEN_KIND(Token__LiteralBegin, "_LiteralBegin"), \
 TOKEN_KIND(Token__LiteralEnd,   "_LiteralEnd"), \
 \
 TOKEN_KIND(Token__OperatorBegin, "_OperatorBegin"), \
-	TOKEN_KIND(Token_Eq,      "="), \
-	TOKEN_KIND(Token_Not,     "!"), \
-	TOKEN_KIND(Token_Hash,    "#"), \
-	TOKEN_KIND(Token_At,      "@"), \
-	TOKEN_KIND(Token_Pointer, "^"), \
-	TOKEN_KIND(Token_Maybe,   "?"), \
-	TOKEN_KIND(Token_Add,     "+"), \
-	TOKEN_KIND(Token_Sub,     "-"), \
-	TOKEN_KIND(Token_Mul,     "*"), \
-	TOKEN_KIND(Token_Quo,     "/"), \
-	TOKEN_KIND(Token_Mod,     "%"), \
-	TOKEN_KIND(Token_And,     "&"), \
-	TOKEN_KIND(Token_Or,      "|"), \
-	TOKEN_KIND(Token_Xor,     "~"), \
-	TOKEN_KIND(Token_AndNot,  "&~"), \
-	TOKEN_KIND(Token_Shl,     "<<"), \
-	TOKEN_KIND(Token_Shr,     ">>"), \
+	TOKEN_KIND(Token_Eq,       "="), \
+	TOKEN_KIND(Token_Not,      "!"), \
+	TOKEN_KIND(Token_Hash,     "#"), \
+	TOKEN_KIND(Token_At,       "@"), \
+	TOKEN_KIND(Token_Dollar,   "$"), \
+	TOKEN_KIND(Token_Pointer,  "^"), \
+	TOKEN_KIND(Token_Question, "?"), \
+	TOKEN_KIND(Token_Add,      "+"), \
+	TOKEN_KIND(Token_Sub,      "-"), \
+	TOKEN_KIND(Token_Mul,      "*"), \
+	TOKEN_KIND(Token_Quo,      "/"), \
+	TOKEN_KIND(Token_Mod,      "%"), \
+	TOKEN_KIND(Token_And,      "&"), \
+	TOKEN_KIND(Token_Or,       "|"), \
+	TOKEN_KIND(Token_Xor,      "~"), \
+	TOKEN_KIND(Token_AndNot,   "&~"), \
+	TOKEN_KIND(Token_Shl,      "<<"), \
+	TOKEN_KIND(Token_Shr,      ">>"), \
 \
 	/*TOKEN_KIND(Token_as,         "as"), */\
 	/*TOKEN_KIND(Token_transmute,  "transmute"), */\
@@ -55,6 +56,8 @@ TOKEN_KIND(Token__AssignOpBegin, "_AssignOpBegin"), \
 TOKEN_KIND(Token__AssignOpEnd,   "_AssignOpEnd"), \
 	TOKEN_KIND(Token_ArrowRight, "->"), \
 	TOKEN_KIND(Token_ArrowLeft,  "<-"), \
+	TOKEN_KIND(Token_Increment,  "++"), \
+	TOKEN_KIND(Token_Decrement,  "--"), \
 \
 TOKEN_KIND(Token__ComparisonBegin, "_ComparisonBegin"), \
 	TOKEN_KIND(Token_CmpEq, "=="), \
@@ -80,45 +83,45 @@ TOKEN_KIND(Token__ComparisonEnd, "_ComparisonEnd"), \
 TOKEN_KIND(Token__OperatorEnd, "_OperatorEnd"), \
 \
 TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
-	/* TODO(bill): So of these keywords are not used but "reserved", why not remove them? */ \
-	TOKEN_KIND(Token_when,           "when"), \
-	TOKEN_KIND(Token_if,             "if"), \
-	TOKEN_KIND(Token_else,           "else"), \
-	TOKEN_KIND(Token_for,            "for"), \
-	TOKEN_KIND(Token_in,             "in"), \
-	TOKEN_KIND(Token_break,          "break"), \
-	TOKEN_KIND(Token_continue,       "continue"), \
-	TOKEN_KIND(Token_fallthrough,    "fallthrough"), \
-	TOKEN_KIND(Token_match,          "match"), \
-	TOKEN_KIND(Token_type,           "type"), \
-	TOKEN_KIND(Token_default,        "default"), \
-	TOKEN_KIND(Token_case,           "case"), \
-	TOKEN_KIND(Token_defer,          "defer"), \
-	TOKEN_KIND(Token_return,         "return"), \
-	TOKEN_KIND(Token_give,           "give"), \
-	TOKEN_KIND(Token_proc,           "proc"), \
-	TOKEN_KIND(Token_macro,          "macro"), \
-	TOKEN_KIND(Token_struct,         "struct"), \
-	TOKEN_KIND(Token_union,          "union"), \
-	TOKEN_KIND(Token_raw_union,      "raw_union"), \
-	TOKEN_KIND(Token_enum,           "enum"), \
-	TOKEN_KIND(Token_vector,         "vector"), \
-	TOKEN_KIND(Token_map,            "map"), \
-	TOKEN_KIND(Token_static,         "static"), \
-	TOKEN_KIND(Token_dynamic,        "dynamic"), \
-	TOKEN_KIND(Token_using,          "using"), \
-	TOKEN_KIND(Token_no_alias,       "no_alias"), \
-	/* TOKEN_KIND(Token_mutable,        "mutable"),  */\
+	/* TODO(bill): Of these keywords are not used but "reserved", why not remove them? */ \
+	TOKEN_KIND(Token_when,           "when"),            \
+	TOKEN_KIND(Token_if,             "if"),              \
+	TOKEN_KIND(Token_else,           "else"),            \
+	TOKEN_KIND(Token_for,            "for"),             \
+	TOKEN_KIND(Token_in,             "in"),              \
+	TOKEN_KIND(Token_break,          "break"),           \
+	TOKEN_KIND(Token_continue,       "continue"),        \
+	TOKEN_KIND(Token_fallthrough,    "fallthrough"),     \
+	TOKEN_KIND(Token_match,          "match"),           \
+	/* TOKEN_KIND(Token_type,           "type"), */      \
+	TOKEN_KIND(Token_default,        "default"),         \
+	TOKEN_KIND(Token_case,           "case"),            \
+	TOKEN_KIND(Token_defer,          "defer"),           \
+	TOKEN_KIND(Token_return,         "return"),          \
+	TOKEN_KIND(Token_give,           "give"),            \
+	TOKEN_KIND(Token_proc,           "proc"),            \
+	TOKEN_KIND(Token_macro,          "macro"),           \
+	TOKEN_KIND(Token_struct,         "struct"),          \
+	TOKEN_KIND(Token_union,          "union"),           \
+	TOKEN_KIND(Token_raw_union,      "raw_union"),       \
+	TOKEN_KIND(Token_enum,           "enum"),            \
+	TOKEN_KIND(Token_vector,         "vector"),          \
+	TOKEN_KIND(Token_map,            "map"),             \
+	TOKEN_KIND(Token_static,         "static"),          \
+	TOKEN_KIND(Token_dynamic,        "dynamic"),         \
+	TOKEN_KIND(Token_using,          "using"),           \
+	TOKEN_KIND(Token_no_alias,       "no_alias"),        \
+	/* TOKEN_KIND(Token_mutable,        "mutable"),  */  \
 	/* TOKEN_KIND(Token_immutable,      "immutable"),  */\
-	TOKEN_KIND(Token_thread_local,   "thread_local"), \
-	TOKEN_KIND(Token_cast,           "cast"), \
-	TOKEN_KIND(Token_transmute,      "transmute"), \
-	TOKEN_KIND(Token_down_cast,      "down_cast"), \
-	TOKEN_KIND(Token_union_cast,     "union_cast"), \
-	TOKEN_KIND(Token_context,        "context"), \
-	TOKEN_KIND(Token_push_context,   "push_context"), \
-	TOKEN_KIND(Token_push_allocator, "push_allocator"), \
-	TOKEN_KIND(Token_asm,            "asm"), \
+	TOKEN_KIND(Token_thread_local,   "thread_local"),    \
+	TOKEN_KIND(Token_cast,           "cast"),            \
+	TOKEN_KIND(Token_transmute,      "transmute"),       \
+	TOKEN_KIND(Token_down_cast,      "down_cast"),       \
+	TOKEN_KIND(Token_union_cast,     "union_cast"),      \
+	TOKEN_KIND(Token_context,        "context"),         \
+	TOKEN_KIND(Token_push_context,   "push_context"),    \
+	TOKEN_KIND(Token_push_allocator, "push_allocator"),  \
+	TOKEN_KIND(Token_asm,            "asm"),             \
 TOKEN_KIND(Token__KeywordEnd, "_KeywordEnd"), \
 	TOKEN_KIND(Token_Count, "")
 
@@ -478,7 +481,6 @@ gb_inline void scan_mantissa(Tokenizer *t, i32 base, bool allow_underscore) {
 	}
 }
 
-
 Token scan_number_to_token(Tokenizer *t, bool seen_decimal_point) {
 	Token token = {0};
 	token.kind = Token_Integer;
@@ -734,20 +736,10 @@ Token tokenizer_get_token(Tokenizer *t) {
 
 		// NOTE(bill): All keywords are > 1
 		if (token.string.len > 1) {
-			/* if (str_eq(token.string, token_strings[Token_as])) {
-				token.kind = Token_as;
-			} else if (str_eq(token.string, token_strings[Token_transmute])) {
-				token.kind = Token_transmute;
-			} else if (str_eq(token.string, token_strings[Token_down_cast])) {
-				token.kind = Token_down_cast;
-			} else if (str_eq(token.string, token_strings[Token_union_cast])) {
-				token.kind = Token_union_cast;
-			} else  */{
-				for (i32 k = Token__KeywordBegin+1; k < Token__KeywordEnd; k++) {
-					if (str_eq(token.string, token_strings[k])) {
-						token.kind = cast(TokenKind)k;
-						break;
-					}
+			for (i32 k = Token__KeywordBegin+1; k < Token__KeywordEnd; k++) {
+				if (str_eq(token.string, token_strings[k])) {
+					token.kind = cast(TokenKind)k;
+					break;
 				}
 			}
 		}
@@ -861,57 +853,28 @@ Token tokenizer_get_token(Tokenizer *t) {
 			}
 			break;
 
-		case '#':
-			token.kind = Token_Hash;
-			break;
-		case '@':
-			token.kind = Token_At;
-			break;
-		case '^':
-			token.kind = Token_Pointer;
-			break;
-		case '?':
-			token.kind = Token_Maybe;
-			break;
-		case ';':
-			token.kind = Token_Semicolon;
-			break;
-		case ',':
-			token.kind = Token_Comma;
-			break;
-		case ':':
-			token.kind = Token_Colon;
-			break;
-		case '(':
-			token.kind = Token_OpenParen;
-			break;
-		case ')':
-			token.kind = Token_CloseParen;
-			break;
-		case '[':
-			token.kind = Token_OpenBracket;
-			break;
-		case ']':
-			token.kind = Token_CloseBracket;
-			break;
-		case '{':
-			token.kind = Token_OpenBrace;
-			break;
-		case '}':
-			token.kind = Token_CloseBrace;
-			break;
-
-		case '*': token.kind = token_kind_variant2(t, Token_Mul,   Token_MulEq);     break;
-		case '%': token.kind = token_kind_variant2(t, Token_Mod,   Token_ModEq);     break;
-		case '=': token.kind = token_kind_variant2(t, Token_Eq,    Token_CmpEq);     break;
-		case '~': token.kind = token_kind_variant2(t, Token_Xor,   Token_XorEq);     break;
-		case '!': token.kind = token_kind_variant2(t, Token_Not,   Token_NotEq);     break;
-		case '+':
-			token.kind = token_kind_variant2(t, Token_Add, Token_AddEq);
-			break;
-		case '-':
-			token.kind = token_kind_variant3(t, Token_Sub, Token_SubEq, '>', Token_ArrowRight);
-			break;
+		case '#': token.kind = Token_Hash;         break;
+		case '@': token.kind = Token_At;           break;
+		case '$': token.kind = Token_Dollar;       break;
+		case '?': token.kind = Token_Question;     break;
+		case '^': token.kind = Token_Pointer;      break;
+		case ';': token.kind = Token_Semicolon;    break;
+		case ',': token.kind = Token_Comma;        break;
+		case ':': token.kind = Token_Colon;        break;
+		case '(': token.kind = Token_OpenParen;    break;
+		case ')': token.kind = Token_CloseParen;   break;
+		case '[': token.kind = Token_OpenBracket;  break;
+		case ']': token.kind = Token_CloseBracket; break;
+		case '{': token.kind = Token_OpenBrace;    break;
+		case '}': token.kind = Token_CloseBrace;   break;
+
+		case '*': token.kind = token_kind_variant2(t, Token_Mul, Token_MulEq);                                              break;
+		case '%': token.kind = token_kind_variant2(t, Token_Mod, Token_ModEq);                                              break;
+		case '=': token.kind = token_kind_variant2(t, Token_Eq,  Token_CmpEq);                                              break;
+		case '~': token.kind = token_kind_variant2(t, Token_Xor, Token_XorEq);                                              break;
+		case '!': token.kind = token_kind_variant2(t, Token_Not, Token_NotEq);                                              break;
+		case '+': token.kind = token_kind_variant3(t, Token_Add, Token_AddEq, '+', Token_Increment);                        break;
+		case '-': token.kind = token_kind_variant4(t, Token_Sub, Token_SubEq, '-', Token_Decrement, '>', Token_ArrowRight); break;
 		case '/': {
 			if (t->curr_rune == '/') {
 				while (t->curr_rune != '\n' && t->curr_rune != GB_RUNE_EOF) {
@@ -951,9 +914,7 @@ Token tokenizer_get_token(Tokenizer *t) {
 				token.kind = token_kind_dub_eq(t, '<', Token_Lt, Token_LtEq, Token_Shl, Token_ShlEq);
 			}
 			break;
-		case '>':
-			token.kind = token_kind_dub_eq(t, '>', Token_Gt, Token_GtEq, Token_Shr, Token_ShrEq);
-			break;
+		case '>': token.kind = token_kind_dub_eq(t, '>', Token_Gt, Token_GtEq, Token_Shr, Token_ShrEq); break;
 
 		case '&':
 			token.kind = Token_And;

+ 31 - 60
src/types.c

@@ -11,6 +11,20 @@ typedef enum BasicKind {
 	Basic_u32,
 	Basic_i64,
 	Basic_u64,
+
+/* 	Basic_i16le,
+	Basic_i16be,
+	Basic_u16le,
+	Basic_u16be,
+	Basic_i32le,
+	Basic_i32be,
+	Basic_u32le,
+	Basic_u32be,
+	Basic_i64le,
+	Basic_i64be,
+	Basic_u64le,
+	Basic_u64be, */
+
 	// Basic_i128,
 	// Basic_u128,
 	// Basic_f16,
@@ -93,6 +107,7 @@ typedef struct TypeRecord {
 	Entity * enum_count;
 	Entity * enum_min_value;
 	Entity * enum_max_value;
+	Entity * enum_names;
 } TypeRecord;
 
 #define TYPE_KINDS                                        \
@@ -102,7 +117,6 @@ typedef struct TypeRecord {
 	TYPE_KIND(DynamicArray, struct { Type *elem; })       \
 	TYPE_KIND(Vector,  struct { Type *elem; i64 count; }) \
 	TYPE_KIND(Slice,   struct { Type *elem; })            \
-	TYPE_KIND(Maybe,   struct { Type *elem; })            \
 	TYPE_KIND(Record,  TypeRecord)                        \
 	TYPE_KIND(Named, struct {                             \
 		String  name;                                     \
@@ -177,16 +191,16 @@ typedef struct BaseTypeSizes {
 } BaseTypeSizes;
 
 
-typedef Array(isize) Array_isize;
+typedef Array(i32) Array_i32;
 
 typedef struct Selection {
-	Entity *    entity;
-	Array_isize index;
-	bool        indirect; // Set if there was a pointer deref anywhere down the line
+	Entity *  entity;
+	Array_i32 index;
+	bool      indirect; // Set if there was a pointer deref anywhere down the line
 } Selection;
 Selection empty_selection = {0};
 
-Selection make_selection(Entity *entity, Array_isize index, bool indirect) {
+Selection make_selection(Entity *entity, Array_i32 index, bool indirect) {
 	Selection s = {entity, index, indirect};
 	return s;
 }
@@ -273,6 +287,7 @@ gb_global Type *t_int_ptr = NULL;
 gb_global Type *t_i64_ptr = NULL;
 gb_global Type *t_f64_ptr = NULL;
 gb_global Type *t_byte_slice = NULL;
+gb_global Type *t_string_slice = NULL;
 
 
 gb_global Type *t_type_info                = NULL;
@@ -289,7 +304,6 @@ gb_global Type *t_type_info_any           = NULL;
 gb_global Type *t_type_info_string        = NULL;
 gb_global Type *t_type_info_boolean       = NULL;
 gb_global Type *t_type_info_pointer       = NULL;
-gb_global Type *t_type_info_maybe         = NULL;
 gb_global Type *t_type_info_procedure     = NULL;
 gb_global Type *t_type_info_array         = NULL;
 gb_global Type *t_type_info_dynamic_array = NULL;
@@ -310,7 +324,6 @@ gb_global Type *t_type_info_any_ptr           = NULL;
 gb_global Type *t_type_info_string_ptr        = NULL;
 gb_global Type *t_type_info_boolean_ptr       = NULL;
 gb_global Type *t_type_info_pointer_ptr       = NULL;
-gb_global Type *t_type_info_maybe_ptr         = NULL;
 gb_global Type *t_type_info_procedure_ptr     = NULL;
 gb_global Type *t_type_info_array_ptr         = NULL;
 gb_global Type *t_type_info_dynamic_array_ptr = NULL;
@@ -393,12 +406,6 @@ Type *make_type_pointer(gbAllocator a, Type *elem) {
 	return t;
 }
 
-Type *make_type_maybe(gbAllocator a, Type *elem) {
-	Type *t = alloc_type(a, Type_Maybe);
-	t->Maybe.elem = elem;
-	return t;
-}
-
 Type *make_type_array(gbAllocator a, Type *elem, i64 count) {
 	Type *t = alloc_type(a, Type_Array);
 	t->Array.elem = elem;
@@ -630,10 +637,6 @@ bool is_type_pointer(Type *t) {
 	}
 	return t->kind == Type_Pointer;
 }
-bool is_type_maybe(Type *t) {
-	t = base_type(t);
-	return t->kind == Type_Maybe;
-}
 bool is_type_tuple(Type *t) {
 	t = base_type(t);
 	return t->kind == Type_Tuple;
@@ -780,7 +783,6 @@ bool type_has_nil(Type *t) {
 	case Type_DynamicArray:
 	case Type_Proc:
 	case Type_Pointer:
-	case Type_Maybe:
 		return true;
 	}
 	return false;
@@ -890,12 +892,6 @@ bool are_types_identical(Type *x, Type *y) {
 		}
 		break;
 
-	case Type_Maybe:
-		if (y->kind == Type_Maybe) {
-			return are_types_identical(x->Maybe.elem, y->Maybe.elem);
-		}
-		break;
-
 	case Type_Named:
 		if (y->kind == Type_Named) {
 			return x->Named.base == y->Named.base;
@@ -981,9 +977,6 @@ bool is_type_cte_safe(Type *type) {
 	case Type_Slice:
 		return false;
 
-	case Type_Maybe:
-		return is_type_cte_safe(type->Maybe.elem);
-
 	case Type_Record: {
 		if (type->Record.kind != TypeRecord_Struct) {
 			return false;
@@ -1026,12 +1019,14 @@ typedef enum ProcTypeOverloadKind {
 	ProcOverload_ResultCount,
 	ProcOverload_ResultTypes,
 
+	ProcOverload_NotProcedure,
+
 } ProcTypeOverloadKind;
 
 
 ProcTypeOverloadKind are_proc_types_overload_safe(Type *x, Type *y) {
-	GB_ASSERT(is_type_proc(x));
-	GB_ASSERT(is_type_proc(y));
+ 	if (!is_type_proc(x)) return ProcOverload_NotProcedure;
+ 	if (!is_type_proc(y)) return ProcOverload_NotProcedure;
 	TypeProc *px = &base_type(x)->Proc;
 	TypeProc *py = &base_type(y)->Proc;
 
@@ -1113,7 +1108,7 @@ Selection lookup_field_from_index(gbAllocator a, Type *type, i64 index) {
 			Entity *f = type->Record.fields[i];
 			if (f->kind == Entity_Variable) {
 				if (f->Variable.field_src_index == index) {
-					Array_isize sel_array = {0};
+					Array_i32 sel_array = {0};
 					array_init_count(&sel_array, a, 1);
 					sel_array.e[0] = i;
 					return make_selection(f, sel_array, false);
@@ -1125,7 +1120,7 @@ Selection lookup_field_from_index(gbAllocator a, Type *type, i64 index) {
 		for (isize i = 0; i < max_count; i++) {
 			Entity *f = type->Tuple.variables[i];
 			if (i == index) {
-				Array_isize sel_array = {0};
+				Array_i32 sel_array = {0};
 				array_init_count(&sel_array, a, 1);
 				sel_array.e[0] = i;
 				return make_selection(f, sel_array, false);
@@ -1352,6 +1347,10 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n
 					sel.entity = type->Record.enum_max_value;
 					return sel;
 				}
+				if (str_eq(field_name, str_lit("names"))) {
+					sel.entity = type->Record.enum_names;
+					return sel;
+				}
 			}
 
 			for (isize i = 0; i < type->Record.field_count; i++) {
@@ -1558,17 +1557,6 @@ i64 type_align_of_internal(BaseTypeSizes s, gbAllocator allocator, Type *t, Type
 		return max;
 	} break;
 
-	case Type_Maybe: {
-		Type *elem = t->Maybe.elem;
-		type_path_push(path, elem);
-		if (path->failure) {
-			return FAILURE_ALIGNMENT;
-		}
-		i64 align = gb_max(type_align_of_internal(s, allocator, t->Maybe.elem, path), type_align_of_internal(s, allocator, t_bool, path));
-		type_path_pop(path);
-		return align;
-	}
-
 	case Type_Map: {
 		if (t->Map.count == 0) { // Dynamic
 			return type_align_of_internal(s, allocator, t->Map.generated_struct_type, path);
@@ -1773,18 +1761,6 @@ i64 type_size_of_internal(BaseTypeSizes s, gbAllocator allocator, Type *t, TypeP
 	case Type_Slice: // ptr + count
 		return 2 * s.word_size;
 
-	case Type_Maybe: { // value + bool
-		i64 align, size;
-		Type *elem = t->Maybe.elem;
-		align = type_align_of_internal(s, allocator, elem, path);
-		if (path->failure) {
-			return FAILURE_SIZE;
-		}
-		size = align_formula(type_size_of_internal(s, allocator, elem, path), align);
-		size += type_size_of_internal(s, allocator, t_bool, path);
-		return align_formula(size, align);
-	}
-
 	case Type_Map: {
 		if (t->Map.count == 0) { // Dynamic
 			return type_size_of_internal(s, allocator, t->Map.generated_struct_type, path);
@@ -1969,11 +1945,6 @@ gbString write_type_to_string(gbString str, Type *type) {
 		str = write_type_to_string(str, type->Pointer.elem);
 		break;
 
-	case Type_Maybe:
-		str = gb_string_appendc(str, "?");
-		str = write_type_to_string(str, type->Maybe.elem);
-		break;
-
 	case Type_Array:
 		str = gb_string_appendc(str, gb_bprintf("[%lld]", type->Array.count));
 		str = write_type_to_string(str, type->Array.elem);

Some files were not shown because too many files changed in this diff