Browse Source

Default result values for procedure types; Named result values in `return` statements

Ginger Bill 8 years ago
parent
commit
8197c02dcf
10 changed files with 484 additions and 194 deletions
  1. 25 35
      core/_preload.odin
  2. 2 6
      core/decimal.odin
  3. 44 88
      core/fmt.odin
  4. 2 2
      misc/shell.bat
  5. 72 7
      src/check_expr.cpp
  6. 126 22
      src/check_stmt.cpp
  7. 33 0
      src/exact_value.cpp
  8. 82 8
      src/ir.cpp
  9. 90 25
      src/parser.cpp
  10. 8 1
      src/tokenizer.cpp

+ 25 - 35
core/_preload.odin

@@ -121,9 +121,8 @@ var (
 )
 )
 
 
 proc type_info_base(info: ^TypeInfo) -> ^TypeInfo {
 proc type_info_base(info: ^TypeInfo) -> ^TypeInfo {
-	if info == nil {
-		return nil;
-	}
+	if info == nil -> return nil;
+
 	var base = info;
 	var base = info;
 	match i in base {
 	match i in base {
 	case TypeInfo.Named:
 	case TypeInfo.Named:
@@ -134,9 +133,8 @@ proc type_info_base(info: ^TypeInfo) -> ^TypeInfo {
 
 
 
 
 proc type_info_base_without_enum(info: ^TypeInfo) -> ^TypeInfo {
 proc type_info_base_without_enum(info: ^TypeInfo) -> ^TypeInfo {
-	if info == nil {
-		return nil;
-	}
+	if info == nil -> return nil;
+
 	var base = info;
 	var base = info;
 	match i in base {
 	match i in base {
 	case TypeInfo.Named:
 	case TypeInfo.Named:
@@ -202,16 +200,20 @@ proc make_source_code_location(file: string, line, column: i64, procedure: strin
 const DEFAULT_ALIGNMENT = align_of([vector 4]f32);
 const DEFAULT_ALIGNMENT = align_of([vector 4]f32);
 
 
 proc __init_context_from_ptr(c: ^Context, other: ^Context) #cc_contextless {
 proc __init_context_from_ptr(c: ^Context, other: ^Context) #cc_contextless {
-	if c == nil {
-		return;
-	}
+	if c == nil -> return;
 	c^ = other^;
 	c^ = other^;
+
+	if c.allocator.procedure == nil {
+		c.allocator = default_allocator();
+	}
+	if c.thread_id == 0 {
+		c.thread_id = os.current_thread_id();
+	}
 }
 }
 
 
 proc __init_context(c: ^Context) #cc_contextless {
 proc __init_context(c: ^Context) #cc_contextless {
-	if c == nil {
-		return;
-	}
+	if c == nil -> return;
+
 	if c.allocator.procedure == nil {
 	if c.allocator.procedure == nil {
 		c.allocator = default_allocator();
 		c.allocator = default_allocator();
 	}
 	}
@@ -497,9 +499,7 @@ proc __dynamic_array_make(array_: rawptr, elem_size, elem_align: int, len, cap:
 proc __dynamic_array_reserve(array_: rawptr, elem_size, elem_align: int, cap: int) -> bool {
 proc __dynamic_array_reserve(array_: rawptr, elem_size, elem_align: int, cap: int) -> bool {
 	var array = ^raw.DynamicArray(array_);
 	var array = ^raw.DynamicArray(array_);
 
 
-	if cap <= array.cap {
-		return true;
-	}
+	if cap <= array.cap -> return true;
 
 
 	// __check_context();
 	// __check_context();
 	if array.allocator.procedure == nil {
 	if array.allocator.procedure == nil {
@@ -512,9 +512,7 @@ proc __dynamic_array_reserve(array_: rawptr, elem_size, elem_align: int, cap: in
 	var allocator = array.allocator;
 	var allocator = array.allocator;
 
 
 	var new_data = allocator.procedure(allocator.data, AllocatorMode.Resize, new_size, elem_align, array.data, old_size, 0);
 	var 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 -> return false;
 
 
 	array.data = new_data;
 	array.data = new_data;
 	array.cap = cap;
 	array.cap = cap;
@@ -525,9 +523,7 @@ proc __dynamic_array_resize(array_: rawptr, elem_size, elem_align: int, len: int
 	var array = ^raw.DynamicArray(array_);
 	var array = ^raw.DynamicArray(array_);
 
 
 	var ok = __dynamic_array_reserve(array_, elem_size, elem_align, len);
 	var ok = __dynamic_array_reserve(array_, elem_size, elem_align, len);
-	if ok {
-		array.len = len;
-	}
+	if ok -> array.len = len;
 	return ok;
 	return ok;
 }
 }
 
 
@@ -546,10 +542,9 @@ proc __dynamic_array_append(array_: rawptr, elem_size, elem_align: int,
 		var cap = 2 * array.cap + max(8, item_count);
 		var cap = 2 * array.cap + max(8, item_count);
 		ok = __dynamic_array_reserve(array, elem_size, elem_align, cap);
 		ok = __dynamic_array_reserve(array, elem_size, elem_align, cap);
 	}
 	}
-	if !ok {
-		// TODO(bill): Better error handling for failed reservation
-		return array.len;
-	}
+	// TODO(bill): Better error handling for failed reservation
+	if !ok -> return array.len;
+
 	var data = ^u8(array.data);
 	var data = ^u8(array.data);
 	assert(data != nil);
 	assert(data != nil);
 	__mem_copy(data + (elem_size*array.len), items, elem_size * item_count);
 	__mem_copy(data + (elem_size*array.len), items, elem_size * item_count);
@@ -565,10 +560,9 @@ proc __dynamic_array_append_nothing(array_: rawptr, elem_size, elem_align: int)
 		var cap = 2 * array.cap + max(8, 1);
 		var cap = 2 * array.cap + max(8, 1);
 		ok = __dynamic_array_reserve(array, elem_size, elem_align, cap);
 		ok = __dynamic_array_reserve(array, elem_size, elem_align, cap);
 	}
 	}
-	if !ok {
-		// TODO(bill): Better error handling for failed reservation
-		return array.len;
-	}
+	// TODO(bill): Better error handling for failed reservation
+	if !ok -> return array.len;
+
 	var data = ^u8(array.data);
 	var data = ^u8(array.data);
 	assert(data != nil);
 	assert(data != nil);
 	__mem_zero(data + (elem_size*array.len), elem_size);
 	__mem_zero(data + (elem_size*array.len), elem_size);
@@ -658,9 +652,7 @@ proc __dynamic_map_rehash(using header: __MapHeader, new_count: int) {
 
 
 	__dynamic_array_resize(nm_hashes, size_of(int), align_of(int), new_count);
 	__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);
 	__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 -> nm.hashes[i] = -1;
 
 
 	for var i = 0; i < m.entries.len; i++ {
 	for var i = 0; i < m.entries.len; i++ {
 		if len(nm.hashes) == 0 {
 		if len(nm.hashes) == 0 {
@@ -750,9 +742,7 @@ proc __dynamic_map_full(using h: __MapHeader) -> bool {
 
 
 proc __dynamic_map_hash_equal(h: __MapHeader, a, b: __MapKey) -> bool {
 proc __dynamic_map_hash_equal(h: __MapHeader, a, b: __MapKey) -> bool {
 	if a.hash == b.hash {
 	if a.hash == b.hash {
-		if h.is_key_string {
-			return a.str == b.str;
-		}
+		if h.is_key_string -> return a.str == b.str;
 		return true;
 		return true;
 	}
 	}
 	return false;
 	return false;

+ 2 - 6
core/decimal.odin

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

+ 44 - 88
core/fmt.odin

@@ -189,9 +189,7 @@ proc fprint_type(fd: os.Handle, info: ^TypeInfo) {
 }
 }
 
 
 proc write_type(buf: ^StringBuffer, ti: ^TypeInfo) {
 proc write_type(buf: ^StringBuffer, ti: ^TypeInfo) {
-	if ti == nil {
-		return;
-	}
+	if ti == nil -> return;
 
 
 	using TypeInfo;
 	using TypeInfo;
 	match info in ti {
 	match info in ti {
@@ -242,7 +240,7 @@ proc write_type(buf: ^StringBuffer, ti: ^TypeInfo) {
 			var t = info.params.(^Tuple);
 			var t = info.params.(^Tuple);
 			write_string(buf, "(");
 			write_string(buf, "(");
 			for t, i in t.types {
 			for t, i in t.types {
-				if i > 0 { write_string(buf, ", "); }
+				if i > 0 -> write_string(buf, ", ");
 				write_type(buf, t);
 				write_type(buf, t);
 			}
 			}
 			write_string(buf, ")");
 			write_string(buf, ")");
@@ -253,9 +251,9 @@ proc write_type(buf: ^StringBuffer, ti: ^TypeInfo) {
 		}
 		}
 	case Tuple:
 	case Tuple:
 		var count = len(info.names);
 		var count = len(info.names);
-		if count != 1 { write_string(buf, "("); }
+		if count != 1 -> write_string(buf, "(");
 		for name, i in info.names {
 		for name, i in info.names {
-			if i > 0 { write_string(buf, ", "); }
+			if i > 0 -> write_string(buf, ", ");
 
 
 			var t = info.types[i];
 			var t = info.types[i];
 
 
@@ -265,7 +263,7 @@ proc write_type(buf: ^StringBuffer, ti: ^TypeInfo) {
 			}
 			}
 			write_type(buf, t);
 			write_type(buf, t);
 		}
 		}
-		if count != 1 { write_string(buf, ")"); }
+		if count != 1 -> write_string(buf, ")");
 
 
 	case Array:
 	case Array:
 		write_string(buf, "[");
 		write_string(buf, "[");
@@ -293,8 +291,8 @@ proc write_type(buf: ^StringBuffer, ti: ^TypeInfo) {
 
 
 	case Struct:
 	case Struct:
 		write_string(buf, "struct ");
 		write_string(buf, "struct ");
-		if info.packed  { write_string(buf, "#packed "); }
-		if info.ordered { write_string(buf, "#ordered "); }
+		if info.packed  -> write_string(buf, "#packed ");
+		if info.ordered -> write_string(buf, "#ordered ");
 		if info.custom_align {
 		if info.custom_align {
 			write_string(buf, "#align ");
 			write_string(buf, "#align ");
 			write_int(buf, i64(info.align), 10);
 			write_int(buf, i64(info.align), 10);
@@ -302,9 +300,7 @@ proc write_type(buf: ^StringBuffer, ti: ^TypeInfo) {
 		}
 		}
 		write_byte(buf, '{');
 		write_byte(buf, '{');
 		for name, i in info.names {
 		for name, i in info.names {
-			if i > 0 {
-				write_string(buf, ", ");
-			}
+			if i > 0 -> write_string(buf, ", ");
 			write_string(buf, name);
 			write_string(buf, name);
 			write_string(buf, ": ");
 			write_string(buf, ": ");
 			write_type(buf, info.types[i]);
 			write_type(buf, info.types[i]);
@@ -316,18 +312,14 @@ proc write_type(buf: ^StringBuffer, ti: ^TypeInfo) {
 		var cf = info.common_fields;
 		var cf = info.common_fields;
 		var total_count = 0;
 		var total_count = 0;
 		for name, i in cf.names {
 		for name, i in cf.names {
-			if i > 0 {
-				write_string(buf, ", ");
-			}
+			if i > 0 -> write_string(buf, ", ");
 			write_string(buf, name);
 			write_string(buf, name);
 			write_string(buf, ": ");
 			write_string(buf, ": ");
 			write_type(buf, cf.types[i]);
 			write_type(buf, cf.types[i]);
 			total_count++;
 			total_count++;
 		}
 		}
 		for name, i in info.variant_names {
 		for name, i in info.variant_names {
-			if total_count > 0 || i > 0 {
-				write_string(buf, ", ");
-			}
+			if total_count > 0 || i > 0 -> write_string(buf, ", ");
 			write_string(buf, name);
 			write_string(buf, name);
 			write_byte(buf, '{');
 			write_byte(buf, '{');
 			defer write_byte(buf, '}');
 			defer write_byte(buf, '}');
@@ -337,9 +329,7 @@ proc write_type(buf: ^StringBuffer, ti: ^TypeInfo) {
 
 
 			var vc = len(variant.names)-len(cf.names);
 			var vc = len(variant.names)-len(cf.names);
 			for j in 0..vc {
 			for j in 0..vc {
-				if j > 0 {
-					write_string(buf, ", ");
-				}
+				if j > 0 -> write_string(buf, ", ");
 				var index = j + len(cf.names);
 				var index = j + len(cf.names);
 				write_string(buf, variant.names[index]);
 				write_string(buf, variant.names[index]);
 				write_string(buf, ": ");
 				write_string(buf, ": ");
@@ -351,9 +341,7 @@ proc write_type(buf: ^StringBuffer, ti: ^TypeInfo) {
 	case RawUnion:
 	case RawUnion:
 		write_string(buf, "raw_union {");
 		write_string(buf, "raw_union {");
 		for name, i in info.names {
 		for name, i in info.names {
-			if i > 0 {
-				write_string(buf, ", ");
-			}
+			if i > 0 -> write_string(buf, ", ");
 			write_string(buf, name);
 			write_string(buf, name);
 			write_string(buf, ": ");
 			write_string(buf, ": ");
 			write_type(buf, info.types[i]);
 			write_type(buf, info.types[i]);
@@ -365,9 +353,7 @@ proc write_type(buf: ^StringBuffer, ti: ^TypeInfo) {
 		write_type(buf, info.base);
 		write_type(buf, info.base);
 		write_string(buf, " {");
 		write_string(buf, " {");
 		for name, i in info.names {
 		for name, i in info.names {
-			if i > 0 {
-				write_string(buf, ", ");
-			}
+			if i > 0 -> write_string(buf, ", ");
 			write_string(buf, name);
 			write_string(buf, name);
 		}
 		}
 		write_string(buf, "}");
 		write_string(buf, "}");
@@ -380,9 +366,7 @@ proc write_type(buf: ^StringBuffer, ti: ^TypeInfo) {
 		}
 		}
 		write_string(buf, " {");
 		write_string(buf, " {");
 		for name, i in info.names {
 		for name, i in info.names {
-			if i > 0 {
-				write_string(buf, ", ");
-			}
+			if i > 0 -> write_string(buf, ", ");
 			write_string(buf, name);
 			write_string(buf, name);
 			write_string(buf, ": ");
 			write_string(buf, ": ");
 			write_int(buf, i64(info.bits[i]), 10);
 			write_int(buf, i64(info.bits[i]), 10);
@@ -404,9 +388,7 @@ proc _parse_int(s: string, offset: int) -> (result: int, offset: int, ok: bool)
 	var i = 0;
 	var i = 0;
 	for i < len(s[offset..]) {
 	for i < len(s[offset..]) {
 		var c = rune(s[offset+i]);
 		var c = rune(s[offset+i]);
-		if !is_digit(c) {
-			break;
-		}
+		if !is_digit(c) -> break;
 		i++;
 		i++;
 
 
 		result *= 10;
 		result *= 10;
@@ -500,19 +482,13 @@ proc fmt_bool(using fi: ^FmtInfo, b: bool, verb: rune) {
 
 
 
 
 proc fmt_write_padding(fi: ^FmtInfo, width: int) {
 proc fmt_write_padding(fi: ^FmtInfo, width: int) {
-	if width <= 0 {
-		return;
-	}
-	var pad_byte: u8 = '0';
-	if fi.space {
-		pad_byte = ' ';
-	}
+	if width <= 0 -> return;
+
+	var pad_byte: u8 = fi.space ? ' ' : '0';
 
 
 	var data = string_buffer_data(fi.buf^);
 	var data = string_buffer_data(fi.buf^);
 	var count = min(width, cap(data)-len(data));
 	var count = min(width, cap(data)-len(data));
-	for _ in 0..<count {
-		write_byte(fi.buf, pad_byte);
-	}
+	for _ in 0..<count -> write_byte(fi.buf, pad_byte);
 }
 }
 
 
 proc _fmt_int(fi: ^FmtInfo, u: u128, base: int, is_signed: bool, bit_size: int, digits: string) {
 proc _fmt_int(fi: ^FmtInfo, u: u128, base: int, is_signed: bool, bit_size: int, digits: string) {
@@ -557,9 +533,9 @@ proc _fmt_int(fi: ^FmtInfo, u: u128, base: int, is_signed: bool, bit_size: int,
 
 
 
 
 	var flags: strconv.IntFlag;
 	var 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 -> flags |= strconv.IntFlag.Prefix;
+	if fi.plus             -> flags |= strconv.IntFlag.Plus;
+	if fi.space            -> flags |= strconv.IntFlag.Space;
 	var s = strconv.append_bits(buf[start..<start], u128(u), base, is_signed, bit_size, digits, flags);
 	var s = strconv.append_bits(buf[start..<start], u128(u), base, is_signed, bit_size, digits, flags);
 
 
 	if fi.hash && fi.zero {
 	if fi.hash && fi.zero {
@@ -642,11 +618,8 @@ proc fmt_float(fi: ^FmtInfo, v: f64, bit_size: int, verb: rune) {
 	// case 'f', 'F', 'v':
 	// case 'f', 'F', 'v':
 
 
 	case 'f', 'F', 'v':
 	case 'f', 'F', 'v':
-		var prec: int = 3;
+		var prec: int = fi.prec_set ? fi.prec : 3;
 		var buf: [386]u8;
 		var buf: [386]u8;
-		if fi.prec_set {
-			prec = fi.prec;
-		}
 
 
 		var str = strconv.append_float(buf[1..<1], v, 'f', prec, bit_size);
 		var str = strconv.append_float(buf[1..<1], v, 'f', prec, bit_size);
 		str = string(buf[0..len(str)]);
 		str = string(buf[0..len(str)]);
@@ -692,9 +665,7 @@ proc fmt_string(fi: ^FmtInfo, s: string, verb: rune) {
 		defer fi.space = space;
 		defer fi.space = space;
 
 
 		for i in 0..<len(s) {
 		for i in 0..<len(s) {
-			if i > 0 && space {
-				write_byte(fi.buf, ' ');
-			}
+			if i > 0 && space -> write_byte(fi.buf, ' ');
 			_fmt_int(fi, u128(s[i]), 16, false, 8, verb == 'x' ? __DIGITS_LOWER : __DIGITS_UPPER);
 			_fmt_int(fi, u128(s[i]), 16, false, 8, verb == 'x' ? __DIGITS_LOWER : __DIGITS_UPPER);
 		}
 		}
 
 
@@ -810,9 +781,7 @@ proc fmt_value(fi: ^FmtInfo, v: any, verb: rune) {
 			write_string(fi.buf, info.name);
 			write_string(fi.buf, info.name);
 			write_byte(fi.buf, '{');
 			write_byte(fi.buf, '{');
 			for _, i in b.names {
 			for _, i in b.names {
-				if i > 0 {
-					write_string(fi.buf, ", ");
-				}
+				if i > 0 -> write_string(fi.buf, ", ");
 				write_string(fi.buf, b.names[i]);
 				write_string(fi.buf, b.names[i]);
 				write_string(fi.buf, " = ");
 				write_string(fi.buf, " = ");
 
 
@@ -846,9 +815,8 @@ proc fmt_value(fi: ^FmtInfo, v: any, verb: rune) {
 		write_byte(fi.buf, '[');
 		write_byte(fi.buf, '[');
 		defer write_byte(fi.buf, ']');
 		defer write_byte(fi.buf, ']');
 		for i in 0..<info.count {
 		for i in 0..<info.count {
-			if i > 0 {
-				write_string(fi.buf, ", ");
-			}
+			if i > 0 -> write_string(fi.buf, ", ");
+
 			var data = ^u8(v.data) + i*info.elem_size;
 			var data = ^u8(v.data) + i*info.elem_size;
 			fmt_arg(fi, any{rawptr(data), info.elem}, verb);
 			fmt_arg(fi, any{rawptr(data), info.elem}, verb);
 		}
 		}
@@ -858,9 +826,8 @@ proc fmt_value(fi: ^FmtInfo, v: any, verb: rune) {
 		defer write_byte(fi.buf, ']');
 		defer write_byte(fi.buf, ']');
 		var array = ^raw.DynamicArray(v.data);
 		var array = ^raw.DynamicArray(v.data);
 		for i in 0..<array.len {
 		for i in 0..<array.len {
-			if i > 0 {
-				write_string(fi.buf, ", ");
-			}
+			if i > 0 -> write_string(fi.buf, ", ");
+
 			var data = ^u8(array.data) + i*info.elem_size;
 			var data = ^u8(array.data) + i*info.elem_size;
 			fmt_arg(fi, any{rawptr(data), info.elem}, verb);
 			fmt_arg(fi, any{rawptr(data), info.elem}, verb);
 		}
 		}
@@ -870,9 +837,8 @@ proc fmt_value(fi: ^FmtInfo, v: any, verb: rune) {
 		defer write_byte(fi.buf, ']');
 		defer write_byte(fi.buf, ']');
 		var slice = ^[]u8(v.data);
 		var slice = ^[]u8(v.data);
 		for _, i in slice {
 		for _, i in slice {
-			if i > 0 {
-				write_string(fi.buf, ", ");
-			}
+			if i > 0 -> write_string(fi.buf, ", ");
+
 			var data = &slice[0] + i*info.elem_size;
 			var data = &slice[0] + i*info.elem_size;
 			fmt_arg(fi, any{rawptr(data), info.elem}, verb);
 			fmt_arg(fi, any{rawptr(data), info.elem}, verb);
 		}
 		}
@@ -882,9 +848,7 @@ proc fmt_value(fi: ^FmtInfo, v: any, verb: rune) {
 		defer write_byte(fi.buf, '>');
 		defer write_byte(fi.buf, '>');
 
 
 		for i in 0..<info.count {
 		for i in 0..<info.count {
-			if i > 0 {
-				write_string(fi.buf, ", ");
-			}
+			if i > 0 -> write_string(fi.buf, ", ");
 
 
 			var data = ^u8(v.data) + i*info.elem_size;
 			var data = ^u8(v.data) + i*info.elem_size;
 			fmt_value(fi, any{rawptr(data), info.elem}, verb);
 			fmt_value(fi, any{rawptr(data), info.elem}, verb);
@@ -906,9 +870,8 @@ proc fmt_value(fi: ^FmtInfo, v: any, verb: rune) {
 			entry_size = ed.elem_size;
 			entry_size = ed.elem_size;
 		)
 		)
 		for i in 0..<entries.len {
 		for i in 0..<entries.len {
-			if i > 0 {
-				write_string(fi.buf, ", ");
-			}
+			if i > 0 -> write_string(fi.buf, ", ");
+
 			var data = ^u8(entries.data) + i*entry_size;
 			var data = ^u8(entries.data) + i*entry_size;
 			var header = ^__MapEntryHeader(data);
 			var header = ^__MapEntryHeader(data);
 
 
@@ -932,9 +895,8 @@ proc fmt_value(fi: ^FmtInfo, v: any, verb: rune) {
 		defer write_byte(fi.buf, '}');
 		defer write_byte(fi.buf, '}');
 
 
 		for _, i in info.names {
 		for _, i in info.names {
-			if i > 0 {
-				write_string(fi.buf, ", ");
-			}
+			if i > 0 -> write_string(fi.buf, ", ");
+
 			write_string(fi.buf, info.names[i]);
 			write_string(fi.buf, info.names[i]);
 			write_string(fi.buf, " = ");
 			write_string(fi.buf, " = ");
 			var data = ^u8(v.data) + info.offsets[i];
 			var data = ^u8(v.data) + info.offsets[i];
@@ -947,9 +909,8 @@ proc fmt_value(fi: ^FmtInfo, v: any, verb: rune) {
 
 
 		var cf = info.common_fields;
 		var cf = info.common_fields;
 		for _, i in cf.names {
 		for _, i in cf.names {
-			if i > 0 {
-				write_string(fi.buf, ", ");
-			}
+			if i > 0 -> write_string(fi.buf, ", ");
+
 			write_string(fi.buf, cf.names[i]);
 			write_string(fi.buf, cf.names[i]);
 			write_string(fi.buf, " = ");
 			write_string(fi.buf, " = ");
 			var data = ^u8(v.data) + cf.offsets[i];
 			var data = ^u8(v.data) + cf.offsets[i];
@@ -1071,9 +1032,8 @@ proc sbprintln(buf: ^StringBuffer, args: ..any) -> string {
 	fi.buf = buf;
 	fi.buf = buf;
 
 
 	for arg, i in args {
 	for arg, i in args {
-		if i > 0 {
-			write_byte(buf, ' ');
-		}
+		if i > 0 -> write_byte(buf, ' ');
+
 		fmt_value(&fi, args[i], 'v');
 		fmt_value(&fi, args[i], 'v');
 	}
 	}
 	write_byte(buf, '\n');
 	write_byte(buf, '\n');
@@ -1200,14 +1160,10 @@ proc sbprintf(b: ^StringBuffer, fmt: string, args: ..any) -> string {
 	if !fi.reordered && arg_index < len(args) {
 	if !fi.reordered && arg_index < len(args) {
 		write_string(b, "%!(EXTRA ");
 		write_string(b, "%!(EXTRA ");
 		for arg, index in args[arg_index..] {
 		for arg, index in args[arg_index..] {
-			if index > 0 {
-				write_string(b, ", ");
-			}
-			if arg == nil {
-				write_string(b, "<nil>");
-			} else {
-				fmt_arg(&fi, args[index], 'v');
-			}
+			if index > 0 -> write_string(b, ", ");
+
+			if arg == nil -> write_string(b, "<nil>");
+			else          -> fmt_arg(&fi, args[index], 'v');
 		}
 		}
 		write_string(b, ")");
 		write_string(b, ")");
 	}
 	}

+ 2 - 2
misc/shell.bat

@@ -1,10 +1,10 @@
 @echo off
 @echo off
 
 
 rem call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" x86 1> NUL
 rem call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" x86 1> NUL
-rem call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" x64 1> NUL
+call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" x64 1> NUL
 rem call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x64 1> NUL
 rem call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x64 1> NUL
 rem call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" x86 1> NUL
 rem call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" x86 1> NUL
-call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" x64 1> NUL
+rem call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" x64 1> NUL
 set _NO_DEBUG_HEAP=1
 set _NO_DEBUG_HEAP=1
 
 
 set path=w:\Odin\misc;%path%
 set path=w:\Odin\misc;%path%

+ 72 - 7
src/check_expr.cpp

@@ -1221,15 +1221,64 @@ Type *check_get_results(Checker *c, Scope *scope, AstNode *_results) {
 	isize variable_index = 0;
 	isize variable_index = 0;
 	for_array(i, results) {
 	for_array(i, results) {
 		ast_node(field, Field, results[i]);
 		ast_node(field, Field, results[i]);
-		Type *type = check_type(c, field->type);
+		AstNode *default_value = unparen_expr(field->default_value);
+		ExactValue value = {};
+		bool default_is_nil = false;
+
+		Type *type = NULL;
+		if (field->type == NULL) {
+			Operand o = {};
+			check_expr(c, &o, default_value);
+			if (is_operand_nil(o)) {
+				default_is_nil = true;
+			} else if (o.mode != Addressing_Constant) {
+				error(default_value, "Default parameter must be a constant");
+			} else {
+				value = o.value;
+			}
+
+			type = default_type(o.type);
+		} else {
+			type = check_type(c, field->type);
+
+			if (default_value != NULL) {
+				Operand o = {};
+				check_expr_with_type_hint(c, &o, default_value, type);
+
+				if (is_operand_nil(o)) {
+					default_is_nil = true;
+				} else if (o.mode != Addressing_Constant) {
+					error(default_value, "Default parameter must be a constant");
+				} else {
+					value = o.value;
+				}
+				check_is_assignable_to(c, &o, type);
+			}
+		}
+
+		if (type == NULL) {
+			error(results[i], "Invalid parameter type");
+			type = t_invalid;
+		}
+		if (is_type_untyped(type)) {
+			error(results[i], "Cannot determine parameter type from a nil");
+			type = t_invalid;
+		}
+
+
 		if (field->names.count == 0) {
 		if (field->names.count == 0) {
 			Token token = ast_node_token(field->type);
 			Token token = ast_node_token(field->type);
 			token.string = str_lit("");
 			token.string = str_lit("");
 			Entity *param = make_entity_param(c->allocator, scope, token, type, false, false);
 			Entity *param = make_entity_param(c->allocator, scope, token, type, false, false);
+			param->Variable.default_value = value;
+			param->Variable.default_is_nil = default_is_nil;
 			variables[variable_index++] = param;
 			variables[variable_index++] = param;
 		} else {
 		} else {
 			for_array(j, field->names) {
 			for_array(j, field->names) {
-				Token token = ast_node_token(field->type);
+				Token token = ast_node_token(results[i]);
+				if (field->type != NULL) {
+					token = ast_node_token(field->type);
+				}
 				token.string = str_lit("");
 				token.string = str_lit("");
 
 
 				AstNode *name = field->names[j];
 				AstNode *name = field->names[j];
@@ -1240,6 +1289,8 @@ Type *check_get_results(Checker *c, Scope *scope, AstNode *_results) {
 				}
 				}
 
 
 				Entity *param = make_entity_param(c->allocator, scope, token, type, false, false);
 				Entity *param = make_entity_param(c->allocator, scope, token, type, false, false);
+				param->Variable.default_value = value;
+				param->Variable.default_is_nil = default_is_nil;
 				variables[variable_index++] = param;
 				variables[variable_index++] = param;
 			}
 			}
 		}
 		}
@@ -5002,6 +5053,20 @@ isize lookup_procedure_parameter(TypeProc *pt, String parameter_name) {
 	}
 	}
 	return -1;
 	return -1;
 }
 }
+isize lookup_procedure_result(TypeProc *pt, String result_name) {
+	isize result_count = pt->result_count;
+	for (isize i = 0; i < result_count; i++) {
+		Entity *e = pt->results->Tuple.variables[i];
+		String name = e->token.string;
+		if (name == "_") {
+			continue;
+		}
+		if (name == result_name) {
+			return i;
+		}
+	}
+	return -1;
+}
 
 
 CALL_ARGUMENT_CHECKER(check_named_call_arguments) {
 CALL_ARGUMENT_CHECKER(check_named_call_arguments) {
 	ast_node(ce, CallExpr, call);
 	ast_node(ce, CallExpr, call);
@@ -5013,7 +5078,7 @@ CALL_ARGUMENT_CHECKER(check_named_call_arguments) {
 	CallArgumentError err = CallArgumentError_None;
 	CallArgumentError err = CallArgumentError_None;
 
 
 	isize param_count = pt->param_count;
 	isize param_count = pt->param_count;
-	bool *params_visited = gb_alloc_array(c->allocator, bool, param_count);
+	bool *visited = gb_alloc_array(c->allocator, bool, param_count);
 
 
 	for_array(i, ce->args) {
 	for_array(i, ce->args) {
 		AstNode *arg = ce->args[i];
 		AstNode *arg = ce->args[i];
@@ -5036,7 +5101,7 @@ CALL_ARGUMENT_CHECKER(check_named_call_arguments) {
 			err = CallArgumentError_ParameterNotFound;
 			err = CallArgumentError_ParameterNotFound;
 			continue;
 			continue;
 		}
 		}
-		if (params_visited[index]) {
+		if (visited[index]) {
 			if (show_error) {
 			if (show_error) {
 				error(arg, "Duplicate parameter `%.*s` in procedure call", LIT(name));
 				error(arg, "Duplicate parameter `%.*s` in procedure call", LIT(name));
 			}
 			}
@@ -5044,7 +5109,7 @@ CALL_ARGUMENT_CHECKER(check_named_call_arguments) {
 			continue;
 			continue;
 		}
 		}
 
 
-		params_visited[index] = true;
+		visited[index] = true;
 		Operand *o = &operands[i];
 		Operand *o = &operands[i];
 		Entity *e = pt->params->Tuple.variables[index];
 		Entity *e = pt->params->Tuple.variables[index];
 
 
@@ -5076,7 +5141,7 @@ CALL_ARGUMENT_CHECKER(check_named_call_arguments) {
 		param_count_to_check--;
 		param_count_to_check--;
 	}
 	}
 	for (isize i = 0; i < param_count_to_check; i++) {
 	for (isize i = 0; i < param_count_to_check; i++) {
-		if (!params_visited[i]) {
+		if (!visited[i]) {
 			Entity *e = pt->params->Tuple.variables[i];
 			Entity *e = pt->params->Tuple.variables[i];
 			if (e->token.string == "_") {
 			if (e->token.string == "_") {
 				continue;
 				continue;
@@ -5095,7 +5160,7 @@ CALL_ARGUMENT_CHECKER(check_named_call_arguments) {
 			if (show_error) {
 			if (show_error) {
 				gbString str = type_to_string(e->type);
 				gbString str = type_to_string(e->type);
 				error(call, "Parameter `%.*s` of type `%s` is missing in procedure call",
 				error(call, "Parameter `%.*s` of type `%s` is missing in procedure call",
-				           LIT(e->token.string), str);
+				      LIT(e->token.string), str);
 				gb_string_free(str);
 				gb_string_free(str);
 			}
 			}
 			err = CallArgumentError_ParameterMissing;
 			err = CallArgumentError_ParameterMissing;

+ 126 - 22
src/check_stmt.cpp

@@ -786,37 +786,141 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
 			break;
 			break;
 		}
 		}
 
 
+		bool first_is_field_value = false;
+		if (rs->results.count > 0) {
+			bool fail = false;
+			first_is_field_value = (rs->results[0]->kind == AstNode_FieldValue);
+			for_array(i, rs->results) {
+				AstNode *arg = rs->results[i];
+				bool mix = false;
+				if (first_is_field_value) {
+					mix = arg->kind != AstNode_FieldValue;
+				} else {
+					mix = arg->kind == AstNode_FieldValue;
+				}
+				if (mix) {
+					error(arg, "Mixture of `field = value` and value elements in a procedure all is not allowed");
+					fail = true;
+				}
+			}
+
+			if (fail) {
+				return;
+			}
+		}
+
 
 
 		Type *proc_type = c->proc_stack[c->proc_stack.count-1];
 		Type *proc_type = c->proc_stack[c->proc_stack.count-1];
+		TypeProc *pt = &proc_type->Proc;
 		isize result_count = 0;
 		isize result_count = 0;
-		if (proc_type->Proc.results) {
+		if (pt->results) {
 			result_count = proc_type->Proc.results->Tuple.variable_count;
 			result_count = proc_type->Proc.results->Tuple.variable_count;
 		}
 		}
 
 
-		if (result_count > 0) {
-			Entity **variables = NULL;
-			if (proc_type->Proc.results != NULL) {
-				TypeTuple *tuple = &proc_type->Proc.results->Tuple;
-				variables = tuple->variables;
+
+		isize result_count_excluding_defaults = result_count;
+		for (isize i = result_count-1; i >= 0; i--) {
+			Entity *e = pt->results->Tuple.variables[i];
+			if (e->kind == Entity_TypeName) {
+				break;
+			}
+
+			GB_ASSERT(e->kind == Entity_Variable);
+			if (e->Variable.default_value.kind != ExactValue_Invalid ||
+			    e->Variable.default_is_nil) {
+				result_count_excluding_defaults--;
+				continue;
+			}
+			break;
+		}
+
+		Array<Operand> operands = {};
+		defer (array_free(&operands));
+
+		if (first_is_field_value) {
+			array_init_count(&operands, heap_allocator(), rs->results.count);
+			for_array(i, rs->results) {
+				AstNode *arg = rs->results[i];
+				ast_node(fv, FieldValue, arg);
+				check_expr(c, &operands[i], fv->value);
 			}
 			}
-			if (rs->results.count == 0) {
-				error(node, "Expected %td return values, got 0", result_count);
+		} else {
+			array_init(&operands, heap_allocator(), 2*rs->results.count);
+			check_unpack_arguments(c, -1, &operands, rs->results, false);
+		}
+
+
+		if (first_is_field_value) {
+			bool *visited = gb_alloc_array(c->allocator, bool, result_count);
+
+			for_array(i, rs->results) {
+				AstNode *arg = rs->results[i];
+				ast_node(fv, FieldValue, arg);
+				if (fv->field->kind != AstNode_Ident) {
+					gbString expr_str = expr_to_string(fv->field);
+					error(arg, "Invalid parameter name `%s` in return statement", expr_str);
+					gb_string_free(expr_str);
+					continue;
+				}
+				String name = fv->field->Ident.string;
+				isize index = lookup_procedure_result(pt, name);
+				if (index < 0) {
+					error(arg, "No result named `%.*s` for this procedure type", LIT(name));
+					continue;
+				}
+				if (visited[index]) {
+					error(arg, "Duplicate result `%.*s` in return statement", LIT(name));
+					continue;
+				}
+
+				visited[index] = true;
+				Operand *o = &operands[i];
+				Entity *e = pt->results->Tuple.variables[index];
+				check_assignment(c, &operands[i], e->type, str_lit("return statement"));
+			}
+
+			for (isize i = 0; i < result_count; i++) {
+				if (!visited[i]) {
+					Entity *e = pt->results->Tuple.variables[i];
+					if (e->token.string == "_") {
+						continue;
+					}
+					GB_ASSERT(e->kind == Entity_Variable);
+					if (e->Variable.default_value.kind != ExactValue_Invalid) {
+						continue;
+					}
+
+					if (e->Variable.default_is_nil) {
+						continue;
+					}
+
+					gbString str = type_to_string(e->type);
+					error(node, "Return value `%.*s` of type `%s` is missing in return statement",
+					      LIT(e->token.string), str);
+					gb_string_free(str);
+				}
+			}
+		} else {
+			// TODO(bill): Cleanup this checking of variables
+			if (result_count == 0 && rs->results.count > 0) {
+				error(rs->results[0], "No return values expected");
+			} else if (operands.count > result_count) {
+				error(node, "Expected a maximum of %td return values, got %td", result_count, operands.count);
+			} else if (operands.count < result_count_excluding_defaults) {
+				error(node, "Expected %td return values, got %td", result_count_excluding_defaults, operands.count);
+			} else if (result_count_excluding_defaults == 0) {
+				return;
+			} else if (rs->results.count == 0) {
+				error(node, "Expected %td return values, got 0", result_count_excluding_defaults);
 			} else {
 			} else {
-				// TokenPos pos = rs->token.pos;
-				// if (pos.line == 10) {
-				// 	gb_printf_err("%s\n", type_to_string(variables[0]->type));
-				// }
-				check_init_variables(c, variables, result_count,
-				                     rs->results, str_lit("return statement"));
-				// if (pos.line == 10) {
-				// 	AstNode *x = rs->results[0];
-				// 	gb_printf_err("%s\n", expr_to_string(x));
-				// 	gb_printf_err("%s\n", type_to_string(type_of_expr(&c->info, x)));
-				// }
-			}
-		} else if (rs->results.count > 0) {
-			error(rs->results[0], "No return values expected");
+				isize max_count = rs->results.count;
+				for (isize i = 0; i < max_count; i++) {
+					Entity *e = pt->results->Tuple.variables[i];
+					check_assignment(c, &operands[i], e->type, str_lit("return statement"));
+				}
+			}
 		}
 		}
+
 	case_end;
 	case_end;
 
 
 	case_ast_node(fs, ForStmt, node);
 	case_ast_node(fs, ForStmt, node);

+ 33 - 0
src/exact_value.cpp

@@ -117,6 +117,39 @@ f64 float_from_string(String string) {
 		i++;
 		i++;
 	}
 	}
 
 
+#if 0
+	if (len-i > 2 &&
+	    str[i] == '0' &&
+	    str[i+1] == 'h') {
+		i += 2;
+		u8 *text = string.text;
+		isize len = string.len;
+		if (has_prefix) {
+			text += 2;
+			len -= 2;
+		}
+
+		u64 base = 16;
+
+		u64 result = {0};
+		for (isize i = 0; i < len; i++) {
+			Rune r = cast(Rune)text[i];
+			if (r == '_') {
+				continue;
+			}
+			u64 v = bit128__digit_value(r);
+			if (v >= base) {
+				break;
+			}
+			result *= base;
+			result += v;
+		}
+
+
+		return *cast(f64 *)&result;
+	}
+#endif
+
 	f64 value = 0.0;
 	f64 value = 0.0;
 	for (; i < len; i++) {
 	for (; i < len; i++) {
 		Rune r = cast(Rune)str[i];
 		Rune r = cast(Rune)str[i];

+ 82 - 8
src/ir.cpp

@@ -6120,21 +6120,81 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
 	case_ast_node(rs, ReturnStmt, node);
 	case_ast_node(rs, ReturnStmt, node);
 		ir_emit_comment(proc, str_lit("ReturnStmt"));
 		ir_emit_comment(proc, str_lit("ReturnStmt"));
 		irValue *v = NULL;
 		irValue *v = NULL;
-		TypeTuple *return_type_tuple  = &proc->type->Proc.results->Tuple;
+		TypeTuple *tuple  = &proc->type->Proc.results->Tuple;
 		isize return_count = proc->type->Proc.result_count;
 		isize return_count = proc->type->Proc.result_count;
-		if (return_count == 0) {
+		isize res_count = rs->results.count;
+
+		if (res_count > 0 &&
+		    rs->results[0]->kind == AstNode_FieldValue) {
+			gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&proc->module->tmp_arena);
+			defer (gb_temp_arena_memory_end(tmp));
+
+			Array<irValue *> results;
+			array_init_count(&results, proc->module->tmp_allocator, return_count);
+
+			for_array(arg_index, rs->results) {
+				AstNode *arg = rs->results[arg_index];
+				ast_node(fv, FieldValue, arg);
+				GB_ASSERT(fv->field->kind == AstNode_Ident);
+				String name = fv->field->Ident.string;
+				isize index = lookup_procedure_result(&proc->type->Proc, name);
+				GB_ASSERT(index >= 0);
+				irValue *expr = ir_build_expr(proc, fv->value);
+				results[index] = expr;
+			}
+			for (isize i = 0; i < return_count; i++) {
+				Entity *e = tuple->variables[i];
+				GB_ASSERT(e->kind == Entity_Variable);
+				if (results[i] == NULL) {
+					if (e->Variable.default_value.kind != ExactValue_Invalid) {
+						results[i] = ir_value_constant(proc->module->allocator, e->type, e->Variable.default_value);
+					} else {
+						results[i] = ir_value_nil(proc->module->allocator, e->type);
+					}
+				} else {
+					results[i] = ir_emit_conv(proc, results[i], e->type);
+				}
+			}
+
+			if (results.count == 1) {
+				v = results[0];
+			} else {
+				GB_ASSERT(results.count == return_count);
+
+				Type *ret_type = proc->type->Proc.results;
+				v = ir_add_local_generated(proc, ret_type);
+				for_array(i, results) {
+					irValue *field = ir_emit_struct_ep(proc, v, i);
+					irValue *res = results[i];
+					ir_emit_store(proc, field, res);
+				}
+
+				v = ir_emit_load(proc, v);
+			}
+		} else if (return_count == 0) {
 			// No return values
 			// No return values
 		} else if (return_count == 1) {
 		} else if (return_count == 1) {
-			Entity *e = return_type_tuple->variables[0];
-			v = ir_build_expr(proc, rs->results[0]);
-			v = ir_emit_conv(proc, v, e->type);
+			Entity *e = tuple->variables[0];
+			if (res_count == 0) {
+				if (e->Variable.default_value.kind != ExactValue_Invalid) {
+					v = ir_value_constant(proc->module->allocator, e->type, e->Variable.default_value);
+				} else {
+					v = ir_value_nil(proc->module->allocator, e->type);
+				}
+			} else {
+				v = ir_build_expr(proc, rs->results[0]);
+				v = ir_emit_conv(proc, v, e->type);
+			}
 		} else {
 		} else {
 			gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&proc->module->tmp_arena);
 			gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&proc->module->tmp_arena);
+			defer (gb_temp_arena_memory_end(tmp));
 
 
 			Array<irValue *> results;
 			Array<irValue *> results;
 			array_init(&results, proc->module->tmp_allocator, return_count);
 			array_init(&results, proc->module->tmp_allocator, return_count);
 
 
-			for_array(res_index, rs->results) {
+			isize total_index = 0;
+			isize res_index = 0;
+			for (; res_index < res_count; res_index++) {
 				irValue *res = ir_build_expr(proc, rs->results[res_index]);
 				irValue *res = ir_build_expr(proc, rs->results[res_index]);
 				Type *t = ir_type(res);
 				Type *t = ir_type(res);
 				if (t->kind == Type_Tuple) {
 				if (t->kind == Type_Tuple) {
@@ -6142,16 +6202,31 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
 						Entity *e = t->Tuple.variables[i];
 						Entity *e = t->Tuple.variables[i];
 						irValue *v = ir_emit_struct_ev(proc, res, i);
 						irValue *v = ir_emit_struct_ev(proc, res, i);
 						array_add(&results, v);
 						array_add(&results, v);
+						total_index++;
 					}
 					}
 				} else {
 				} else {
 					array_add(&results, res);
 					array_add(&results, res);
+					total_index++;
+				}
+			}
+			while (total_index < return_count) {
+				Entity *e = tuple->variables[total_index];
+				irValue *res = NULL;
+				if (e->Variable.default_value.kind != ExactValue_Invalid) {
+					res = ir_value_constant(proc->module->allocator, e->type, e->Variable.default_value);
+				} else {
+					res = ir_value_nil(proc->module->allocator, e->type);
 				}
 				}
+				array_add(&results, res);
+				total_index++;
 			}
 			}
 
 
+			GB_ASSERT(results.count == return_count);
+
 			Type *ret_type = proc->type->Proc.results;
 			Type *ret_type = proc->type->Proc.results;
 			v = ir_add_local_generated(proc, ret_type);
 			v = ir_add_local_generated(proc, ret_type);
 			for_array(i, results) {
 			for_array(i, results) {
-				Entity *e = return_type_tuple->variables[i];
+				Entity *e = tuple->variables[i];
 				irValue *res = ir_emit_conv(proc, results[i], e->type);
 				irValue *res = ir_emit_conv(proc, results[i], e->type);
 				irValue *field = ir_emit_struct_ep(proc, v, i);
 				irValue *field = ir_emit_struct_ep(proc, v, i);
 				ir_emit_store(proc, field, res);
 				ir_emit_store(proc, field, res);
@@ -6159,7 +6234,6 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
 
 
 			v = ir_emit_load(proc, v);
 			v = ir_emit_load(proc, v);
 
 
-			gb_temp_arena_memory_end(tmp);
 		}
 		}
 
 
 		ir_emit_return(proc, v);
 		ir_emit_return(proc, v);

+ 90 - 25
src/parser.cpp

@@ -3158,7 +3158,7 @@ AstNode *parse_block_stmt(AstFile *f, b32 is_when) {
 	return parse_body(f);
 	return parse_body(f);
 }
 }
 
 
-AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKind follow);
+AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKind follow, bool allow_default_parameters);
 
 
 
 
 AstNode *parse_results(AstFile *f) {
 AstNode *parse_results(AstFile *f) {
@@ -3170,7 +3170,7 @@ AstNode *parse_results(AstFile *f) {
 		CommentGroup empty_group = {};
 		CommentGroup empty_group = {};
 		Token begin_token = f->curr_token;
 		Token begin_token = f->curr_token;
 		Array<AstNode *> empty_names = {};
 		Array<AstNode *> empty_names = {};
-		Array<AstNode *> list = make_ast_node_array(f);
+		Array<AstNode *> list = make_ast_node_array(f, 1);
 		AstNode *type = parse_type(f);
 		AstNode *type = parse_type(f);
 		array_add(&list, ast_field(f, empty_names, type, NULL, 0, empty_group, empty_group));
 		array_add(&list, ast_field(f, empty_names, type, NULL, 0, empty_group, empty_group));
 		return ast_field_list(f, begin_token, list);
 		return ast_field_list(f, begin_token, list);
@@ -3178,7 +3178,7 @@ AstNode *parse_results(AstFile *f) {
 
 
 	AstNode *list = NULL;
 	AstNode *list = NULL;
 	expect_token(f, Token_OpenParen);
 	expect_token(f, Token_OpenParen);
-	list = parse_field_list(f, NULL, 0, Token_CloseParen);
+	list = parse_field_list(f, NULL, 0, Token_CloseParen, true);
 	expect_token_after(f, Token_CloseParen, "parameter list");
 	expect_token_after(f, Token_CloseParen, "parameter list");
 	return list;
 	return list;
 }
 }
@@ -3188,7 +3188,7 @@ AstNode *parse_proc_type(AstFile *f, Token proc_token, String *link_name_) {
 	AstNode *results = NULL;
 	AstNode *results = NULL;
 
 
 	expect_token(f, Token_OpenParen);
 	expect_token(f, Token_OpenParen);
-	params = parse_field_list(f, NULL, FieldFlag_Signature, Token_CloseParen);
+	params = parse_field_list(f, NULL, FieldFlag_Signature, Token_CloseParen, true);
 	expect_token_after(f, Token_CloseParen, "parameter list");
 	expect_token_after(f, Token_CloseParen, "parameter list");
 	results = parse_results(f);
 	results = parse_results(f);
 
 
@@ -3357,7 +3357,7 @@ bool parse_expect_field_separator(AstFile *f, AstNode *param) {
 	return false;
 	return false;
 }
 }
 
 
-AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKind follow) {
+AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKind follow, bool allow_default_parameters) {
 	TokenKind separator = Token_Comma;
 	TokenKind separator = Token_Comma;
 	Token start_token = f->curr_token;
 	Token start_token = f->curr_token;
 
 
@@ -3370,13 +3370,12 @@ AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, Tok
 
 
 	isize total_name_count = 0;
 	isize total_name_count = 0;
 	bool allow_ellipsis = allowed_flags&FieldFlag_ellipsis;
 	bool allow_ellipsis = allowed_flags&FieldFlag_ellipsis;
-	bool is_procedure = allowed_flags == FieldFlag_Signature;
 
 
 	while (f->curr_token.kind != follow &&
 	while (f->curr_token.kind != follow &&
 	       f->curr_token.kind != Token_Colon &&
 	       f->curr_token.kind != Token_Colon &&
 	       f->curr_token.kind != Token_EOF) {
 	       f->curr_token.kind != Token_EOF) {
 		u32 flags = parse_field_prefixes(f);
 		u32 flags = parse_field_prefixes(f);
-		AstNode *param = parse_var_type(f, allow_ellipsis, is_procedure);
+		AstNode *param = parse_var_type(f, allow_ellipsis, allow_default_parameters);
 		AstNodeAndFlags naf = {param, flags};
 		AstNodeAndFlags naf = {param, flags};
 		array_add(&list, naf);
 		array_add(&list, naf);
 		if (f->curr_token.kind != Token_Comma) {
 		if (f->curr_token.kind != Token_Comma) {
@@ -3403,12 +3402,12 @@ AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, Tok
 
 
 		if (f->curr_token.kind != Token_Eq) {
 		if (f->curr_token.kind != Token_Eq) {
 			expect_token_after(f, Token_Colon, "field list");
 			expect_token_after(f, Token_Colon, "field list");
-			type = parse_var_type(f, allow_ellipsis, is_procedure);
+			type = parse_var_type(f, allow_ellipsis, allow_default_parameters);
 		}
 		}
 		if (allow_token(f, Token_Eq)) {
 		if (allow_token(f, Token_Eq)) {
 			// TODO(bill): Should this be true==lhs or false==rhs?
 			// TODO(bill): Should this be true==lhs or false==rhs?
 			default_value = parse_expr(f, false);
 			default_value = parse_expr(f, false);
-			if (!is_procedure) {
+			if (!allow_default_parameters) {
 				syntax_error(f->curr_token, "Default parameters are only allowed for procedures");
 				syntax_error(f->curr_token, "Default parameters are only allowed for procedures");
 			}
 			}
 		}
 		}
@@ -3439,12 +3438,12 @@ AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, Tok
 			AstNode *default_value = NULL;
 			AstNode *default_value = NULL;
 			if (f->curr_token.kind != Token_Eq) {
 			if (f->curr_token.kind != Token_Eq) {
 				expect_token_after(f, Token_Colon, "field list");
 				expect_token_after(f, Token_Colon, "field list");
-				type = parse_var_type(f, allow_ellipsis, is_procedure);
+				type = parse_var_type(f, allow_ellipsis, allow_default_parameters);
 			}
 			}
 			if (allow_token(f, Token_Eq)) {
 			if (allow_token(f, Token_Eq)) {
 				// TODO(bill): Should this be true==lhs or false==rhs?
 				// TODO(bill): Should this be true==lhs or false==rhs?
 				default_value = parse_expr(f, false);
 				default_value = parse_expr(f, false);
-				if (!is_procedure) {
+				if (!allow_default_parameters) {
 					syntax_error(f->curr_token, "Default parameters are only allowed for procedures");
 					syntax_error(f->curr_token, "Default parameters are only allowed for procedures");
 				}
 				}
 			}
 			}
@@ -3486,7 +3485,7 @@ AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, Tok
 
 
 
 
 AstNode *parse_record_fields(AstFile *f, isize *field_count_, u32 flags, String context) {
 AstNode *parse_record_fields(AstFile *f, isize *field_count_, u32 flags, String context) {
-	return parse_field_list(f, field_count_, flags, Token_CloseBrace);
+	return parse_field_list(f, field_count_, flags, Token_CloseBrace, false);
 }
 }
 
 
 AstNode *parse_type_or_ident(AstFile *f) {
 AstNode *parse_type_or_ident(AstFile *f) {
@@ -3821,7 +3820,14 @@ AstNode *parse_if_stmt(AstFile *f) {
 		syntax_error(f->curr_token, "Expected condition for if statement");
 		syntax_error(f->curr_token, "Expected condition for if statement");
 	}
 	}
 
 
-	body = parse_block_stmt(f, false);
+	if (allow_token(f, Token_ArrowRight)) {
+		body = parse_stmt(f);
+		if (body->kind == AstNode_BlockStmt) {
+			syntax_error(body, "Expected a normal statement rather than a block statement");
+		}
+	} else {
+		body = parse_block_stmt(f, false);
+	}
 
 
 	if (allow_token(f, Token_else)) {
 	if (allow_token(f, Token_else)) {
 		switch (f->curr_token.kind) {
 		switch (f->curr_token.kind) {
@@ -3831,6 +3837,13 @@ AstNode *parse_if_stmt(AstFile *f) {
 		case Token_OpenBrace:
 		case Token_OpenBrace:
 			else_stmt = parse_block_stmt(f, false);
 			else_stmt = parse_block_stmt(f, false);
 			break;
 			break;
+		case Token_ArrowRight: {
+			Token arrow = expect_token(f, Token_ArrowRight);
+			body = parse_stmt(f);
+			if (body->kind == AstNode_BlockStmt) {
+				syntax_error(body, "Expected a normal statement rather than a block statement");
+			}
+		} break;
 		default:
 		default:
 			syntax_error(f->curr_token, "Expected if statement block statement");
 			syntax_error(f->curr_token, "Expected if statement block statement");
 			else_stmt = ast_bad_stmt(f, f->curr_token, f->tokens[f->curr_token_index+1]);
 			else_stmt = ast_bad_stmt(f, f->curr_token, f->tokens[f->curr_token_index+1]);
@@ -3858,7 +3871,14 @@ AstNode *parse_when_stmt(AstFile *f) {
 		syntax_error(f->curr_token, "Expected condition for when statement");
 		syntax_error(f->curr_token, "Expected condition for when statement");
 	}
 	}
 
 
-	body = parse_block_stmt(f, true);
+	if (allow_token(f, Token_ArrowRight)) {
+		body = parse_stmt(f);
+		if (body->kind == AstNode_BlockStmt) {
+			syntax_error(body, "Expected a normal statement rather than a block statement");
+		}
+	} else {
+		body = parse_block_stmt(f, true);
+	}
 
 
 	if (allow_token(f, Token_else)) {
 	if (allow_token(f, Token_else)) {
 		switch (f->curr_token.kind) {
 		switch (f->curr_token.kind) {
@@ -3868,6 +3888,13 @@ AstNode *parse_when_stmt(AstFile *f) {
 		case Token_OpenBrace:
 		case Token_OpenBrace:
 			else_stmt = parse_block_stmt(f, true);
 			else_stmt = parse_block_stmt(f, true);
 			break;
 			break;
+		case Token_ArrowRight: {
+			Token arrow = expect_token(f, Token_ArrowRight);
+			body = parse_stmt(f);
+			if (body->kind == AstNode_BlockStmt) {
+				syntax_error(body, "Expected a normal statement rather than a block statement");
+			}
+		} break;
 		default:
 		default:
 			syntax_error(f->curr_token, "Expected when statement block statement");
 			syntax_error(f->curr_token, "Expected when statement block statement");
 			else_stmt = ast_bad_stmt(f, f->curr_token, f->tokens[f->curr_token_index+1]);
 			else_stmt = ast_bad_stmt(f, f->curr_token, f->tokens[f->curr_token_index+1]);
@@ -3890,11 +3917,22 @@ AstNode *parse_return_stmt(AstFile *f) {
 	}
 	}
 
 
 	Token token = expect_token(f, Token_return);
 	Token token = expect_token(f, Token_return);
-	Array<AstNode *> results;
-	if (f->curr_token.kind != Token_Semicolon && f->curr_token.kind != Token_CloseBrace) {
-		results = parse_rhs_expr_list(f);
-	} else {
-		results = make_ast_node_array(f);
+	Array<AstNode *> results = make_ast_node_array(f);
+
+	while (f->curr_token.kind != Token_Semicolon) {
+		AstNode *arg = parse_expr(f, false);
+		if (f->curr_token.kind == Token_Eq) {
+			Token eq = expect_token(f, Token_Eq);
+			AstNode *value = parse_value(f);
+			arg = ast_field_value(f, arg, value, eq);
+		}
+
+		array_add(&results, arg);
+		if (f->curr_token.kind != Token_Comma ||
+		    f->curr_token.kind == Token_EOF) {
+		    break;
+		}
+		next_token(f);
 	}
 	}
 
 
 	AstNode *end = NULL;
 	AstNode *end = NULL;
@@ -3952,7 +3990,8 @@ AstNode *parse_for_stmt(AstFile *f) {
 			}
 			}
 		}
 		}
 
 
-		if (!is_range && f->curr_token.kind == Token_Semicolon) {
+		if (!is_range && (f->curr_token.kind == Token_Semicolon ||
+		                  f->curr_token.kind == Token_ArrowRight)) {
 			next_token(f);
 			next_token(f);
 			init = cond;
 			init = cond;
 			cond = NULL;
 			cond = NULL;
@@ -3960,7 +3999,8 @@ AstNode *parse_for_stmt(AstFile *f) {
 				cond = parse_simple_stmt(f, StmtAllowFlag_None);
 				cond = parse_simple_stmt(f, StmtAllowFlag_None);
 			}
 			}
 			expect_semicolon(f, cond);
 			expect_semicolon(f, cond);
-			if (f->curr_token.kind != Token_OpenBrace) {
+			if (f->curr_token.kind != Token_OpenBrace &&
+			    f->curr_token.kind != Token_ArrowRight) {
 				post = parse_simple_stmt(f, StmtAllowFlag_None);
 				post = parse_simple_stmt(f, StmtAllowFlag_None);
 			}
 			}
 		}
 		}
@@ -3968,7 +4008,14 @@ AstNode *parse_for_stmt(AstFile *f) {
 		f->expr_level = prev_level;
 		f->expr_level = prev_level;
 	}
 	}
 
 
-	body = parse_block_stmt(f, false);
+	if (allow_token(f, Token_ArrowRight)) {
+		body = parse_stmt(f);
+		if (body->kind == AstNode_BlockStmt) {
+			syntax_error(body, "Expected a normal statement rather than a block statement");
+		}
+	} else {
+		body = parse_block_stmt(f, false);
+	}
 
 
 	if (is_range) {
 	if (is_range) {
 		GB_ASSERT(cond->kind == AstNode_AssignStmt);
 		GB_ASSERT(cond->kind == AstNode_AssignStmt);
@@ -4002,7 +4049,7 @@ AstNode *parse_for_stmt(AstFile *f) {
 
 
 AstNode *parse_case_clause(AstFile *f, bool is_type) {
 AstNode *parse_case_clause(AstFile *f, bool is_type) {
 	Token token = f->curr_token;
 	Token token = f->curr_token;
-	Array<AstNode *> list = make_ast_node_array(f);
+	Array<AstNode *> list = {};
 	expect_token(f, Token_case);
 	expect_token(f, Token_case);
 	bool prev_allow_range = f->allow_range;
 	bool prev_allow_range = f->allow_range;
 	f->allow_range = !is_type;
 	f->allow_range = !is_type;
@@ -4224,23 +4271,41 @@ AstNode *parse_stmt(AstFile *f) {
 
 
 	case Token_push_allocator: {
 	case Token_push_allocator: {
 		next_token(f);
 		next_token(f);
+		AstNode *body = NULL;
 		isize prev_level = f->expr_level;
 		isize prev_level = f->expr_level;
 		f->expr_level = -1;
 		f->expr_level = -1;
 		AstNode *expr = parse_expr(f, false);
 		AstNode *expr = parse_expr(f, false);
 		f->expr_level = prev_level;
 		f->expr_level = prev_level;
 
 
-		AstNode *body = parse_block_stmt(f, false);
+		if (allow_token(f, Token_ArrowRight)) {
+			body = parse_stmt(f);
+			if (body->kind == AstNode_BlockStmt) {
+				syntax_error(body, "Expected a normal statement rather than a block statement");
+			}
+		} else {
+			body = parse_block_stmt(f, false);
+		}
+
 		return ast_push_allocator(f, token, expr, body);
 		return ast_push_allocator(f, token, expr, body);
 	} break;
 	} break;
 
 
 	case Token_push_context: {
 	case Token_push_context: {
 		next_token(f);
 		next_token(f);
+		AstNode *body = NULL;
 		isize prev_level = f->expr_level;
 		isize prev_level = f->expr_level;
 		f->expr_level = -1;
 		f->expr_level = -1;
 		AstNode *expr = parse_expr(f, false);
 		AstNode *expr = parse_expr(f, false);
 		f->expr_level = prev_level;
 		f->expr_level = prev_level;
 
 
-		AstNode *body = parse_block_stmt(f, false);
+		if (allow_token(f, Token_ArrowRight)) {
+			body = parse_stmt(f);
+			if (body->kind == AstNode_BlockStmt) {
+				syntax_error(body, "Expected a normal statement rather than a block statement");
+			}
+		} else {
+			body = parse_block_stmt(f, false);
+		}
+
 		return ast_push_context(f, token, expr, body);
 		return ast_push_context(f, token, expr, body);
 	} break;
 	} break;
 
 

+ 8 - 1
src/tokenizer.cpp

@@ -546,7 +546,14 @@ Token scan_number_to_token(Tokenizer *t, bool seen_decimal_point) {
 			if (t->curr - prev <= 2) {
 			if (t->curr - prev <= 2) {
 				token.kind = Token_Invalid;
 				token.kind = Token_Invalid;
 			}
 			}
-		} else {
+		} /* else if (t->curr_rune == 'h') { // Hexadecimal Float
+			token.kind = Token_Float;
+			advance_to_next_rune(t);
+			scan_mantissa(t, 16);
+			if (t->curr - prev <= 2) {
+				token.kind = Token_Invalid;
+			}
+		} */ else {
 			seen_decimal_point = false;
 			seen_decimal_point = false;
 			scan_mantissa(t, 10);
 			scan_mantissa(t, 10);