Преглед на файлове

Nearly finished Jai-like declarations

Ginger Bill преди 8 години
родител
ревизия
9202bd1b06
променени са 18 файла, в които са добавени 841 реда и са изтрити 1057 реда
  1. 10 12
      code/demo.odin
  2. 109 113
      core/_preload.odin
  3. 24 24
      core/atomic.odin
  4. 37 37
      core/fmt.odin
  5. 7 7
      core/hash.odin
  6. 52 54
      core/math.odin
  7. 38 40
      core/mem.odin
  8. 28 28
      core/opengl.odin
  9. 18 20
      core/os_windows.odin
  10. 19 21
      core/sync.odin
  11. 222 229
      core/sys/windows.odin
  12. 7 7
      core/utf8.odin
  13. 0 36
      src/checker/checker.c
  14. 83 184
      src/checker/decl.c
  15. 11 38
      src/checker/expr.c
  16. 0 25
      src/checker/stmt.c
  17. 81 56
      src/parser.c
  18. 95 126
      src/ssa.c

+ 10 - 12
code/demo.odin

@@ -1,15 +1,13 @@
-import {
-	"atomic.odin";
-	"fmt.odin";
-	"hash.odin";
-	"math.odin";
-	"mem.odin";
-	"opengl.odin";
-	"os.odin";
-	"sync.odin";
-	"utf8.odin";
-	win32 "sys/windows.odin";
-}
+import "atomic.odin";
+import "fmt.odin";
+import "hash.odin";
+import "math.odin";
+import "mem.odin";
+import "opengl.odin";
+import "os.odin";
+import "sync.odin";
+import "utf8.odin";
+import win32 "sys/windows.odin";
 
 Thing :: enum f64 {
 	_, // Ignore first value

+ 109 - 113
core/_preload.odin

@@ -12,74 +12,72 @@ import "mem.odin";
 
 // IMPORTANT NOTE(bill): Do not change the order of any of this data
 // The compiler relies upon this _exact_ order
-type {
-	Type_Info_Member struct #ordered {
-		name      string;     // can be empty if tuple
-		type_info ^Type_Info;
-		offset    int;        // offsets are not used in tuples
-	}
-	Type_Info_Record struct #ordered {
-		fields  []Type_Info_Member;
-		size    int; // in bytes
-		align   int; // in bytes
-		packed  bool;
-		ordered bool;
-	}
+Type_Info_Member :: struct #ordered {
+	name      string;     // can be empty if tuple
+	type_info ^Type_Info;
+	offset    int;        // offsets are not used in tuples
+}
+Type_Info_Record :: struct #ordered {
+	fields  []Type_Info_Member;
+	size    int; // in bytes
+	align   int; // in bytes
+	packed  bool;
+	ordered bool;
+}
 
-	Type_Info union {
-		Named struct #ordered {
-			name string;
-			base ^Type_Info; // This will _not_ be a Type_Info.Named
-		};
-		Integer struct #ordered {
-			size   int; // in bytes
-			signed bool;
-		};
-		Float struct #ordered {
-			size int; // in bytes
-		};
-		Any     struct #ordered {};
-		String  struct #ordered {};
-		Boolean 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
-			variadic bool;
-		};
-		Array struct #ordered {
-			elem      ^Type_Info;
-			elem_size int;
-			count     int;
-		};
-		Slice struct #ordered {
-			elem      ^Type_Info;
-			elem_size int;
-		};
-		Vector struct #ordered {
-			elem      ^Type_Info;
-			elem_size int;
-			count     int;
-			align     int;
-		};
-		Tuple     Type_Info_Record;
-		Struct    Type_Info_Record;
-		Union     Type_Info_Record;
-		Raw_Union Type_Info_Record;
-		Enum struct #ordered {
-			base  ^Type_Info;
-			names []string;
-			// TODO(bill): store values some how. Maybe using a raw_union
-		};
-	}
+Type_Info :: union {
+	Named struct #ordered {
+		name string;
+		base ^Type_Info; // This will _not_ be a Type_Info.Named
+	};
+	Integer struct #ordered {
+		size   int; // in bytes
+		signed bool;
+	};
+	Float struct #ordered {
+		size int; // in bytes
+	};
+	Any     struct #ordered {};
+	String  struct #ordered {};
+	Boolean 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
+		variadic bool;
+	};
+	Array struct #ordered {
+		elem      ^Type_Info;
+		elem_size int;
+		count     int;
+	};
+	Slice struct #ordered {
+		elem      ^Type_Info;
+		elem_size int;
+	};
+	Vector struct #ordered {
+		elem      ^Type_Info;
+		elem_size int;
+		count     int;
+		align     int;
+	};
+	Tuple     Type_Info_Record;
+	Struct    Type_Info_Record;
+	Union     Type_Info_Record;
+	Raw_Union Type_Info_Record;
+	Enum struct #ordered {
+		base  ^Type_Info;
+		names []string;
+		// TODO(bill): store values some how. Maybe using a raw_union
+	};
 }
 
-proc type_info_base(info ^Type_Info) -> ^Type_Info {
+type_info_base :: proc(info ^Type_Info) -> ^Type_Info {
 	if info == nil {
 		return nil;
 	}
@@ -93,51 +91,49 @@ proc type_info_base(info ^Type_Info) -> ^Type_Info {
 
 
 
-proc assume(cond bool) #foreign "llvm.assume"
+assume :: proc(cond bool) #foreign "llvm.assume"
 
-proc __debug_trap      ()        #foreign "llvm.debugtrap"
-proc __trap            ()        #foreign "llvm.trap"
-proc read_cycle_counter() -> u64 #foreign "llvm.readcyclecounter"
+__debug_trap       :: proc()        #foreign "llvm.debugtrap"
+__trap             :: proc()        #foreign "llvm.trap"
+read_cycle_counter :: proc() -> u64 #foreign "llvm.readcyclecounter"
 
-proc bit_reverse16(b u16) -> u16 #foreign "llvm.bitreverse.i16"
-proc bit_reverse32(b u32) -> u32 #foreign "llvm.bitreverse.i32"
-proc bit_reverse64(b u64) -> u64 #foreign "llvm.bitreverse.i64"
+bit_reverse16 :: proc(b u16) -> u16 #foreign "llvm.bitreverse.i16"
+bit_reverse32 :: proc(b u32) -> u32 #foreign "llvm.bitreverse.i32"
+bit_reverse64 :: proc(b u64) -> u64 #foreign "llvm.bitreverse.i64"
 
-proc byte_swap16(b u16) -> u16 #foreign "llvm.bswap.i16"
-proc byte_swap32(b u32) -> u32 #foreign "llvm.bswap.i32"
-proc byte_swap64(b u64) -> u64 #foreign "llvm.bswap.i64"
+byte_swap16 :: proc(b u16) -> u16 #foreign "llvm.bswap.i16"
+byte_swap32 :: proc(b u32) -> u32 #foreign "llvm.bswap.i32"
+byte_swap64 :: proc(b u64) -> u64 #foreign "llvm.bswap.i64"
 
-proc fmuladd32(a, b, c f32) -> f32 #foreign "llvm.fmuladd.f32"
-proc fmuladd64(a, b, c f64) -> f64 #foreign "llvm.fmuladd.f64"
+fmuladd32 :: proc(a, b, c f32) -> f32 #foreign "llvm.fmuladd.f32"
+fmuladd64 :: proc(a, b, c f64) -> f64 #foreign "llvm.fmuladd.f64"
 
 
 
 
 
 
-type Allocator_Mode enum u8 {
+Allocator_Mode :: enum u8 {
 	ALLOC = iota,
 	FREE,
 	FREE_ALL,
 	RESIZE,
 }
-type {
-	Allocator_Proc 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;
-	}
+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;
+}
 
-	Context struct #ordered {
-		thread_id int;
+Context :: struct #ordered {
+	thread_id int;
 
-		allocator Allocator;
+	allocator Allocator;
 
-		user_data  rawptr;
-		user_index int;
-	}
+	user_data  rawptr;
+	user_index int;
 }
 
 #thread_local __context: Context;
@@ -146,7 +142,7 @@ type {
 DEFAULT_ALIGNMENT :: align_of([vector 4]f32);
 
 
-proc __check_context() {
+__check_context:: proc() {
 	c := ^__context;
 
 	if c.allocator.procedure == nil {
@@ -157,30 +153,30 @@ proc __check_context() {
 	}
 }
 
-proc alloc(size int) -> rawptr #inline { return alloc_align(size, DEFAULT_ALIGNMENT); }
+alloc:: proc(size int) -> rawptr #inline { return alloc_align(size, DEFAULT_ALIGNMENT); }
 
-proc alloc_align(size, alignment int) -> rawptr #inline {
+alloc_align:: proc(size, alignment int) -> rawptr #inline {
 	__check_context();
 	a := context.allocator;
 	return a.procedure(a.data, Allocator_Mode.ALLOC, size, alignment, nil, 0, 0);
 }
 
-proc free(ptr rawptr) #inline {
+free:: proc(ptr rawptr) #inline {
 	__check_context();
 	a := context.allocator;
 	if ptr != nil {
 		a.procedure(a.data, Allocator_Mode.FREE, 0, 0, ptr, 0, 0);
 	}
 }
-proc free_all() #inline {
+free_all:: proc() #inline {
 	__check_context();
 	a := context.allocator;
 	a.procedure(a.data, Allocator_Mode.FREE_ALL, 0, 0, nil, 0, 0);
 }
 
 
-proc resize      (ptr rawptr, old_size, new_size int) -> rawptr #inline { return resize_align(ptr, old_size, new_size, DEFAULT_ALIGNMENT); }
-proc resize_align(ptr rawptr, old_size, new_size, alignment int) -> rawptr #inline {
+resize:: proc      (ptr rawptr, old_size, new_size int) -> rawptr #inline { return resize_align(ptr, old_size, new_size, DEFAULT_ALIGNMENT); }
+resize_align:: proc(ptr rawptr, old_size, new_size, alignment int) -> rawptr #inline {
 	__check_context();
 	a := context.allocator;
 	return a.procedure(a.data, Allocator_Mode.RESIZE, new_size, alignment, ptr, old_size, 0);
@@ -188,7 +184,7 @@ proc resize_align(ptr rawptr, old_size, new_size, alignment int) -> rawptr #inli
 
 
 
-proc default_resize_align(old_memory rawptr, old_size, new_size, alignment int) -> rawptr {
+default_resize_align:: proc(old_memory rawptr, old_size, new_size, alignment int) -> rawptr {
 	if old_memory == nil {
 		return alloc_align(new_size, alignment);
 	}
@@ -213,7 +209,7 @@ proc default_resize_align(old_memory rawptr, old_size, new_size, alignment int)
 }
 
 
-proc default_allocator_proc(allocator_data rawptr, mode Allocator_Mode,
+default_allocator_proc:: proc(allocator_data rawptr, mode Allocator_Mode,
                             size, alignment int,
                             old_memory rawptr, old_size int, flags u64) -> rawptr {
 	using Allocator_Mode;
@@ -263,7 +259,7 @@ proc default_allocator_proc(allocator_data rawptr, mode Allocator_Mode,
 	return nil;
 }
 
-proc default_allocator() -> Allocator {
+default_allocator:: proc() -> Allocator {
 	return Allocator{
 		procedure = default_allocator_proc,
 		data = nil,
@@ -280,7 +276,7 @@ proc default_allocator() -> Allocator {
 
 
 
-proc __string_eq(a, b string) -> bool {
+__string_eq:: proc(a, b string) -> bool {
 	if a.count != b.count {
 		return false;
 	}
@@ -290,24 +286,24 @@ proc __string_eq(a, b string) -> bool {
 	return mem.compare(a.data, b.data, a.count) == 0;
 }
 
-proc __string_cmp(a, b string) -> int {
+__string_cmp:: proc(a, b string) -> int {
 	return mem.compare(a.data, b.data, min(a.count, b.count));
 }
 
-proc __string_ne(a, b string) -> bool #inline { return !__string_eq(a, b); }
-proc __string_lt(a, b string) -> bool #inline { return __string_cmp(a, b) < 0; }
-proc __string_gt(a, b string) -> bool #inline { return __string_cmp(a, b) > 0; }
-proc __string_le(a, b string) -> bool #inline { return __string_cmp(a, b) <= 0; }
-proc __string_ge(a, b string) -> bool #inline { return __string_cmp(a, b) >= 0; }
+__string_ne:: proc(a, b string) -> bool #inline { return !__string_eq(a, b); }
+__string_lt:: proc(a, b string) -> bool #inline { return __string_cmp(a, b) < 0; }
+__string_gt:: proc(a, b string) -> bool #inline { return __string_cmp(a, b) > 0; }
+__string_le:: proc(a, b string) -> bool #inline { return __string_cmp(a, b) <= 0; }
+__string_ge:: proc(a, b string) -> bool #inline { return __string_cmp(a, b) >= 0; }
 
 
-proc __assert(file string, line, column int, msg string) #inline {
+__assert:: proc(file string, line, column int, msg string) #inline {
 	fmt.fprintf(os.stderr, "%(%:%) Runtime assertion: %\n",
 	            file, line, column, msg);
 	__debug_trap();
 }
 
-proc __bounds_check_error(file string, line, column int, index, count int) {
+__bounds_check_error:: proc(file string, line, column int, index, count int) {
 	if 0 <= index && index < count {
 		return;
 	}
@@ -316,7 +312,7 @@ proc __bounds_check_error(file string, line, column int, index, count int) {
 	__debug_trap();
 }
 
-proc __slice_expr_error(file string, line, column int, low, high, max int) {
+__slice_expr_error:: proc(file string, line, column int, low, high, max int) {
 	if 0 <= low && low <= high && high <= max {
 		return;
 	}
@@ -324,7 +320,7 @@ proc __slice_expr_error(file string, line, column int, low, high, max int) {
 	            file, line, column, low, high, max);
 	__debug_trap();
 }
-proc __substring_expr_error(file string, line, column int, low, high int) {
+__substring_expr_error:: proc(file string, line, column int, low, high int) {
 	if 0 <= low && low <= high {
 		return;
 	}

+ 24 - 24
core/atomic.odin

@@ -5,36 +5,36 @@ import win32 "sys/windows.odin" when ODIN_OS == "windows";
 _ := compile_assert(ODIN_ARCH == "amd64"); // TODO(bill): x86 version
 
 
-proc yield_thread() { win32._mm_pause(); }
-proc mfence      () { win32.ReadWriteBarrier(); }
-proc sfence      () { win32.WriteBarrier(); }
-proc lfence      () { win32.ReadBarrier(); }
+yield_thread :: proc() { win32._mm_pause(); }
+mfence       :: proc() { win32.ReadWriteBarrier(); }
+sfence       :: proc() { win32.WriteBarrier(); }
+lfence       :: proc() { win32.ReadBarrier(); }
 
 
-proc load32(a ^i32) -> i32 {
+load32 :: proc(a ^i32) -> i32 {
 	return a^;
 }
-proc store32(a ^i32, value i32) {
+store32 :: proc(a ^i32, value i32) {
 	a^ = value;
 }
-proc compare_exchange32(a ^i32, expected, desired i32) -> i32 {
+compare_exchange32 :: proc(a ^i32, expected, desired i32) -> i32 {
 	return win32.InterlockedCompareExchange(a, desired, expected);
 }
-proc exchanged32(a ^i32, desired i32) -> i32 {
+exchanged32 :: proc(a ^i32, desired i32) -> i32 {
 	return win32.InterlockedExchange(a, desired);
 }
-proc fetch_add32(a ^i32, operand i32) -> i32 {
+fetch_add32 :: proc(a ^i32, operand i32) -> i32 {
 	return win32.InterlockedExchangeAdd(a, operand);
 
 }
-proc fetch_and32(a ^i32, operand i32) -> i32 {
+fetch_and32 :: proc(a ^i32, operand i32) -> i32 {
 	return win32.InterlockedAnd(a, operand);
 
 }
-proc fetch_or32(a ^i32, operand i32) -> i32 {
+fetch_or32 :: proc(a ^i32, operand i32) -> i32 {
 	return win32.InterlockedOr(a, operand);
 }
-proc spin_lock32(a ^i32, time_out int) -> bool { // NOTE(bill) time_out = -1 as default
+spin_lock32 :: proc(a ^i32, time_out int) -> bool { // NOTE(bill) time_out = -1 as default
 	old_value := compare_exchange32(a, 1, 0);
 	counter := 0;
 	for old_value != 0 && (time_out < 0 || counter < time_out) {
@@ -45,11 +45,11 @@ proc spin_lock32(a ^i32, time_out int) -> bool { // NOTE(bill) time_out = -1 as
 	}
 	return old_value == 0;
 }
-proc spin_unlock32(a ^i32) {
+spin_unlock32 :: proc(a ^i32) {
 	store32(a, 0);
 	mfence();
 }
-proc try_acquire_lock32(a ^i32) -> bool {
+try_acquire_lock32 :: proc(a ^i32) -> bool {
 	yield_thread();
 	old_value := compare_exchange32(a, 1, 0);
 	mfence();
@@ -57,28 +57,28 @@ proc try_acquire_lock32(a ^i32) -> bool {
 }
 
 
-proc load64(a ^i64) -> i64 {
+load64 :: proc(a ^i64) -> i64 {
 	return a^;
 }
-proc store64(a ^i64, value i64) {
+store64 :: proc(a ^i64, value i64) {
 	a^ = value;
 }
-proc compare_exchange64(a ^i64, expected, desired i64) -> i64 {
+compare_exchange64 :: proc(a ^i64, expected, desired i64) -> i64 {
 	return win32.InterlockedCompareExchange64(a, desired, expected);
 }
-proc exchanged64(a ^i64, desired i64) -> i64 {
+exchanged64 :: proc(a ^i64, desired i64) -> i64 {
 	return win32.InterlockedExchange64(a, desired);
 }
-proc fetch_add64(a ^i64, operand i64) -> i64 {
+fetch_add64 :: proc(a ^i64, operand i64) -> i64 {
 	return win32.InterlockedExchangeAdd64(a, operand);
 }
-proc fetch_and64(a ^i64, operand i64) -> i64 {
+fetch_and64 :: proc(a ^i64, operand i64) -> i64 {
 	return win32.InterlockedAnd64(a, operand);
 }
-proc fetch_or64(a ^i64, operand i64) -> i64 {
+fetch_or64 :: proc(a ^i64, operand i64) -> i64 {
 	return win32.InterlockedOr64(a, operand);
 }
-proc spin_lock64(a ^i64, time_out int) -> bool { // NOTE(bill) time_out = -1 as default
+spin_lock64 :: proc(a ^i64, time_out int) -> bool { // NOTE(bill) time_out = -1 as default
 	old_value := compare_exchange64(a, 1, 0);
 	counter := 0;
 	for old_value != 0 && (time_out < 0 || counter < time_out) {
@@ -89,11 +89,11 @@ proc spin_lock64(a ^i64, time_out int) -> bool { // NOTE(bill) time_out = -1 as
 	}
 	return old_value == 0;
 }
-proc spin_unlock64(a ^i64) {
+spin_unlock64 :: proc(a ^i64) {
 	store64(a, 0);
 	mfence();
 }
-proc try_acquire_lock64(a ^i64) -> bool {
+try_acquire_lock64 :: proc(a ^i64) -> bool {
 	yield_thread();
 	old_value := compare_exchange64(a, 1, 0);
 	mfence();

+ 37 - 37
core/fmt.odin

@@ -6,23 +6,23 @@ import {
 
 PRINT_BUF_SIZE :: 1<<12;
 
-proc fprint(fd os.Handle, args ..any) -> int {
-	data :[PRINT_BUF_SIZE]byte;
+fprint :: proc(fd os.Handle, args ..any) -> int {
+	data: [PRINT_BUF_SIZE]byte;
 	buf := data[:0];
 	bprint(^buf, ..args);
 	os.write(fd, buf);
 	return buf.count;
 }
 
-proc fprintln(fd os.Handle, args ..any) -> int {
-	data :[PRINT_BUF_SIZE]byte;
+fprintln :: proc(fd os.Handle, args ..any) -> int {
+	data: [PRINT_BUF_SIZE]byte;
 	buf := data[:0];
 	bprintln(^buf, ..args);
 	os.write(fd, buf);
 	return buf.count;
 }
-proc fprintf(fd os.Handle, fmt string, args ..any) -> int {
-	data :[PRINT_BUF_SIZE]byte;
+fprintf :: proc(fd os.Handle, fmt string, args ..any) -> int {
+	data: [PRINT_BUF_SIZE]byte;
 	buf := data[:0];
 	bprintf(^buf, fmt, ..args);
 	os.write(fd, buf);
@@ -30,20 +30,20 @@ proc fprintf(fd os.Handle, fmt string, args ..any) -> int {
 }
 
 
-proc print(args ..any) -> int {
+print :: proc(args ..any) -> int {
 	return fprint(os.stdout, ..args);
 }
-proc println(args ..any) -> int {
+println :: proc(args ..any) -> int {
 	return fprintln(os.stdout, ..args);
 }
-proc printf(fmt string, args ..any) -> int {
+printf :: proc(fmt string, args ..any) -> int {
 	return fprintf(os.stdout, fmt, ..args);
 }
 
 
 
-proc fprint_type(fd os.Handle, info ^Type_Info) {
-	data :[PRINT_BUF_SIZE]byte;
+fprint_type :: proc(fd os.Handle, info ^Type_Info) {
+	data: [PRINT_BUF_SIZE]byte;
 	buf := data[:0];
 	bprint_type(^buf, info);
 	os.write(fd, buf);
@@ -51,7 +51,7 @@ proc fprint_type(fd os.Handle, info ^Type_Info) {
 
 
 
-proc print_byte_buffer(buf ^[]byte, b []byte) {
+print_byte_buffer :: proc(buf ^[]byte, b []byte) {
 	if buf.count < buf.capacity {
 		n := min(buf.capacity-buf.count, b.count);
 		if n > 0 {
@@ -61,29 +61,29 @@ proc print_byte_buffer(buf ^[]byte, b []byte) {
 	}
 }
 
-proc bprint_string(buf ^[]byte, s string) {
+bprint_string :: proc(buf ^[]byte, s string) {
 	print_byte_buffer(buf, s as []byte);
 }
 
 
-proc byte_reverse(b []byte) {
+byte_reverse :: proc(b []byte) {
 	n := b.count;
 	for i := 0; i < n/2; i++ {
 		b[i], b[n-1-i] = b[n-1-i], b[i];
 	}
 }
 
-proc bprint_rune(buf ^[]byte, r rune) {
+bprint_rune :: proc(buf ^[]byte, r rune) {
 	b, n := utf8.encode_rune(r);
 	bprint_string(buf, b[:n] as string);
 }
 
-proc bprint_space(buf ^[]byte) { bprint_rune(buf, ' '); }
-proc bprint_nl   (buf ^[]byte) { bprint_rune(buf, '\n'); }
+bprint_space :: proc(buf ^[]byte) { bprint_rune(buf, ' '); }
+bprint_nl :: proc   (buf ^[]byte) { bprint_rune(buf, '\n'); }
 
 __NUM_TO_CHAR_TABLE := "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@$";
 
-proc bprint_bool(buffer ^[]byte, b bool) {
+bprint_bool :: proc(buffer ^[]byte, b bool) {
 	if b {
 		bprint_string(buffer, "true");
 	} else {
@@ -91,15 +91,15 @@ proc bprint_bool(buffer ^[]byte, b bool) {
 	}
 }
 
-proc bprint_pointer(buffer ^[]byte, p rawptr) #inline {
+bprint_pointer :: proc(buffer ^[]byte, p rawptr) #inline {
 	bprint_string(buffer, "0x");
 	bprint_u64(buffer, p as uint as u64);
 }
 
-proc bprint_f16 (buffer ^[]byte, f f32)  #inline { print__f64(buffer, f as f64, 4); }
-proc bprint_f32 (buffer ^[]byte, f f32)  #inline { print__f64(buffer, f as f64, 7); }
-proc bprint_f64 (buffer ^[]byte, f f64)  #inline { print__f64(buffer, f as f64, 16); }
-proc bprint_u64(buffer ^[]byte, value u64) {
+bprint_f16 :: proc (buffer ^[]byte, f f32)  #inline { print__f64(buffer, f as f64, 4); }
+bprint_f32 :: proc (buffer ^[]byte, f f32)  #inline { print__f64(buffer, f as f64, 7); }
+bprint_f64 :: proc (buffer ^[]byte, f f64)  #inline { print__f64(buffer, f as f64, 16); }
+bprint_u64 :: proc(buffer ^[]byte, value u64) {
 	i := value;
 	buf :[20]byte;
 	len := 0;
@@ -115,7 +115,7 @@ proc bprint_u64(buffer ^[]byte, value u64) {
 	byte_reverse(buf[:len]);
 	bprint_string(buffer, buf[:len] as string);
 }
-proc bprint_i64(buffer ^[]byte, value i64) {
+bprint_i64 :: proc(buffer ^[]byte, value i64) {
 	// TODO(bill): Cleanup printing
 	i := value;
 	if i < 0 {
@@ -126,14 +126,14 @@ proc bprint_i64(buffer ^[]byte, value i64) {
 }
 
 /*
-proc bprint_u128(buffer ^[]byte, value u128) {
+bprint_u128 :: proc(buffer ^[]byte, value u128) {
 	a := value transmute [2]u64;
 	if a[1] != 0 {
 		bprint_u64(buffer, a[1]);
 	}
 	bprint_u64(buffer, a[0]);
 }
-proc bprint_i128(buffer ^[]byte, value i128) {
+bprint_i128 :: proc(buffer ^[]byte, value i128) {
 	i := value;
 	if i < 0 {
 		i = -i;
@@ -144,7 +144,7 @@ proc bprint_i128(buffer ^[]byte, value i128) {
 */
 
 
-proc print__f64(buffer ^[]byte, value f64, decimal_places int) {
+print__f64 :: proc(buffer ^[]byte, value f64, decimal_places int) {
 	f := value;
 	if f == 0 {
 		bprint_rune(buffer, '0');
@@ -170,7 +170,7 @@ proc print__f64(buffer ^[]byte, value f64, decimal_places int) {
 	}
 }
 
-proc bprint_type(buf ^[]byte, ti ^Type_Info) {
+bprint_type :: proc(buf ^[]byte, ti ^Type_Info) {
 	if ti == nil {
 		return;
 	}
@@ -302,14 +302,14 @@ proc bprint_type(buf ^[]byte, ti ^Type_Info) {
 }
 
 
-proc make_any(type_info ^Type_Info, data rawptr) -> any {
+make_any :: proc(type_info ^Type_Info, data rawptr) -> any {
 	a :any;
 	a.type_info = type_info;
 	a.data = data;
 	return a;
 }
 
-proc bprint_any(buf ^[]byte, arg any) {
+bprint_any :: proc(buf ^[]byte, arg any) {
 	if arg.type_info == nil {
 		bprint_string(buf, "<nil>");
 		return;
@@ -423,7 +423,7 @@ proc bprint_any(buf ^[]byte, arg any) {
 		}
 
 	case Vector:
-		proc is_bool(type_info ^Type_Info) -> bool {
+		is_bool :: proc(type_info ^Type_Info) -> bool {
 			match type info : type_info {
 			case Named:
 				return is_bool(info.base);
@@ -481,12 +481,12 @@ proc bprint_any(buf ^[]byte, arg any) {
 }
 
 
-proc bprintf(buf ^[]byte, fmt string, args ..any) -> int {
-	proc is_digit(r rune) -> bool #inline {
+bprintf :: proc(buf ^[]byte, fmt string, args ..any) -> int {
+	is_digit :: proc(r rune) -> bool #inline {
 		return '0' <= r && r <= '9';
 	}
 
-	proc parse_int(s string, offset int) -> (int, int) {
+	parse_int :: proc(s string, offset int) -> (int, int) {
 		result := 0;
 
 		for ; offset < s.count; offset++ {
@@ -546,8 +546,8 @@ proc bprintf(buf ^[]byte, fmt string, args ..any) -> int {
 }
 
 
-proc bprint(buf ^[]byte, args ..any) -> int {
-	proc is_type_string(info ^Type_Info) -> bool {
+bprint :: proc(buf ^[]byte, args ..any) -> int {
+	is_type_string :: proc(info ^Type_Info) -> bool {
 		using Type_Info;
 		if info == nil {
 			return false;
@@ -574,7 +574,7 @@ proc bprint(buf ^[]byte, args ..any) -> int {
 	return buf.count;
 }
 
-proc bprintln(buf ^[]byte, args ..any) -> int {
+bprintln :: proc(buf ^[]byte, args ..any) -> int {
 	for i := 0; i < args.count; i++ {
 		if i > 0 {
 			append(buf, ' ');

+ 7 - 7
core/hash.odin

@@ -1,4 +1,4 @@
-proc crc32(data rawptr, len int) -> u32 {
+crc32 :: proc(data rawptr, len int) -> u32 {
 	result := ~(0 as u32);
 	s := slice_ptr(data as ^u8, len);
 	for i := 0; i < len; i++ {
@@ -7,7 +7,7 @@ proc crc32(data rawptr, len int) -> u32 {
 	}
 	return ~result;
 }
-proc crc64(data rawptr, len int) -> u64 {
+crc64 :: proc(data rawptr, len int) -> u64 {
 	result := ~(0 as u64);
 	s := slice_ptr(data as ^u8, len);
 	for i := 0; i < len; i++ {
@@ -17,7 +17,7 @@ proc crc64(data rawptr, len int) -> u64 {
 	return ~result;
 }
 
-proc fnv32(data rawptr, len int) -> u32 {
+fnv32 :: proc(data rawptr, len int) -> u32 {
 	s := slice_ptr(data as ^u8, len);
 
 	h :u32 = 0x811c9dc5;
@@ -27,7 +27,7 @@ proc fnv32(data rawptr, len int) -> u32 {
 	return h;
 }
 
-proc fnv64(data rawptr, len int) -> u64 {
+fnv64 :: proc(data rawptr, len int) -> u64 {
 	s := slice_ptr(data as ^u8, len);
 
 	h :u64 = 0xcbf29ce484222325;
@@ -37,7 +37,7 @@ proc fnv64(data rawptr, len int) -> u64 {
 	return h;
 }
 
-proc fnv32a(data rawptr, len int) -> u32 {
+fnv32a :: proc(data rawptr, len int) -> u32 {
 	s := slice_ptr(data as ^u8, len);
 
 	h :u32 = 0x811c9dc5;
@@ -47,7 +47,7 @@ proc fnv32a(data rawptr, len int) -> u32 {
 	return h;
 }
 
-proc fnv64a(data rawptr, len int) -> u64 {
+fnv64a :: proc(data rawptr, len int) -> u64 {
 	s := slice_ptr(data as ^u8, len);
 
 	h :u64 = 0xcbf29ce484222325;
@@ -58,7 +58,7 @@ proc fnv64a(data rawptr, len int) -> u64 {
 }
 
 
-proc murmur64(data_ rawptr, len int) -> u64 {
+murmur64 :: proc(data_ rawptr, len int) -> u64 {
 	SEED :: 0x9747b28c;
 
 	when size_of(int) == 8 {

+ 52 - 54
core/math.odin

@@ -16,67 +16,65 @@ EPSILON      :: 1.19209290e-7;
 τ :: TAU;
 π :: PI;
 
-type {
-	Vec2 [vector 2]f32;
-	Vec3 [vector 3]f32;
-	Vec4 [vector 4]f32;
-
-	Mat2 [2]Vec2;
-	Mat3 [3]Vec3;
-	Mat4 [4]Vec4;
-}
+Vec2 :: [vector 2]f32;
+Vec3 :: [vector 3]f32;
+Vec4 :: [vector 4]f32;
+
+Mat2 :: [2]Vec2;
+Mat3 :: [3]Vec3;
+Mat4 :: [4]Vec4;
 
-proc sqrt32(x f32) -> f32 #foreign "llvm.sqrt.f32"
-proc sqrt64(x f64) -> f64 #foreign "llvm.sqrt.f64"
+sqrt32 :: proc(x f32) -> f32 #foreign "llvm.sqrt.f32"
+sqrt64 :: proc(x f64) -> f64 #foreign "llvm.sqrt.f64"
 
-proc sin32(x f32) -> f32 #foreign "llvm.sin.f32"
-proc sin64(x f64) -> f64 #foreign "llvm.sin.f64"
+sin32 :: proc(x f32) -> f32 #foreign "llvm.sin.f32"
+sin64 :: proc(x f64) -> f64 #foreign "llvm.sin.f64"
 
-proc cos32(x f32) -> f32 #foreign "llvm.cos.f32"
-proc cos64(x f64) -> f64 #foreign "llvm.cos.f64"
+cos32 :: proc(x f32) -> f32 #foreign "llvm.cos.f32"
+cos64 :: proc(x f64) -> f64 #foreign "llvm.cos.f64"
 
-proc tan32(x f32) -> f32 #inline { return sin32(x)/cos32(x); }
-proc tan64(x f64) -> f64 #inline { return sin64(x)/cos64(x); }
+tan32 :: proc(x f32) -> f32 #inline { return sin32(x)/cos32(x); }
+tan64 :: proc(x f64) -> f64 #inline { return sin64(x)/cos64(x); }
 
-proc lerp32(a, b, t f32) -> f32 { return a*(1-t) + b*t; }
-proc lerp64(a, b, t f64) -> f64 { return a*(1-t) + b*t; }
+lerp32 :: proc(a, b, t f32) -> f32 { return a*(1-t) + b*t; }
+lerp64 :: proc(a, b, t f64) -> f64 { return a*(1-t) + b*t; }
 
-proc sign32(x f32) -> f32 { if x >= 0 { return +1; } return -1; }
-proc sign64(x f64) -> f64 { if x >= 0 { return +1; } return -1; }
+sign32 :: proc(x f32) -> f32 { if x >= 0 { return +1; } return -1; }
+sign64 :: proc(x f64) -> f64 { if x >= 0 { return +1; } return -1; }
 
 
 
-proc copy_sign32(x, y f32) -> f32 {
+copy_sign32 :: proc(x, y f32) -> f32 {
 	ix := x transmute u32;
 	iy := y transmute u32;
 	ix &= 0x7fffffff;
 	ix |= iy & 0x80000000;
 	return ix transmute f32;
 }
-proc round32(x f32) -> f32 {
+round32 :: proc(x f32) -> f32 {
 	if x >= 0 {
 		return floor32(x + 0.5);
 	}
 	return ceil32(x - 0.5);
 }
-proc floor32(x f32) -> f32 {
+floor32 :: proc(x f32) -> f32 {
 	if x >= 0 {
 		return x as int as f32;
 	}
 	return (x-0.5) as int as f32;
 }
-proc ceil32(x f32) -> f32 {
+ceil32 :: proc(x f32) -> f32 {
 	if x < 0 {
 		return x as int as f32;
 	}
 	return ((x as int)+1) as f32;
 }
 
-proc remainder32(x, y f32) -> f32 {
+remainder32 :: proc(x, y f32) -> f32 {
 	return x - round32(x/y) * y;
 }
 
-proc fmod32(x, y f32) -> f32 {
+fmod32 :: proc(x, y f32) -> f32 {
 	y = abs(y);
 	result := remainder32(abs(x), y);
 	if sign32(result) < 0 {
@@ -86,32 +84,32 @@ proc fmod32(x, y f32) -> f32 {
 }
 
 
-proc to_radians(degrees f32) -> f32 { return degrees * TAU / 360; }
-proc to_degrees(radians f32) -> f32 { return radians * 360 / TAU; }
+to_radians :: proc(degrees f32) -> f32 { return degrees * TAU / 360; }
+to_degrees :: proc(radians f32) -> f32 { return radians * 360 / TAU; }
 
 
 
 
-proc dot2(a, b Vec2) -> f32 { c := a*b; return c.x + c.y; }
-proc dot3(a, b Vec3) -> f32 { c := a*b; return c.x + c.y + c.z; }
-proc dot4(a, b Vec4) -> f32 { c := a*b; return c.x + c.y + c.z + c.w; }
+dot2 :: proc(a, b Vec2) -> f32 { c := a*b; return c.x + c.y; }
+dot3 :: proc(a, b Vec3) -> f32 { c := a*b; return c.x + c.y + c.z; }
+dot4 :: proc(a, b Vec4) -> f32 { c := a*b; return c.x + c.y + c.z + c.w; }
 
-proc cross3(x, y Vec3) -> Vec3 {
+cross3 :: proc(x, y Vec3) -> Vec3 {
 	a := swizzle(x, 1, 2, 0) * swizzle(y, 2, 0, 1);
 	b := swizzle(x, 2, 0, 1) * swizzle(y, 1, 2, 0);
 	return a - b;
 }
 
 
-proc vec2_mag(v Vec2) -> f32 { return sqrt32(dot2(v, v)); }
-proc vec3_mag(v Vec3) -> f32 { return sqrt32(dot3(v, v)); }
-proc vec4_mag(v Vec4) -> f32 { return sqrt32(dot4(v, v)); }
+vec2_mag :: proc(v Vec2) -> f32 { return sqrt32(dot2(v, v)); }
+vec3_mag :: proc(v Vec3) -> f32 { return sqrt32(dot3(v, v)); }
+vec4_mag :: proc(v Vec4) -> f32 { return sqrt32(dot4(v, v)); }
 
-proc vec2_norm(v Vec2) -> Vec2 { return v / Vec2{vec2_mag(v)}; }
-proc vec3_norm(v Vec3) -> Vec3 { return v / Vec3{vec3_mag(v)}; }
-proc vec4_norm(v Vec4) -> Vec4 { return v / Vec4{vec4_mag(v)}; }
+vec2_norm :: proc(v Vec2) -> Vec2 { return v / Vec2{vec2_mag(v)}; }
+vec3_norm :: proc(v Vec3) -> Vec3 { return v / Vec3{vec3_mag(v)}; }
+vec4_norm :: proc(v Vec4) -> Vec4 { return v / Vec4{vec4_mag(v)}; }
 
-proc vec2_norm0(v Vec2) -> Vec2 {
+vec2_norm0 :: proc(v Vec2) -> Vec2 {
 	m := vec2_mag(v);
 	if m == 0 {
 		return Vec2{0};
@@ -119,7 +117,7 @@ proc vec2_norm0(v Vec2) -> Vec2 {
 	return v / Vec2{m};
 }
 
-proc vec3_norm0(v Vec3) -> Vec3 {
+vec3_norm0 :: proc(v Vec3) -> Vec3 {
 	m := vec3_mag(v);
 	if m == 0 {
 		return Vec3{0};
@@ -127,7 +125,7 @@ proc vec3_norm0(v Vec3) -> Vec3 {
 	return v / Vec3{m};
 }
 
-proc vec4_norm0(v Vec4) -> Vec4 {
+vec4_norm0 :: proc(v Vec4) -> Vec4 {
 	m := vec4_mag(v);
 	if m == 0 {
 		return Vec4{0};
@@ -137,7 +135,7 @@ proc vec4_norm0(v Vec4) -> Vec4 {
 
 
 
-proc mat4_identity() -> Mat4 {
+mat4_identity :: proc() -> Mat4 {
 	return Mat4{
 		{1, 0, 0, 0},
 		{0, 1, 0, 0},
@@ -146,7 +144,7 @@ proc mat4_identity() -> Mat4 {
 	};
 }
 
-proc mat4_transpose(m Mat4) -> Mat4 {
+mat4_transpose :: proc(m Mat4) -> Mat4 {
 	for j := 0; j < 4; j++ {
 		for i := 0; i < 4; i++ {
 			m[i][j], m[j][i] = m[j][i], m[i][j];
@@ -155,7 +153,7 @@ proc mat4_transpose(m Mat4) -> Mat4 {
 	return m;
 }
 
-proc mat4_mul(a, b Mat4) -> Mat4 {
+mat4_mul :: proc(a, b Mat4) -> Mat4 {
 	c: Mat4;
 	for j := 0; j < 4; j++ {
 		for i := 0; i < 4; i++ {
@@ -168,7 +166,7 @@ proc mat4_mul(a, b Mat4) -> Mat4 {
 	return c;
 }
 
-proc mat4_mul_vec4(m Mat4, v Vec4) -> Vec4 {
+mat4_mul_vec4 :: proc(m Mat4, v Vec4) -> Vec4 {
 	return Vec4{
 		m[0][0]*v.x + m[1][0]*v.y + m[2][0]*v.z + m[3][0]*v.w,
 		m[0][1]*v.x + m[1][1]*v.y + m[2][1]*v.z + m[3][1]*v.w,
@@ -177,7 +175,7 @@ proc mat4_mul_vec4(m Mat4, v Vec4) -> Vec4 {
 	};
 }
 
-proc mat4_inverse(m Mat4) -> Mat4 {
+mat4_inverse :: proc(m Mat4) -> Mat4 {
 	o: Mat4;
 
 	sf00 := m[2][2] * m[3][3] - m[3][2] * m[2][3];
@@ -246,7 +244,7 @@ proc mat4_inverse(m Mat4) -> Mat4 {
 }
 
 
-proc mat4_translate(v Vec3) -> Mat4 {
+mat4_translate :: proc(v Vec3) -> Mat4 {
 	m := mat4_identity();
 	m[3][0] = v.x;
 	m[3][1] = v.y;
@@ -255,7 +253,7 @@ proc mat4_translate(v Vec3) -> Mat4 {
 	return m;
 }
 
-proc mat4_rotate(v Vec3, angle_radians f32) -> Mat4 {
+mat4_rotate :: proc(v Vec3, angle_radians f32) -> Mat4 {
 	c := cos32(angle_radians);
 	s := sin32(angle_radians);
 
@@ -282,14 +280,14 @@ proc mat4_rotate(v Vec3, angle_radians f32) -> Mat4 {
 	return rot;
 }
 
-proc mat4_scale(m Mat4, v Vec3) -> Mat4 {
+mat4_scale :: proc(m Mat4, v Vec3) -> Mat4 {
 	m[0][0] *= v.x;
 	m[1][1] *= v.y;
 	m[2][2] *= v.z;
 	return m;
 }
 
-proc mat4_scalef(m Mat4, s f32) -> Mat4 {
+mat4_scalef :: proc(m Mat4, s f32) -> Mat4 {
 	m[0][0] *= s;
 	m[1][1] *= s;
 	m[2][2] *= s;
@@ -297,7 +295,7 @@ proc mat4_scalef(m Mat4, s f32) -> Mat4 {
 }
 
 
-proc mat4_look_at(eye, centre, up Vec3) -> Mat4 {
+mat4_look_at :: proc(eye, centre, up Vec3) -> Mat4 {
 	f := vec3_norm(centre - eye);
 	s := vec3_norm(cross3(f, up));
 	u := cross3(s, f);
@@ -311,7 +309,7 @@ proc mat4_look_at(eye, centre, up Vec3) -> Mat4 {
 
 	return m;
 }
-proc mat4_perspective(fovy, aspect, near, far f32) -> Mat4 {
+mat4_perspective :: proc(fovy, aspect, near, far f32) -> Mat4 {
 	m: Mat4;
 	tan_half_fovy := tan32(0.5 * fovy);
 	m[0][0] = 1.0 / (aspect*tan_half_fovy);
@@ -323,7 +321,7 @@ proc mat4_perspective(fovy, aspect, near, far f32) -> Mat4 {
 }
 
 
-proc mat4_ortho3d(left, right, bottom, top, near, far f32) -> Mat4 {
+mat4_ortho3d :: proc(left, right, bottom, top, near, far f32) -> Mat4 {
 	m := mat4_identity();
 	m[0][0] = +2.0 / (right - left);
 	m[1][1] = +2.0 / (top - bottom);

+ 38 - 40
core/mem.odin

@@ -3,32 +3,31 @@ import {
 	"os.odin";
 }
 
-proc set(data rawptr, value i32, len int) -> rawptr #link_name "__mem_set" {
-	proc llvm_memset_64bit(dst rawptr, val byte, len int, align i32, is_volatile bool) #foreign "llvm.memset.p0i8.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.memset.p0i8.i64"
 	llvm_memset_64bit(data, value as byte, len, 1, false);
 	return data;
 }
 
-proc zero(data rawptr, len int) -> rawptr #link_name "__mem_zero" {
+zero :: proc(data rawptr, len int) -> rawptr #link_name "__mem_zero" {
 	return set(data, 0, len);
 }
 
-proc copy(dst, src rawptr, len int) -> rawptr #link_name "__mem_copy" {
+copy :: proc(dst, src rawptr, len int) -> rawptr #link_name "__mem_copy" {
 	// NOTE(bill): This _must_ implemented like C's memmove
-	proc llvm_memmove_64bit(dst, src rawptr, len int, align i32, is_volatile bool) #foreign "llvm.memmove.p0i8.p0i8.i64"
+	llvm_memmove_64bit :: proc(dst, src rawptr, len int, align i32, is_volatile bool) #foreign "llvm.memmove.p0i8.p0i8.i64"
 	llvm_memmove_64bit(dst, src, len, 1, false);
 	return dst;
 }
 
-proc copy_non_overlapping(dst, src rawptr, len int) -> rawptr #link_name "__mem_copy_non_overlapping" {
+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
-	proc llvm_memcpy_64bit(dst, src rawptr, len int, align i32, is_volatile bool) #foreign "llvm.memcpy.p0i8.p0i8.i64"
+	llvm_memcpy_64bit :: proc(dst, src rawptr, len int, align i32, is_volatile bool) #foreign "llvm.memcpy.p0i8.p0i8.i64"
 	llvm_memcpy_64bit(dst, src, len, 1, false);
 	return dst;
 }
 
-
-proc compare(dst, src rawptr, n int) -> int #link_name "__mem_compare" {
+compare :: proc(dst, src rawptr, n int) -> int #link_name "__mem_compare" {
 	// Translation of http://mgronhol.github.io/fast-strcmp/
 	a := slice_ptr(dst as ^byte, n);
 	b := slice_ptr(src as ^byte, n);
@@ -65,19 +64,19 @@ proc compare(dst, src rawptr, n int) -> int #link_name "__mem_compare" {
 
 
 
-proc kilobytes(x int) -> int #inline { return          (x) * 1024; }
-proc megabytes(x int) -> int #inline { return kilobytes(x) * 1024; }
-proc gigabytes(x int) -> int #inline { return gigabytes(x) * 1024; }
-proc terabytes(x int) -> int #inline { return terabytes(x) * 1024; }
+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; }
 
-proc is_power_of_two(x int) -> bool {
+is_power_of_two :: proc(x int) -> bool {
 	if x <= 0 {
 		return false;
 	}
 	return (x & (x-1)) == 0;
 }
 
-proc align_forward(ptr rawptr, align int) -> rawptr {
+align_forward :: proc(ptr rawptr, align int) -> rawptr {
 	assert(is_power_of_two(align));
 
 	a := align as uint;
@@ -91,11 +90,11 @@ proc align_forward(ptr rawptr, align int) -> rawptr {
 
 
 
-type Allocation_Header struct {
+Allocation_Header :: struct {
 	size int;
 }
 
-proc allocation_header_fill(header ^Allocation_Header, data rawptr, size int) {
+allocation_header_fill :: proc(header ^Allocation_Header, data rawptr, size int) {
 	header.size = size;
 	ptr := (header+1) as ^int;
 
@@ -103,7 +102,7 @@ proc allocation_header_fill(header ^Allocation_Header, data rawptr, size int) {
 		(ptr+i)^ = -1;
 	}
 }
-proc allocation_header(data rawptr) -> ^Allocation_Header {
+allocation_header :: proc(data rawptr) -> ^Allocation_Header {
 	p := data as ^int;
 	for (p-1)^ == -1 {
 		p = (p-1);
@@ -116,35 +115,34 @@ proc allocation_header(data rawptr) -> ^Allocation_Header {
 
 
 // Custom allocators
-type {
-	Arena struct {
-		backing    Allocator;
-		memory     []byte;
-		temp_count int;
-	}
+Arena :: struct {
+	backing    Allocator;
+	memory     []byte;
+	temp_count int;
+}
 
-	Arena_Temp_Memory struct {
-		arena          ^Arena;
-		original_count int;
-	}
+Arena_Temp_Memory :: struct {
+	arena          ^Arena;
+	original_count int;
 }
 
 
 
 
-proc init_arena_from_memory(using a ^Arena, data []byte) {
+
+init_arena_from_memory :: proc(using a ^Arena, data []byte) {
 	backing    = Allocator{};
 	memory     = data[:0];
 	temp_count = 0;
 }
 
-proc init_arena_from_context(using a ^Arena, size int) {
+init_arena_from_context :: proc(using a ^Arena, size int) {
 	backing = context.allocator;
 	memory = new_slice(byte, 0, size);
 	temp_count = 0;
 }
 
-proc free_arena(using a ^Arena) {
+free_arena :: proc(using a ^Arena) {
 	if backing.procedure != nil {
 		push_allocator backing {
 			free(memory.data);
@@ -153,14 +151,14 @@ proc free_arena(using a ^Arena) {
 	}
 }
 
-proc arena_allocator(arena ^Arena) -> Allocator {
+arena_allocator :: proc(arena ^Arena) -> Allocator {
 	return Allocator{
 		procedure = arena_allocator_proc,
 		data = arena,
 	};
 }
 
-proc arena_allocator_proc(allocator_data rawptr, mode Allocator_Mode,
+arena_allocator_proc :: proc(allocator_data rawptr, mode Allocator_Mode,
                           size, alignment int,
                           old_memory rawptr, old_size int, flags u64) -> rawptr {
 	using Allocator_Mode;
@@ -195,7 +193,7 @@ proc arena_allocator_proc(allocator_data rawptr, mode Allocator_Mode,
 	return nil;
 }
 
-proc begin_arena_temp_memory(a ^Arena) -> Arena_Temp_Memory {
+begin_arena_temp_memory :: proc(a ^Arena) -> Arena_Temp_Memory {
 	tmp: Arena_Temp_Memory;
 	tmp.arena = a;
 	tmp.original_count = a.memory.count;
@@ -203,7 +201,7 @@ proc begin_arena_temp_memory(a ^Arena) -> Arena_Temp_Memory {
 	return tmp;
 }
 
-proc end_arena_temp_memory(using tmp Arena_Temp_Memory) {
+end_arena_temp_memory :: proc(using tmp Arena_Temp_Memory) {
 	assert(arena.memory.count >= original_count);
 	assert(arena.temp_count > 0);
 	arena.memory.count = original_count;
@@ -216,8 +214,8 @@ proc end_arena_temp_memory(using tmp Arena_Temp_Memory) {
 
 
 
-proc align_of_type_info(type_info ^Type_Info) -> int {
-	proc prev_pow2(n i64) -> i64 {
+align_of_type_info :: proc(type_info ^Type_Info) -> int {
+	prev_pow2 :: proc(n i64) -> i64 {
 		if n <= 0 {
 			return 0;
 		}
@@ -271,12 +269,12 @@ proc align_of_type_info(type_info ^Type_Info) -> int {
 	return 0;
 }
 
-proc align_formula(size, align int) -> int {
+align_formula :: proc(size, align int) -> int {
 	result := size + align-1;
 	return result - result%align;
 }
 
-proc size_of_type_info(type_info ^Type_Info) -> int {
+size_of_type_info :: proc(type_info ^Type_Info) -> int {
 	WORD_SIZE :: size_of(int);
 	using Type_Info;
 	match type info : type_info {
@@ -310,7 +308,7 @@ proc size_of_type_info(type_info ^Type_Info) -> int {
 	case Slice:
 		return 3*WORD_SIZE;
 	case Vector:
-		proc is_bool(type_info ^Type_Info) -> bool {
+		is_bool :: proc(type_info ^Type_Info) -> bool {
 			match type info : type_info {
 			case Named:
 				return is_bool(info.base);

+ 28 - 28
core/opengl.odin

@@ -2,37 +2,37 @@
 import win32 "sys/windows.odin" when ODIN_OS == "windows";
 include "opengl_constants.odin";
 
-proc Clear         (mask u32)                                #foreign "glClear"
-proc ClearColor    (r, g, b, a f32)                          #foreign "glClearColor"
-proc Begin         (mode i32)                                #foreign "glBegin"
-proc End           ()                                        #foreign "glEnd"
-proc Finish        ()                                        #foreign "glFinish"
-proc BlendFunc     (sfactor, dfactor i32)                    #foreign "glBlendFunc"
-proc Enable        (cap i32)                                 #foreign "glEnable"
-proc Disable       (cap i32)                                 #foreign "glDisable"
-proc GenTextures   (count i32, result ^u32)                  #foreign "glGenTextures"
-proc DeleteTextures(count i32, result ^u32)                  #foreign "glDeleteTextures"
-proc TexParameteri (target, pname, param i32)                #foreign "glTexParameteri"
-proc TexParameterf (target i32, pname i32, param f32)        #foreign "glTexParameterf"
-proc BindTexture   (target i32, texture u32)                 #foreign "glBindTexture"
-proc LoadIdentity  ()                                        #foreign "glLoadIdentity"
-proc Viewport      (x, y, width, height i32)                 #foreign "glViewport"
-proc Ortho         (left, right, bottom, top, near, far f64) #foreign "glOrtho"
-proc Color3f       (r, g, b f32)                             #foreign "glColor3f"
-proc Vertex3f      (x, y, z f32)                             #foreign "glVertex3f"
-proc TexImage2D    (target, level, internal_format,
-                    width, height, border,
-                    format, _type i32, pixels rawptr) #foreign "glTexImage2D"
-
-proc GetError   () -> i32            #foreign "glGetError"
-proc GetString  (name i32) -> ^byte #foreign "glGetString"
-proc GetIntegerv(name i32, v ^i32) #foreign "glGetIntegerv"
+Clear         :: proc(mask u32)                                #foreign "glClear"
+ClearColor    :: proc(r, g, b, a f32)                          #foreign "glClearColor"
+Begin         :: proc(mode i32)                                #foreign "glBegin"
+End           :: proc()                                        #foreign "glEnd"
+Finish        :: proc()                                        #foreign "glFinish"
+BlendFunc     :: proc(sfactor, dfactor i32)                    #foreign "glBlendFunc"
+Enable        :: proc(cap i32)                                 #foreign "glEnable"
+Disable       :: proc(cap i32)                                 #foreign "glDisable"
+GenTextures   :: proc(count i32, result ^u32)                  #foreign "glGenTextures"
+DeleteTextures:: proc(count i32, result ^u32)                  #foreign "glDeleteTextures"
+TexParameteri :: proc(target, pname, param i32)                #foreign "glTexParameteri"
+TexParameterf :: proc(target i32, pname i32, param f32)        #foreign "glTexParameterf"
+BindTexture   :: proc(target i32, texture u32)                 #foreign "glBindTexture"
+LoadIdentity  :: proc()                                        #foreign "glLoadIdentity"
+Viewport      :: proc(x, y, width, height i32)                 #foreign "glViewport"
+Ortho         :: proc(left, right, bottom, top, near, far f64) #foreign "glOrtho"
+Color3f       :: proc(r, g, b f32)                             #foreign "glColor3f"
+Vertex3f      :: proc(x, y, z f32)                             #foreign "glVertex3f"
+TexImage2D    :: proc(target, level, internal_format,
+                      width, height, border,
+                      format, _type i32, pixels rawptr) #foreign "glTexImage2D"
+
+GetError    :: proc() -> i32            #foreign "glGetError"
+GetString   :: proc(name i32) -> ^byte #foreign "glGetString"
+GetIntegerv :: proc(name i32, v ^i32) #foreign "glGetIntegerv"
 
 
 
 _libgl := win32.LoadLibraryA(("opengl32.dll\x00" as string).data);
 
-proc GetProcAddress(name string) -> proc() #cc_c {
+GetProcAddress :: proc(name string) -> proc() #cc_c {
 	assert(name[name.count-1] == 0);
 	res := win32.wglGetProcAddress(name.data);
 	if res == nil {
@@ -99,8 +99,8 @@ UniformMatrix4fv:  proc(loc i32, count u32, transpose i32, value ^f32) #cc_c;
 
 GetUniformLocation:  proc(program u32, name ^byte) -> i32 #cc_c;
 
-proc init() {
-	proc set_proc_address(p rawptr, name string) #inline { (p as ^(proc() #cc_c))^ = GetProcAddress(name); }
+init :: proc() {
+	set_proc_address :: proc(p rawptr, name string) #inline { (p as ^(proc() #cc_c))^ = GetProcAddress(name); }
 
 	set_proc_address(^GenBuffers,      "glGenBuffers\x00");
 	set_proc_address(^GenVertexArrays, "glGenVertexArrays\x00");

+ 18 - 20
core/os_windows.odin

@@ -4,11 +4,9 @@ import {
 }
 
 
-type {
-	Handle    uint;
-	File_Time u64;
-	Error     int;
-}
+Handle    :: uint;
+File_Time :: u64;
+Error     :: int;
 
 INVALID_HANDLE: Handle : ~(0 as Handle);
 
@@ -56,7 +54,7 @@ ERROR_FILE_IS_PIPE : Error : 1<<29 + 0;
 
 
 
-proc open(path string, mode int, perm u32) -> (Handle, Error) {
+open :: proc(path string, mode int, perm u32) -> (Handle, Error) {
 	using win32;
 	if path.count == 0 {
 		return INVALID_HANDLE, ERROR_FILE_NOT_FOUND;
@@ -109,11 +107,11 @@ proc open(path string, mode int, perm u32) -> (Handle, Error) {
 	return INVALID_HANDLE, err as Error;
 }
 
-proc close(fd Handle) {
+close :: proc(fd Handle) {
 	win32.CloseHandle(fd as win32.HANDLE);
 }
 
-proc write(fd Handle, data []byte) -> (int, Error) {
+write :: proc(fd Handle, data []byte) -> (int, Error) {
 	bytes_written: i32;
 	e := win32.WriteFile(fd as win32.HANDLE, data.data, data.count as i32, ^bytes_written, nil);
 	if e != 0 {
@@ -122,7 +120,7 @@ proc write(fd Handle, data []byte) -> (int, Error) {
 	return bytes_written as int, ERROR_NONE;
 }
 
-proc read(fd Handle, data []byte) -> (int, Error) {
+read :: proc(fd Handle, data []byte) -> (int, Error) {
 	bytes_read: i32;
 	e := win32.ReadFile(fd as win32.HANDLE, data.data, data.count as u32, ^bytes_read, nil);
 	if e != win32.FALSE {
@@ -132,7 +130,7 @@ proc read(fd Handle, data []byte) -> (int, Error) {
 	return bytes_read as int, ERROR_NONE;
 }
 
-proc seek(fd Handle, offset i64, whence int) -> (i64, Error) {
+seek :: proc(fd Handle, offset i64, whence int) -> (i64, Error) {
 	using win32;
 	w: u32;
 	match whence {
@@ -161,7 +159,7 @@ stdout := get_std_handle(win32.STD_OUTPUT_HANDLE);
 stderr := get_std_handle(win32.STD_ERROR_HANDLE);
 
 
-proc get_std_handle(h int) -> Handle {
+get_std_handle :: proc(h int) -> Handle {
 	fd := win32.GetStdHandle(h as i32);
 	win32.SetHandleInformation(fd, win32.HANDLE_FLAG_INHERIT, 0);
 	return fd as Handle;
@@ -172,7 +170,7 @@ proc get_std_handle(h int) -> Handle {
 
 
 
-proc last_write_time(fd Handle) -> File_Time {
+last_write_time :: proc(fd Handle) -> File_Time {
 	file_info: win32.BY_HANDLE_FILE_INFORMATION;
 	win32.GetFileInformationByHandle(fd as win32.HANDLE, ^file_info);
 	lo := file_info.last_write_time.lo as File_Time;
@@ -180,7 +178,7 @@ proc last_write_time(fd Handle) -> File_Time {
 	return lo | hi << 32;
 }
 
-proc last_write_time_by_name(name string) -> File_Time {
+last_write_time_by_name :: proc(name string) -> File_Time {
 	last_write_time: win32.FILETIME;
 	data: win32.FILE_ATTRIBUTE_DATA;
 	buf: [1024]byte;
@@ -202,7 +200,7 @@ proc last_write_time_by_name(name string) -> File_Time {
 
 
 
-proc read_entire_file(name string) -> ([]byte, bool) {
+read_entire_file :: proc(name string) -> ([]byte, bool) {
 	buf: [300]byte;
 	copy(buf[:], name as []byte);
 
@@ -250,25 +248,25 @@ proc read_entire_file(name string) -> ([]byte, bool) {
 
 
 
-proc heap_alloc(size int) -> rawptr {
+heap_alloc :: proc(size int) -> rawptr {
 	return win32.HeapAlloc(win32.GetProcessHeap(), win32.HEAP_ZERO_MEMORY, size);
 }
-proc heap_resize(ptr rawptr, new_size int) -> rawptr {
+heap_resize :: proc(ptr rawptr, new_size int) -> rawptr {
 	return win32.HeapReAlloc(win32.GetProcessHeap(), win32.HEAP_ZERO_MEMORY, ptr, new_size);
 }
-proc heap_free(ptr rawptr) {
+heap_free :: proc(ptr rawptr) {
 	win32.HeapFree(win32.GetProcessHeap(), 0, ptr);
 }
 
 
-proc exit(code int) {
+exit :: proc(code int) {
 	win32.ExitProcess(code as u32);
 }
 
 
 
-proc current_thread_id() -> int {
-	proc GetCurrentThreadId() -> u32 #foreign #dll_import
+current_thread_id :: proc() -> int {
+	GetCurrentThreadId :: proc() -> u32 #foreign #dll_import
 	return GetCurrentThreadId() as int;
 }
 

+ 19 - 21
core/sync.odin

@@ -3,52 +3,50 @@ import {
 	"atomic.odin";
 }
 
-type {
-	Semaphore struct {
-		handle win32.HANDLE;
-	}
+Semaphore :: struct {
+	handle win32.HANDLE;
+}
 
-	Mutex struct {
-		semaphore Semaphore;
-		counter   i32;
-		owner     i32;
-		recursion i32;
-	}
+Mutex :: struct {
+	semaphore Semaphore;
+	counter   i32;
+	owner     i32;
+	recursion i32;
 }
 
-proc current_thread_id() -> i32 {
+current_thread_id :: proc() -> i32 {
 	return win32.GetCurrentThreadId() as i32;
 }
 
-proc semaphore_init(s ^Semaphore) {
+semaphore_init :: proc(s ^Semaphore) {
 	s.handle = win32.CreateSemaphoreA(nil, 0, 1<<31-1, nil);
 }
 
-proc semaphore_destroy(s ^Semaphore) {
+semaphore_destroy :: proc(s ^Semaphore) {
 	win32.CloseHandle(s.handle);
 }
 
-proc semaphore_post(s ^Semaphore, count int) {
+semaphore_post :: proc(s ^Semaphore, count int) {
 	win32.ReleaseSemaphore(s.handle, count as i32, nil);
 }
 
-proc semaphore_release(s ^Semaphore) #inline { semaphore_post(s, 1); }
+semaphore_release :: proc(s ^Semaphore) #inline { semaphore_post(s, 1); }
 
-proc semaphore_wait(s ^Semaphore) {
+semaphore_wait :: proc(s ^Semaphore) {
 	win32.WaitForSingleObject(s.handle, win32.INFINITE);
 }
 
 
-proc mutex_init(m ^Mutex) {
+mutex_init :: proc(m ^Mutex) {
 	atomic.store32(^m.counter, 0);
 	atomic.store32(^m.owner, current_thread_id());
 	semaphore_init(^m.semaphore);
 	m.recursion = 0;
 }
-proc mutex_destroy(m ^Mutex) {
+mutex_destroy :: proc(m ^Mutex) {
 	semaphore_destroy(^m.semaphore);
 }
-proc mutex_lock(m ^Mutex) {
+mutex_lock :: proc(m ^Mutex) {
 	thread_id := current_thread_id();
 	if atomic.fetch_add32(^m.counter, 1) > 0 {
 		if thread_id != atomic.load32(^m.owner) {
@@ -58,7 +56,7 @@ proc mutex_lock(m ^Mutex) {
 	atomic.store32(^m.owner, thread_id);
 	m.recursion++;
 }
-proc mutex_try_lock(m ^Mutex) -> bool {
+mutex_try_lock :: proc(m ^Mutex) -> bool {
 	thread_id := current_thread_id();
 	if atomic.load32(^m.owner) == thread_id {
 		atomic.fetch_add32(^m.counter, 1);
@@ -75,7 +73,7 @@ proc mutex_try_lock(m ^Mutex) -> bool {
 	m.recursion++;
 	return true;
 }
-proc mutex_unlock(m ^Mutex) {
+mutex_unlock :: proc(m ^Mutex) {
 	recursion: i32;
 	thread_id := current_thread_id();
 	assert(thread_id == atomic.load32(^m.owner));

+ 222 - 229
core/sys/windows.odin

@@ -1,24 +1,22 @@
 #foreign_system_library "user32" when ODIN_OS == "windows";
 #foreign_system_library "gdi32"  when ODIN_OS == "windows";
 
-type {
-	HANDLE    rawptr;
-	HWND      HANDLE;
-	HDC       HANDLE;
-	HINSTANCE HANDLE;
-	HICON     HANDLE;
-	HCURSOR   HANDLE;
-	HMENU     HANDLE;
-	HBRUSH    HANDLE;
-	HGDIOBJ   HANDLE;
-	HMODULE   HANDLE;
-	WPARAM    uint;
-	LPARAM    int;
-	LRESULT   int;
-	ATOM      i16;
-	BOOL      i32;
-	WNDPROC   proc(hwnd HWND, msg u32, wparam WPARAM, lparam LPARAM) -> LRESULT;
-}
+HANDLE    :: rawptr;
+HWND      :: HANDLE;
+HDC       :: HANDLE;
+HINSTANCE :: HANDLE;
+HICON     :: HANDLE;
+HCURSOR   :: HANDLE;
+HMENU     :: HANDLE;
+HBRUSH    :: HANDLE;
+HGDIOBJ   :: HANDLE;
+HMODULE   :: HANDLE;
+WPARAM    :: uint;
+LPARAM    :: int;
+LRESULT   :: int;
+ATOM      :: i16;
+BOOL      :: i32;
+WNDPROC   :: type proc(hwnd HWND, msg u32, wparam WPARAM, lparam LPARAM) -> LRESULT;
 
 
 INVALID_HANDLE_VALUE :: (-1 as int) as HANDLE;
@@ -57,137 +55,136 @@ SM_CYSCREEN :: 1;
 SW_SHOW :: 5;
 
 
-type {
-	POINT struct #ordered {
-		x, y i32;
-	}
-
-	WNDCLASSEXA struct #ordered {
-		size, style           u32;
-		wnd_proc              WNDPROC;
-		cls_extra, wnd_extra  i32;
-		instance              HINSTANCE;
-		icon                  HICON;
-		cursor                HCURSOR;
-		background            HBRUSH;
-		menu_name, class_name ^u8;
-		sm                    HICON;
-	}
-
-	MSG struct #ordered {
-		hwnd    HWND;
-		message u32;
-		wparam  WPARAM;
-		lparam  LPARAM;
-		time    u32;
-		pt      POINT;
-	}
-
-	RECT struct #ordered {
-		left   i32;
-		top    i32;
-		right  i32;
-		bottom i32;
-	}
-
-	FILETIME struct #ordered {
-		lo, hi u32;
-	}
-
-	BY_HANDLE_FILE_INFORMATION struct #ordered {
-		file_attributes      u32;
-		creation_time,
-		last_access_time,
-		last_write_time      FILETIME;
-		volume_serial_number,
-		file_size_high,
-		file_size_low,
-		number_of_links,
-		file_index_high,
-		file_index_low       u32;
-	}
-
-	FILE_ATTRIBUTE_DATA struct #ordered {
-		file_attributes  u32;
-		creation_time,
-		last_access_time,
-		last_write_time  FILETIME;
-		file_size_high,
-		file_size_low    u32;
-	}
-
-	GET_FILEEX_INFO_LEVELS i32;
+POINT :: struct #ordered {
+	x, y i32;
+}
+
+WNDCLASSEXA :: struct #ordered {
+	size, style           u32;
+	wnd_proc              WNDPROC;
+	cls_extra, wnd_extra  i32;
+	instance              HINSTANCE;
+	icon                  HICON;
+	cursor                HCURSOR;
+	background            HBRUSH;
+	menu_name, class_name ^u8;
+	sm                    HICON;
+}
+
+MSG :: struct #ordered {
+	hwnd    HWND;
+	message u32;
+	wparam  WPARAM;
+	lparam  LPARAM;
+	time    u32;
+	pt      POINT;
+}
+
+RECT :: struct #ordered {
+	left   i32;
+	top    i32;
+	right  i32;
+	bottom i32;
 }
+
+FILETIME :: struct #ordered {
+	lo, hi u32;
+}
+
+BY_HANDLE_FILE_INFORMATION :: struct #ordered {
+	file_attributes      u32;
+	creation_time,
+	last_access_time,
+	last_write_time      FILETIME;
+	volume_serial_number,
+	file_size_high,
+	file_size_low,
+	number_of_links,
+	file_index_high,
+	file_index_low       u32;
+}
+
+FILE_ATTRIBUTE_DATA :: struct #ordered {
+	file_attributes  u32;
+	creation_time,
+	last_access_time,
+	last_write_time  FILETIME;
+	file_size_high,
+	file_size_low    u32;
+}
+
+GET_FILEEX_INFO_LEVELS :: i32;
+
 GetFileExInfoStandard: GET_FILEEX_INFO_LEVELS : 0;
 GetFileExMaxInfoLevel: GET_FILEEX_INFO_LEVELS : 1;
 
-proc GetLastError    () -> i32                           #foreign #dll_import
-proc ExitProcess     (exit_code u32)                    #foreign #dll_import
-proc GetDesktopWindow() -> HWND                          #foreign #dll_import
-proc GetCursorPos    (p ^POINT) -> i32                  #foreign #dll_import
-proc ScreenToClient  (h HWND, p ^POINT) -> i32         #foreign #dll_import
-proc GetModuleHandleA(module_name ^u8) -> HINSTANCE     #foreign #dll_import
-proc GetStockObject  (fn_object i32) -> HGDIOBJ         #foreign #dll_import
-proc PostQuitMessage (exit_code i32)                    #foreign #dll_import
-proc SetWindowTextA  (hwnd HWND, c_string ^u8) -> BOOL #foreign #dll_import
-
-proc QueryPerformanceFrequency(result ^i64) -> i32 #foreign #dll_import
-proc QueryPerformanceCounter  (result ^i64) -> i32 #foreign #dll_import
-
-proc Sleep(ms i32) -> i32 #foreign #dll_import
-
-proc OutputDebugStringA(c_str ^u8) #foreign #dll_import
-
-
-proc RegisterClassExA(wc ^WNDCLASSEXA) -> ATOM #foreign #dll_import
-proc CreateWindowExA (ex_style u32,
-                      class_name, title ^u8,
-                      style u32,
-                      x, y, w, h i32,
-                      parent HWND, menu HMENU, instance HINSTANCE,
-                      param rawptr) -> HWND #foreign #dll_import
-
-proc ShowWindow      (hwnd HWND, cmd_show i32) -> BOOL #foreign #dll_import
-proc TranslateMessage(msg ^MSG) -> BOOL                 #foreign #dll_import
-proc DispatchMessageA(msg ^MSG) -> LRESULT              #foreign #dll_import
-proc UpdateWindow    (hwnd HWND) -> BOOL                #foreign #dll_import
-proc PeekMessageA    (msg ^MSG, hwnd HWND,
+GetLastError     :: proc() -> i32                          #foreign #dll_import
+ExitProcess      :: proc(exit_code u32)                    #foreign #dll_import
+GetDesktopWindow :: proc() -> HWND                         #foreign #dll_import
+GetCursorPos     :: proc(p ^POINT) -> i32                  #foreign #dll_import
+ScreenToClient   :: proc(h HWND, p ^POINT) -> i32          #foreign #dll_import
+GetModuleHandleA :: proc(module_name ^u8) -> HINSTANCE     #foreign #dll_import
+GetStockObject   :: proc(fn_object i32) -> HGDIOBJ         #foreign #dll_import
+PostQuitMessage  :: proc(exit_code i32)                    #foreign #dll_import
+SetWindowTextA   :: proc(hwnd HWND, c_string ^u8) -> BOOL  #foreign #dll_import
+
+QueryPerformanceFrequency :: proc(result ^i64) -> i32 #foreign #dll_import
+QueryPerformanceCounter   :: proc(result ^i64) -> i32 #foreign #dll_import
+
+Sleep :: proc(ms i32) -> i32 #foreign #dll_import
+
+OutputDebugStringA :: proc(c_str ^u8) #foreign #dll_import
+
+
+RegisterClassExA :: proc(wc ^WNDCLASSEXA) -> ATOM #foreign #dll_import
+CreateWindowExA  :: proc(ex_style u32,
+                         class_name, title ^u8,
+                         style u32,
+                         x, y, w, h i32,
+                         parent HWND, menu HMENU, instance HINSTANCE,
+                         param rawptr) -> HWND #foreign #dll_import
+
+ShowWindow       :: proc(hwnd HWND, cmd_show i32) -> BOOL #foreign #dll_import
+TranslateMessage :: proc(msg ^MSG) -> BOOL                 #foreign #dll_import
+DispatchMessageA :: proc(msg ^MSG) -> LRESULT              #foreign #dll_import
+UpdateWindow     :: proc(hwnd HWND) -> BOOL                #foreign #dll_import
+PeekMessageA     :: proc(msg ^MSG, hwnd HWND,
                          msg_filter_min, msg_filter_max, remove_msg u32) -> BOOL #foreign #dll_import
 
-proc DefWindowProcA  (hwnd HWND, msg u32, wparam WPARAM, lparam LPARAM) -> LRESULT #foreign #dll_import
+DefWindowProcA :: proc(hwnd HWND, msg u32, wparam WPARAM, lparam LPARAM) -> LRESULT #foreign #dll_import
 
-proc AdjustWindowRect(rect ^RECT, style u32, menu BOOL) -> BOOL #foreign #dll_import
-proc GetActiveWindow () -> HWND #foreign #dll_import
+AdjustWindowRect :: proc(rect ^RECT, style u32, menu BOOL) -> BOOL #foreign #dll_import
+GetActiveWindow  :: proc() -> HWND #foreign #dll_import
 
 
-proc GetQueryPerformanceFrequency() -> i64 {
+GetQueryPerformanceFrequency :: proc() -> i64 {
 	r: i64;
 	QueryPerformanceFrequency(^r);
 	return r;
 }
 
-proc GetCommandLineA() -> ^u8 #foreign #dll_import
-proc GetSystemMetrics(index i32) -> i32 #foreign #dll_import
-proc GetCurrentThreadId() -> u32 #foreign #dll_import
+GetCommandLineA    :: proc() -> ^u8 #foreign #dll_import
+GetSystemMetrics   :: proc(index i32) -> i32 #foreign #dll_import
+GetCurrentThreadId :: proc() -> u32 #foreign #dll_import
 
 // File Stuff
 
-proc CloseHandle (h HANDLE) -> i32 #foreign #dll_import
-proc GetStdHandle(h i32) -> HANDLE #foreign #dll_import
-proc CreateFileA (filename ^u8, desired_access, share_mode u32,
+CloseHandle  :: proc(h HANDLE) -> i32 #foreign #dll_import
+GetStdHandle :: proc(h i32) -> HANDLE #foreign #dll_import
+CreateFileA  :: proc(filename ^u8, desired_access, share_mode u32,
                   security rawptr,
                   creation, flags_and_attribs u32, template_file HANDLE) -> HANDLE #foreign #dll_import
-proc ReadFile    (h HANDLE, buf rawptr, to_read u32, bytes_read ^i32, overlapped rawptr) -> BOOL #foreign #dll_import
-proc WriteFile   (h HANDLE, buf rawptr, len i32, written_result ^i32, overlapped rawptr) -> i32 #foreign #dll_import
+ReadFile  :: proc(h HANDLE, buf rawptr, to_read u32, bytes_read ^i32, overlapped rawptr) -> BOOL #foreign #dll_import
+WriteFile :: proc(h HANDLE, buf rawptr, len i32, written_result ^i32, overlapped rawptr) -> i32 #foreign #dll_import
 
-proc GetFileSizeEx             (file_handle HANDLE, file_size ^i64) -> BOOL #foreign #dll_import
-proc GetFileAttributesExA      (filename ^u8, info_level_id GET_FILEEX_INFO_LEVELS, file_info rawptr) -> BOOL #foreign #dll_import
-proc GetFileInformationByHandle(file_handle HANDLE, file_info ^BY_HANDLE_FILE_INFORMATION) -> BOOL #foreign #dll_import
+GetFileSizeEx              :: proc(file_handle HANDLE, file_size ^i64) -> BOOL #foreign #dll_import
+GetFileAttributesExA       :: proc(filename ^u8, info_level_id GET_FILEEX_INFO_LEVELS, file_info rawptr) -> BOOL #foreign #dll_import
+GetFileInformationByHandle :: proc(file_handle HANDLE, file_info ^BY_HANDLE_FILE_INFORMATION) -> BOOL #foreign #dll_import
 
-proc GetFileType(file_handle HANDLE) -> u32 #foreign #dll_import
-proc SetFilePointer(file_handle HANDLE, distance_to_move i32, distance_to_move_high ^i32, move_method u32) -> u32 #foreign #dll_import
+GetFileType    :: proc(file_handle HANDLE) -> u32 #foreign #dll_import
+SetFilePointer :: proc(file_handle HANDLE, distance_to_move i32, distance_to_move_high ^i32, move_method u32) -> u32 #foreign #dll_import
 
-proc SetHandleInformation(obj HANDLE, mask, flags u32) -> BOOL #foreign #dll_import
+SetHandleInformation :: proc(obj HANDLE, mask, flags u32) -> BOOL #foreign #dll_import
 
 HANDLE_FLAG_INHERIT :: 1;
 HANDLE_FLAG_PROTECT_FROM_CLOSE :: 2;
@@ -241,17 +238,17 @@ INVALID_SET_FILE_POINTER :: ~(0 as u32);
 
 
 
-proc HeapAlloc     (h HANDLE, flags u32, bytes int) -> rawptr                 #foreign #dll_import
-proc HeapReAlloc   (h HANDLE, flags u32, memory rawptr, bytes int) -> rawptr #foreign #dll_import
-proc HeapFree      (h HANDLE, flags u32, memory rawptr) -> BOOL               #foreign #dll_import
-proc GetProcessHeap() -> HANDLE #foreign #dll_import
+HeapAlloc      :: proc (h HANDLE, flags u32, bytes int) -> rawptr                 #foreign #dll_import
+HeapReAlloc    :: proc (h HANDLE, flags u32, memory rawptr, bytes int) -> rawptr #foreign #dll_import
+HeapFree       :: proc (h HANDLE, flags u32, memory rawptr) -> BOOL               #foreign #dll_import
+GetProcessHeap :: proc () -> HANDLE #foreign #dll_import
 
 
 HEAP_ZERO_MEMORY :: 0x00000008;
 
 // Synchronization
 
-type SECURITY_ATTRIBUTES struct #ordered {
+SECURITY_ATTRIBUTES :: struct #ordered {
 	length              u32;
 	security_descriptor rawptr;
 	inherit_handle      BOOL;
@@ -259,51 +256,49 @@ type SECURITY_ATTRIBUTES struct #ordered {
 
 INFINITE :: 0xffffffff;
 
-proc CreateSemaphoreA   (attributes ^SECURITY_ATTRIBUTES, initial_count, maximum_count i32, name ^byte) -> HANDLE #foreign #dll_import
-proc ReleaseSemaphore   (semaphore HANDLE, release_count i32, previous_count ^i32) -> BOOL #foreign #dll_import
-proc WaitForSingleObject(handle HANDLE, milliseconds u32) -> u32 #foreign #dll_import
+CreateSemaphoreA    :: proc(attributes ^SECURITY_ATTRIBUTES, initial_count, maximum_count i32, name ^byte) -> HANDLE #foreign #dll_import
+ReleaseSemaphore    :: proc(semaphore HANDLE, release_count i32, previous_count ^i32) -> BOOL #foreign #dll_import
+WaitForSingleObject :: proc(handle HANDLE, milliseconds u32) -> u32 #foreign #dll_import
 
 
-proc InterlockedCompareExchange(dst ^i32, exchange, comparand i32) -> i32 #foreign
-proc InterlockedExchange       (dst ^i32, desired i32) -> i32 #foreign
-proc InterlockedExchangeAdd    (dst ^i32, desired i32) -> i32 #foreign
-proc InterlockedAnd            (dst ^i32, desired i32) -> i32 #foreign
-proc InterlockedOr             (dst ^i32, desired i32) -> i32 #foreign
+InterlockedCompareExchange :: proc(dst ^i32, exchange, comparand i32) -> i32 #foreign
+InterlockedExchange        :: proc(dst ^i32, desired i32) -> i32 #foreign
+InterlockedExchangeAdd     :: proc(dst ^i32, desired i32) -> i32 #foreign
+InterlockedAnd             :: proc(dst ^i32, desired i32) -> i32 #foreign
+InterlockedOr              :: proc(dst ^i32, desired i32) -> i32 #foreign
 
-proc InterlockedCompareExchange64(dst ^i64, exchange, comparand i64) -> i64 #foreign
-proc InterlockedExchange64       (dst ^i64, desired i64) -> i64 #foreign
-proc InterlockedExchangeAdd64    (dst ^i64, desired i64) -> i64 #foreign
-proc InterlockedAnd64            (dst ^i64, desired i64) -> i64 #foreign
-proc InterlockedOr64             (dst ^i64, desired i64) -> i64 #foreign
+InterlockedCompareExchange64 :: proc(dst ^i64, exchange, comparand i64) -> i64 #foreign
+InterlockedExchange64        :: proc(dst ^i64, desired i64) -> i64 #foreign
+InterlockedExchangeAdd64     :: proc(dst ^i64, desired i64) -> i64 #foreign
+InterlockedAnd64             :: proc(dst ^i64, desired i64) -> i64 #foreign
+InterlockedOr64              :: proc(dst ^i64, desired i64) -> i64 #foreign
 
-proc _mm_pause       () #foreign
-proc ReadWriteBarrier() #foreign
-proc WriteBarrier    () #foreign
-proc ReadBarrier     () #foreign
+_mm_pause        :: proc() #foreign
+ReadWriteBarrier :: proc() #foreign
+WriteBarrier     :: proc() #foreign
+ReadBarrier      :: proc() #foreign
 
 
 // GDI
-type {
-	BITMAPINFOHEADER struct #ordered {
-		size              u32;
-		width, height     i32;
-		planes, bit_count i16;
-		compression       u32;
-		size_image        u32;
-		x_pels_per_meter  i32;
-		y_pels_per_meter  i32;
-		clr_used          u32;
-		clr_important     u32;
-	}
-	BITMAPINFO struct #ordered {
-		using header BITMAPINFOHEADER;
-		colors       [1]RGBQUAD;
-	}
-
-
-	RGBQUAD struct #ordered {
-		blue, green, red, reserved byte;
-	}
+BITMAPINFOHEADER :: struct #ordered {
+	size              u32;
+	width, height     i32;
+	planes, bit_count i16;
+	compression       u32;
+	size_image        u32;
+	x_pels_per_meter  i32;
+	y_pels_per_meter  i32;
+	clr_used          u32;
+	clr_important     u32;
+}
+BITMAPINFO :: struct #ordered {
+	using header BITMAPINFOHEADER;
+	colors       [1]RGBQUAD;
+}
+
+
+RGBQUAD :: struct #ordered {
+	blue, green, red, reserved byte;
 }
 
 BI_RGB         :: 0;
@@ -311,20 +306,20 @@ DIB_RGB_COLORS :: 0x00;
 SRCCOPY: u32    : 0x00cc0020;
 
 
-proc StretchDIBits(hdc HDC,
-                   x_dst, y_dst, width_dst, height_dst i32,
-                   x_src, y_src, width_src, header_src i32,
-                   bits rawptr, bits_info ^BITMAPINFO,
-                   usage u32,
-                   rop u32) -> i32 #foreign #dll_import
+StretchDIBits :: proc (hdc HDC,
+                       x_dst, y_dst, width_dst, height_dst i32,
+                       x_src, y_src, width_src, header_src i32,
+                       bits rawptr, bits_info ^BITMAPINFO,
+                       usage u32,
+                       rop u32) -> i32 #foreign #dll_import
 
 
 
-proc LoadLibraryA  (c_str ^u8) -> HMODULE #foreign
-proc FreeLibrary   (h HMODULE) #foreign
-proc GetProcAddress(h HMODULE, c_str ^u8) -> PROC #foreign
+LoadLibraryA   :: proc (c_str ^u8) -> HMODULE #foreign
+FreeLibrary    :: proc (h HMODULE) #foreign
+GetProcAddress :: proc (h HMODULE, c_str ^u8) -> PROC #foreign
 
-proc GetClientRect(hwnd HWND, rect ^RECT) -> BOOL #foreign
+GetClientRect :: proc(hwnd HWND, rect ^RECT) -> BOOL #foreign
 
 
 
@@ -351,49 +346,47 @@ PFD_DEPTH_DONTCARE        :: 0x20000000;
 PFD_DOUBLEBUFFER_DONTCARE :: 0x40000000;
 PFD_STEREO_DONTCARE       :: 0x80000000;
 
-type {
-	HGLRC HANDLE;
-	PROC  proc() #cc_c;
-	wglCreateContextAttribsARBType proc(hdc HDC, hshareContext rawptr, attribList ^i32) -> HGLRC;
-
-
-	PIXELFORMATDESCRIPTOR struct #ordered {
-		size,
-		version,
-		flags u32;
-
-		pixel_type,
-		color_bits,
-		red_bits,
-		red_shift,
-		green_bits,
-		green_shift,
-		blue_bits,
-		blue_shift,
-		alpha_bits,
-		alpha_shift,
-		accum_bits,
-		accum_red_bits,
-		accum_green_bits,
-		accum_blue_bits,
-		accum_alpha_bits,
-		depth_bits,
-		stencil_bits,
-		aux_buffers,
-		layer_type,
-		reserved byte;
-
-		layer_mask,
-		visible_mask,
-		damage_mask u32;
-	}
+HGLRC :: HANDLE;
+PROC  :: type proc() #cc_c;
+wglCreateContextAttribsARBType :: proc(hdc HDC, hshareContext rawptr, attribList ^i32) -> HGLRC;
+
+
+PIXELFORMATDESCRIPTOR :: struct #ordered {
+	size,
+	version,
+	flags u32;
+
+	pixel_type,
+	color_bits,
+	red_bits,
+	red_shift,
+	green_bits,
+	green_shift,
+	blue_bits,
+	blue_shift,
+	alpha_bits,
+	alpha_shift,
+	accum_bits,
+	accum_red_bits,
+	accum_green_bits,
+	accum_blue_bits,
+	accum_alpha_bits,
+	depth_bits,
+	stencil_bits,
+	aux_buffers,
+	layer_type,
+	reserved byte;
+
+	layer_mask,
+	visible_mask,
+	damage_mask u32;
 }
 
-proc GetDC            (h HANDLE) -> HDC #foreign
-proc SetPixelFormat   (hdc HDC, pixel_format i32, pfd ^PIXELFORMATDESCRIPTOR ) -> BOOL #foreign #dll_import
-proc ChoosePixelFormat(hdc HDC, pfd ^PIXELFORMATDESCRIPTOR) -> i32 #foreign #dll_import
-proc SwapBuffers      (hdc HDC) -> BOOL #foreign #dll_import
-proc ReleaseDC        (wnd HWND, hdc HDC) -> i32 #foreign #dll_import
+GetDC             :: proc(h HANDLE) -> HDC #foreign
+SetPixelFormat    :: proc(hdc HDC, pixel_format i32, pfd ^PIXELFORMATDESCRIPTOR ) -> BOOL #foreign #dll_import
+ChoosePixelFormat :: proc(hdc HDC, pfd ^PIXELFORMATDESCRIPTOR) -> i32 #foreign #dll_import
+SwapBuffers       :: proc(hdc HDC) -> BOOL #foreign #dll_import
+ReleaseDC         :: proc(wnd HWND, hdc HDC) -> i32 #foreign #dll_import
 
 WGL_CONTEXT_MAJOR_VERSION_ARB             :: 0x2091;
 WGL_CONTEXT_MINOR_VERSION_ARB             :: 0x2092;
@@ -401,19 +394,19 @@ WGL_CONTEXT_PROFILE_MASK_ARB              :: 0x9126;
 WGL_CONTEXT_CORE_PROFILE_BIT_ARB          :: 0x0001;
 WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB :: 0x0002;
 
-proc wglCreateContext (hdc HDC) -> HGLRC #foreign #dll_import
-proc wglMakeCurrent   (hdc HDC, hglrc HGLRC) -> BOOL #foreign #dll_import
-proc wglGetProcAddress(c_str ^u8) -> PROC #foreign #dll_import
-proc wglDeleteContext (hglrc HGLRC) -> BOOL #foreign #dll_import
+wglCreateContext  :: proc(hdc HDC) -> HGLRC #foreign #dll_import
+wglMakeCurrent    :: proc(hdc HDC, hglrc HGLRC) -> BOOL #foreign #dll_import
+wglGetProcAddress :: proc(c_str ^u8) -> PROC #foreign #dll_import
+wglDeleteContext  :: proc(hglrc HGLRC) -> BOOL #foreign #dll_import
 
 
 
-proc GetKeyState     (v_key i32) -> i16 #foreign #dll_import
-proc GetAsyncKeyState(v_key i32) -> i16 #foreign #dll_import
+GetKeyState      :: proc(v_key i32) -> i16 #foreign #dll_import
+GetAsyncKeyState :: proc(v_key i32) -> i16 #foreign #dll_import
 
-proc is_key_down(key Key_Code) -> bool #inline { return GetAsyncKeyState(key as i32) < 0; }
+is_key_down :: proc(key Key_Code) -> bool #inline { return GetAsyncKeyState(key as i32) < 0; }
 
-type Key_Code enum i32 {
+Key_Code :: enum i32 {
 	LBUTTON    = 0x01,
 	RBUTTON    = 0x02,
 	CANCEL     = 0x03,

+ 7 - 7
core/utf8.odin

@@ -8,7 +8,7 @@ UTF_MAX    :: 4;
 SURROGATE_MIN :: 0xd800;
 SURROGATE_MAX :: 0xdfff;
 
-type Accept_Range struct {
+Accept_Range :: struct {
 	lo, hi u8;
 }
 
@@ -40,7 +40,7 @@ accept_sizes := [256]byte{
 	0x34, 0x04, 0x04, 0x04, 0x44, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xf0-0xff
 };
 
-proc encode_rune(r rune) -> ([4]byte, int) {
+encode_rune :: proc(r rune) -> ([4]byte, int) {
 	buf: [4]byte;
 	i := r as u32;
 	mask: byte : 0x3f;
@@ -74,7 +74,7 @@ proc encode_rune(r rune) -> ([4]byte, int) {
 	return buf, 4;
 }
 
-proc decode_rune(s string) -> (rune, int) {
+decode_rune :: proc(s string) -> (rune, int) {
 	n := s.count;
 	if n < 1 {
 		return RUNE_ERROR, 0;
@@ -119,7 +119,7 @@ proc decode_rune(s string) -> (rune, int) {
 }
 
 
-proc valid_rune(r rune) -> bool {
+valid_rune :: proc(r rune) -> bool {
 	if r < 0 {
 		return false;
 	} else if SURROGATE_MIN <= r && r <= SURROGATE_MAX {
@@ -130,7 +130,7 @@ proc valid_rune(r rune) -> bool {
 	return true;
 }
 
-proc valid_string(s string) -> bool {
+valid_string :: proc(s string) -> bool {
 	n := s.count;
 	for i := 0; i < n; {
 		si := s[i];
@@ -163,7 +163,7 @@ proc valid_string(s string) -> bool {
 	return true;
 }
 
-proc rune_count(s string) -> int {
+rune_count :: proc(s string) -> int {
 	count := 0;
 	n := s.count;
 	for i := 0; i < n; count++ {
@@ -200,7 +200,7 @@ proc rune_count(s string) -> int {
 }
 
 
-proc rune_size(r rune) -> int {
+rune_size :: proc(r rune) -> int {
 	match {
 	case r < 0:          return -1;
 	case r <= 1<<7  - 1: return 1;

+ 0 - 36
src/checker/checker.c

@@ -308,11 +308,6 @@ bool decl_info_has_init(DeclInfo *d) {
 	}
 	if (d->proc_decl != NULL) {
 		switch (d->proc_decl->kind) {
-		case_ast_node(pd, ProcDecl, d->proc_decl);
-			if (pd->body != NULL) {
-				return true;
-			}
-		case_end;
 		case_ast_node(pd, ProcLit, d->proc_decl);
 			if (pd->body != NULL) {
 				return true;
@@ -1260,23 +1255,6 @@ void check_global_collect_entities_from_file(Checker *c, Scope *parent_scope, As
 					DelayedDecl di = {parent_scope, spec};
 					array_add(&c->delayed_imports, di);
 				case_end;
-
-				case_ast_node(ts, TypeSpec, spec);
-					if (ts->name->kind != AstNode_Ident) {
-						error_node(ts->name, "A declaration's name must be an identifier, got %.*s", LIT(ast_node_strings[ts->name->kind]));
-						continue;
-					}
-					ast_node(n, Ident, ts->name);
-
-					Entity *e = make_entity_type_name(c->allocator, parent_scope, *n, NULL);
-					e->identifier = ts->name;
-
-					DeclInfo *d = make_declaration_info(c->allocator, e->scope);
-					d->type_expr = ts->type;
-					d->init_expr = ts->type;
-					add_entity_and_decl_info(c, ts->name, e, d);
-				case_end;
-
 				default:
 					error(ast_node_token(spec), "Invalid specification in declaration: `%.*s`", LIT(ast_node_strings[spec->kind]));
 					break;
@@ -1293,20 +1271,6 @@ void check_global_collect_entities_from_file(Checker *c, Scope *parent_scope, As
 			DelayedDecl di = {parent_scope, decl};
 			array_add(&c->delayed_foreign_libraries, di);
 		case_end;
-		case_ast_node(pd, ProcDecl, decl);
-			if (pd->name->kind != AstNode_Ident) {
-				error_node(pd->name, "A declaration's name must be an identifier, got %.*s", LIT(ast_node_strings[pd->name->kind]));
-				continue;
-			}
-			ast_node(n, Ident, pd->name);
-			Token token = *n;
-			Entity *e = make_entity_procedure(c->allocator, parent_scope, token, NULL, pd->tags);
-			e->identifier = pd->name;
-			DeclInfo *d = make_declaration_info(c->allocator, e->scope);
-			d->proc_decl = decl;
-			add_entity_and_decl_info(c, pd->name, e, d);
-		case_end;
-
 		default:
 			if (parent_scope->is_file) {
 				error_node(decl, "Only declarations are allowed at file scope");

+ 83 - 184
src/checker/decl.c

@@ -282,6 +282,10 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init,
 
 	check_init_constant(c, e, &operand);
 	c->context.iota = (ExactValue){0};
+
+	if (e->type == t_invalid) {
+		error(e->token, "Illegal cyclic declaration");
+	}
 }
 
 
@@ -326,224 +330,119 @@ bool are_signatures_similar_enough(Type *a_, Type *b_) {
 
 void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
 	GB_ASSERT(e->type == NULL);
+	if (d->proc_decl->kind != AstNode_ProcLit) {
+		// TOOD(bill): Better error message
+		error_node(d->proc_decl, "Expected a procedure to check");
+		return;
+	}
 
 	Type *proc_type = make_type_proc(c->allocator, e->scope, NULL, 0, NULL, 0, false, ProcCC_Odin);
 	e->type = proc_type;
-	if (d->proc_decl->kind == AstNode_ProcDecl) {
-		ast_node(pd, ProcDecl, d->proc_decl);
-
-		check_open_scope(c, pd->type);
-		check_procedure_type(c, proc_type, pd->type);
-
-		bool is_foreign      = (pd->tags & ProcTag_foreign)   != 0;
-		bool is_link_name    = (pd->tags & ProcTag_link_name) != 0;
-		bool is_export       = (pd->tags & ProcTag_export)    != 0;
-		bool is_inline       = (pd->tags & ProcTag_inline)    != 0;
-		bool is_no_inline    = (pd->tags & ProcTag_no_inline) != 0;
-
-		if ((d->scope->is_file || d->scope->is_global) &&
-		    str_eq(e->token.string, str_lit("main"))) {
-			if (proc_type != NULL) {
-				TypeProc *pt = &proc_type->Proc;
-				if (pt->param_count != 0 ||
-				    pt->result_count != 0) {
-					gbString str = type_to_string(proc_type);
-					error(e->token, "Procedure type of `main` was expected to be `proc()`, got %s", str);
-					gb_string_free(str);
-				}
+	ast_node(pd, ProcLit, d->proc_decl);
+
+	check_open_scope(c, pd->type);
+	check_procedure_type(c, proc_type, pd->type);
+
+	bool is_foreign      = (pd->tags & ProcTag_foreign)   != 0;
+	bool is_link_name    = (pd->tags & ProcTag_link_name) != 0;
+	bool is_export       = (pd->tags & ProcTag_export)    != 0;
+	bool is_inline       = (pd->tags & ProcTag_inline)    != 0;
+	bool is_no_inline    = (pd->tags & ProcTag_no_inline) != 0;
+
+	if ((d->scope->is_file || d->scope->is_global) &&
+	    str_eq(e->token.string, str_lit("main"))) {
+		if (proc_type != NULL) {
+			TypeProc *pt = &proc_type->Proc;
+			if (pt->param_count != 0 ||
+			    pt->result_count != 0) {
+				gbString str = type_to_string(proc_type);
+				error(e->token, "Procedure type of `main` was expected to be `proc()`, got %s", str);
+				gb_string_free(str);
 			}
 		}
+	}
 
-		if (is_inline && is_no_inline) {
-			error_node(pd->type, "You cannot apply both `inline` and `no_inline` to a procedure");
-		}
-
-		if (is_foreign && is_link_name) {
-			error_node(pd->type, "You cannot apply both `foreign` and `link_name` to a procedure");
-		} else if (is_foreign && is_export) {
-			error_node(pd->type, "You cannot apply both `foreign` and `export` to a procedure");
-		}
-
-
-		if (pd->body != NULL) {
-			if (is_foreign) {
-				error_node(pd->body, "A procedure tagged as `#foreign` cannot have a body");
-			}
-
-			if (proc_type->Proc.calling_convention != ProcCC_Odin) {
-				error_node(d->proc_decl, "An internal procedure may only have the Odin calling convention");
-				proc_type->Proc.calling_convention = ProcCC_Odin;
-			}
+	if (is_inline && is_no_inline) {
+		error_node(pd->type, "You cannot apply both `inline` and `no_inline` to a procedure");
+	}
 
-			d->scope = c->context.scope;
+	if (is_foreign && is_link_name) {
+		error_node(pd->type, "You cannot apply both `foreign` and `link_name` to a procedure");
+	} else if (is_foreign && is_export) {
+		error_node(pd->type, "You cannot apply both `foreign` and `export` to a procedure");
+	}
 
-			GB_ASSERT(pd->body->kind == AstNode_BlockStmt);
-			check_procedure_later(c, c->curr_ast_file, e->token, d, proc_type, pd->body, pd->tags);
-		}
 
+	if (pd->body != NULL) {
 		if (is_foreign) {
-			MapEntity *fp = &c->info.foreign_procs;
-			AstNodeProcDecl *proc_decl = &d->proc_decl->ProcDecl;
-			String name = proc_decl->name->Ident.string;
-			if (proc_decl->foreign_name.len > 0) {
-				name = proc_decl->foreign_name;
-			}
-
-			e->Procedure.is_foreign = true;
-			e->Procedure.foreign_name = name;
-
-			HashKey key = hash_string(name);
-			Entity **found = map_entity_get(fp, key);
-			if (found) {
-				Entity *f = *found;
-				TokenPos pos = f->token.pos;
-				Type *this_type = base_type(e->type);
-				Type *other_type = base_type(f->type);
-				if (!are_signatures_similar_enough(this_type, other_type)) {
-					error_node(d->proc_decl,
-					           "Redeclaration of #foreign procedure `%.*s` with different type signatures\n"
-					           "\tat %.*s(%td:%td)",
-					           LIT(name), LIT(pos.file), pos.line, pos.column);
-				}
-			} else {
-				map_entity_set(fp, key, e);
-			}
-		} else {
-			String name = e->token.string;
-			if (is_link_name) {
-				AstNodeProcDecl *proc_decl = &d->proc_decl->ProcDecl;
-				name = proc_decl->link_name;
-			}
-
-			if (is_link_name || is_export) {
-				MapEntity *fp = &c->info.foreign_procs;
-
-				e->Procedure.link_name = name;
-
-				HashKey key = hash_string(name);
-				Entity **found = map_entity_get(fp, key);
-				if (found) {
-					Entity *f = *found;
-					TokenPos pos = f->token.pos;
-					// TODO(bill): Better error message?
-					error_node(d->proc_decl,
-					           "Non unique linking name for procedure `%.*s`\n"
-					           "\tother at %.*s(%td:%td)",
-					           LIT(name), LIT(pos.file), pos.line, pos.column);
-				} else {
-					map_entity_set(fp, key, e);
-				}
-			}
+			error_node(pd->body, "A procedure tagged as `#foreign` cannot have a body");
 		}
 
-		check_close_scope(c);
-	} else if (d->proc_decl->kind == AstNode_ProcLit) {
-		ast_node(pd, ProcLit, d->proc_decl);
-
-		check_open_scope(c, pd->type);
-		check_procedure_type(c, proc_type, pd->type);
-
-		bool is_foreign      = (pd->tags & ProcTag_foreign)   != 0;
-		bool is_link_name    = (pd->tags & ProcTag_link_name) != 0;
-		bool is_export       = (pd->tags & ProcTag_export)    != 0;
-		bool is_inline       = (pd->tags & ProcTag_inline)    != 0;
-		bool is_no_inline    = (pd->tags & ProcTag_no_inline) != 0;
-
-		if ((d->scope->is_file || d->scope->is_global) &&
-		    str_eq(e->token.string, str_lit("main"))) {
-			if (proc_type != NULL) {
-				TypeProc *pt = &proc_type->Proc;
-				if (pt->param_count != 0 ||
-				    pt->result_count != 0) {
-					gbString str = type_to_string(proc_type);
-					error(e->token, "Procedure type of `main` was expected to be `proc()`, got %s", str);
-					gb_string_free(str);
-				}
-			}
+		if (proc_type->Proc.calling_convention != ProcCC_Odin) {
+			error_node(d->proc_decl, "An internal procedure may only have the Odin calling convention");
+			proc_type->Proc.calling_convention = ProcCC_Odin;
 		}
 
-		if (is_inline && is_no_inline) {
-			error_node(pd->type, "You cannot apply both `inline` and `no_inline` to a procedure");
-		}
+		d->scope = c->context.scope;
+
+		GB_ASSERT(pd->body->kind == AstNode_BlockStmt);
+		check_procedure_later(c, c->curr_ast_file, e->token, d, proc_type, pd->body, pd->tags);
+	}
 
-		if (is_foreign && is_link_name) {
-			error_node(pd->type, "You cannot apply both `foreign` and `link_name` to a procedure");
-		} else if (is_foreign && is_export) {
-			error_node(pd->type, "You cannot apply both `foreign` and `export` to a procedure");
+	if (is_foreign) {
+		MapEntity *fp = &c->info.foreign_procs;
+		String name = e->token.string;
+		if (pd->foreign_name.len > 0) {
+			name = pd->foreign_name;
 		}
 
+		e->Procedure.is_foreign = true;
+		e->Procedure.foreign_name = name;
 
-		if (pd->body != NULL) {
-			if (is_foreign) {
-				error_node(pd->body, "A procedure tagged as `#foreign` cannot have a body");
-			}
-
-			if (proc_type->Proc.calling_convention != ProcCC_Odin) {
-				error_node(d->proc_decl, "An internal procedure may only have the Odin calling convention");
-				proc_type->Proc.calling_convention = ProcCC_Odin;
+		HashKey key = hash_string(name);
+		Entity **found = map_entity_get(fp, key);
+		if (found) {
+			Entity *f = *found;
+			TokenPos pos = f->token.pos;
+			Type *this_type = base_type(e->type);
+			Type *other_type = base_type(f->type);
+			if (!are_signatures_similar_enough(this_type, other_type)) {
+				error_node(d->proc_decl,
+				           "Redeclaration of #foreign procedure `%.*s` with different type signatures\n"
+				           "\tat %.*s(%td:%td)",
+				           LIT(name), LIT(pos.file), pos.line, pos.column);
 			}
-
-			d->scope = c->context.scope;
-
-			GB_ASSERT(pd->body->kind == AstNode_BlockStmt);
-			check_procedure_later(c, c->curr_ast_file, e->token, d, proc_type, pd->body, pd->tags);
+		} else {
+			map_entity_set(fp, key, e);
+		}
+	} else {
+		String name = e->token.string;
+		if (is_link_name) {
+			name = pd->link_name;
 		}
 
-		if (is_foreign) {
+		if (is_link_name || is_export) {
 			MapEntity *fp = &c->info.foreign_procs;
-			String name = e->token.string;
-			if (pd->foreign_name.len > 0) {
-				name = pd->foreign_name;
-			}
 
-			e->Procedure.is_foreign = true;
-			e->Procedure.foreign_name = name;
+			e->Procedure.link_name = name;
 
 			HashKey key = hash_string(name);
 			Entity **found = map_entity_get(fp, key);
 			if (found) {
 				Entity *f = *found;
 				TokenPos pos = f->token.pos;
-				Type *this_type = base_type(e->type);
-				Type *other_type = base_type(f->type);
-				if (!are_signatures_similar_enough(this_type, other_type)) {
-					error_node(d->proc_decl,
-					           "Redeclaration of #foreign procedure `%.*s` with different type signatures\n"
-					           "\tat %.*s(%td:%td)",
-					           LIT(name), LIT(pos.file), pos.line, pos.column);
-				}
+				// TODO(bill): Better error message?
+				error_node(d->proc_decl,
+				           "Non unique linking name for procedure `%.*s`\n"
+				           "\tother at %.*s(%td:%td)",
+				           LIT(name), LIT(pos.file), pos.line, pos.column);
 			} else {
 				map_entity_set(fp, key, e);
 			}
-		} else {
-			String name = e->token.string;
-			if (is_link_name) {
-				name = pd->link_name;
-			}
-
-			if (is_link_name || is_export) {
-				MapEntity *fp = &c->info.foreign_procs;
-
-				e->Procedure.link_name = name;
-
-				HashKey key = hash_string(name);
-				Entity **found = map_entity_get(fp, key);
-				if (found) {
-					Entity *f = *found;
-					TokenPos pos = f->token.pos;
-					// TODO(bill): Better error message?
-					error_node(d->proc_decl,
-					           "Non unique linking name for procedure `%.*s`\n"
-					           "\tother at %.*s(%td:%td)",
-					           LIT(name), LIT(pos.file), pos.line, pos.column);
-				} else {
-					map_entity_set(fp, key, e);
-				}
-			}
 		}
-
-		check_close_scope(c);
 	}
+
+	check_close_scope(c);
 }
 
 void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count, AstNode *type_expr, AstNode *init_expr) {

+ 11 - 38
src/checker/expr.c

@@ -137,43 +137,6 @@ void check_local_collect_entities(Checker *c, AstNodeArray nodes, DelayedEntitie
 				switch (spec->kind) {
 				case_ast_node(bd, BadDecl, spec);
 				case_end;
-				case_ast_node(ts, TypeSpec, spec);
-					if (ts->name->kind != AstNode_Ident) {
-						error_node(ts->name, "A declaration's name must be an identifier, got %.*s", LIT(ast_node_strings[ts->name->kind]));
-						break;
-					}
-
-					Token name_token = ts->name->Ident;
-
-					Entity *e = make_entity_type_name(c->allocator, c->context.scope, name_token, NULL);
-					e->identifier = ts->name;
-
-					DeclInfo *d = make_declaration_info(c->allocator, e->scope);
-					d->type_expr = ts->type;
-
-					add_entity_and_decl_info(c, ts->name, e, d);
-
-					DelayedEntity delay = {ts->name, e, d};
-					array_add(delayed_entities, delay);
-
-
-					if (dof != NULL) {
-						if (str_eq(name_token.string, str_lit("_"))) {
-							dof->other_fields[dof->other_field_index++] = e;
-						} else {
-							HashKey key = hash_string(name_token.string);
-							if (map_entity_get(dof->entity_map, key) != NULL) {
-								// TODO(bill): Scope checking already checks the declaration
-								error(name_token, "`%.*s` is already declared in this record", LIT(name_token.string));
-							} else {
-								map_entity_set(dof->entity_map, key, e);
-								dof->other_fields[dof->other_field_index++] = e;
-							}
-							add_entity(c, c->context.scope, ts->name, e);
-							add_entity_use(c, ts->name, e);
-						}
-					}
-				case_end;
 				}
 			}
 		case_end;
@@ -975,7 +938,7 @@ void check_identifier(Checker *c, Operand *o, AstNode *n, Type *named_type) {
 		}
 		if (e == e_iota) {
 			if (c->context.iota.kind == ExactValue_Invalid) {
-				error(e->token, "Use of `iota` outside a constant declaration is not allowed");
+				error(e->token, "Use of `iota` outside a enumeration is not allowed");
 				return;
 			}
 			o->value = c->context.iota;
@@ -1141,6 +1104,11 @@ Type *check_type_extra(Checker *c, AstNode *e, Type *named_type) {
 		}
 	case_end;
 
+	case_ast_node(ht, HelperType, e);
+		type = check_type(c, ht->type);
+		goto end;
+	case_end;
+
 	case_ast_node(pt, PointerType, e);
 		Type *elem = check_type(c, pt->type);
 		type = make_type_pointer(c->allocator, elem);
@@ -4825,6 +4793,11 @@ gbString write_expr_to_string(gbString str, AstNode *node) {
 		str = gb_string_appendc(str, "{");
 		str = gb_string_appendc(str, "}");
 	case_end;
+
+	case_ast_node(ht, HelperType, node);
+		str = gb_string_appendc(str, "type ");
+		str = write_expr_to_string(str, ht->type);
+	case_end;
 	}
 
 	return str;

+ 0 - 25
src/checker/stmt.c

@@ -1170,36 +1170,11 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
 			switch (spec->kind) {
 			case_ast_node(bd, BadDecl, spec);
 			case_end;
-			case_ast_node(ts, TypeSpec, spec);
-				// NOTE(bill): Handled elsewhere
-			case_end;
-
 			default:
 				error(ast_node_token(spec), "Invalid specification in declaration: `%.*s`", LIT(ast_node_strings[spec->kind]));
 				break;
 			}
 		}
 	case_end;
-
-	case_ast_node(pd, ProcDecl, node);
-		// NOTE(bill): Handled elsewhere
-	#if 1
-		// NOTE(bill): This must be handled here so it has access to the parent scope stuff
-		// e.g. using
-		if (pd->name->kind != AstNode_Ident) {
-			error_node(pd->name, "A declaration's name must be an identifier, got %.*s", LIT(ast_node_strings[pd->name->kind]));
-			break;
-		}
-
-		Entity *e = make_entity_procedure(c->allocator, c->context.scope, pd->name->Ident, NULL, pd->tags);
-		e->identifier = pd->name;
-
-		DeclInfo *d = make_declaration_info(c->allocator, e->scope);
-		d->proc_decl = node;
-
-		add_entity_and_decl_info(c, pd->name, e, d);
-		check_entity_decl(c, e, d, NULL);
-	#endif
-	case_end;
 	}
 }

+ 81 - 56
src/parser.c

@@ -281,15 +281,6 @@ AST_NODE_KIND(_DeclBegin,      "", i32) \
 		AstNodeArray values; \
 		u64          tags;   \
 	}) \
-	AST_NODE_KIND(ProcDecl, "procedure declaration", struct { \
-		AstNode *name;         \
-		AstNode *type;         \
-		AstNode *body;         \
-		u64      tags;         \
-		String   foreign_name; \
-		String   link_name;    \
-		AstNode *note;         \
-	}) \
 	AST_NODE_KIND(ForeignLibrary, "foreign library", struct { \
 		Token token, filepath; \
 		String base_dir;       \
@@ -303,6 +294,10 @@ AST_NODE_KIND(_DeclEnd,   "", i32) \
 		bool         is_using; \
 	}) \
 AST_NODE_KIND(_TypeBegin, "", i32) \
+	AST_NODE_KIND(HelperType, "type", struct { \
+		Token token; \
+		AstNode *type; \
+	}) \
 	AST_NODE_KIND(ProcType, "procedure type", struct { \
 		Token token;          \
 		AstNodeArray params;  \
@@ -501,8 +496,6 @@ Token ast_node_token(AstNode *node) {
 		return node->GenericDecl.token;
 	case AstNode_ValueDecl:
 		return ast_node_token(node->ValueDecl.names.e[0]);
-	case AstNode_ProcDecl:
-		return ast_node_token(node->ProcDecl.name);
 
 	case AstNode_ForeignLibrary:
 		return node->ForeignLibrary.token;
@@ -519,6 +512,10 @@ Token ast_node_token(AstNode *node) {
 			return ast_node_token(node->Field.type);
 		}
 	}
+
+
+	case AstNode_HelperType:
+		return node->HelperType.token;
 	case AstNode_ProcType:
 		return node->ProcType.token;
 	case AstNode_PointerType:
@@ -969,6 +966,15 @@ AstNode *make_field(AstFile *f, AstNodeArray names, AstNode *type, bool is_using
 	return result;
 }
 
+
+AstNode *make_helper_type(AstFile *f, Token token, AstNode *type) {
+	AstNode *result = make_node(f, AstNode_HelperType);
+	result->HelperType.token = token;
+	result->HelperType.type = type;
+	return result;
+}
+
+
 AstNode *make_proc_type(AstFile *f, Token token, AstNodeArray params, AstNodeArray results, u64 tags, ProcCallingConvention calling_convention) {
 	AstNode *result = make_node(f, AstNode_ProcType);
 	result->ProcType.token = token;
@@ -979,17 +985,6 @@ AstNode *make_proc_type(AstFile *f, Token token, AstNodeArray params, AstNodeArr
 	return result;
 }
 
-AstNode *make_proc_decl(AstFile *f, AstNode *name, AstNode *proc_type, AstNode *body, u64 tags, String foreign_name, String link_name) {
-	AstNode *result = make_node(f, AstNode_ProcDecl);
-	result->ProcDecl.name = name;
-	result->ProcDecl.type = proc_type;
-	result->ProcDecl.body = body;
-	result->ProcDecl.tags = tags;
-	result->ProcDecl.foreign_name = foreign_name;
-	result->ProcDecl.link_name = link_name;
-	return result;
-}
-
 AstNode *make_pointer_type(AstFile *f, Token token, AstNode *type) {
 	AstNode *result = make_node(f, AstNode_PointerType);
 	result->PointerType.token = token;
@@ -1264,6 +1259,52 @@ Token expect_closing(AstFile *f, TokenKind kind, String context) {
 	return expect_token(f, kind);
 }
 
+bool is_semicolon_optional_for_node(AstFile *f, AstNode *s) {
+	if (s == NULL) {
+		return false;
+	}
+
+	switch (s->kind) {
+	case AstNode_HelperType:
+		return is_semicolon_optional_for_node(f, s->HelperType.type);
+
+	case AstNode_StructType:
+	case AstNode_UnionType:
+	case AstNode_RawUnionType:
+	case AstNode_EnumType:
+		return true;
+	case AstNode_ProcLit:
+		return true;
+
+	case AstNode_ValueDecl:
+		if (!s->ValueDecl.is_var) {
+			if (s->ValueDecl.values.count > 0) {
+				AstNode *last = s->ValueDecl.values.e[s->ValueDecl.values.count-1];
+				return is_semicolon_optional_for_node(f, last);
+			}
+		}
+		break;
+
+	case AstNode_GenericDecl:
+		if (s->GenericDecl.close.kind == Token_CloseBrace) {
+			return true;
+		} else if (s->GenericDecl.token.kind == Token_type) {
+			if (f->prev_token.kind == Token_CloseBrace) {
+				return true;
+			}
+		}
+		break;
+
+	case AstNode_TypeSpec:
+		if (f->prev_token.kind == Token_CloseBrace) {
+			return true;
+		}
+		break;
+	}
+
+	return false;
+}
+
 void expect_semicolon(AstFile *f, AstNode *s) {
 	if (allow_token(f, Token_Semicolon)) {
 		return;
@@ -1277,24 +1318,8 @@ void expect_semicolon(AstFile *f, AstNode *s) {
 
 	if (s != NULL) {
 		if (prev_token.pos.line != f->curr_token.pos.line) {
-			switch (s->kind) {
-			case AstNode_ProcDecl:
+			if (is_semicolon_optional_for_node(f, s)) {
 				return;
-			case AstNode_GenericDecl:
-				if (s->GenericDecl.close.kind == Token_CloseBrace) {
-					return;
-				} else if (s->GenericDecl.token.kind == Token_type) {
-					if (f->prev_token.kind == Token_CloseBrace) {
-						return;
-					}
-				}
-				break;
-
-			case AstNode_TypeSpec:
-				if (f->prev_token.kind == Token_CloseBrace) {
-					return;
-				}
-				break;
 			}
 		} else {
 			switch (s->kind) {
@@ -1319,7 +1344,6 @@ AstNode *    parse_proc_type(AstFile *f, String *foreign_name_, String *link_nam
 AstNodeArray parse_stmt_list(AstFile *f);
 AstNode *    parse_stmt(AstFile *f);
 AstNode *    parse_body(AstFile *f);
-AstNode *    parse_proc_decl(AstFile *f);
 void         parse_proc_signature(AstFile *f, AstNodeArray *params, AstNodeArray *results);
 
 
@@ -1571,6 +1595,7 @@ void parse_proc_tags(AstFile *f, u64 *tags, String *foreign_name, String *link_n
 AstNodeArray parse_lhs_expr_list(AstFile *f);
 AstNodeArray parse_rhs_expr_list(AstFile *f);
 AstNode *    parse_simple_stmt  (AstFile *f);
+AstNode *    parse_type         (AstFile *f);
 
 AstNode *convert_stmt_to_expr(AstFile *f, AstNode *statement, String kind) {
 	if (statement == NULL) {
@@ -1745,10 +1770,9 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
 		String foreign_name = {0};
 		String link_name = {0};
 		AstNode *type = parse_proc_type(f, &foreign_name, &link_name);
+		u64 tags = type->ProcType.tags;
 
 		if (f->curr_token.kind == Token_OpenBrace) {
-			u64 tags = type->ProcType.tags;
-
 			if ((tags & ProcTag_foreign) != 0) {
 				syntax_error(token, "A procedure tagged as `#foreign` cannot have a body");
 			}
@@ -1760,6 +1784,13 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
 			return make_proc_lit(f, type, body, tags, foreign_name, link_name);
 		}
 
+		if ((tags & ProcTag_foreign) != 0) {
+			return make_proc_lit(f, type, NULL, tags, foreign_name, link_name);
+		}
+		if ((tags & ProcTag_link_name) != 0) {
+			syntax_error(token, "A procedure typed cannot be tagged with `#link_name`");
+		}
+
 		return type;
 	}
 
@@ -1932,7 +1963,6 @@ AstNode *parse_atom_expr(AstFile *f, bool lhs) {
 	return operand;
 }
 
-AstNode *parse_type(AstFile *f);
 
 AstNode *parse_unary_expr(AstFile *f, bool lhs) {
 	switch (f->curr_token.kind) {
@@ -2240,17 +2270,6 @@ PARSE_SPEC_PROC(parse_include_spec) {
 
 AstNode *parse_decl(AstFile *f) {
 	switch (f->curr_token.kind) {
-	// case Token_var:
-	// case Token_const:
-		// return parse_generic_decl(f, f->curr_token.kind, parse_value_spec);
-
-	case Token_type:
-		return parse_generic_decl(f, f->curr_token.kind, parse_type_spec);
-
-	case Token_proc:
-		// TODO(bill): Should I allow procedures to use the generic declaration syntax?
-		return parse_proc_decl(f);
-
 	case Token_import:
 		return parse_generic_decl(f, f->curr_token.kind, parse_import_spec);
 	case Token_include:
@@ -2504,6 +2523,12 @@ AstNode *parse_identifier_or_type(AstFile *f) {
 		return e;
 	}
 
+	case Token_type: {
+		Token token = expect_token(f, Token_type);
+		AstNode *type = parse_type(f);
+		return make_helper_type(f, token, type);
+	}
+
 	case Token_Pointer: {
 		Token token = expect_token(f, Token_Pointer);
 		AstNode *elem = parse_type(f);
@@ -2681,7 +2706,7 @@ AstNode *parse_body(AstFile *f) {
 }
 
 
-
+/*
 AstNode *parse_proc_decl(AstFile *f) {
 	if (look_ahead_token_kind(f, 1) == Token_OpenParen) {
 		// NOTE(bill): It's an anonymous procedure
@@ -2720,7 +2745,7 @@ AstNode *parse_proc_decl(AstFile *f) {
 	}
 
 	return make_proc_decl(f, name, proc_type, body, tags, foreign_name, link_name);
-}
+} */
 
 AstNode *parse_if_stmt(AstFile *f) {
 	if (f->curr_proc == NULL) {

+ 95 - 126
src/ssa.c

@@ -3978,104 +3978,96 @@ void ssa_build_stmt_internal(ssaProcedure *proc, AstNode *node) {
 			}
 
 			gb_temp_arena_memory_end(tmp);
-		}
-	case_end;
-
-	case_ast_node(gd, GenericDecl, node);
-		for_array(spec_index, gd->specs) {
-			AstNode *spec = gd->specs.e[spec_index];
-			switch (spec->kind) {
-			case_ast_node(ts, TypeSpec, spec);
-				// NOTE(bill): Generate a new name
-				// parent_proc.name-guid
-				String ts_name = ts->name->Ident.string;
-				isize name_len = proc->name.len + 1 + ts_name.len + 1 + 10 + 1;
-				u8 *name_text = gb_alloc_array(proc->module->allocator, u8, name_len);
-				i32 guid = cast(i32)proc->module->members.entries.count;
-				name_len = gb_snprintf(cast(char *)name_text, name_len, "%.*s.%.*s-%d", LIT(proc->name), LIT(ts_name), guid);
-				String name = make_string(name_text, name_len-1);
-
-				Entity **found = map_entity_get(&proc->module->info->definitions, hash_pointer(ts->name));
-				GB_ASSERT(found != NULL);
-				Entity *e = *found;
-				ssaValue *value = ssa_make_value_type_name(proc->module->allocator,
-				                                           name, e->type);
-				map_string_set(&proc->module->type_names, hash_pointer(e->type), name);
-				ssa_gen_global_type_name(proc->module, e, name);
-			case_end;
-			}
-		}
-	case_end;
-
-	case_ast_node(pd, ProcDecl, node);
-		if (pd->body != NULL) {
-			CheckerInfo *info = proc->module->info;
-
-			Entity **found = map_entity_get(&info->definitions, hash_pointer(pd->name));
-			GB_ASSERT_MSG(found != NULL, "Unable to find: %.*s", LIT(pd->name->Ident.string));
-			Entity *e = *found;
-
-
-			if (map_entity_get(&proc->module->min_dep_map, hash_pointer(e)) == NULL) {
-				// NOTE(bill): Nothing depends upon it so doesn't need to be built
-				break;
-			}
-
-			// NOTE(bill): Generate a new name
-			// parent.name-guid
-			String original_name = pd->name->Ident.string;
-			String pd_name = original_name;
-			if (pd->link_name.len > 0) {
-				pd_name = pd->link_name;
-			}
+		} else {
+			for_array(i, vd->names) {
+				AstNode *ident = vd->names.e[i];
+				GB_ASSERT(ident->kind == AstNode_Ident);
+				Entity *e = entity_of_ident(proc->module->info, ident);
+				GB_ASSERT(e != NULL);
+				switch (e->kind) {
+				case Entity_TypeName: {
+					// NOTE(bill): Generate a new name
+					// parent_proc.name-guid
+					String ts_name = e->token.string;
+					isize name_len = proc->name.len + 1 + ts_name.len + 1 + 10 + 1;
+					u8 *name_text = gb_alloc_array(proc->module->allocator, u8, name_len);
+					i32 guid = cast(i32)proc->module->members.entries.count;
+					name_len = gb_snprintf(cast(char *)name_text, name_len, "%.*s.%.*s-%d", LIT(proc->name), LIT(ts_name), guid);
+					String name = make_string(name_text, name_len-1);
+
+					ssaValue *value = ssa_make_value_type_name(proc->module->allocator,
+					                                           name, e->type);
+					map_string_set(&proc->module->type_names, hash_pointer(e->type), name);
+					ssa_gen_global_type_name(proc->module, e, name);
+				} break;
+				case Entity_Procedure: {
+					DeclInfo **decl_info = map_decl_info_get(&proc->module->info->entities, hash_pointer(e));
+					GB_ASSERT(decl_info != NULL);
+					DeclInfo *dl = *decl_info;
+					ast_node(pd, ProcLit, dl->proc_decl);
+					if (pd->body != NULL) {
+						CheckerInfo *info = proc->module->info;
+
+						if (map_entity_get(&proc->module->min_dep_map, hash_pointer(e)) == NULL) {
+							// NOTE(bill): Nothing depends upon it so doesn't need to be built
+							break;
+						}
 
-			isize name_len = proc->name.len + 1 + pd_name.len + 1 + 10 + 1;
-			u8 *name_text = gb_alloc_array(proc->module->allocator, u8, name_len);
-			i32 guid = cast(i32)proc->children.count;
-			name_len = gb_snprintf(cast(char *)name_text, name_len, "%.*s.%.*s-%d", LIT(proc->name), LIT(pd_name), guid);
-			String name = make_string(name_text, name_len-1);
+						// NOTE(bill): Generate a new name
+						// parent.name-guid
+						String original_name = e->token.string;
+						String pd_name = original_name;
+						if (pd->link_name.len > 0) {
+							pd_name = pd->link_name;
+						}
 
+						isize name_len = proc->name.len + 1 + pd_name.len + 1 + 10 + 1;
+						u8 *name_text = gb_alloc_array(proc->module->allocator, u8, name_len);
+						i32 guid = cast(i32)proc->children.count;
+						name_len = gb_snprintf(cast(char *)name_text, name_len, "%.*s.%.*s-%d", LIT(proc->name), LIT(pd_name), guid);
+						String name = make_string(name_text, name_len-1);
 
-			ssaValue *value = ssa_make_value_procedure(proc->module->allocator,
-			                                           proc->module, e, e->type, pd->type, pd->body, name);
 
-			value->Proc.tags = pd->tags;
-			value->Proc.parent = proc;
+						ssaValue *value = ssa_make_value_procedure(proc->module->allocator,
+						                                           proc->module, e, e->type, pd->type, pd->body, name);
 
-			ssa_module_add_value(proc->module, e, value);
-			array_add(&proc->children, &value->Proc);
-			array_add(&proc->module->procs_to_generate, value);
-		} else {
-			CheckerInfo *info = proc->module->info;
+						value->Proc.tags = pd->tags;
+						value->Proc.parent = proc;
 
-			Entity **found = map_entity_get(&info->definitions, hash_pointer(pd->name));
-			GB_ASSERT_MSG(found != NULL, "Unable to find: %.*s", LIT(pd->name->Ident.string));
-			Entity *e = *found;
+						ssa_module_add_value(proc->module, e, value);
+						array_add(&proc->children, &value->Proc);
+						array_add(&proc->module->procs_to_generate, value);
+					} else {
+						CheckerInfo *info = proc->module->info;
 
-			// FFI - Foreign function interace
-			String original_name = pd->name->Ident.string;
-			String name = original_name;
-			if (pd->foreign_name.len > 0) {
-				name = pd->foreign_name;
-			}
+						// FFI - Foreign function interace
+						String original_name = e->token.string;
+						String name = original_name;
+						if (pd->foreign_name.len > 0) {
+							name = pd->foreign_name;
+						}
 
-			ssaValue *value = ssa_make_value_procedure(proc->module->allocator,
-			                                           proc->module, e, e->type, pd->type, pd->body, name);
+						ssaValue *value = ssa_make_value_procedure(proc->module->allocator,
+						                                           proc->module, e, e->type, pd->type, pd->body, name);
 
-			value->Proc.tags = pd->tags;
+						value->Proc.tags = pd->tags;
 
-			ssa_module_add_value(proc->module, e, value);
-			ssa_build_proc(value, proc);
+						ssa_module_add_value(proc->module, e, value);
+						ssa_build_proc(value, proc);
 
-			if (value->Proc.tags & ProcTag_foreign) {
-				HashKey key = hash_string(name);
-				ssaValue **prev_value = map_ssa_value_get(&proc->module->members, key);
-				if (prev_value == NULL) {
-					// NOTE(bill): Don't do mutliple declarations in the IR
-					map_ssa_value_set(&proc->module->members, key, value);
+						if (value->Proc.tags & ProcTag_foreign) {
+							HashKey key = hash_string(name);
+							ssaValue **prev_value = map_ssa_value_get(&proc->module->members, key);
+							if (prev_value == NULL) {
+								// NOTE(bill): Don't do mutliple declarations in the IR
+								map_ssa_value_set(&proc->module->members, key, value);
+							}
+						} else {
+							array_add(&proc->children, &value->Proc);
+						}
+					}
+				} break;
 				}
-			} else {
-				array_add(&proc->children, &value->Proc);
 			}
 		}
 	case_end;
@@ -5034,48 +5026,25 @@ void ssa_gen_tree(ssaGen *s) {
 		} break;
 
 		case Entity_Procedure: {
-			if (decl->proc_decl->kind == AstNode_ProcDecl) {
-				AstNodeProcDecl *pd = &decl->proc_decl->ProcDecl;
-				String original_name = name;
-				AstNode *body = pd->body;
-				if (e->Procedure.is_foreign) {
-					name = e->token.string; // NOTE(bill): Don't use the mangled name
-				}
-				if (pd->foreign_name.len > 0) {
-					name = pd->foreign_name;
-				} else if (pd->link_name.len > 0) {
-					name = pd->link_name;
-				}
-
-				ssaValue *p = ssa_make_value_procedure(a, m, e, e->type, decl->type_expr, body, name);
-				p->Proc.tags = pd->tags;
-
-				ssa_module_add_value(m, e, p);
-				HashKey hash_name = hash_string(name);
-				if (map_ssa_value_get(&m->members, hash_name) == NULL) {
-					map_ssa_value_set(&m->members, hash_name, p);
-				}
-			} else if (decl->proc_decl->kind == AstNode_ProcLit) {
-				AstNodeProcLit *pd = &decl->proc_decl->ProcLit;
-				String original_name = name;
-				AstNode *body = pd->body;
-				if (e->Procedure.is_foreign) {
-					name = e->token.string; // NOTE(bill): Don't use the mangled name
-				}
-				if (pd->foreign_name.len > 0) {
-					name = pd->foreign_name;
-				} else if (pd->link_name.len > 0) {
-					name = pd->link_name;
-				}
+			ast_node(pd, ProcLit, decl->proc_decl);
+			String original_name = name;
+			AstNode *body = pd->body;
+			if (e->Procedure.is_foreign) {
+				name = e->token.string; // NOTE(bill): Don't use the mangled name
+			}
+			if (pd->foreign_name.len > 0) {
+				name = pd->foreign_name;
+			} else if (pd->link_name.len > 0) {
+				name = pd->link_name;
+			}
 
-				ssaValue *p = ssa_make_value_procedure(a, m, e, e->type, decl->type_expr, body, name);
-				p->Proc.tags = pd->tags;
+			ssaValue *p = ssa_make_value_procedure(a, m, e, e->type, decl->type_expr, body, name);
+			p->Proc.tags = pd->tags;
 
-				ssa_module_add_value(m, e, p);
-				HashKey hash_name = hash_string(name);
-				if (map_ssa_value_get(&m->members, hash_name) == NULL) {
-					map_ssa_value_set(&m->members, hash_name, p);
-				}
+			ssa_module_add_value(m, e, p);
+			HashKey hash_name = hash_string(name);
+			if (map_ssa_value_get(&m->members, hash_name) == NULL) {
+				map_ssa_value_set(&m->members, hash_name, p);
 			}
 		} break;
 		}