Преглед изворни кода

Remove len(), cap() and replace with selectors; fix defer in match

Ginger Bill пре 9 година
родитељ
комит
817ae643c5
11 измењених фајлова са 452 додато и 331 уклоњено
  1. 6 2
      code/demo.odin
  2. 2 2
      code/file.odin
  3. 174 52
      code/print.odin
  4. 94 75
      code/runtime.odin
  5. 0 6
      src/checker/checker.cpp
  6. 0 67
      src/checker/expr.cpp
  7. 81 3
      src/checker/type.cpp
  8. 13 3
      src/codegen/codegen.cpp
  9. 1 1
      src/codegen/print_llvm.cpp
  10. 51 105
      src/codegen/ssa.cpp
  11. 30 15
      src/parser.cpp

+ 6 - 2
code/demo.odin

@@ -1,6 +1,10 @@
 #load "basic.odin"
 #load "basic.odin"
 
 
 main :: proc() {
 main :: proc() {
-	println("% % % %", "Hellope", true, 6.28, [4]int{1, 2, 3, 4})
-	println("%0 %1 %0", "Hellope", 34)
+	println("% % % %", "Hellope", true, 6.28, {4}int{1, 2, 3, 4})
+	x: struct #ordered {
+		x, y: int
+		z: f32
+	}
+	println("%", x)
 }
 }

+ 2 - 2
code/file.odin

@@ -31,7 +31,7 @@ file_close :: proc(f: ^File) {
 
 
 file_write :: proc(f: ^File, buf: []byte) -> bool {
 file_write :: proc(f: ^File, buf: []byte) -> bool {
 	bytes_written: i32
 	bytes_written: i32
-	return WriteFile(f.handle, ^buf[0], len(buf) as i32, ^bytes_written, null) != 0
+	return WriteFile(f.handle, ^buf[0], buf.count as i32, ^bytes_written, null) != 0
 }
 }
 
 
 File_Standard :: type enum {
 File_Standard :: type enum {
@@ -95,7 +95,7 @@ read_entire_file :: proc(name: string) -> (string, bool) {
 
 
 		ReadFile(f.handle as HANDLE, ^data[total_read], to_read, ^single_read_length, null)
 		ReadFile(f.handle as HANDLE, ^data[total_read], to_read, ^single_read_length, null)
 		if single_read_length <= 0 {
 		if single_read_length <= 0 {
-			delete(data)
+			free(^data[0])
 			return "", false
 			return "", false
 		}
 		}
 
 

+ 174 - 52
code/print.odin

@@ -3,22 +3,12 @@
 #load "file.odin"
 #load "file.odin"
 
 
 print_byte_buffer :: proc(buf: ^[]byte, b: []byte) {
 print_byte_buffer :: proc(buf: ^[]byte, b: []byte) {
-	// NOTE(bill): This is quite a hack
-	// TODO(bill): Should I allow the raw editing of a slice by exposing its
-	// internal members?
-	Raw_Bytes :: struct #ordered {
-		data: ^byte
-		len:  int
-		cap:  int
-	}
-
-	slice := buf as ^Raw_Bytes
-	if slice.len < slice.cap {
-		n := min(slice.cap-slice.len, len(b))
+	if buf.count < buf.capacity {
+		n := min(buf.capacity-buf.count, b.count)
 		if n > 0 {
 		if n > 0 {
-			offset := ptr_offset(slice.data, slice.len)
+			offset := ptr_offset(buf.data, buf.count)
 			memory_copy(offset, ^b[0], n)
 			memory_copy(offset, ^b[0], n)
-			slice.len += n
+			buf.count += n
 		}
 		}
 	}
 	}
 }
 }
@@ -29,7 +19,7 @@ print_string_to_buffer :: proc(buf: ^[]byte, s: string) {
 
 
 
 
 byte_reverse :: proc(b: []byte) {
 byte_reverse :: proc(b: []byte) {
-	n := len(b)
+	n := b.count
 	for i := 0; i < n/2; i++ {
 	for i := 0; i < n/2; i++ {
 		b[i], b[n-1-i] = b[n-1-i], b[i]
 		b[i], b[n-1-i] = b[n-1-i], b[i]
 	}
 	}
@@ -184,6 +174,128 @@ print__f64 :: proc(buffer: ^[]byte, f: f64, decimal_places: int) {
 	}
 	}
 }
 }
 
 
+print_type_to_buffer :: proc(buf: ^[]byte, ti: ^Type_Info) {
+	if ti == null { return }
+
+	using Type_Info
+	match type info : ti {
+	case Named:
+		print_string_to_buffer(buf, info.name)
+	case Integer:
+		match {
+		case ti == type_info(int):
+			print_string_to_buffer(buf, "int")
+		case ti == type_info(uint):
+			print_string_to_buffer(buf, "uint")
+		default:
+			if info.signed {
+				print_string_to_buffer(buf, "i")
+			} else {
+				print_string_to_buffer(buf, "u")
+			}
+			print_int_to_buffer(buf, 8*info.size)
+		}
+
+	case Float:
+		match info.size {
+		case 4: print_string_to_buffer(buf, "f32")
+		case 8: print_string_to_buffer(buf, "f64")
+		}
+	case String:  print_string_to_buffer(buf, "string")
+	case Boolean: print_string_to_buffer(buf, "bool")
+	case Pointer:
+		print_string_to_buffer(buf, "^")
+		print_type_to_buffer(buf, info.elem)
+	case Procedure:
+		print_string_to_buffer(buf, "proc")
+		if info.params == null {
+			print_string_to_buffer(buf, "()")
+		} else {
+			count := (info.params as ^Tuple).fields.count
+			if count == 1 { print_string_to_buffer(buf, "(") }
+			print_type_to_buffer(buf, info.params)
+			if count == 1 { print_string_to_buffer(buf, ")") }
+		}
+		if info.results != null {
+			print_string_to_buffer(buf, " -> ")
+			print_type_to_buffer(buf, info.results)
+		}
+	case Tuple:
+		count := info.fields.count
+		if count != 1 { print_string_to_buffer(buf, "(") }
+		for i := 0; i < count; i++ {
+			if i > 0 { print_string_to_buffer(buf, ", ") }
+
+			f := info.fields[i]
+
+			if f.name.count > 0 {
+				print_string_to_buffer(buf, f.name)
+				print_string_to_buffer(buf, ": ")
+			}
+			print_type_to_buffer(buf, f.type_info)
+		}
+		if count != 1 { print_string_to_buffer(buf, ")") }
+
+	case Array:
+		print_string_to_buffer(buf, "[")
+		print_int_to_buffer(buf, info.count)
+		print_string_to_buffer(buf, "]")
+		print_type_to_buffer(buf, info.elem)
+	case Slice:
+		print_string_to_buffer(buf, "[")
+		print_string_to_buffer(buf, "]")
+		print_type_to_buffer(buf, info.elem)
+	case Vector:
+		print_string_to_buffer(buf, "{")
+		print_int_to_buffer(buf, info.count)
+		print_string_to_buffer(buf, "}")
+		print_type_to_buffer(buf, info.elem)
+
+	case Struct:
+		print_string_to_buffer(buf, "struct ")
+		if info.packed  { print_string_to_buffer(buf, "#packed ") }
+		if info.ordered { print_string_to_buffer(buf, "#ordered ") }
+		print_string_to_buffer(buf, "{")
+		for i := 0; i < info.fields.count; i++ {
+			if i > 0 {
+				print_string_to_buffer(buf, ", ")
+			}
+			print_any_to_buffer(buf, info.fields[i].name)
+			print_string_to_buffer(buf, ": ")
+			print_type_to_buffer(buf, info.fields[i].type_info)
+		}
+		print_string_to_buffer(buf, "}")
+
+	case Union:
+		print_string_to_buffer(buf, "union {")
+		for i := 0; i < info.fields.count; i++ {
+			if i > 0 {
+				print_string_to_buffer(buf, ", ")
+			}
+			print_any_to_buffer(buf, info.fields[i].name)
+			print_string_to_buffer(buf, ": ")
+			print_type_to_buffer(buf, info.fields[i].type_info)
+		}
+		print_string_to_buffer(buf, "}")
+
+	case Raw_Union:
+		print_string_to_buffer(buf, "raw_union {")
+		for i := 0; i < info.fields.count; i++ {
+			if i > 0 {
+				print_string_to_buffer(buf, ", ")
+			}
+			print_any_to_buffer(buf, info.fields[i].name)
+			print_string_to_buffer(buf, ": ")
+			print_type_to_buffer(buf, info.fields[i].type_info)
+		}
+		print_string_to_buffer(buf, "}")
+
+	case Enum:
+		print_string_to_buffer(buf, "enum ")
+		print_type_to_buffer(buf, info.base)
+		print_string_to_buffer(buf, "{}")
+	}
+}
 
 
 
 
 print_any_to_buffer :: proc(buf: ^[]byte, arg: any)  {
 print_any_to_buffer :: proc(buf: ^[]byte, arg: any)  {
@@ -197,7 +309,7 @@ print_any_to_buffer :: proc(buf: ^[]byte, arg: any)  {
 		case Struct:
 		case Struct:
 			print_string_to_buffer(buf, info.name)
 			print_string_to_buffer(buf, info.name)
 			print_string_to_buffer(buf, "{")
 			print_string_to_buffer(buf, "{")
-			for i := 0; i < len(b.fields); i++ {
+			for i := 0; i < b.fields.count; i++ {
 				f := b.fields[i];
 				f := b.fields[i];
 				if i > 0 {
 				if i > 0 {
 					print_string_to_buffer(buf, ", ")
 					print_string_to_buffer(buf, ", ")
@@ -282,7 +394,9 @@ print_any_to_buffer :: proc(buf: ^[]byte, arg: any)  {
 
 
 	case Array:
 	case Array:
 		print_string_to_buffer(buf, "[")
 		print_string_to_buffer(buf, "[")
-		for i := 0; i < info.len; i++ {
+		defer print_string_to_buffer(buf, "]")
+
+		for i := 0; i < info.count; i++ {
 			if i > 0 {
 			if i > 0 {
 				print_string_to_buffer(buf, ", ")
 				print_string_to_buffer(buf, ", ")
 			}
 			}
@@ -292,55 +406,66 @@ print_any_to_buffer :: proc(buf: ^[]byte, arg: any)  {
 			elem.type_info = info.elem
 			elem.type_info = info.elem
 			print_any_to_buffer(buf, elem)
 			print_any_to_buffer(buf, elem)
 		}
 		}
-		print_string_to_buffer(buf, "]")
 
 
 	case Slice:
 	case Slice:
-		slice := arg.data as ^struct { data: rawptr; len, cap: int }
+		slice := arg.data as ^[]byte
 		print_string_to_buffer(buf, "[")
 		print_string_to_buffer(buf, "[")
-		for i := 0; i < slice.len; i++ {
+		defer print_string_to_buffer(buf, "]")
+
+		for i := 0; i < slice.count; i++ {
 			if i > 0 {
 			if i > 0 {
 				print_string_to_buffer(buf, ", ")
 				print_string_to_buffer(buf, ", ")
 			}
 			}
 
 
 			elem: any
 			elem: any
-			elem.data = (slice.data as int + i*info.elem_size) as rawptr
+			elem.data = ptr_offset(slice.data, i*info.elem_size)
 			elem.type_info = info.elem
 			elem.type_info = info.elem
 			print_any_to_buffer(buf, elem)
 			print_any_to_buffer(buf, elem)
 		}
 		}
-		print_string_to_buffer(buf, "]")
 
 
 	case Vector:
 	case Vector:
 		print_string_to_buffer(buf, "<")
 		print_string_to_buffer(buf, "<")
-		for i := 0; i < info.len; i++ {
+		defer print_string_to_buffer(buf, ">")
+
+		for i := 0; i < info.count; i++ {
 			if i > 0 {
 			if i > 0 {
 				print_string_to_buffer(buf, ", ")
 				print_string_to_buffer(buf, ", ")
 			}
 			}
 
 
 			elem: any
 			elem: any
-			elem.data = (arg.data as int + i*info.elem_size) as rawptr
+			elem.data = ptr_offset(arg.data as ^byte, i*info.elem_size)
 			elem.type_info = info.elem
 			elem.type_info = info.elem
 			print_any_to_buffer(buf, elem)
 			print_any_to_buffer(buf, elem)
 		}
 		}
-		print_string_to_buffer(buf, ">")
 
 
 
 
 	case Struct:
 	case Struct:
-		print_string_to_buffer(buf, "(struct ")
-		for i := 0; i < len(info.fields); i++ {
+		print_string_to_buffer(buf, "struct")
+		print_string_to_buffer(buf, "{")
+		defer print_string_to_buffer(buf, "}")
+
+		for i := 0; i < info.fields.count; i++ {
 			if i > 0 {
 			if i > 0 {
 				print_string_to_buffer(buf, ", ")
 				print_string_to_buffer(buf, ", ")
 			}
 			}
 			print_any_to_buffer(buf, info.fields[i].name)
 			print_any_to_buffer(buf, info.fields[i].name)
+			print_string_to_buffer(buf, " = ")
+			a: any
+			a.data = ptr_offset(arg.data as ^byte, info.fields[i].offset)
+			a.type_info = info.fields[i].type_info
+			print_any_to_buffer(buf, a)
 		}
 		}
-		print_string_to_buffer(buf, ")")
-	case Union:     print_string_to_buffer(buf, "(union)")
-	case Raw_Union: print_string_to_buffer(buf, "(raw_union)")
+
+	case Union:
+		print_string_to_buffer(buf, "(union)")
+	case Raw_Union:
+		print_string_to_buffer(buf, "(raw_union)")
 	case Procedure:
 	case Procedure:
-		print_string_to_buffer(buf, "(procedure 0x")
+		print_type_to_buffer(buf, arg.type_info)
+		print_string_to_buffer(buf, " @ 0x")
 		print_pointer_to_buffer(buf, (arg.data as ^rawptr)^)
 		print_pointer_to_buffer(buf, (arg.data as ^rawptr)^)
-		print_string_to_buffer(buf, ")")
+
 	default:
 	default:
-		print_string_to_buffer(buf, "")
 	}
 	}
 }
 }
 
 
@@ -373,7 +498,7 @@ print_to_buffer :: proc(buf: ^[]byte, fmt: string, args: ..any) {
 	parse_int :: proc(s: string, offset: int) -> (int, int) {
 	parse_int :: proc(s: string, offset: int) -> (int, int) {
 		result := 0
 		result := 0
 
 
-		for ; offset < len(s); offset++ {
+		for ; offset < s.count; offset++ {
 			c := s[offset] as rune
 			c := s[offset] as rune
 			if !is_digit(c) {
 			if !is_digit(c) {
 				break
 				break
@@ -389,8 +514,9 @@ print_to_buffer :: proc(buf: ^[]byte, fmt: string, args: ..any) {
 	prev := 0
 	prev := 0
 	implicit_index := 0
 	implicit_index := 0
 
 
-	for i := 0; i < len(fmt); i++ {
+	for i := 0; i < fmt.count; i++ {
 		r := fmt[i] as rune
 		r := fmt[i] as rune
+		index := implicit_index
 
 
 		if r != #rune "%" {
 		if r != #rune "%" {
 			continue
 			continue
@@ -398,26 +524,22 @@ print_to_buffer :: proc(buf: ^[]byte, fmt: string, args: ..any) {
 
 
 		print_string_to_buffer(buf, fmt[prev:i])
 		print_string_to_buffer(buf, fmt[prev:i])
 		i++ // Skip %
 		i++ // Skip %
-		if i >= len(fmt) {
-			return
-		}
-
-		next := fmt[i] as rune
-		if next == #rune "%" {
-			print_string_to_buffer(buf, "%")
-			i++
-			prev = i
-			continue
-		}
-
-		index := implicit_index
-		set_prev := true
+		if i < fmt.count {
+			next := fmt[i] as rune
+
+			if next == #rune "%" {
+				print_string_to_buffer(buf, "%")
+				i++
+				prev = i
+				continue
+			}
 
 
-		if is_digit(next) {
-			index, i = parse_int(fmt, i)
+			if is_digit(next) {
+				index, i = parse_int(fmt, i)
+			}
 		}
 		}
 
 
-		if 0 <= index && index < len(args) {
+		if 0 <= index && index < args.count {
 			print_any_to_buffer(buf, args[index])
 			print_any_to_buffer(buf, args[index])
 			implicit_index = index+1
 			implicit_index = index+1
 		} else {
 		} else {

+ 94 - 75
code/runtime.odin

@@ -11,6 +11,8 @@ Type_Info :: union {
 	}
 	}
 	Record :: struct #ordered {
 	Record :: struct #ordered {
 		fields: []Member
 		fields: []Member
+		packed: bool
+		ordered: bool
 	}
 	}
 
 
 
 
@@ -38,7 +40,7 @@ Type_Info :: union {
 	Array: struct #ordered {
 	Array: struct #ordered {
 		elem: ^Type_Info
 		elem: ^Type_Info
 		elem_size: int
 		elem_size: int
-		len: int
+		count: int
 	}
 	}
 	Slice: struct #ordered {
 	Slice: struct #ordered {
 		elem: ^Type_Info
 		elem: ^Type_Info
@@ -47,7 +49,7 @@ Type_Info :: union {
 	Vector: struct #ordered {
 	Vector: struct #ordered {
 		elem: ^Type_Info
 		elem: ^Type_Info
 		elem_size: int
 		elem_size: int
-		len: int
+		count: int
 	}
 	}
 	Tuple:     Record
 	Tuple:     Record
 	Struct:    Record
 	Struct:    Record
@@ -81,7 +83,7 @@ heap_alloc   :: proc(len: int) -> rawptr {
 	return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len)
 	return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len)
 }
 }
 
 
-heap_dealloc :: proc(ptr: rawptr) {
+heap_free :: proc(ptr: rawptr) {
 	_ = HeapFree(GetProcessHeap(), 0, ptr)
 	_ = HeapFree(GetProcessHeap(), 0, ptr)
 }
 }
 
 
@@ -108,18 +110,18 @@ memory_copy :: proc(dst, src: rawptr, len: int) #inline {
 }
 }
 
 
 __string_eq :: proc(a, b: string) -> bool {
 __string_eq :: proc(a, b: string) -> bool {
-	if len(a) != len(b) {
+	if a.count != b.count {
 		return false
 		return false
 	}
 	}
 	if ^a[0] == ^b[0] {
 	if ^a[0] == ^b[0] {
 		return true
 		return true
 	}
 	}
-	return memory_compare(^a[0], ^b[0], len(a)) == 0
+	return memory_compare(^a[0], ^b[0], a.count) == 0
 }
 }
 
 
 __string_cmp :: proc(a, b : string) -> int {
 __string_cmp :: proc(a, b : string) -> int {
 	// Translation of http://mgronhol.github.io/fast-strcmp/
 	// Translation of http://mgronhol.github.io/fast-strcmp/
-	n := min(len(a), len(b))
+	n := min(a.count, b.count)
 
 
 	fast := n/size_of(int) + 1
 	fast := n/size_of(int) + 1
 	offset := (fast-1)*size_of(int)
 	offset := (fast-1)*size_of(int)
@@ -159,20 +161,64 @@ __string_ge :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) >
 
 
 
 
 
 
+__assert :: proc(msg: string) {
+	file_write(file_get_standard(File_Standard.ERROR), msg as []byte)
+	__debug_trap()
+}
 
 
-Allocation_Mode :: enum {
-	ALLOC,
-	DEALLOC,
-	DEALLOC_ALL,
-	RESIZE,
+__bounds_check_error :: proc(file: string, line, column: int,
+                             index, count: int) {
+	if 0 <= index && index < count {
+		return
+	}
+	// TODO(bill): Probably reduce the need for `print` in the runtime if possible
+	println_err("%(%:%) Index % is out of bounds range [0, %)",
+	            file, line, column, index, count)
+	__debug_trap()
+}
+
+__slice_expr_error :: proc(file: string, line, column: int,
+                           low, high, max: int) {
+	if 0 <= low && low <= high && high <= max {
+		return
+	}
+	println_err("%(%:%) Invalid slice indices: [%:%:%]",
+	          file, line, column, low, high, max)
+	__debug_trap()
 }
 }
+__substring_expr_error :: proc(file: string, line, column: int,
+                               low, high: int) {
+	if 0 <= low && low <= high {
+		return
+	}
+	println_err("%(%:%) Invalid substring indices: [%:%:%]",
+	          file, line, column, low, high)
+	__debug_trap()
+}
+
+
+
+
+
+
+
+
+
 
 
-Allocator_Proc :: type proc(allocator_data: rawptr, mode: Allocation_Mode,
-                            size, alignment: int,
-                            old_memory: rawptr, old_size: int, flags: u64) -> rawptr
 
 
 Allocator :: struct {
 Allocator :: struct {
-	procedure: Allocator_Proc;
+	Mode :: enum {
+		ALLOC,
+		FREE,
+		FREE_ALL,
+		RESIZE,
+	}
+	Proc :: type proc(allocator_data: rawptr, mode: Mode,
+	                  size, alignment: int,
+	                  old_memory: rawptr, old_size: int, flags: u64) -> rawptr
+
+
+	procedure: Proc;
 	data:      rawptr
 	data:      rawptr
 }
 }
 
 
@@ -180,24 +226,26 @@ Allocator :: struct {
 Context :: struct {
 Context :: struct {
 	thread_ptr: rawptr
 	thread_ptr: rawptr
 
 
+	allocator: Allocator
+
 	user_data:  rawptr
 	user_data:  rawptr
 	user_index: int
 	user_index: int
-
-	allocator: Allocator
 }
 }
 
 
-#thread_local context: Context
+#thread_local __context: Context
+
 
 
 DEFAULT_ALIGNMENT :: 2*size_of(int)
 DEFAULT_ALIGNMENT :: 2*size_of(int)
 
 
 
 
-__check_context :: proc() {
-	if context.allocator.procedure == null {
-		context.allocator = __default_allocator()
+__check_context :: proc(c: ^Context) {
+	assert(c != null)
+	if c.allocator.procedure == null {
+		c.allocator = __default_allocator()
 	}
 	}
-	if context.thread_ptr == null {
+	if c.thread_ptr == null {
 		// TODO(bill):
 		// TODO(bill):
-		// context.thread_ptr = current_thread_pointer()
+		// c.thread_ptr = current_thread_pointer()
 	}
 	}
 }
 }
 
 
@@ -205,28 +253,28 @@ __check_context :: proc() {
 alloc :: proc(size: int) -> rawptr #inline { return alloc_align(size, DEFAULT_ALIGNMENT) }
 alloc :: proc(size: int) -> rawptr #inline { return alloc_align(size, DEFAULT_ALIGNMENT) }
 
 
 alloc_align :: proc(size, alignment: int) -> rawptr #inline {
 alloc_align :: proc(size, alignment: int) -> rawptr #inline {
-	__check_context()
-	a := context.allocator
-	return a.procedure(a.data, Allocation_Mode.ALLOC, size, alignment, null, 0, 0)
+	__check_context(^__context)
+	a := __context.allocator
+	return a.procedure(a.data, Allocator.Mode.ALLOC, size, alignment, null, 0, 0)
 }
 }
 
 
-dealloc :: proc(ptr: rawptr) #inline {
-	__check_context()
-	a := context.allocator
-	_ = a.procedure(a.data, Allocation_Mode.DEALLOC, 0, 0, ptr, 0, 0)
+free :: proc(ptr: rawptr) #inline {
+	__check_context(^__context)
+	a := __context.allocator
+	_ = a.procedure(a.data, Allocator.Mode.FREE, 0, 0, ptr, 0, 0)
 }
 }
-dealloc_all :: proc(ptr: rawptr) #inline {
-	__check_context()
-	a := context.allocator
-	_ = a.procedure(a.data, Allocation_Mode.DEALLOC_ALL, 0, 0, ptr, 0, 0)
+free_all :: proc() #inline {
+	__check_context(^__context)
+	a := __context.allocator
+	_ = a.procedure(a.data, Allocator.Mode.FREE_ALL, 0, 0, null, 0, 0)
 }
 }
 
 
 
 
 resize       :: proc(ptr: rawptr, old_size, new_size: int) -> rawptr #inline { return resize_align(ptr, old_size, new_size, DEFAULT_ALIGNMENT) }
 resize       :: proc(ptr: rawptr, old_size, new_size: int) -> rawptr #inline { return resize_align(ptr, old_size, new_size, DEFAULT_ALIGNMENT) }
 resize_align :: proc(ptr: rawptr, old_size, new_size, alignment: int) -> rawptr #inline {
 resize_align :: proc(ptr: rawptr, old_size, new_size, alignment: int) -> rawptr #inline {
-	__check_context()
-	a := context.allocator
-	return a.procedure(a.data, Allocation_Mode.RESIZE, new_size, alignment, ptr, old_size, 0)
+	__check_context(^__context)
+	a := __context.allocator
+	return a.procedure(a.data, Allocator.Mode.RESIZE, new_size, alignment, ptr, old_size, 0)
 }
 }
 
 
 
 
@@ -237,7 +285,7 @@ default_resize_align :: proc(old_memory: rawptr, old_size, new_size, alignment:
 	}
 	}
 
 
 	if new_size == 0 {
 	if new_size == 0 {
-		dealloc(old_memory)
+		free(old_memory)
 		return null
 		return null
 	}
 	}
 
 
@@ -251,24 +299,24 @@ default_resize_align :: proc(old_memory: rawptr, old_size, new_size, alignment:
 	}
 	}
 
 
 	memory_copy(new_memory, old_memory, min(old_size, new_size));
 	memory_copy(new_memory, old_memory, min(old_size, new_size));
-	dealloc(old_memory)
+	free(old_memory)
 	return new_memory
 	return new_memory
 }
 }
 
 
 
 
-__default_allocator_proc :: proc(allocator_data: rawptr, mode: Allocation_Mode,
+__default_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator.Mode,
                                  size, alignment: int,
                                  size, alignment: int,
                                  old_memory: rawptr, old_size: int, flags: u64) -> rawptr {
                                  old_memory: rawptr, old_size: int, flags: u64) -> rawptr {
-	using Allocation_Mode
+	using Allocator.Mode
 	match mode {
 	match mode {
 	case ALLOC:
 	case ALLOC:
 		return heap_alloc(size)
 		return heap_alloc(size)
 	case RESIZE:
 	case RESIZE:
 		return default_resize_align(old_memory, old_size, size, alignment)
 		return default_resize_align(old_memory, old_size, size, alignment)
-	case DEALLOC:
-		heap_dealloc(old_memory)
+	case FREE:
+		heap_free(old_memory)
 		return null
 		return null
-	case DEALLOC_ALL:
+	case FREE_ALL:
 		// NOTE(bill): Does nothing
 		// NOTE(bill): Does nothing
 	}
 	}
 
 
@@ -277,40 +325,11 @@ __default_allocator_proc :: proc(allocator_data: rawptr, mode: Allocation_Mode,
 
 
 __default_allocator :: proc() -> Allocator {
 __default_allocator :: proc() -> Allocator {
 	return Allocator{
 	return Allocator{
-		__default_allocator_proc,
-		null,
+		procedure = __default_allocator_proc,
+		data = null,
 	}
 	}
 }
 }
 
 
 
 
 
 
 
 
-__assert :: proc(msg: string) {
-	file_write(file_get_standard(File_Standard.ERROR), msg as []byte)
-	__debug_trap()
-}
-
-__bounds_check_error :: proc(file: string, line, column: int,
-                             index, count: int) {
-	println_err("%(%:%) Index % is out of bounds range [0, %)",
-	            file, line, column, index, count)
-	__debug_trap()
-}
-
-__slice_expr_error :: proc(file: string, line, column: int,
-                           low, high, max: int) {
-	print_err("%(%:%) Invalid slice indices: [%:%:%]\n",
-	          file, line, column, low, high, max)
-	__debug_trap()
-}
-__substring_expr_error :: proc(file: string, line, column: int,
-                               low, high: int) {
-	print_err("%(%:%) Invalid substring indices: [%:%:%]\n",
-	          file, line, column, low, high)
-	__debug_trap()
-}
-
-
-
-
-

+ 0 - 6
src/checker/checker.cpp

@@ -124,7 +124,6 @@ enum BuiltinProcId {
 
 
 	BuiltinProc_new,
 	BuiltinProc_new,
 	BuiltinProc_new_slice,
 	BuiltinProc_new_slice,
-	BuiltinProc_delete,
 
 
 	BuiltinProc_size_of,
 	BuiltinProc_size_of,
 	BuiltinProc_size_of_val,
 	BuiltinProc_size_of_val,
@@ -139,8 +138,6 @@ enum BuiltinProcId {
 	BuiltinProc_compile_assert,
 	BuiltinProc_compile_assert,
 	BuiltinProc_assert,
 	BuiltinProc_assert,
 
 
-	BuiltinProc_len,
-	BuiltinProc_cap,
 	BuiltinProc_copy,
 	BuiltinProc_copy,
 	BuiltinProc_append,
 	BuiltinProc_append,
 
 
@@ -168,7 +165,6 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_Count] = {
 
 
 	{STR_LIT("new"),              1, false, Expr_Expr},
 	{STR_LIT("new"),              1, false, Expr_Expr},
 	{STR_LIT("new_slice"),        2, true,  Expr_Expr},
 	{STR_LIT("new_slice"),        2, true,  Expr_Expr},
-	{STR_LIT("delete"),           1, false, Expr_Stmt},
 
 
 	{STR_LIT("size_of"),          1, false, Expr_Expr},
 	{STR_LIT("size_of"),          1, false, Expr_Expr},
 	{STR_LIT("size_of_val"),      1, false, Expr_Expr},
 	{STR_LIT("size_of_val"),      1, false, Expr_Expr},
@@ -183,8 +179,6 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_Count] = {
 	{STR_LIT("compile_assert"),   1, false, Expr_Stmt},
 	{STR_LIT("compile_assert"),   1, false, Expr_Stmt},
 	{STR_LIT("assert"),           1, false, Expr_Stmt},
 	{STR_LIT("assert"),           1, false, Expr_Stmt},
 
 
-	{STR_LIT("len"),              1, false, Expr_Expr},
-	{STR_LIT("cap"),              1, false, Expr_Expr},
 	{STR_LIT("copy"),             2, false, Expr_Expr},
 	{STR_LIT("copy"),             2, false, Expr_Expr},
 	{STR_LIT("append"),           2, false, Expr_Expr},
 	{STR_LIT("append"),           2, false, Expr_Expr},
 
 

+ 0 - 67
src/checker/expr.cpp

@@ -2095,21 +2095,6 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
 		operand->mode = Addressing_Value;
 		operand->mode = Addressing_Value;
 		operand->type = make_type_slice(c->allocator, type);
 		operand->type = make_type_slice(c->allocator, type);
 	} break;
 	} break;
-	case BuiltinProc_delete: {
-		// delete :: proc(ptr: ^T)
-		Type *type = get_base_type(operand->type);
-		if (!is_type_pointer(type) && !is_type_slice(type)) {
-			gbString type_str = type_to_string(operand->type);
-			defer (gb_string_free(type_str));
-			error(&c->error_collector, ast_node_token(call),
-			      "Expected a pointer or slice to `delete`, got `%s`",
-			      type_str);
-			return false;
-		}
-
-		operand->mode = Addressing_NoValue;
-		operand->type = NULL;
-	} break;
 
 
 	case BuiltinProc_size_of: {
 	case BuiltinProc_size_of: {
 		// size_of :: proc(Type) -> int
 		// size_of :: proc(Type) -> int
@@ -2289,58 +2274,6 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
 		}
 		}
 		break;
 		break;
 
 
-	// TODO(bill): Should these be procedures and are their names appropriate?
-	case BuiltinProc_len:
-	case BuiltinProc_cap: {
-		Type *t = get_base_type(operand->type);
-
-		AddressingMode mode = Addressing_Invalid;
-		ExactValue value = {};
-
-		switch (t->kind) {
-		case Type_Basic:
-			if (id == BuiltinProc_len) {
-				if (is_type_string(t)) {
-					if (operand->mode == Addressing_Constant) {
-						mode = Addressing_Constant;
-						value = make_exact_value_integer(operand->value.value_string);
-					} else {
-						mode = Addressing_Value;
-					}
-				}
-			}
-			break;
-
-		case Type_Array:
-			mode = Addressing_Constant;
-			value = make_exact_value_integer(t->Array.count);
-			break;
-
-		case Type_Vector:
-			mode = Addressing_Constant;
-			value = make_exact_value_integer(t->Vector.count);
-			break;
-
-		case Type_Slice:
-			mode = Addressing_Value;
-			break;
-		}
-
-		if (mode == Addressing_Invalid) {
-			gbString str = expr_to_string(operand->expr);
-			error(&c->error_collector, ast_node_token(operand->expr),
-			      "Invalid expression `%s` for `%.*s`",
-			      str, LIT(bp->name));
-			gb_string_free(str);
-			return false;
-		}
-
-		operand->mode = mode;
-		operand->type = t_int;
-		operand->value = value;
-
-	} break;
-
 	case BuiltinProc_copy: {
 	case BuiltinProc_copy: {
 		// copy :: proc(x, y: []Type) -> int
 		// copy :: proc(x, y: []Type) -> int
 		Type *dest_type = NULL, *src_type = NULL;
 		Type *dest_type = NULL, *src_type = NULL;

+ 81 - 3
src/checker/type.cpp

@@ -350,6 +350,7 @@ gb_global Type *t_untyped_rune    = &basic_types[Basic_UntypedRune];
 gb_global Type *t_byte            = &basic_type_aliases[Basic_byte];
 gb_global Type *t_byte            = &basic_type_aliases[Basic_byte];
 gb_global Type *t_rune            = &basic_type_aliases[Basic_rune];
 gb_global Type *t_rune            = &basic_type_aliases[Basic_rune];
 
 
+
 gb_global Type *t_type_info            = NULL;
 gb_global Type *t_type_info            = NULL;
 gb_global Type *t_type_info_ptr        = NULL;
 gb_global Type *t_type_info_ptr        = NULL;
 gb_global Type *t_type_info_member     = NULL;
 gb_global Type *t_type_info_member     = NULL;
@@ -588,7 +589,9 @@ b32 are_types_identical(Type *x, Type *y) {
 				case TypeRecord_Struct:
 				case TypeRecord_Struct:
 				case TypeRecord_RawUnion:
 				case TypeRecord_RawUnion:
 				case TypeRecord_Union:
 				case TypeRecord_Union:
-					if (x->Record.field_count == y->Record.field_count) {
+					if (x->Record.field_count == y->Record.field_count &&
+					    x->Record.struct_is_packed == y->Record.struct_is_packed &&
+					    x->Record.struct_is_ordered == y->Record.struct_is_ordered) {
 						for (isize i = 0; i < x->Record.field_count; i++) {
 						for (isize i = 0; i < x->Record.field_count; i++) {
 							if (!are_types_identical(x->Record.fields[i]->type, y->Record.fields[i]->type)) {
 							if (!are_types_identical(x->Record.fields[i]->type, y->Record.fields[i]->type)) {
 								return false;
 								return false;
@@ -709,6 +712,8 @@ void selection_add_index(Selection *s, isize index) {
 
 
 gb_global Entity *entity__any_type_info = NULL;
 gb_global Entity *entity__any_type_info = NULL;
 gb_global Entity *entity__any_data      = NULL;
 gb_global Entity *entity__any_data      = NULL;
+gb_global Entity *entity__string_data   = NULL;
+gb_global Entity *entity__string_count = NULL;
 
 
 Selection lookup_field(Type *type_, String field_name, b32 is_type, Selection sel = empty_selection) {
 Selection lookup_field(Type *type_, String field_name, b32 is_type, Selection sel = empty_selection) {
 	GB_ASSERT(type_ != NULL);
 	GB_ASSERT(type_ != NULL);
@@ -717,6 +722,7 @@ Selection lookup_field(Type *type_, String field_name, b32 is_type, Selection se
 		return empty_selection;
 		return empty_selection;
 	}
 	}
 
 
+	gbAllocator a = gb_heap_allocator();
 	Type *type = type_deref(type_);
 	Type *type = type_deref(type_);
 	b32 is_ptr = type != type_;
 	b32 is_ptr = type != type_;
 	type = get_base_type(type);
 	type = get_base_type(type);
@@ -729,12 +735,12 @@ Selection lookup_field(Type *type_, String field_name, b32 is_type, Selection se
 			if (entity__any_type_info == NULL) {
 			if (entity__any_type_info == NULL) {
 				Token token = {Token_Identifier};
 				Token token = {Token_Identifier};
 				token.string = type_info_str;
 				token.string = type_info_str;
-				entity__any_type_info = make_entity_field(gb_heap_allocator(), NULL, token, t_type_info_ptr, false, 0);
+				entity__any_type_info = make_entity_field(a, NULL, token, t_type_info_ptr, false, 0);
 			}
 			}
 			if (entity__any_data == NULL) {
 			if (entity__any_data == NULL) {
 				Token token = {Token_Identifier};
 				Token token = {Token_Identifier};
 				token.string = data_str;
 				token.string = data_str;
-				entity__any_data = make_entity_field(gb_heap_allocator(), NULL, token, t_rawptr, false, 1);
+				entity__any_data = make_entity_field(a, NULL, token, t_rawptr, false, 1);
 			}
 			}
 
 
 			if (are_strings_equal(field_name, type_info_str)) {
 			if (are_strings_equal(field_name, type_info_str)) {
@@ -747,9 +753,81 @@ Selection lookup_field(Type *type_, String field_name, b32 is_type, Selection se
 				return sel;
 				return sel;
 			}
 			}
 		} break;
 		} break;
+		case Basic_string: {
+			String data_str = make_string("data");
+			String count_str = make_string("count");
+			if (entity__string_data == NULL) {
+				Token token = {Token_Identifier};
+				token.string = data_str;
+				entity__string_data = make_entity_field(a, NULL, token, make_type_pointer(a, t_byte), false, 0);
+			}
+
+			if (entity__string_count == NULL) {
+				Token token = {Token_Identifier};
+				token.string = count_str;
+				entity__string_count = make_entity_field(a, NULL, token, t_int, false, 1);
+			}
+
+			if (are_strings_equal(field_name, data_str)) {
+				selection_add_index(&sel, 0);
+				sel.entity = entity__string_data;
+				return sel;
+			} else if (are_strings_equal(field_name, count_str)) {
+				selection_add_index(&sel, 1);
+				sel.entity = entity__string_count;
+				return sel;
+			}
+		} break;
 		}
 		}
 
 
 		return sel;
 		return sel;
+	} else if (type->kind == Type_Array) {
+		String count_str = make_string("count");
+		// NOTE(bill):U nderlying memory address cannot be changed
+		if (are_strings_equal(field_name, count_str)) {
+			Token token = {Token_Identifier};
+			token.string = count_str;
+			// HACK(bill): Memory leak
+			sel.entity = make_entity_constant(a, NULL, token, t_int, make_exact_value_integer(type->Array.count));
+			return sel;
+		}
+	} else if (type->kind == Type_Vector) {
+		String count_str = make_string("count");
+		// NOTE(bill): Vectors are not addressable
+		if (are_strings_equal(field_name, count_str)) {
+			Token token = {Token_Identifier};
+			token.string = count_str;
+			// HACK(bill): Memory leak
+			sel.entity = make_entity_constant(a, NULL, token, t_int, make_exact_value_integer(type->Vector.count));
+			return sel;
+		}
+	} else if (type->kind == Type_Slice) {
+		String data_str     = make_string("data");
+		String count_str    = make_string("count");
+		String capacity_str = make_string("capacity");
+
+		if (are_strings_equal(field_name, data_str)) {
+			selection_add_index(&sel, 0);
+			Token token = {Token_Identifier};
+			token.string = data_str;
+			// HACK(bill): Memory leak
+			sel.entity = make_entity_field(a, NULL, token, make_type_pointer(a, type->Slice.elem), false, 0);
+			return sel;
+		} else if (are_strings_equal(field_name, count_str)) {
+			selection_add_index(&sel, 1);
+			Token token = {Token_Identifier};
+			token.string = count_str;
+			// HACK(bill): Memory leak
+			sel.entity = make_entity_field(a, NULL, token, t_int, false, 1);
+			return sel;
+		} else if (are_strings_equal(field_name, capacity_str)) {
+			selection_add_index(&sel, 2);
+			Token token = {Token_Identifier};
+			token.string = capacity_str;
+			// HACK(bill): Memory leak
+			sel.entity = make_entity_field(a, NULL, token, t_int, false, 2);
+			return sel;
+		}
 	}
 	}
 
 
 	if (type->kind != Type_Record) {
 	if (type->kind != Type_Record) {

+ 13 - 3
src/codegen/codegen.cpp

@@ -330,6 +330,13 @@ void ssa_gen_tree(ssaGen *s) {
 					case TypeRecord_Struct: {
 					case TypeRecord_Struct: {
 						tag = ssa_add_local_generated(proc, t_type_info_struct);
 						tag = ssa_add_local_generated(proc, t_type_info_struct);
 
 
+						{
+							ssaValue *packed  = ssa_make_const_bool(a, t->Record.struct_is_packed);
+							ssaValue *ordered = ssa_make_const_bool(a, t->Record.struct_is_ordered);
+							ssa_emit_store(proc, ssa_emit_struct_gep(proc, tag, v_one32, t_bool_ptr), packed);
+							ssa_emit_store(proc, ssa_emit_struct_gep(proc, tag, v_two32, t_bool_ptr), ordered);
+						}
+
 						ssaValue *memory = type_info_member_offset(proc, type_info_member_data, t->Record.field_count, &type_info_member_index);
 						ssaValue *memory = type_info_member_offset(proc, type_info_member_data, t->Record.field_count, &type_info_member_index);
 
 
 						type_set_offsets(m->sizes, a, t); // NOTE(bill): Just incase the offsets have not been set yet
 						type_set_offsets(m->sizes, a, t); // NOTE(bill): Just incase the offsets have not been set yet
@@ -456,9 +463,12 @@ void ssa_gen_tree(ssaGen *s) {
 					ssaValue *results  = ssa_emit_struct_gep(proc, tag, v_one32,  t_type_info_ptr_ptr);
 					ssaValue *results  = ssa_emit_struct_gep(proc, tag, v_one32,  t_type_info_ptr_ptr);
 					ssaValue *variadic = ssa_emit_struct_gep(proc, tag, v_two32,  t_bool_ptr);
 					ssaValue *variadic = ssa_emit_struct_gep(proc, tag, v_two32,  t_bool_ptr);
 
 
-
-					ssa_emit_store(proc, params,   get_type_info_ptr(proc, type_info_data, t->Proc.params));
-					ssa_emit_store(proc, results,  get_type_info_ptr(proc, type_info_data, t->Proc.results));
+					if (t->Proc.params) {
+						ssa_emit_store(proc, params,   get_type_info_ptr(proc, type_info_data, t->Proc.params));
+					}
+					if (t->Proc.results) {
+						ssa_emit_store(proc, results,  get_type_info_ptr(proc, type_info_data, t->Proc.results));
+					}
 					ssa_emit_store(proc, variadic, ssa_make_const_bool(a, t->Proc.variadic));
 					ssa_emit_store(proc, variadic, ssa_make_const_bool(a, t->Proc.variadic));
 
 
 					// TODO(bill): Type_Info for procedures
 					// TODO(bill): Type_Info for procedures

+ 1 - 1
src/codegen/print_llvm.cpp

@@ -121,7 +121,7 @@ void ssa_print_encoded_local(ssaFileBuffer *f, String name) {
 
 
 void ssa_print_encoded_global(ssaFileBuffer *f, String name, b32 global_scope = false) {
 void ssa_print_encoded_global(ssaFileBuffer *f, String name, b32 global_scope = false) {
 	ssa_fprintf(f, "@");
 	ssa_fprintf(f, "@");
-	if (!global_scope) {
+	if (!global_scope && !are_strings_equal(name, make_string("main"))) {
 		ssa_fprintf(f, ".");
 		ssa_fprintf(f, ".");
 	}
 	}
 	ssa_print_escape_string(f, name, true);
 	ssa_print_escape_string(f, name, true);

+ 51 - 105
src/codegen/ssa.cpp

@@ -1116,10 +1116,16 @@ ssaValue *ssa_emit_deep_field_gep(ssaProcedure *proc, Type *type, ssaValue *e, S
 				e = ssa_emit_struct_gep(proc, e, index, make_type_pointer(proc->module->allocator, type));
 				e = ssa_emit_struct_gep(proc, e, index, make_type_pointer(proc->module->allocator, type));
 			} break;
 			} break;
 
 
+			case Basic_string:
+				e = ssa_emit_struct_gep(proc, e, index, make_type_pointer(proc->module->allocator, sel.entity->type));
+				break;
+
 			default:
 			default:
 				GB_PANIC("un-gep-able type");
 				GB_PANIC("un-gep-able type");
 				break;
 				break;
 			}
 			}
+		} else if (type->kind == Type_Slice) {
+			e = ssa_emit_struct_gep(proc, e, index, make_type_pointer(proc->module->allocator, sel.entity->type));
 		} else {
 		} else {
 			GB_PANIC("un-gep-able type");
 			GB_PANIC("un-gep-able type");
 		}
 		}
@@ -1159,10 +1165,16 @@ ssaValue *ssa_emit_deep_field_ev(ssaProcedure *proc, Type *type, ssaValue *e, Se
 				e = ssa_emit_struct_ev(proc, e, index, type);
 				e = ssa_emit_struct_ev(proc, e, index, type);
 			} break;
 			} break;
 
 
+			case Basic_string:
+				e = ssa_emit_struct_ev(proc, e, index, sel.entity->type);
+				break;
+
 			default:
 			default:
 				GB_PANIC("un-ev-able type");
 				GB_PANIC("un-ev-able type");
 				break;
 				break;
 			}
 			}
+		} else if (type->kind == Type_Slice) {
+			e = ssa_emit_struct_gep(proc, e, index, make_type_pointer(proc->module->allocator, sel.entity->type));
 		} else {
 		} else {
 			GB_PANIC("un-ev-able type");
 			GB_PANIC("un-ev-able type");
 		}
 		}
@@ -1194,6 +1206,9 @@ isize ssa_type_info_index(CheckerInfo *info, Type *type) {
 			}
 			}
 		}
 		}
 	}
 	}
+	if (entry_index < 0) {
+		gb_printf_err("%s\n", type_to_string(type));
+	}
 	GB_ASSERT(entry_index >= 0);
 	GB_ASSERT(entry_index >= 0);
 	return entry_index;
 	return entry_index;
 }
 }
@@ -1599,7 +1614,7 @@ ssaValue *ssa_emit_conv(ssaProcedure *proc, ssaValue *value, Type *t, b32 is_arg
 		ssaValue *result = ssa_add_local_generated(proc, t_any);
 		ssaValue *result = ssa_add_local_generated(proc, t_any);
 
 
 		ssaValue *data = NULL;
 		ssaValue *data = NULL;
-		if (false && value->kind == ssaValue_Instr &&
+		if (value->kind == ssaValue_Instr &&
 		    value->Instr.kind == ssaInstr_Load) {
 		    value->Instr.kind == ssaInstr_Load) {
 			// NOTE(bill): Addressable value
 			// NOTE(bill): Addressable value
 			data = value->Instr.Load.address;
 			data = value->Instr.Load.address;
@@ -1704,37 +1719,16 @@ void ssa_array_bounds_check(ssaProcedure *proc, Token token, ssaValue *index, ss
 	if ((proc->module->stmt_state_flags & StmtStateFlag_no_bounds_check) != 0) {
 	if ((proc->module->stmt_state_flags & StmtStateFlag_no_bounds_check) != 0) {
 		return;
 		return;
 	}
 	}
-	ssa_emit_comment(proc, make_string("ArrayBoundsCheck"));
-	index = ssa_emit_conv(proc, index, t_int);
-	len = ssa_emit_conv(proc, len, t_int);
-
-	Token le = {Token_LtEq};
-	Token lt = {Token_Lt};
-	Token cmp_and = {Token_And}; // NOTE(bill): Doesn't need to be logical
-	ssaValue *c0 = ssa_emit_comp(proc, le, v_zero, index);
-	ssaValue *c1 = ssa_emit_comp(proc, lt, index, len);
-	ssaValue *cond = ssa_emit_comp(proc, cmp_and, c0, c1);
-
-	ssaBlock *then = ssa_add_block(proc, NULL, make_string("abc.then"));
-	ssaBlock *done = ssa__make_block(proc, NULL, make_string("abc.done"));
-
-	ssa_emit_if(proc, cond, done, then);
-	proc->curr_block = then;
-
 
 
 	gbAllocator a = proc->module->allocator;
 	gbAllocator a = proc->module->allocator;
 	ssaValue **args = gb_alloc_array(a, ssaValue *, 5);
 	ssaValue **args = gb_alloc_array(a, ssaValue *, 5);
 	args[0] = ssa_emit_global_string(proc, token.pos.file);
 	args[0] = ssa_emit_global_string(proc, token.pos.file);
 	args[1] = ssa_make_const_int(a, token.pos.line);
 	args[1] = ssa_make_const_int(a, token.pos.line);
 	args[2] = ssa_make_const_int(a, token.pos.column);
 	args[2] = ssa_make_const_int(a, token.pos.column);
-	args[3] = index;
-	args[4] = len;
+	args[3] = ssa_emit_conv(proc, index, t_int);
+	args[4] = ssa_emit_conv(proc, len, t_int);
 
 
 	ssa_emit_global_call(proc, "__bounds_check_error", args, 5);
 	ssa_emit_global_call(proc, "__bounds_check_error", args, 5);
-
-	ssa_emit_jump(proc, done);
-	gb_array_append(proc->blocks, done);
-	proc->curr_block = done;
 }
 }
 
 
 void ssa_slice_bounds_check(ssaProcedure *proc, Token token, ssaValue *low, ssaValue *high, ssaValue *max, b32 is_substring) {
 void ssa_slice_bounds_check(ssaProcedure *proc, Token token, ssaValue *low, ssaValue *high, ssaValue *max, b32 is_substring) {
@@ -1742,43 +1736,20 @@ void ssa_slice_bounds_check(ssaProcedure *proc, Token token, ssaValue *low, ssaV
 		return;
 		return;
 	}
 	}
 
 
-	low  = ssa_emit_conv(proc, low, t_int);
-	high = ssa_emit_conv(proc, high, t_int);
-	max  = ssa_emit_conv(proc, max, t_int);
-
-	Token le = {Token_LtEq};
-	Token cmp_and = {Token_And}; // NOTE(bill): Doesn't need to be logical
-	ssaValue *c0 = ssa_emit_comp(proc, le, v_zero, low);
-	ssaValue *c1 = ssa_emit_comp(proc, le, low, high);
-	ssaValue *c2 = ssa_emit_comp(proc, le, high, max);
-	ssaValue *cond = NULL;
-	cond = ssa_emit_comp(proc, cmp_and, c0, c1);
-	cond = ssa_emit_comp(proc, cmp_and, cond, c2);
-
-	ssaBlock *then = ssa_add_block(proc, NULL, make_string("seb.then"));
-	ssaBlock *done = ssa__make_block(proc, NULL, make_string("seb.done"));
-
-	ssa_emit_if(proc, cond, done, then);
-	proc->curr_block = then;
-
 	gbAllocator a = proc->module->allocator;
 	gbAllocator a = proc->module->allocator;
 	ssaValue **args = gb_alloc_array(a, ssaValue *, 6);
 	ssaValue **args = gb_alloc_array(a, ssaValue *, 6);
 	args[0] = ssa_emit_global_string(proc, token.pos.file);
 	args[0] = ssa_emit_global_string(proc, token.pos.file);
 	args[1] = ssa_make_const_int(a, token.pos.line);
 	args[1] = ssa_make_const_int(a, token.pos.line);
 	args[2] = ssa_make_const_int(a, token.pos.column);
 	args[2] = ssa_make_const_int(a, token.pos.column);
-	args[3] = low;
-	args[4] = high;
-	args[5] = max;
+	args[3] = ssa_emit_conv(proc, low, t_int);
+	args[4] = ssa_emit_conv(proc, high, t_int);
+	args[5] = ssa_emit_conv(proc, max, t_int);
 
 
 	if (!is_substring) {
 	if (!is_substring) {
 		ssa_emit_global_call(proc, "__slice_expr_error", args, 6);
 		ssa_emit_global_call(proc, "__slice_expr_error", args, 6);
 	} else {
 	} else {
 		ssa_emit_global_call(proc, "__substring_expr_error", args, 5);
 		ssa_emit_global_call(proc, "__substring_expr_error", args, 5);
 	}
 	}
-
-	ssa_emit_jump(proc, done);
-	gb_array_append(proc->blocks, done);
-	proc->curr_block = done;
 }
 }
 
 
 
 
@@ -2109,26 +2080,6 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
 					return ssa_emit_load(proc, slice);
 					return ssa_emit_load(proc, slice);
 				} break;
 				} break;
 
 
-				case BuiltinProc_delete: {
-					ssa_emit_comment(proc, make_string("delete"));
-					// delete :: proc(ptr: ^Type)
-					// delete :: proc(slice: []Type)
-					gbAllocator allocator = proc->module->allocator;
-
-					ssaValue *value = ssa_build_expr(proc, ce->args[0]);
-
-					if (is_type_slice(ssa_type(value))) {
-						Type *etp = get_base_type(ssa_type(value));
-						etp = make_type_pointer(allocator, etp->Slice.elem);
-						value = ssa_emit(proc, ssa_make_instr_extract_value(proc, value, 0, etp));
-					}
-
-					ssaValue **args = gb_alloc_array(allocator, ssaValue *, 1);
-					args[0] = ssa_emit_conv(proc, value, t_rawptr, true);
-					return ssa_emit_global_call(proc, "dealloc", args, 1);
-				} break;
-
-
 				case BuiltinProc_assert: {
 				case BuiltinProc_assert: {
 					ssa_emit_comment(proc, make_string("assert"));
 					ssa_emit_comment(proc, make_string("assert"));
 					ssaValue *cond = ssa_build_expr(proc, ce->args[0]);
 					ssaValue *cond = ssa_build_expr(proc, ce->args[0]);
@@ -2174,25 +2125,6 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
 					return NULL;
 					return NULL;
 				} break;
 				} break;
 
 
-				case BuiltinProc_len: {
-					ssa_emit_comment(proc, make_string("len"));
-					// len :: proc(v: Type) -> int
-					// NOTE(bill): len of an array is a constant expression
-					ssaValue *v = ssa_build_expr(proc, ce->args[0]);
-					Type *t = get_base_type(ssa_type(v));
-					if (t == t_string)
-						return ssa_string_len(proc, v);
-					else if (t->kind == Type_Slice)
-						return ssa_slice_len(proc, v);
-				} break;
-				case BuiltinProc_cap: {
-					ssa_emit_comment(proc, make_string("cap"));
-					// cap :: proc(v: Type) -> int
-					// NOTE(bill): cap of an array is a constant expression
-					ssaValue *v = ssa_build_expr(proc, ce->args[0]);
-					Type *t = get_base_type(ssa_type(v));
-					return ssa_slice_cap(proc, v);
-				} break;
 				case BuiltinProc_copy: {
 				case BuiltinProc_copy: {
 					ssa_emit_comment(proc, make_string("copy"));
 					ssa_emit_comment(proc, make_string("copy"));
 					// copy :: proc(dst, src: []Type) -> int
 					// copy :: proc(dst, src: []Type) -> int
@@ -3393,9 +3325,15 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
 				gb_array_append(proc->blocks, body);
 				gb_array_append(proc->blocks, body);
 			}
 			}
 			proc->curr_block = body;
 			proc->curr_block = body;
+
+			// TODO(bill): Handle fallthrough scope exit correctly
+			proc->scope_index++;
 			ssa_push_target_list(proc, done, NULL, fall);
 			ssa_push_target_list(proc, done, NULL, fall);
 			ssa_build_stmt_list(proc, cc->stmts);
 			ssa_build_stmt_list(proc, cc->stmts);
+			ssa_emit_defer_stmts(proc, ssaDefer_Default, body);
 			ssa_pop_target_list(proc);
 			ssa_pop_target_list(proc);
+			proc->scope_index--;
+
 			ssa_emit_jump(proc, done);
 			ssa_emit_jump(proc, done);
 			proc->curr_block = next_cond;
 			proc->curr_block = next_cond;
 		}
 		}
@@ -3404,9 +3342,14 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
 			ssa_emit_jump(proc, default_block);
 			ssa_emit_jump(proc, default_block);
 			gb_array_append(proc->blocks, default_block);
 			gb_array_append(proc->blocks, default_block);
 			proc->curr_block = default_block;
 			proc->curr_block = default_block;
+
+			// TODO(bill): Handle fallthrough scope exit correctly
+			proc->scope_index++;
 			ssa_push_target_list(proc, done, NULL, default_fall);
 			ssa_push_target_list(proc, done, NULL, default_fall);
 			ssa_build_stmt_list(proc, default_stmts);
 			ssa_build_stmt_list(proc, default_stmts);
+			ssa_emit_defer_stmts(proc, ssaDefer_Default, default_block);
 			ssa_pop_target_list(proc);
 			ssa_pop_target_list(proc);
+			proc->scope_index--;
 		}
 		}
 
 
 		ssa_emit_jump(proc, done);
 		ssa_emit_jump(proc, done);
@@ -3490,9 +3433,14 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
 
 
 			gb_array_append(proc->blocks, body);
 			gb_array_append(proc->blocks, body);
 			proc->curr_block = body;
 			proc->curr_block = body;
+
+			proc->scope_index++;
 			ssa_push_target_list(proc, done, NULL, NULL);
 			ssa_push_target_list(proc, done, NULL, NULL);
 			ssa_build_stmt_list(proc, cc->stmts);
 			ssa_build_stmt_list(proc, cc->stmts);
+			ssa_emit_defer_stmts(proc, ssaDefer_Default, body);
 			ssa_pop_target_list(proc);
 			ssa_pop_target_list(proc);
+			proc->scope_index--;
+
 			ssa_emit_jump(proc, done);
 			ssa_emit_jump(proc, done);
 			proc->curr_block = next_cond;
 			proc->curr_block = next_cond;
 		}
 		}
@@ -3501,9 +3449,13 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
 			ssa_emit_jump(proc, default_block);
 			ssa_emit_jump(proc, default_block);
 			gb_array_append(proc->blocks, default_block);
 			gb_array_append(proc->blocks, default_block);
 			proc->curr_block = default_block;
 			proc->curr_block = default_block;
+
+			proc->scope_index++;
 			ssa_push_target_list(proc, done, NULL, NULL);
 			ssa_push_target_list(proc, done, NULL, NULL);
 			ssa_build_stmt_list(proc, default_stmts);
 			ssa_build_stmt_list(proc, default_stmts);
+			ssa_emit_defer_stmts(proc, ssaDefer_Default, default_block);
 			ssa_pop_target_list(proc);
 			ssa_pop_target_list(proc);
+			proc->scope_index--;
 		}
 		}
 
 
 		ssa_emit_jump(proc, done);
 		ssa_emit_jump(proc, done);
@@ -3513,24 +3465,18 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
 
 
 	case_ast_node(bs, BranchStmt, node);
 	case_ast_node(bs, BranchStmt, node);
 		ssaBlock *block = NULL;
 		ssaBlock *block = NULL;
+		#define branch_case(x) case GB_JOIN2(Token_, x): \
+			for (ssaTargetList *t = proc->target_list; t != NULL && block == NULL; t = t->prev) { \
+				block = GB_JOIN3(t->, x, _); \
+			} break
 		switch (bs->token.kind) {
 		switch (bs->token.kind) {
-		case Token_break: {
-			for (ssaTargetList *t = proc->target_list; t != NULL && block == NULL; t = t->prev) {
-				block = t->break_;
-			}
-		} break;
-		case Token_continue: {
-			for (ssaTargetList *t = proc->target_list; t != NULL && block == NULL; t = t->prev) {
-				block = t->continue_;
-			}
-		} break;
-		case Token_fallthrough: {
-			for (ssaTargetList *t = proc->target_list; t != NULL && block == NULL; t = t->prev) {
-				block = t->fallthrough_;
-			}
-		} break;
+		branch_case(break);
+		branch_case(continue);
+		branch_case(fallthrough);
 		}
 		}
-		if (block != NULL && bs->token.kind != Token_fallthrough) {
+		// TODO(bill): Handle fallthrough scope exit correctly
+		// if (block != NULL && bs->token.kind != Token_fallthrough) {
+		if (block != NULL) {
 			ssa_emit_defer_stmts(proc, ssaDefer_Branch, block);
 			ssa_emit_defer_stmts(proc, ssaDefer_Branch, block);
 		}
 		}
 		switch (bs->token.kind) {
 		switch (bs->token.kind) {

+ 30 - 15
src/parser.cpp

@@ -64,6 +64,7 @@ enum ProcTag {
 	ProcTag_foreign         = GB_BIT(2),
 	ProcTag_foreign         = GB_BIT(2),
 	ProcTag_inline          = GB_BIT(3),
 	ProcTag_inline          = GB_BIT(3),
 	ProcTag_no_inline       = GB_BIT(4),
 	ProcTag_no_inline       = GB_BIT(4),
+	ProcTag_no_context      = GB_BIT(5),
 };
 };
 
 
 enum VarDeclTag {
 enum VarDeclTag {
@@ -1173,14 +1174,16 @@ void parse_proc_tags(AstFile *f, u64 *tags, String *foreign_name) {
 
 
 				next_token(f);
 				next_token(f);
 			}
 			}
-		} else if (are_strings_equal(tag_name, make_string("inline"))) {
-			check_proc_add_tag(f, tag_expr, tags, ProcTag_inline, tag_name);
-		} else if (are_strings_equal(tag_name, make_string("no_inline"))) {
-			check_proc_add_tag(f, tag_expr, tags, ProcTag_no_inline, tag_name);
 		} else if (are_strings_equal(tag_name, make_string("bounds_check"))) {
 		} else if (are_strings_equal(tag_name, make_string("bounds_check"))) {
 			check_proc_add_tag(f, tag_expr, tags, ProcTag_bounds_check, tag_name);
 			check_proc_add_tag(f, tag_expr, tags, ProcTag_bounds_check, tag_name);
 		} else if (are_strings_equal(tag_name, make_string("no_bounds_check"))) {
 		} else if (are_strings_equal(tag_name, make_string("no_bounds_check"))) {
 			check_proc_add_tag(f, tag_expr, tags, ProcTag_no_bounds_check, tag_name);
 			check_proc_add_tag(f, tag_expr, tags, ProcTag_no_bounds_check, tag_name);
+		} else if (are_strings_equal(tag_name, make_string("inline"))) {
+			check_proc_add_tag(f, tag_expr, tags, ProcTag_inline, tag_name);
+		} else if (are_strings_equal(tag_name, make_string("no_inline"))) {
+			check_proc_add_tag(f, tag_expr, tags, ProcTag_no_inline, tag_name);
+		} else if (are_strings_equal(tag_name, make_string("no_context"))) {
+			check_proc_add_tag(f, tag_expr, tags, ProcTag_no_context, tag_name);
 		} else {
 		} else {
 			ast_file_err(f, ast_node_token(tag_expr), "Unknown procedure tag");
 			ast_file_err(f, ast_node_token(tag_expr), "Unknown procedure tag");
 		}
 		}
@@ -1490,17 +1493,16 @@ AstNode *parse_binary_expr(AstFile *f, b32 lhs, i32 prec_in) {
 			}
 			}
 
 
 			switch (op.kind) {
 			switch (op.kind) {
-			// case Token_DoublePrime: {
-			// 	AstNode *proc = parse_identifier(f);
-			// 	AstNode *right = parse_binary_expr(f, false, prec+1);
-			// 	expression->next = right;
-			// 	gbArray(AstNode *) args;
-			// 	gb_array_init_reserve(args, gb_arena_allocator(&f->arena), 2);
-			// 	gb_array_append(args, expression);
-			// 	gb_array_append(args, right);
-			// 	expression = make_call_expr(f, proc, args, op, ast_node_token(right), empty_token);
-			// 	continue;
-			// } break;
+			case Token_DoublePrime: {
+				AstNode *proc = parse_identifier(f);
+				AstNode *right = parse_binary_expr(f, false, prec+1);
+				gbArray(AstNode *) args;
+				gb_array_init_reserve(args, gb_arena_allocator(&f->arena), 2);
+				gb_array_append(args, expression);
+				gb_array_append(args, right);
+				expression = make_call_expr(f, proc, args, op, ast_node_token(right), empty_token);
+				continue;
+			} break;
 
 
 			case Token_as:
 			case Token_as:
 			case Token_transmute:
 			case Token_transmute:
@@ -2074,6 +2076,18 @@ AstNode *parse_decl(AstFile *f, AstNodeArray names) {
 	AstNodeArray values = NULL;
 	AstNodeArray values = NULL;
 	AstNode *type = NULL;
 	AstNode *type = NULL;
 
 
+	gb_for_array(i, names) {
+		AstNode *name = names[i];
+		if (name->kind == AstNode_Ident) {
+			String n = name->Ident.string;
+			// NOTE(bill): Check for reserved identifiers
+			if (are_strings_equal(n, make_string("context"))) {
+				ast_file_err(f, ast_node_token(name), "`context` is a reserved identifier");
+				break;
+			}
+		}
+	}
+
 	if (allow_token(f, Token_Colon)) {
 	if (allow_token(f, Token_Colon)) {
 		if (!allow_token(f, Token_type)) {
 		if (!allow_token(f, Token_type)) {
 			type = parse_identifier_or_type(f);
 			type = parse_identifier_or_type(f);
@@ -2449,6 +2463,7 @@ AstNode *parse_stmt(AstFile *f) {
 	case Token_Rune:
 	case Token_Rune:
 	case Token_String:
 	case Token_String:
 	case Token_OpenParen:
 	case Token_OpenParen:
+	case Token_proc:
 	// Unary Operators
 	// Unary Operators
 	case Token_Add:
 	case Token_Add:
 	case Token_Sub:
 	case Token_Sub: