Browse Source

`do` keyword for inline statements instead of blocks

Ginger Bill 8 years ago
parent
commit
ed089b44b9
11 changed files with 198 additions and 164 deletions
  1. 12 17
      code/demo.odin
  2. 30 49
      core/_preload.odin
  3. 1 1
      core/_soft_numbers.odin
  4. 2 2
      core/decimal.odin
  5. 33 33
      core/fmt.odin
  6. 40 23
      src/check_expr.cpp
  7. 8 1
      src/checker.cpp
  8. 1 0
      src/entity.cpp
  9. 36 12
      src/parser.cpp
  10. 30 23
      src/tokenizer.cpp
  11. 5 3
      src/types.cpp

+ 12 - 17
code/demo.odin

@@ -1,8 +1,9 @@
 import (
+	"fmt.odin";
+/*
 	"atomics.odin";
 	"bits.odin";
 	"decimal.odin";
-	"fmt.odin";
 	"hash.odin";
 	"math.odin";
 	"mem.odin";
@@ -15,6 +16,7 @@ import (
 	"types.odin";
 	"utf8.odin";
 	"utf16.odin";
+*/
 )
 
 general_stuff :: proc() {
@@ -34,6 +36,8 @@ general_stuff :: proc() {
 		// The variadic part allows for extra type checking too which C does not provide
 		c_printf :: proc(fmt: ^u8, #c_vararg args: ..any) -> i32 #link_name "printf" ---;
 	}
+	str := "%d\n";
+	c_printf(&str[0], i32(789456123));
 
 
 	Foo :: struct {
@@ -72,9 +76,7 @@ foreign_blocks :: proc() {
 }
 
 default_arguments :: proc() {
-	hello :: proc(a: int = 9, b: int = 9) {
-		fmt.printf("a is %d; b is %d\n", a, b);
-	}
+	hello :: proc(a: int = 9, b: int = 9) do fmt.printf("a is %d; b is %d\n", a, b);
 	fmt.println("\nTesting default arguments:");
 	hello(1, 2);
 	hello(1);
@@ -179,7 +181,7 @@ default_return_values :: proc() {
 
 	some_thing :: proc(input: int) -> (result: ^Entity = nil, err := Error.None) {
 		match {
-		case input == 3: return err = Error.WhyTheNumberThree;
+		case input == 3:  return err = Error.WhyTheNumberThree;
 		case input >= 10: return err = Error.TenIsTooBig;
 		}
 
@@ -215,9 +217,7 @@ call_location :: proc() {
 
 explicit_parametric_polymorphic_procedures :: proc() {
 	// This is how `new` is actually implemented, see _preload.odin
-	alloc_type :: proc(T: type) -> ^T {
-		return ^T(alloc(size_of(T), align_of(T)));
-	}
+	alloc_type :: proc(T: type) -> ^T do return ^T(alloc(size_of(T), align_of(T)));
 
 	int_ptr := alloc_type(int);
 	defer free(int_ptr);
@@ -231,9 +231,7 @@ explicit_parametric_polymorphic_procedures :: proc() {
 
 	add :: proc(T: type, args: ..T) -> T {
 		res: T;
-		for arg in args {
-			res += arg;
-		}
+		for arg in args do res += arg;
 		return res;
 	}
 
@@ -298,7 +296,7 @@ explicit_parametric_polymorphic_procedures :: proc() {
 
 	use_empty_slot :: proc(manager: ^EntityManager, batch: ^EntityBatch) -> ^Entity {
 		for ok, i in batch.occupied {
-			if ok -> continue;
+			if ok do continue;
 			batch.occupied[i] = true;
 
 			e := &batch.data[i];
@@ -314,7 +312,7 @@ explicit_parametric_polymorphic_procedures :: proc() {
 	gen_new_entity :: proc(manager: ^EntityManager) -> ^Entity {
 		for b in manager.batches {
 			e := use_empty_slot(manager, b);
-			if e != nil -> return e;
+			if e != nil do return e;
 		}
 
 		new_batch := new(EntityBatch);
@@ -366,12 +364,9 @@ explicit_parametric_polymorphic_procedures :: proc() {
 	}
 }
 
-
-
-
 main :: proc() {
-/*
 	general_stuff();
+/*
 	foreign_blocks();
 	default_arguments();
 	named_arguments();

+ 30 - 49
core/_preload.odin

@@ -118,7 +118,7 @@ __argc__: i32;
 
 
 type_info_base :: proc(info: ^TypeInfo) -> ^TypeInfo {
-	if info == nil -> return nil;
+	if info == nil do return nil;
 
 	base := info;
 	match i in base {
@@ -130,7 +130,7 @@ type_info_base :: proc(info: ^TypeInfo) -> ^TypeInfo {
 
 
 type_info_base_without_enum :: proc(info: ^TypeInfo) -> ^TypeInfo {
-	if info == nil -> return nil;
+	if info == nil do return nil;
 
 	base := info;
 	match i in base {
@@ -195,7 +195,7 @@ make_source_code_location :: proc(file: string, line, column: i64, procedure: st
 DEFAULT_ALIGNMENT :: align_of([vector 4]f32);
 
 __init_context_from_ptr :: proc(c: ^Context, other: ^Context) #cc_contextless {
-	if c == nil -> return;
+	if c == nil do return;
 	c^ = other^;
 
 	if c.allocator.procedure == nil {
@@ -207,7 +207,7 @@ __init_context_from_ptr :: proc(c: ^Context, other: ^Context) #cc_contextless {
 }
 
 __init_context :: proc(c: ^Context) #cc_contextless {
-	if c == nil -> return;
+	if c == nil do return;
 
 	if c.allocator.procedure == nil {
 		c.allocator = default_allocator();
@@ -259,30 +259,22 @@ resize :: proc(ptr: rawptr, old_size, new_size: int, alignment: int = DEFAULT_AL
 }
 
 
-new :: proc(T: type) -> ^T #inline {
-	return ^T(alloc(size_of(T), align_of(T)));
-}
+new :: proc(T: type) -> ^T #inline do return ^T(alloc(size_of(T), align_of(T)));
 
 
 
 default_resize_align :: proc(old_memory: rawptr, old_size, new_size, alignment: int) -> rawptr {
-	if old_memory == nil {
-		return alloc(new_size, alignment);
-	}
+	if old_memory == nil do return alloc(new_size, alignment);
 
 	if new_size == 0 {
 		free(old_memory);
 		return nil;
 	}
 
-	if new_size == old_size {
-		return old_memory;
-	}
+	if new_size == old_size do return old_memory;
 
 	new_memory := alloc(new_size, alignment);
-	if new_memory == nil {
-		return nil;
-	}
+	if new_memory == nil do return nil;
 
 	__mem_copy(new_memory, old_memory, min(old_size, new_size));;
 	free(old_memory);
@@ -326,9 +318,9 @@ default_allocator :: proc() -> Allocator {
 assert :: proc(condition: bool, message := "", using location := #caller_location) -> bool #cc_contextless {
 	if !condition {
 		if len(message) > 0 {
-			fmt.printf("%s(%d:%d) Runtime assertion: %s\n", fully_pathed_filename, line, column, message);
+			fmt.fprintf(os.stderr, "%s(%d:%d) Runtime assertion: %s\n", fully_pathed_filename, line, column, message);
 		} else {
-			fmt.printf("%s(%d:%d) Runtime assertion\n", fully_pathed_filename, line, column);
+			fmt.fprintf(os.stderr, "%s(%d:%d) Runtime assertion\n", fully_pathed_filename, line, column);
 		}
 		__debug_trap();
 	}
@@ -337,9 +329,9 @@ assert :: proc(condition: bool, message := "", using location := #caller_locatio
 
 panic :: proc(message := "", using location := #caller_location) #cc_contextless {
 	if len(message) > 0 {
-		fmt.printf("%s(%d:%d) Panic: %s\n", fully_pathed_filename, line, column, message);
+		fmt.fprintf(os.stderr, "%s(%d:%d) Panic: %s\n", fully_pathed_filename, line, column, message);
 	} else {
-		fmt.printf("%s(%d:%d) Panic\n", fully_pathed_filename, line, column);
+		fmt.fprintf(os.stderr, "%s(%d:%d) Panic\n", fully_pathed_filename, line, column);
 	}
 	__debug_trap();
 }
@@ -348,14 +340,10 @@ panic :: proc(message := "", using location := #caller_location) #cc_contextless
 
 
 __string_eq :: proc(a, b: string) -> bool #cc_contextless {
-	if len(a) != len(b) {
-		return false;
-	}
-	if len(a) == 0 {
-		return true;
-	}
-	if &a[0] == &b[0] {
-		return true;
+	match {
+	case len(a) != len(b): return false;
+	case len(a) == 0:      return true;
+	case &a[0] == &b[0]:   return true;
 	}
 	return __string_cmp(a, b) == 0;
 }
@@ -379,37 +367,30 @@ __complex128_ne :: proc(a, b: complex128) -> bool #cc_contextless #inline { retu
 
 
 __bounds_check_error :: proc(file: string, line, column: int, index, count: int) #cc_contextless {
-	if 0 <= index && index < count {
-		return;
-	}
+	if 0 <= index && index < count do return;
 	fmt.fprintf(os.stderr, "%s(%d:%d) Index %d is out of bounds range 0..<%d\n",
 	            file, line, column, index, count);
 	__debug_trap();
 }
 
 __slice_expr_error :: proc(file: string, line, column: int, low, high, max: int) #cc_contextless {
-	if 0 <= low && low <= high && high <= max {
-		return;
-	}
+	if 0 <= low && low <= high && high <= max do return;
 	fmt.fprintf(os.stderr, "%s(%d:%d) Invalid slice indices: [%d..<%d..<%d]\n",
 	            file, line, column, low, high, max);
 	__debug_trap();
 }
 
 __substring_expr_error :: proc(file: string, line, column: int, low, high: int) #cc_contextless {
-	if 0 <= low && low <= high {
-		return;
-	}
+	if 0 <= low && low <= high do return;
 	fmt.fprintf(os.stderr, "%s(%d:%d) Invalid substring indices: [%d..<%d]\n",
 	            file, line, column, low, high);
 	__debug_trap();
 }
 __type_assertion_check :: proc(ok: bool, file: string, line, column: int, from, to: ^TypeInfo) #cc_contextless {
-	if !ok {
-		fmt.fprintf(os.stderr, "%s(%d:%d) Invalid type_assertion from %T to %T\n",
-		            file, line, column, from, to);
-		__debug_trap();
-	}
+	if ok do return;
+	fmt.fprintf(os.stderr, "%s(%d:%d) Invalid type_assertion from %T to %T\n",
+	            file, line, column, from, to);
+	__debug_trap();
 }
 
 __string_decode_rune :: proc(s: string) -> (rune, int) #cc_contextless #inline {
@@ -499,7 +480,7 @@ __dynamic_array_make :: proc(array_: rawptr, elem_size, elem_align: int, len, ca
 __dynamic_array_reserve :: proc(array_: rawptr, elem_size, elem_align: int, cap: int) -> bool {
 	array := ^raw.DynamicArray(array_);
 
-	if cap <= array.cap -> return true;
+	if cap <= array.cap do return true;
 
 	// __check_context();
 	if array.allocator.procedure == nil {
@@ -512,7 +493,7 @@ __dynamic_array_reserve :: proc(array_: rawptr, elem_size, elem_align: int, cap:
 	allocator := array.allocator;
 
 	new_data := allocator.procedure(allocator.data, AllocatorMode.Resize, new_size, elem_align, array.data, old_size, 0);
-	if new_data == nil -> return false;
+	if new_data == nil do return false;
 
 	array.data = new_data;
 	array.cap = cap;
@@ -523,7 +504,7 @@ __dynamic_array_resize :: proc(array_: rawptr, elem_size, elem_align: int, len:
 	array := ^raw.DynamicArray(array_);
 
 	ok := __dynamic_array_reserve(array_, elem_size, elem_align, len);
-	if ok -> array.len = len;
+	if ok do array.len = len;
 	return ok;
 }
 
@@ -543,7 +524,7 @@ __dynamic_array_append :: proc(array_: rawptr, elem_size, elem_align: int,
 		ok = __dynamic_array_reserve(array, elem_size, elem_align, cap);
 	}
 	// TODO(bill): Better error handling for failed reservation
-	if !ok -> return array.len;
+	if !ok do return array.len;
 
 	data := ^u8(array.data);
 	assert(data != nil);
@@ -561,7 +542,7 @@ __dynamic_array_append_nothing :: proc(array_: rawptr, elem_size, elem_align: in
 		ok = __dynamic_array_reserve(array, elem_size, elem_align, cap);
 	}
 	// TODO(bill): Better error handling for failed reservation
-	if !ok -> return array.len;
+	if !ok do return array.len;
 
 	data := ^u8(array.data);
 	assert(data != nil);
@@ -650,7 +631,7 @@ __dynamic_map_rehash :: proc(using header: __MapHeader, new_count: int) {
 
 	__dynamic_array_resize(nm_hashes, size_of(int), align_of(int), new_count);
 	__dynamic_array_reserve(&nm.entries, entry_size, entry_align, m.entries.len);
-	for i in 0..<new_count -> nm.hashes[i] = -1;
+	for i in 0..<new_count do nm.hashes[i] = -1;
 
 	for i := 0; i < m.entries.len; i++ {
 		if len(nm.hashes) == 0 {
@@ -740,7 +721,7 @@ __dynamic_map_full :: proc(using h: __MapHeader) -> bool {
 
 __dynamic_map_hash_equal :: proc(h: __MapHeader, a, b: __MapKey) -> bool {
 	if a.hash == b.hash {
-		if h.is_key_string -> return a.str == b.str;
+		if h.is_key_string do return a.str == b.str;
 		return true;
 	}
 	return false;

+ 1 - 1
core/_soft_numbers.odin

@@ -98,7 +98,7 @@ __u128_quo_mod :: proc(a, b: u128, rem: ^u128) -> (quo: u128) #cc_c #link_name "
 		d >>= 1;
 	}
 
-	if rem != nil { rem^ = r; }
+	if rem != nil do rem^ = r;
 	return q;
 }
 

+ 2 - 2
core/decimal.odin

@@ -11,7 +11,7 @@ Decimal :: struct {
 
 decimal_to_string :: proc(buf: []u8, a: ^Decimal) -> string {
 	digit_zero :: proc(buf: []u8) -> int {
-		for _, i in buf -> buf[i] = '0';
+		for _, i in buf do buf[i] = '0';
 		return len(buf);
 	}
 
@@ -194,7 +194,7 @@ shift :: proc(a: ^Decimal, k: int) {
 can_round_up :: proc(a: ^Decimal, nd: int) -> bool {
 	if nd < 0 || nd >= a.count { return false ; }
 	if a.digits[nd] == '5' && nd+1 == a.count {
-		if a.trunc -> return true;
+		if a.trunc do return true;
 		return nd > 0 && (a.digits[nd-1]-'0')%2 != 0;
 	}
 

+ 33 - 33
core/fmt.odin

@@ -189,7 +189,7 @@ fprint_type :: proc(fd: os.Handle, info: ^TypeInfo) {
 }
 
 write_type :: proc(buf: ^StringBuffer, ti: ^TypeInfo) {
-	if ti == nil -> return;
+	if ti == nil do return;
 
 	using TypeInfo;
 	match info in ti {
@@ -240,7 +240,7 @@ write_type :: proc(buf: ^StringBuffer, ti: ^TypeInfo) {
 			t := info.params.(^Tuple);
 			write_string(buf, "(");
 			for t, i in t.types {
-				if i > 0 -> write_string(buf, ", ");
+				if i > 0 do write_string(buf, ", ");
 				write_type(buf, t);
 			}
 			write_string(buf, ")");
@@ -251,9 +251,9 @@ write_type :: proc(buf: ^StringBuffer, ti: ^TypeInfo) {
 		}
 	case Tuple:
 		count := len(info.names);
-		if count != 1 -> write_string(buf, "(");
+		if count != 1 do write_string(buf, "(");
 		for name, i in info.names {
-			if i > 0 -> write_string(buf, ", ");
+			if i > 0 do write_string(buf, ", ");
 
 			t := info.types[i];
 
@@ -263,7 +263,7 @@ write_type :: proc(buf: ^StringBuffer, ti: ^TypeInfo) {
 			}
 			write_type(buf, t);
 		}
-		if count != 1 -> write_string(buf, ")");
+		if count != 1 do write_string(buf, ")");
 
 	case Array:
 		write_string(buf, "[");
@@ -291,8 +291,8 @@ write_type :: proc(buf: ^StringBuffer, ti: ^TypeInfo) {
 
 	case Struct:
 		write_string(buf, "struct ");
-		if info.packed  -> write_string(buf, "#packed ");
-		if info.ordered -> write_string(buf, "#ordered ");
+		if info.packed  do write_string(buf, "#packed ");
+		if info.ordered do write_string(buf, "#ordered ");
 		if info.custom_align {
 			write_string(buf, "#align ");
 			write_int(buf, i64(info.align), 10);
@@ -300,7 +300,7 @@ write_type :: proc(buf: ^StringBuffer, ti: ^TypeInfo) {
 		}
 		write_byte(buf, '{');
 		for name, i in info.names {
-			if i > 0 -> write_string(buf, ", ");
+			if i > 0 do write_string(buf, ", ");
 			write_string(buf, name);
 			write_string(buf, ": ");
 			write_type(buf, info.types[i]);
@@ -312,14 +312,14 @@ write_type :: proc(buf: ^StringBuffer, ti: ^TypeInfo) {
 		cf := info.common_fields;
 		total_count := 0;
 		for name, i in cf.names {
-			if i > 0 -> write_string(buf, ", ");
+			if i > 0 do write_string(buf, ", ");
 			write_string(buf, name);
 			write_string(buf, ": ");
 			write_type(buf, cf.types[i]);
 			total_count++;
 		}
 		for name, i in info.variant_names {
-			if total_count > 0 || i > 0 -> write_string(buf, ", ");
+			if total_count > 0 || i > 0 do write_string(buf, ", ");
 			write_string(buf, name);
 			write_byte(buf, '{');
 			defer write_byte(buf, '}');
@@ -329,7 +329,7 @@ write_type :: proc(buf: ^StringBuffer, ti: ^TypeInfo) {
 
 			vc := len(variant.names)-len(cf.names);
 			for j in 0..<vc {
-				if j > 0 -> write_string(buf, ", ");
+				if j > 0 do write_string(buf, ", ");
 				index := j + len(cf.names);
 				write_string(buf, variant.names[index]);
 				write_string(buf, ": ");
@@ -341,7 +341,7 @@ write_type :: proc(buf: ^StringBuffer, ti: ^TypeInfo) {
 	case RawUnion:
 		write_string(buf, "raw_union {");
 		for name, i in info.names {
-			if i > 0 -> write_string(buf, ", ");
+			if i > 0 do write_string(buf, ", ");
 			write_string(buf, name);
 			write_string(buf, ": ");
 			write_type(buf, info.types[i]);
@@ -353,7 +353,7 @@ write_type :: proc(buf: ^StringBuffer, ti: ^TypeInfo) {
 		write_type(buf, info.base);
 		write_string(buf, " {");
 		for name, i in info.names {
-			if i > 0 -> write_string(buf, ", ");
+			if i > 0 do write_string(buf, ", ");
 			write_string(buf, name);
 		}
 		write_string(buf, "}");
@@ -366,7 +366,7 @@ write_type :: proc(buf: ^StringBuffer, ti: ^TypeInfo) {
 		}
 		write_string(buf, " {");
 		for name, i in info.names {
-			if i > 0 -> write_string(buf, ", ");
+			if i > 0 do write_string(buf, ", ");
 			write_string(buf, name);
 			write_string(buf, ": ");
 			write_int(buf, i64(info.bits[i]), 10);
@@ -388,7 +388,7 @@ _parse_int :: proc(s: string, offset: int) -> (result: int, offset: int, ok: boo
 	i := 0;
 	for i < len(s[offset..]) {
 		c := rune(s[offset+i]);
-		if !is_digit(c) -> break;
+		if !is_digit(c) do break;
 		i++;
 
 		result *= 10;
@@ -482,13 +482,13 @@ fmt_bool :: proc(using fi: ^FmtInfo, b: bool, verb: rune) {
 
 
 fmt_write_padding :: proc(fi: ^FmtInfo, width: int) {
-	if width <= 0 -> return;
+	if width <= 0 do return;
 
 	pad_byte: u8 = fi.space ? ' ' : '0';
 
 	data := string_buffer_data(fi.buf^);
 	count := min(width, cap(data)-len(data));
-	for _ in 0..<count -> write_byte(fi.buf, pad_byte);
+	for _ in 0..<count do write_byte(fi.buf, pad_byte);
 }
 
 _fmt_int :: proc(fi: ^FmtInfo, u: u128, base: int, is_signed: bool, bit_size: int, digits: string) {
@@ -533,9 +533,9 @@ _fmt_int :: proc(fi: ^FmtInfo, u: u128, base: int, is_signed: bool, bit_size: in
 
 
 	flags: strconv.IntFlag;
-	if fi.hash && !fi.zero -> flags |= strconv.IntFlag.Prefix;
-	if fi.plus             -> flags |= strconv.IntFlag.Plus;
-	if fi.space            -> flags |= strconv.IntFlag.Space;
+	if fi.hash && !fi.zero do flags |= strconv.IntFlag.Prefix;
+	if fi.plus             do flags |= strconv.IntFlag.Plus;
+	if fi.space            do flags |= strconv.IntFlag.Space;
 	s := strconv.append_bits(buf[start..<start], u128(u), base, is_signed, bit_size, digits, flags);
 
 	if fi.hash && fi.zero {
@@ -664,7 +664,7 @@ fmt_string :: proc(fi: ^FmtInfo, s: string, verb: rune) {
 		defer fi.space = space;
 
 		for i in 0..<len(s) {
-			if i > 0 && space -> write_byte(fi.buf, ' ');
+			if i > 0 && space do write_byte(fi.buf, ' ');
 			_fmt_int(fi, u128(s[i]), 16, false, 8, verb == 'x' ? __DIGITS_LOWER : __DIGITS_UPPER);
 		}
 
@@ -777,7 +777,7 @@ fmt_value :: proc(fi: ^FmtInfo, v: any, verb: rune) {
 			write_string(fi.buf, info.name);
 			write_byte(fi.buf, '{');
 			for _, i in b.names {
-				if i > 0 -> write_string(fi.buf, ", ");
+				if i > 0 do write_string(fi.buf, ", ");
 				write_string(fi.buf, b.names[i]);
 				write_string(fi.buf, " = ");
 
@@ -811,7 +811,7 @@ fmt_value :: proc(fi: ^FmtInfo, v: any, verb: rune) {
 		write_byte(fi.buf, '[');
 		defer write_byte(fi.buf, ']');
 		for i in 0..<info.count {
-			if i > 0 -> write_string(fi.buf, ", ");
+			if i > 0 do write_string(fi.buf, ", ");
 
 			data := ^u8(v.data) + i*info.elem_size;
 			fmt_arg(fi, any{rawptr(data), info.elem}, verb);
@@ -822,7 +822,7 @@ fmt_value :: proc(fi: ^FmtInfo, v: any, verb: rune) {
 		defer write_byte(fi.buf, ']');
 		array := ^raw.DynamicArray(v.data);
 		for i in 0..<array.len {
-			if i > 0 -> write_string(fi.buf, ", ");
+			if i > 0 do write_string(fi.buf, ", ");
 
 			data := ^u8(array.data) + i*info.elem_size;
 			fmt_arg(fi, any{rawptr(data), info.elem}, verb);
@@ -833,7 +833,7 @@ fmt_value :: proc(fi: ^FmtInfo, v: any, verb: rune) {
 		defer write_byte(fi.buf, ']');
 		slice := ^[]u8(v.data);
 		for _, i in slice {
-			if i > 0 -> write_string(fi.buf, ", ");
+			if i > 0 do write_string(fi.buf, ", ");
 
 			data := &slice[0] + i*info.elem_size;
 			fmt_arg(fi, any{rawptr(data), info.elem}, verb);
@@ -844,7 +844,7 @@ fmt_value :: proc(fi: ^FmtInfo, v: any, verb: rune) {
 		defer write_byte(fi.buf, '>');
 
 		for i in 0..<info.count {
-			if i > 0 -> write_string(fi.buf, ", ");
+			if i > 0 do write_string(fi.buf, ", ");
 
 			data := ^u8(v.data) + i*info.elem_size;
 			fmt_value(fi, any{rawptr(data), info.elem}, verb);
@@ -866,7 +866,7 @@ fmt_value :: proc(fi: ^FmtInfo, v: any, verb: rune) {
 		entry_size := ed.elem_size;
 
 		for i in 0..<entries.len {
-			if i > 0 -> write_string(fi.buf, ", ");
+			if i > 0 do write_string(fi.buf, ", ");
 
 			data := ^u8(entries.data) + i*entry_size;
 			header := ^__MapEntryHeader(data);
@@ -891,7 +891,7 @@ fmt_value :: proc(fi: ^FmtInfo, v: any, verb: rune) {
 		defer write_byte(fi.buf, '}');
 
 		for _, i in info.names {
-			if i > 0 -> write_string(fi.buf, ", ");
+			if i > 0 do write_string(fi.buf, ", ");
 
 			write_string(fi.buf, info.names[i]);
 			write_string(fi.buf, " = ");
@@ -905,7 +905,7 @@ fmt_value :: proc(fi: ^FmtInfo, v: any, verb: rune) {
 
 		cf := info.common_fields;
 		for _, i in cf.names {
-			if i > 0 -> write_string(fi.buf, ", ");
+			if i > 0 do write_string(fi.buf, ", ");
 
 			write_string(fi.buf, cf.names[i]);
 			write_string(fi.buf, " = ");
@@ -1028,7 +1028,7 @@ sbprintln :: proc(buf: ^StringBuffer, args: ..any) -> string {
 	fi.buf = buf;
 
 	for arg, i in args {
-		if i > 0 -> write_byte(buf, ' ');
+		if i > 0 do write_byte(buf, ' ');
 
 		fmt_value(&fi, args[i], 'v');
 	}
@@ -1155,10 +1155,10 @@ sbprintf :: proc(b: ^StringBuffer, fmt: string, args: ..any) -> string {
 	if !fi.reordered && arg_index < len(args) {
 		write_string(b, "%!(EXTRA ");
 		for arg, index in args[arg_index..] {
-			if index > 0 -> write_string(b, ", ");
+			if index > 0 do write_string(b, ", ");
 
-			if arg == nil -> write_string(b, "<nil>");
-			else          -> fmt_arg(&fi, args[index], 'v');
+			if arg == nil do write_string(b, "<nil>");
+			else          do fmt_arg(&fi, args[index], 'v');
 		}
 		write_string(b, ")");
 	}

+ 40 - 23
src/check_expr.cpp

@@ -1073,7 +1073,7 @@ void check_bit_field_type(Checker *c, Type *bit_field_type, Type *named_type, As
 	}
 }
 
-bool is_polymorphic_type_assignable(Checker *c, Type *poly, Type *source, bool compound) {
+bool is_polymorphic_type_assignable(Checker *c, Type *poly, Type *source, bool compound, bool modify_type) {
 	Operand o = {Addressing_Value};
 	o.type = source;
 	switch (poly->kind) {
@@ -1085,40 +1085,42 @@ bool is_polymorphic_type_assignable(Checker *c, Type *poly, Type *source, bool c
 		return check_is_assignable_to(c, &o, poly);
 
 	case Type_Generic: {
-		Type *ds = default_type(source);
-		gb_memmove(poly, ds, gb_size_of(Type));
+		if (modify_type) {
+			Type *ds = default_type(source);
+			gb_memmove(poly, ds, gb_size_of(Type));
+		}
 		return true;
 	}
 	case Type_Pointer:
 		if (source->kind == Type_Pointer) {
-			return is_polymorphic_type_assignable(c, poly->Pointer.elem, source->Pointer.elem, true);
+			return is_polymorphic_type_assignable(c, poly->Pointer.elem, source->Pointer.elem, true, modify_type);
 		}
 		return false;
 	case Type_Atomic:
 		if (source->kind == Type_Atomic) {
-			return is_polymorphic_type_assignable(c, poly->Atomic.elem, source->Atomic.elem, true);
+			return is_polymorphic_type_assignable(c, poly->Atomic.elem, source->Atomic.elem, true, modify_type);
 		}
 		return false;
 	case Type_Array:
 		if (source->kind == Type_Array &&
 		    poly->Array.count == source->Array.count) {
-			return is_polymorphic_type_assignable(c, poly->Array.elem, source->Array.elem, true);
+			return is_polymorphic_type_assignable(c, poly->Array.elem, source->Array.elem, true, modify_type);
 		}
 		return false;
 	case Type_DynamicArray:
 		if (source->kind == Type_DynamicArray) {
-			return is_polymorphic_type_assignable(c, poly->DynamicArray.elem, source->DynamicArray.elem, true);
+			return is_polymorphic_type_assignable(c, poly->DynamicArray.elem, source->DynamicArray.elem, true, modify_type);
 		}
 		return false;
 	case Type_Vector:
 		if (source->kind == Type_Vector &&
 		    poly->Vector.count == source->Vector.count) {
-			return is_polymorphic_type_assignable(c, poly->Vector.elem, source->Vector.elem, true);
+			return is_polymorphic_type_assignable(c, poly->Vector.elem, source->Vector.elem, true, modify_type);
 		}
 		return false;
 	case Type_Slice:
 		if (source->kind == Type_Slice) {
-			return is_polymorphic_type_assignable(c, poly->Slice.elem, source->Slice.elem, true);
+			return is_polymorphic_type_assignable(c, poly->Slice.elem, source->Slice.elem, true, modify_type);
 		}
 		return false;
 
@@ -1137,8 +1139,8 @@ bool is_polymorphic_type_assignable(Checker *c, Type *poly, Type *source, bool c
 		return false;
 	case Type_Map:
 		if (source->kind == Type_Map) {
-			bool key   = is_polymorphic_type_assignable(c, poly->Map.key, source->Map.key, true);
-			bool value = is_polymorphic_type_assignable(c, poly->Map.value, source->Map.value, true);
+			bool key   = is_polymorphic_type_assignable(c, poly->Map.key, source->Map.key, true, modify_type);
+			bool value = is_polymorphic_type_assignable(c, poly->Map.value, source->Map.value, true, modify_type);
 			return key || value;
 		}
 		return false;
@@ -1147,21 +1149,26 @@ bool is_polymorphic_type_assignable(Checker *c, Type *poly, Type *source, bool c
 }
 
 Type *determine_type_from_polymorphic(Checker *c, Type *poly_type, Operand operand) {
+	bool modify_type = !c->context.no_polymorphic_errors;
 	if (!is_operand_value(operand)) {
-		error(operand.expr, "Cannot determine polymorphic type from parameter");
+		if (modify_type) {
+			error(operand.expr, "Cannot determine polymorphic type from parameter");
+		}
 		return t_invalid;
 	}
-	if (is_polymorphic_type_assignable(c, poly_type, operand.type, false)) {
+	if (is_polymorphic_type_assignable(c, poly_type, operand.type, false, modify_type)) {
 		return poly_type;
 	}
-	gbString pts = type_to_string(poly_type);
-	gbString ots = type_to_string(operand.type);
-	defer (gb_string_free(pts));
-	defer (gb_string_free(ots));
-	error(operand.expr,
-	      "Cannot determine polymorphic type from parameter: `%s` to `%s`\n"
-	      "\tNote: Record and procedure types are not yet supported",
-	      ots, pts);
+	if (modify_type) {
+		gbString pts = type_to_string(poly_type);
+		gbString ots = type_to_string(operand.type);
+		defer (gb_string_free(pts));
+		defer (gb_string_free(ots));
+		error(operand.expr,
+		      "Cannot determine polymorphic type from parameter: `%s` to `%s`\n"
+		      "\tNote: Record and procedure types are not yet supported",
+		      ots, pts);
+	}
 	return t_invalid;
 }
 
@@ -1332,7 +1339,10 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
 						if (o.mode == Addressing_Type) {
 							type = o.type;
 						} else {
-							error(o.expr, "Expected a type to assign to the type parameter");
+							if (!c->context.no_polymorphic_errors) {
+								error(o.expr, "Expected a type to assign to the type parameter");
+							}
+							success = false;
 							type = t_invalid;
 						}
 					}
@@ -5338,7 +5348,9 @@ CALL_ARGUMENT_CHECKER(check_call_arguments_internal) {
 					if (o.mode == Addressing_Invalid) {
 						continue;
 					} else if (o.mode != Addressing_Type) {
-						error(o.expr, "Expected a type for the argument `%.*s`", LIT(e->token.string));
+						if (show_error) {
+							error(o.expr, "Expected a type for the argument `%.*s`", LIT(e->token.string));
+						}
 						err = CallArgumentError_WrongTypes;
 					}
 
@@ -5641,6 +5653,7 @@ CallArgumentData check_call_arguments(Checker *c, Operand *operand, Type *proc_t
 
 		for (isize i = 0; i < overload_count; i++) {
 			Entity *e = procs[i];
+			GB_ASSERT(e->token.string == name);
 			DeclInfo *d = decl_info_of_entity(&c->info, e);
 			GB_ASSERT(d != NULL);
 			check_entity_decl(c, e, d, NULL);
@@ -5651,7 +5664,11 @@ CallArgumentData check_call_arguments(Checker *c, Operand *operand, Type *proc_t
 			Type *pt = base_type(p->type);
 			if (pt != NULL && is_type_proc(pt)) {
 				CallArgumentData data = {};
+				bool prev = c->context.no_polymorphic_errors;
+				defer (c->context.no_polymorphic_errors = prev);
+				c->context.no_polymorphic_errors = true;
 				CallArgumentError err = call_checker(c, call, pt, p, operands, CallArgumentMode_NoErrors, &data);
+
 				if (err == CallArgumentError_None) {
 					valids[valid_count].index = i;
 					valids[valid_count].score = data.score;

+ 8 - 1
src/checker.cpp

@@ -262,6 +262,7 @@ struct CheckerContext {
 	u32        stmt_state_flags;
 	bool       in_defer; // TODO(bill): Actually handle correctly
 	bool       allow_polymorphic_types;
+	bool       no_polymorphic_errors;
 	String     proc_name;
 	Type *     type_hint;
 	DeclInfo * curr_proc_decl;
@@ -1474,8 +1475,10 @@ void check_procedure_overloading(Checker *c, Entity *e) {
 				is_invalid = true;
 				break;
 			case ProcOverload_Polymorphic:
+				#if 1
 				error(p->token, "Overloaded procedure `%.*s` has a polymorphic counterpart in this scope which is not allowed", LIT(name));
 				is_invalid = true;
+				#endif
 				break;
 			case ProcOverload_ParamCount:
 			case ProcOverload_ParamTypes:
@@ -1705,7 +1708,11 @@ void check_collect_entities(Checker *c, Array<AstNode *> nodes, bool is_file_sco
 					e->identifier = name;
 
 					if (fl != NULL && e->kind != Entity_Procedure) {
-						error(name, "Only procedures and variables are allowed to be in a foreign block, got %.*s", LIT(ast_node_strings[init->kind]));
+						AstNodeKind kind = init->kind;
+						error(name, "Only procedures and variables are allowed to be in a foreign block, got %.*s", LIT(ast_node_strings[kind]));
+						if (kind == AstNode_ProcType) {
+							gb_printf_err("\tDid you forget to append `---` to the procedure?\n");
+						}
 						// continue;
 					}
 

+ 1 - 0
src/entity.cpp

@@ -92,6 +92,7 @@ struct Entity {
 			bool       is_foreign;
 			Entity *   foreign_library;
 			AstNode *  foreign_library_ident;
+			String     link_name;
 		} Variable;
 		struct {
 			bool is_type_alias;

+ 36 - 12
src/parser.cpp

@@ -882,9 +882,13 @@ AstNode *clone_ast_node(gbAllocator a, AstNode *node) {
 
 
 void error(AstNode *node, char *fmt, ...) {
+	Token token = {};
+	if (node != NULL) {
+		token = ast_node_token(node);
+	}
 	va_list va;
 	va_start(va, fmt);
-	error_va(ast_node_token(node), fmt, va);
+	error_va(token, fmt, va);
 	va_end(va);
 }
 
@@ -2265,6 +2269,26 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
 			body = parse_body(f);
 			f->curr_proc = curr_proc;
 
+			return ast_proc_lit(f, type, body, tags, link_name);
+		} else if (allow_token(f, Token_do)) {
+			if ((tags & ProcTag_foreign) != 0) {
+				syntax_error(token, "A procedure tagged as `#foreign` cannot have a body");
+			}
+			AstNode *curr_proc = f->curr_proc;
+			AstNode *body = NULL;
+			f->curr_proc = type;
+			body = parse_stmt(f);
+			if (body->kind == AstNode_BlockStmt) {
+				syntax_error(body, "Expected a normal statement rather than a block statement");
+			} else {
+				Token open = ast_node_token(body);
+				Token close = ast_node_token(body);
+				Array<AstNode *> stmts = make_ast_node_array(f, 1);
+				array_add(&stmts, body);
+				body = ast_block_stmt(f, stmts, open, close);
+			}
+			f->curr_proc = curr_proc;
+
 			return ast_proc_lit(f, type, body, tags, link_name);
 		}
 
@@ -3787,7 +3811,7 @@ AstNode *parse_if_stmt(AstFile *f) {
 		syntax_error(f->curr_token, "Expected condition for if statement");
 	}
 
-	if (allow_token(f, Token_ArrowRight)) {
+	if (allow_token(f, Token_do)) {
 		body = parse_stmt(f);
 		if (body->kind == AstNode_BlockStmt) {
 			syntax_error(body, "Expected a normal statement rather than a block statement");
@@ -3804,8 +3828,8 @@ AstNode *parse_if_stmt(AstFile *f) {
 		case Token_OpenBrace:
 			else_stmt = parse_block_stmt(f, false);
 			break;
-		case Token_ArrowRight: {
-			Token arrow = expect_token(f, Token_ArrowRight);
+		case Token_do: {
+			Token arrow = expect_token(f, Token_do);
 			body = parse_stmt(f);
 			if (body->kind == AstNode_BlockStmt) {
 				syntax_error(body, "Expected a normal statement rather than a block statement");
@@ -3838,7 +3862,7 @@ AstNode *parse_when_stmt(AstFile *f) {
 		syntax_error(f->curr_token, "Expected condition for when statement");
 	}
 
-	if (allow_token(f, Token_ArrowRight)) {
+	if (allow_token(f, Token_do)) {
 		body = parse_stmt(f);
 		if (body->kind == AstNode_BlockStmt) {
 			syntax_error(body, "Expected a normal statement rather than a block statement");
@@ -3855,8 +3879,8 @@ AstNode *parse_when_stmt(AstFile *f) {
 		case Token_OpenBrace:
 			else_stmt = parse_block_stmt(f, true);
 			break;
-		case Token_ArrowRight: {
-			Token arrow = expect_token(f, Token_ArrowRight);
+		case Token_do: {
+			Token arrow = expect_token(f, Token_do);
 			body = parse_stmt(f);
 			if (body->kind == AstNode_BlockStmt) {
 				syntax_error(body, "Expected a normal statement rather than a block statement");
@@ -3958,7 +3982,7 @@ AstNode *parse_for_stmt(AstFile *f) {
 		}
 
 		if (!is_range && (f->curr_token.kind == Token_Semicolon ||
-		                  f->curr_token.kind == Token_ArrowRight)) {
+		                  f->curr_token.kind == Token_do)) {
 			next_token(f);
 			init = cond;
 			cond = NULL;
@@ -3967,7 +3991,7 @@ AstNode *parse_for_stmt(AstFile *f) {
 			}
 			expect_semicolon(f, cond);
 			if (f->curr_token.kind != Token_OpenBrace &&
-			    f->curr_token.kind != Token_ArrowRight) {
+			    f->curr_token.kind != Token_do) {
 				post = parse_simple_stmt(f, StmtAllowFlag_None);
 			}
 		}
@@ -3975,7 +3999,7 @@ AstNode *parse_for_stmt(AstFile *f) {
 		f->expr_level = prev_level;
 	}
 
-	if (allow_token(f, Token_ArrowRight)) {
+	if (allow_token(f, Token_do)) {
 		body = parse_stmt(f);
 		if (body->kind == AstNode_BlockStmt) {
 			syntax_error(body, "Expected a normal statement rather than a block statement");
@@ -4236,7 +4260,7 @@ AstNode *parse_stmt(AstFile *f) {
 		AstNode *expr = parse_expr(f, false);
 		f->expr_level = prev_level;
 
-		if (allow_token(f, Token_ArrowRight)) {
+		if (allow_token(f, Token_do)) {
 			body = parse_stmt(f);
 			if (body->kind == AstNode_BlockStmt) {
 				syntax_error(body, "Expected a normal statement rather than a block statement");
@@ -4256,7 +4280,7 @@ AstNode *parse_stmt(AstFile *f) {
 		AstNode *expr = parse_expr(f, false);
 		f->expr_level = prev_level;
 
-		if (allow_token(f, Token_ArrowRight)) {
+		if (allow_token(f, Token_do)) {
 			body = parse_stmt(f);
 			if (body->kind == AstNode_BlockStmt) {
 				syntax_error(body, "Expected a normal statement rather than a block statement");

+ 30 - 23
src/tokenizer.cpp

@@ -36,27 +36,28 @@ TOKEN_KIND(Token__OperatorBegin, "_OperatorBegin"), \
 	TOKEN_KIND(Token_CmpAnd, "&&"), \
 	TOKEN_KIND(Token_CmpOr,  "||"), \
 \
-TOKEN_KIND(Token__AssignOpBegin,      "_AssignOpBegin"), \
-	TOKEN_KIND(Token_AddEq,           "+="), \
-	TOKEN_KIND(Token_SubEq,           "-="), \
-	TOKEN_KIND(Token_MulEq,           "*="), \
-	TOKEN_KIND(Token_QuoEq,           "/="), \
-	TOKEN_KIND(Token_ModEq,           "%="), \
-	TOKEN_KIND(Token_ModModEq,        "%%="), \
-	TOKEN_KIND(Token_AndEq,           "&="), \
-	TOKEN_KIND(Token_OrEq,            "|="), \
-	TOKEN_KIND(Token_XorEq,           "~="), \
-	TOKEN_KIND(Token_AndNotEq,        "&~="), \
-	TOKEN_KIND(Token_ShlEq,           "<<="), \
-	TOKEN_KIND(Token_ShrEq,           ">>="), \
-	TOKEN_KIND(Token_CmpAndEq,        "&&="), \
-	TOKEN_KIND(Token_CmpOrEq,         "||="), \
-TOKEN_KIND(Token__AssignOpEnd,        "_AssignOpEnd"), \
-	TOKEN_KIND(Token_ArrowRight,      "->"), \
-	TOKEN_KIND(Token_ThickArrowRight, "=>"), \
-	TOKEN_KIND(Token_Inc,             "++"), \
-	TOKEN_KIND(Token_Dec,             "--"), \
-	TOKEN_KIND(Token_Undef,           "---"), \
+TOKEN_KIND(Token__AssignOpBegin, "_AssignOpBegin"), \
+	TOKEN_KIND(Token_AddEq,    "+="), \
+	TOKEN_KIND(Token_SubEq,    "-="), \
+	TOKEN_KIND(Token_MulEq,    "*="), \
+	TOKEN_KIND(Token_QuoEq,    "/="), \
+	TOKEN_KIND(Token_ModEq,    "%="), \
+	TOKEN_KIND(Token_ModModEq, "%%="), \
+	TOKEN_KIND(Token_AndEq,    "&="), \
+	TOKEN_KIND(Token_OrEq,     "|="), \
+	TOKEN_KIND(Token_XorEq,    "~="), \
+	TOKEN_KIND(Token_AndNotEq, "&~="), \
+	TOKEN_KIND(Token_ShlEq,    "<<="), \
+	TOKEN_KIND(Token_ShrEq,    ">>="), \
+	TOKEN_KIND(Token_CmpAndEq, "&&="), \
+	TOKEN_KIND(Token_CmpOrEq,  "||="), \
+TOKEN_KIND(Token__AssignOpEnd, "_AssignOpEnd"), \
+	TOKEN_KIND(Token_ArrowRight,       "->"), \
+	TOKEN_KIND(Token_ArrowLeft,        "<-"), \
+	TOKEN_KIND(Token_DoubleArrowRight, "=>"), \
+	TOKEN_KIND(Token_Inc,              "++"), \
+	TOKEN_KIND(Token_Dec,              "--"), \
+	TOKEN_KIND(Token_Undef,            "---"), \
 \
 TOKEN_KIND(Token__ComparisonBegin, "_ComparisonBegin"), \
 	TOKEN_KIND(Token_CmpEq, "=="), \
@@ -100,6 +101,7 @@ TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
 	TOKEN_KIND(Token_continue,               "continue"),               \
 	TOKEN_KIND(Token_fallthrough,            "fallthrough"),            \
 	TOKEN_KIND(Token_defer,                  "defer"),                  \
+	TOKEN_KIND(Token_do,                     "do"),                     \
 	TOKEN_KIND(Token_return,                 "return"),                 \
 	TOKEN_KIND(Token_proc,                   "proc"),                   \
 	TOKEN_KIND(Token_macro,                  "macro"),                  \
@@ -914,7 +916,7 @@ Token tokenizer_get_token(Tokenizer *t) {
 			token.kind = Token_Eq;
 			if (t->curr_rune == '>') {
 				advance_to_next_rune(t);
-				token.kind = Token_ThickArrowRight;
+				token.kind = Token_DoubleArrowRight;
 			} else if (t->curr_rune == '=') {
 				advance_to_next_rune(t);
 				token.kind = Token_CmpEq;
@@ -976,7 +978,12 @@ Token tokenizer_get_token(Tokenizer *t) {
 		} break;
 
 		case '<':
-			token.kind = token_kind_dub_eq(t, '<', Token_Lt, Token_LtEq, Token_Shl, Token_ShlEq);
+			if (t->curr_rune == '-') {
+				advance_to_next_rune(t);
+				token.kind = Token_ArrowLeft;
+			} else {
+				token.kind = token_kind_dub_eq(t, '<', Token_Lt, Token_LtEq, Token_Shl, Token_ShlEq);
+			}
 			break;
 		case '>': token.kind = token_kind_dub_eq(t, '>', Token_Gt, Token_GtEq, Token_Shr, Token_ShrEq); break;
 

+ 5 - 3
src/types.cpp

@@ -1353,14 +1353,16 @@ ProcTypeOverloadKind are_proc_types_overload_safe(Type *x, Type *y) {
 	TypeProc px = base_type(x)->Proc;
 	TypeProc py = base_type(y)->Proc;
 
-	// if (px.calling_convention != py.calling_convention) {
-		// return ProcOverload_CallingConvention;
-	// }
 
 	if (px.is_polymorphic != py.is_polymorphic) {
 		return ProcOverload_Polymorphic;
 	}
 
+
+	// if (px.calling_convention != py.calling_convention) {
+		// return ProcOverload_CallingConvention;
+	// }
+
 	if (px.param_count != py.param_count) {
 		return ProcOverload_ParamCount;
 	}