Browse Source

Merge pull request #1082 from odin-lang/or_else-or_return-operator

`or_else` and `or_return` operators
gingerBill 4 years ago
parent
commit
5f072591ba

+ 1 - 3
core/bufio/writer.odin

@@ -183,9 +183,7 @@ writer_read_from :: proc(b: ^Writer, r: io.Reader) -> (n: i64, err: io.Error) {
 
 
 	for {
 	for {
 		if writer_available(b) == 0 {
 		if writer_available(b) == 0 {
-			if ferr := writer_flush(b); ferr != nil {
-				return n, ferr;
-			}
+			writer_flush(b) or_return;
 		}
 		}
 		if b.max_consecutive_empty_writes <= 0 {
 		if b.max_consecutive_empty_writes <= 0 {
 			b.max_consecutive_empty_writes = DEFAULT_MAX_CONSECUTIVE_EMPTY_READS;
 			b.max_consecutive_empty_writes = DEFAULT_MAX_CONSECUTIVE_EMPTY_READS;

+ 19 - 58
core/compress/zlib/zlib.odin

@@ -442,24 +442,22 @@ inflate_from_context :: proc(using ctx: ^compress.Context_Memory_Input, raw := f
 			return E_General.Unknown_Compression_Method;
 			return E_General.Unknown_Compression_Method;
 		}
 		}
 
 
-		cinfo  := (cmf >> 4) & 0xf;
-		if cinfo > 7 {
+		if cinfo := (cmf >> 4) & 0xf; cinfo > 7 {
 			return E_ZLIB.Unsupported_Window_Size;
 			return E_ZLIB.Unsupported_Window_Size;
 		}
 		}
 		flg, _ := compress.read_u8(ctx);
 		flg, _ := compress.read_u8(ctx);
 
 
-		fcheck  := flg & 0x1f;
+		fcheck := flg & 0x1f;
 		fcheck_computed := (cmf << 8 | flg) & 0x1f;
 		fcheck_computed := (cmf << 8 | flg) & 0x1f;
 		if fcheck != fcheck_computed {
 		if fcheck != fcheck_computed {
 			return E_General.Checksum_Failed;
 			return E_General.Checksum_Failed;
 		}
 		}
 
 
-		fdict   := (flg >> 5) & 1;
 		/*
 		/*
 			We don't handle built-in dictionaries for now.
 			We don't handle built-in dictionaries for now.
 			They're application specific and PNG doesn't use them.
 			They're application specific and PNG doesn't use them.
 		*/
 		*/
-		if fdict != 0 {
+		if fdict := (flg >> 5) & 1; fdict != 0 {
 			return E_ZLIB.FDICT_Unsupported;
 			return E_ZLIB.FDICT_Unsupported;
 		}
 		}
 
 
@@ -473,10 +471,7 @@ inflate_from_context :: proc(using ctx: ^compress.Context_Memory_Input, raw := f
 	}
 	}
 
 
 	// Parse ZLIB stream without header.
 	// Parse ZLIB stream without header.
-	err = inflate_raw(z=ctx, expected_output_size=expected_output_size);
-	if err != nil {
-		return err;
-	}
+	inflate_raw(z=ctx, expected_output_size=expected_output_size) or_return;
 
 
 	if !raw {
 	if !raw {
 		compress.discard_to_next_byte_lsb(ctx);
 		compress.discard_to_next_byte_lsb(ctx);
@@ -527,23 +522,14 @@ inflate_raw :: proc(z: ^$C, expected_output_size := -1, allocator := context.all
 	z_repeat:      ^Huffman_Table;
 	z_repeat:      ^Huffman_Table;
 	z_offset:      ^Huffman_Table;
 	z_offset:      ^Huffman_Table;
 	codelength_ht: ^Huffman_Table;
 	codelength_ht: ^Huffman_Table;
-
-	z_repeat, err = allocate_huffman_table(allocator=context.allocator);
-	if err != nil {
-		return err;
-	}
-	z_offset, err = allocate_huffman_table(allocator=context.allocator);
-	if err != nil {
-		return err;
-	}
-	codelength_ht, err = allocate_huffman_table(allocator=context.allocator);
-	if err != nil {
-		return err;
-	}
 	defer free(z_repeat);
 	defer free(z_repeat);
 	defer free(z_offset);
 	defer free(z_offset);
 	defer free(codelength_ht);
 	defer free(codelength_ht);
 
 
+	z_repeat      = allocate_huffman_table(allocator=context.allocator) or_return;
+	z_offset      = allocate_huffman_table(allocator=context.allocator) or_return;
+	codelength_ht = allocate_huffman_table(allocator=context.allocator) or_return;
+
 	final := u32(0);
 	final := u32(0);
 	type  := u32(0);
 	type  := u32(0);
 
 
@@ -560,8 +546,8 @@ inflate_raw :: proc(z: ^$C, expected_output_size := -1, allocator := context.all
 			// Discard bits until next byte boundary
 			// Discard bits until next byte boundary
 			compress.discard_to_next_byte_lsb(z);
 			compress.discard_to_next_byte_lsb(z);
 
 
-			uncompressed_len  := i16(compress.read_bits_lsb(z, 16));
-			length_check      := i16(compress.read_bits_lsb(z, 16));
+			uncompressed_len := i16(compress.read_bits_lsb(z, 16));
+			length_check     := i16(compress.read_bits_lsb(z, 16));
 
 
 			// fmt.printf("LEN: %v, ~LEN: %v, NLEN: %v, ~NLEN: %v\n", uncompressed_len, ~uncompressed_len, length_check, ~length_check);
 			// fmt.printf("LEN: %v, ~LEN: %v, NLEN: %v, ~NLEN: %v\n", uncompressed_len, ~uncompressed_len, length_check, ~length_check);
 
 
@@ -586,14 +572,8 @@ inflate_raw :: proc(z: ^$C, expected_output_size := -1, allocator := context.all
 			// log.debugf("Err: %v | Final: %v | Type: %v\n", err, final, type);
 			// log.debugf("Err: %v | Final: %v | Type: %v\n", err, final, type);
 			if type == 1 {
 			if type == 1 {
 				// Use fixed code lengths.
 				// Use fixed code lengths.
-				err = build_huffman(z_repeat, Z_FIXED_LENGTH[:]);
-				if err != nil {
-					return err;
-				}
-				err = build_huffman(z_offset, Z_FIXED_DIST[:]);
-				if err != nil {
-					return err;
-				}
+				build_huffman(z_repeat, Z_FIXED_LENGTH[:]) or_return;
+				build_huffman(z_offset, Z_FIXED_DIST[:])  or_return;
 			} else {
 			} else {
 				lencodes: [286+32+137]u8;
 				lencodes: [286+32+137]u8;
 				codelength_sizes: [19]u8;
 				codelength_sizes: [19]u8;
@@ -611,19 +591,13 @@ inflate_raw :: proc(z: ^$C, expected_output_size := -1, allocator := context.all
 					s := compress.read_bits_lsb(z, 3);
 					s := compress.read_bits_lsb(z, 3);
 					codelength_sizes[Z_LENGTH_DEZIGZAG[i]] = u8(s);
 					codelength_sizes[Z_LENGTH_DEZIGZAG[i]] = u8(s);
 				}
 				}
-				err = build_huffman(codelength_ht, codelength_sizes[:]);
-				if err != nil {
-					return err;
-				}
+				build_huffman(codelength_ht, codelength_sizes[:]) or_return;
 
 
 				n = 0;
 				n = 0;
 				c: u16;
 				c: u16;
 
 
 				for n < ntot {
 				for n < ntot {
-					c, err = decode_huffman(z, codelength_ht);
-					if err != nil {
-						return err;
-					}
+					c = decode_huffman(z, codelength_ht) or_return;
 
 
 					if c < 0 || c >= 19 {
 					if c < 0 || c >= 19 {
 						return E_Deflate.Huffman_Bad_Code_Lengths;
 						return E_Deflate.Huffman_Bad_Code_Lengths;
@@ -664,21 +638,10 @@ inflate_raw :: proc(z: ^$C, expected_output_size := -1, allocator := context.all
 					return E_Deflate.Huffman_Bad_Code_Lengths;
 					return E_Deflate.Huffman_Bad_Code_Lengths;
 				}
 				}
 
 
-				err = build_huffman(z_repeat, lencodes[:hlit]);
-				if err != nil {
-					return err;
-				}
-
-				err = build_huffman(z_offset, lencodes[hlit:ntot]);
-				if err != nil {
-					return err;
-				}
-			}
-			err = parse_huffman_block(z, z_repeat, z_offset);
-			// log.debugf("Err: %v | Final: %v | Type: %v\n", err, final, type);
-			if err != nil {
-				return err;
+				build_huffman(z_repeat, lencodes[:hlit])     or_return;
+				build_huffman(z_offset, lencodes[hlit:ntot]) or_return;
 			}
 			}
+			parse_huffman_block(z, z_repeat, z_offset) or_return;
 		}
 		}
 		if final == 1 {
 		if final == 1 {
 			break;
 			break;
@@ -698,9 +661,7 @@ inflate_from_byte_array :: proc(input: []u8, buf: ^bytes.Buffer, raw := false, e
 	ctx.input_data = input;
 	ctx.input_data = input;
 	ctx.output = buf;
 	ctx.output = buf;
 
 
-	err = inflate_from_context(ctx=&ctx, raw=raw, expected_output_size=expected_output_size);
-
-	return err;
+	return inflate_from_context(ctx=&ctx, raw=raw, expected_output_size=expected_output_size);
 }
 }
 
 
 inflate_from_byte_array_raw :: proc(input: []u8, buf: ^bytes.Buffer, raw := false, expected_output_size := -1) -> (err: Error) {
 inflate_from_byte_array_raw :: proc(input: []u8, buf: ^bytes.Buffer, raw := false, expected_output_size := -1) -> (err: Error) {
@@ -712,4 +673,4 @@ inflate_from_byte_array_raw :: proc(input: []u8, buf: ^bytes.Buffer, raw := fals
 	return inflate_raw(z=&ctx, expected_output_size=expected_output_size);
 	return inflate_raw(z=&ctx, expected_output_size=expected_output_size);
 }
 }
 
 
-inflate     :: proc{inflate_from_context, inflate_from_byte_array};
+inflate :: proc{inflate_from_context, inflate_from_byte_array};

+ 10 - 31
core/encoding/csv/writer.odin

@@ -64,21 +64,15 @@ write :: proc(w: ^Writer, record: []string) -> io.Error {
 		field := record[field_idx];
 		field := record[field_idx];
 
 
 		if field_idx > 0 {
 		if field_idx > 0 {
-			if _, err := io.write_rune(w.w, w.comma); err != nil {
-				return err;
-			}
+			io.write_rune(w.w, w.comma) or_return;
 		}
 		}
 
 
 		if !field_needs_quoting(w, field) {
 		if !field_needs_quoting(w, field) {
-			if _, err := io.write_string(w.w, field); err != nil {
-				return err;
-			}
+			io.write_string(w.w, field) or_return;
 			continue;
 			continue;
 		}
 		}
 
 
-		if err := io.write_byte(w.w, '"'); err != nil {
-			return err;
-		}
+		io.write_byte(w.w, '"') or_return;
 
 
 		for len(field) > 0 {
 		for len(field) > 0 {
 			i := strings.index_any(field, CHAR_SET);
 			i := strings.index_any(field, CHAR_SET);
@@ -86,40 +80,28 @@ write :: proc(w: ^Writer, record: []string) -> io.Error {
 				i = len(field);
 				i = len(field);
 			}
 			}
 
 
-			if _, err := io.write_string(w.w, field[:i]); err != nil {
-				return err;
-			}
+			io.write_string(w.w, field[:i]) or_return;
 			field = field[i:];
 			field = field[i:];
 
 
 			if len(field) > 0 {
 			if len(field) > 0 {
 				switch field[0] {
 				switch field[0] {
 				case '\r':
 				case '\r':
 					if !w.use_crlf {
 					if !w.use_crlf {
-						if err := io.write_byte(w.w, '\r'); err != nil {
-							return err;
-						}
+						io.write_byte(w.w, '\r') or_return;
 					}
 					}
 				case '\n':
 				case '\n':
 					if w.use_crlf {
 					if w.use_crlf {
-						if _, err := io.write_string(w.w, "\r\n"); err != nil {
-							return err;
-						}
+						io.write_string(w.w, "\r\n") or_return;
 					} else {
 					} else {
-						if err := io.write_byte(w.w, '\n'); err != nil {
-							return err;
-						}
+						io.write_byte(w.w, '\n') or_return;
 					}
 					}
 				case '"':
 				case '"':
-					if _, err := io.write_string(w.w, `""`); err != nil {
-						return err;
-					}
+					io.write_string(w.w, `""`) or_return;
 				}
 				}
 				field = field[1:];
 				field = field[1:];
 			}
 			}
 		}
 		}
-		if err := io.write_byte(w.w, '"'); err != nil {
-			return err;
-		}
+		io.write_byte(w.w, '"') or_return;
 	}
 	}
 
 
 	if w.use_crlf {
 	if w.use_crlf {
@@ -132,10 +114,7 @@ write :: proc(w: ^Writer, record: []string) -> io.Error {
 // write_all writes multiple CSV records to w using write, and then flushes (if necessary).
 // write_all writes multiple CSV records to w using write, and then flushes (if necessary).
 write_all :: proc(w: ^Writer, records: [][]string) -> io.Error {
 write_all :: proc(w: ^Writer, records: [][]string) -> io.Error {
 	for record in records {
 	for record in records {
-		err := write(w, record);
-		if err != nil {
-			return err;
-		}
+		write(w, record) or_return;
 	}
 	}
 	return writer_flush(w);
 	return writer_flush(w);
 }
 }

+ 32 - 53
core/encoding/hxa/read.odin

@@ -67,17 +67,9 @@ read :: proc(data: []byte, filename := "<input>", print_error := false, allocato
 	}
 	}
 
 
 	read_name :: proc(r: ^Reader) -> (value: string, err: Read_Error) {
 	read_name :: proc(r: ^Reader) -> (value: string, err: Read_Error) {
-		len: u8;
-		data: []byte;
-		len, err = read_value(r, u8);
-		if err != nil {
-			return;
-		}
-		data, err = read_array(r, byte, int(len));
-		if err == nil {
-			value = string(data[:len]);
-		}
-		return;
+		len  := read_value(r, u8)             or_return;
+		data := read_array(r, byte, int(len)) or_return;
+		return string(data[:len]), nil;
 	}
 	}
 
 
 	read_meta :: proc(r: ^Reader, capacity: u32le) -> (meta_data: []Meta, err: Read_Error) {
 	read_meta :: proc(r: ^Reader, capacity: u32le) -> (meta_data: []Meta, err: Read_Error) {
@@ -85,10 +77,9 @@ read :: proc(data: []byte, filename := "<input>", print_error := false, allocato
 		count := 0;
 		count := 0;
 		defer meta_data = meta_data[:count];
 		defer meta_data = meta_data[:count];
 		for m in &meta_data {
 		for m in &meta_data {
-			if m.name, err = read_name(r); err != nil { return };
+			m.name = read_name(r) or_return;
 
 
-			type: Meta_Value_Type;
-			if type, err = read_value(r, Meta_Value_Type); err != nil { return }
+			type := read_value(r, Meta_Value_Type) or_return;
 			if type > max(Meta_Value_Type) {
 			if type > max(Meta_Value_Type) {
 				if r.print_error {
 				if r.print_error {
 					fmt.eprintf("HxA Error: file '%s' has meta value type %d. Maximum value is ", r.filename, u8(type), u8(max(Meta_Value_Type)));
 					fmt.eprintf("HxA Error: file '%s' has meta value type %d. Maximum value is ", r.filename, u8(type), u8(max(Meta_Value_Type)));
@@ -96,22 +87,15 @@ read :: proc(data: []byte, filename := "<input>", print_error := false, allocato
 				err = .Invalid_Data;
 				err = .Invalid_Data;
 				return;
 				return;
 			}
 			}
-			array_length: u32le;
-			if array_length, err = read_value(r, u32le); err != nil { return }
+			array_length := read_value(r, u32le) or_return;
 
 
 			switch type {
 			switch type {
-			case .Int64:
-				if m.value, err = read_array(r, i64le, int(array_length)); err != nil { return }
-			case .Double:
-				if m.value, err = read_array(r, f64le, int(array_length)); err != nil { return }
-			case .Node:
-				if m.value, err = read_array(r, Node_Index, int(array_length)); err != nil { return }
-			case .Text:
-				if m.value, err = read_string(r, int(array_length)); err != nil { return }
-			case .Binary:
-				if m.value, err = read_array(r, byte, int(array_length)); err != nil { return }
-			case .Meta:
-				if m.value, err = read_meta(r, array_length); err != nil { return }
+			case .Int64:  m.value = read_array(r, i64le, int(array_length))      or_return;
+			case .Double: m.value = read_array(r, f64le, int(array_length))      or_return;
+			case .Node:   m.value = read_array(r, Node_Index, int(array_length)) or_return;
+			case .Text:   m.value = read_string(r, int(array_length))            or_return;
+			case .Binary: m.value = read_array(r, byte, int(array_length))       or_return;
+			case .Meta:   m.value = read_meta(r, array_length)                   or_return;
 			}
 			}
 
 
 			count += 1;
 			count += 1;
@@ -120,16 +104,14 @@ read :: proc(data: []byte, filename := "<input>", print_error := false, allocato
 	}
 	}
 
 
 	read_layer_stack :: proc(r: ^Reader, capacity: u32le) -> (layers: Layer_Stack, err: Read_Error) {
 	read_layer_stack :: proc(r: ^Reader, capacity: u32le) -> (layers: Layer_Stack, err: Read_Error) {
-		stack_count: u32le;
-		if stack_count, err = read_value(r, u32le); err != nil { return }
+		stack_count := read_value(r, u32le) or_return;
 		layer_count := 0;
 		layer_count := 0;
 		layers = make(Layer_Stack, stack_count);
 		layers = make(Layer_Stack, stack_count);
 		defer layers = layers[:layer_count];
 		defer layers = layers[:layer_count];
 		for layer in &layers {
 		for layer in &layers {
-			type: Layer_Data_Type;
-			if layer.name, err = read_name(r); err != nil { return }
-			if layer.components, err = read_value(r, u8); err != nil { return }
-			if type, err = read_value(r, Layer_Data_Type); err != nil { return }
+			layer.name = read_name(r) or_return;
+			layer.components = read_value(r, u8) or_return;
+			type := read_value(r, Layer_Data_Type) or_return;
 			if type > max(type) {
 			if type > max(type) {
 				if r.print_error {
 				if r.print_error {
 					fmt.eprintf("HxA Error: file '%s' has layer data type %d. Maximum value is ", r.filename, u8(type), u8(max(Layer_Data_Type)));
 					fmt.eprintf("HxA Error: file '%s' has layer data type %d. Maximum value is ", r.filename, u8(type), u8(max(Layer_Data_Type)));
@@ -140,10 +122,10 @@ read :: proc(data: []byte, filename := "<input>", print_error := false, allocato
 			data_len := int(layer.components) * int(capacity);
 			data_len := int(layer.components) * int(capacity);
 
 
 			switch type {
 			switch type {
-			case .Uint8:  if layer.data, err = read_array(r, u8,    data_len); err != nil { return }
-			case .Int32:  if layer.data, err = read_array(r, i32le, data_len); err != nil { return }
-			case .Float:  if layer.data, err = read_array(r, f32le, data_len); err != nil { return }
-			case .Double: if layer.data, err = read_array(r, f64le, data_len); err != nil { return }
+			case .Uint8:  layer.data = read_array(r, u8,    data_len) or_return;
+			case .Int32:  layer.data = read_array(r, i32le, data_len) or_return;
+			case .Float:  layer.data = read_array(r, f32le, data_len) or_return;
+			case .Double: layer.data = read_array(r, f64le, data_len) or_return;
 			}
 			}
 			layer_count += 1;
 			layer_count += 1;
 		}
 		}
@@ -177,8 +159,7 @@ read :: proc(data: []byte, filename := "<input>", print_error := false, allocato
 
 
 	for node_idx in 0..<header.internal_node_count {
 	for node_idx in 0..<header.internal_node_count {
 		node := &file.nodes[node_count];
 		node := &file.nodes[node_count];
-		type: Node_Type;
-		if type, err = read_value(r, Node_Type); err != nil { return }
+		type := read_value(r, Node_Type) or_return;
 		if type > max(Node_Type) {
 		if type > max(Node_Type) {
 			if r.print_error {
 			if r.print_error {
 				fmt.eprintf("HxA Error: file '%s' has node type %d. Maximum value is ", r.filename, u8(type), u8(max(Node_Type)));
 				fmt.eprintf("HxA Error: file '%s' has node type %d. Maximum value is ", r.filename, u8(type), u8(max(Node_Type)));
@@ -188,9 +169,7 @@ read :: proc(data: []byte, filename := "<input>", print_error := false, allocato
 		}
 		}
 		node_count += 1;
 		node_count += 1;
 
 
-		meta_data_count: u32le;
-		if meta_data_count, err = read_value(r, u32le); err != nil { return }
-		if node.meta_data, err = read_meta(r, meta_data_count); err != nil { return }
+		node.meta_data = read_meta(r, read_value(r, u32le) or_return) or_return;
 
 
 		switch type {
 		switch type {
 		case .Meta_Only:
 		case .Meta_Only:
@@ -198,35 +177,35 @@ read :: proc(data: []byte, filename := "<input>", print_error := false, allocato
 		case .Geometry:
 		case .Geometry:
 			g: Node_Geometry;
 			g: Node_Geometry;
 
 
-			if g.vertex_count, err = read_value(r, u32le); err != nil { return }
-			if g.vertex_stack, err = read_layer_stack(r, g.vertex_count); err != nil { return }
-			if g.edge_corner_count, err = read_value(r, u32le); err != nil { return }
-			if g.corner_stack, err = read_layer_stack(r, g.edge_corner_count); err != nil { return }
+			g.vertex_count      = read_value(r, u32le)                     or_return;
+			g.vertex_stack      = read_layer_stack(r, g.vertex_count)      or_return;
+			g.edge_corner_count = read_value(r, u32le)                     or_return;
+			g.corner_stack      = read_layer_stack(r, g.edge_corner_count) or_return;
 			if header.version > 2 {
 			if header.version > 2 {
-				if g.edge_stack, err = read_layer_stack(r, g.edge_corner_count); err != nil { return }
+				g.edge_stack = read_layer_stack(r, g.edge_corner_count) or_return;
 			}
 			}
-			if g.face_count, err = read_value(r, u32le); err != nil { return }
-			if g.face_stack, err = read_layer_stack(r, g.face_count); err != nil { return }
+			g.face_count = read_value(r, u32le)              or_return;
+			g.face_stack = read_layer_stack(r, g.face_count) or_return;
 
 
 			node.content = g;
 			node.content = g;
 
 
 		case .Image:
 		case .Image:
 			img: Node_Image;
 			img: Node_Image;
 
 
-			if img.type, err = read_value(r, Image_Type); err != nil { return }
+			img.type = read_value(r, Image_Type) or_return;
 			dimensions := int(img.type);
 			dimensions := int(img.type);
 			if img.type == .Image_Cube {
 			if img.type == .Image_Cube {
 				dimensions = 2;
 				dimensions = 2;
 			}
 			}
 			img.resolution = {1, 1, 1};
 			img.resolution = {1, 1, 1};
 			for d in 0..<dimensions {
 			for d in 0..<dimensions {
-				if img.resolution[d], err = read_value(r, u32le); err != nil { return }
+				img.resolution[d] = read_value(r, u32le) or_return;
 			}
 			}
 			size := img.resolution[0]*img.resolution[1]*img.resolution[2];
 			size := img.resolution[0]*img.resolution[1]*img.resolution[2];
 			if img.type == .Image_Cube {
 			if img.type == .Image_Cube {
 				size *= 6;
 				size *= 6;
 			}
 			}
-			if img.image_stack, err = read_layer_stack(r, size); err != nil { return }
+			img.image_stack = read_layer_stack(r, size) or_return;
 
 
 			node.content = img;
 			node.content = img;
 		}
 		}

+ 6 - 24
core/encoding/json/parser.odin

@@ -133,9 +133,7 @@ parse_value :: proc(p: ^Parser) -> (value: Value, err: Error) {
 }
 }
 
 
 parse_array :: proc(p: ^Parser) -> (value: Value, err: Error) {
 parse_array :: proc(p: ^Parser) -> (value: Value, err: Error) {
-	if err = expect_token(p, .Open_Bracket); err != .None {
-		return;
-	}
+	expect_token(p, .Open_Bracket) or_return;
 
 
 	array: Array;
 	array: Array;
 	array.allocator = p.allocator;
 	array.allocator = p.allocator;
@@ -147,11 +145,7 @@ parse_array :: proc(p: ^Parser) -> (value: Value, err: Error) {
 	}
 	}
 
 
 	for p.curr_token.kind != .Close_Bracket {
 	for p.curr_token.kind != .Close_Bracket {
-		elem, elem_err := parse_value(p);
-		if elem_err != .None {
-			err = elem_err;
-			return;
-		}
+		elem := parse_value(p) or_return;
 		append(&array, elem);
 		append(&array, elem);
 
 
 		// Disallow trailing commas for the time being
 		// Disallow trailing commas for the time being
@@ -162,10 +156,7 @@ parse_array :: proc(p: ^Parser) -> (value: Value, err: Error) {
 		}
 		}
 	}
 	}
 
 
-	if err = expect_token(p, .Close_Bracket); err != .None {
-		return;
-	}
-
+	expect_token(p, .Close_Bracket) or_return;
 	value = array;
 	value = array;
 	return;
 	return;
 }
 }
@@ -200,9 +191,7 @@ parse_object_key :: proc(p: ^Parser) -> (key: string, err: Error) {
 }
 }
 
 
 parse_object :: proc(p: ^Parser) -> (value: Value, err: Error) {
 parse_object :: proc(p: ^Parser) -> (value: Value, err: Error) {
-	if err = expect_token(p, .Open_Brace); err != .None {
-		return;
-	}
+	expect_token(p, .Open_Brace) or_return;
 
 
 	obj: Object;
 	obj: Object;
 	obj.allocator = p.allocator;
 	obj.allocator = p.allocator;
@@ -227,11 +216,7 @@ parse_object :: proc(p: ^Parser) -> (value: Value, err: Error) {
 			return;
 			return;
 		}
 		}
 
 
-		elem, elem_err := parse_value(p);
-		if elem_err != .None {
-			err = elem_err;
-			return;
-		}
+		elem := parse_value(p) or_return;
 
 
 		if key in obj {
 		if key in obj {
 			err = .Duplicate_Object_Key;
 			err = .Duplicate_Object_Key;
@@ -256,10 +241,7 @@ parse_object :: proc(p: ^Parser) -> (value: Value, err: Error) {
 		}
 		}
 	}
 	}
 
 
-	if err = expect_token(p, .Close_Brace); err != .None {
-		return;
-	}
-
+	expect_token(p, .Close_Brace) or_return;
 	value = obj;
 	value = obj;
 	return;
 	return;
 }
 }

+ 9 - 30
core/image/png/png.odin

@@ -372,8 +372,7 @@ load_from_file :: proc(filename: string, options := Options{}, allocator := cont
 	defer delete(data);
 	defer delete(data);
 
 
 	if ok {
 	if ok {
-		img, err = load_from_slice(data, options, allocator);
-		return;
+		return load_from_slice(data, options, allocator);
 	} else {
 	} else {
 		img = new(Image);
 		img = new(Image);
 		return img, E_General.File_Not_Found;
 		return img, E_General.File_Not_Found;
@@ -453,10 +452,7 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a
 			}
 			}
 			seen_ihdr = true;
 			seen_ihdr = true;
 
 
-			header, err = read_header(ctx);
-			if err != nil {
-				return img, err;
-			}
+			header = read_header(ctx) or_return;
 
 
 			if .Paletted in header.color_type {
 			if .Paletted in header.color_type {
 				// Color type 3
 				// Color type 3
@@ -506,10 +502,7 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a
 				return img, E_PNG.PLTE_Encountered_Unexpectedly;
 				return img, E_PNG.PLTE_Encountered_Unexpectedly;
 			}
 			}
 
 
-			c, err = read_chunk(ctx);
-			if err != nil {
-				return img, err;
-			}
+			c = read_chunk(ctx) or_return;
 
 
 			if c.header.length % 3 != 0 || c.header.length > 768 {
 			if c.header.length % 3 != 0 || c.header.length > 768 {
 				return img, E_PNG.PLTE_Invalid_Length;
 				return img, E_PNG.PLTE_Invalid_Length;
@@ -540,10 +533,7 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a
 
 
 			next := ch.type;
 			next := ch.type;
 			for next == .IDAT {
 			for next == .IDAT {
-				c, err = read_chunk(ctx);
-				if err != nil {
-					return img, err;
-				}
+				c = read_chunk(ctx) or_return;
 
 
 				bytes.buffer_write(&idat_b, c.data);
 				bytes.buffer_write(&idat_b, c.data);
 				idat_length += c.header.length;
 				idat_length += c.header.length;
@@ -560,19 +550,13 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a
 			}
 			}
 			seen_idat = true;
 			seen_idat = true;
 		case .IEND:
 		case .IEND:
-			c, err = read_chunk(ctx);
-			if err != nil {
-				return img, err;
-			}
+			c = read_chunk(ctx) or_return;
 			seen_iend = true;
 			seen_iend = true;
 		case .bKGD:
 		case .bKGD:
 
 
 			// TODO: Make sure that 16-bit bKGD + tRNS chunks return u16 instead of u16be
 			// TODO: Make sure that 16-bit bKGD + tRNS chunks return u16 instead of u16be
 
 
-			c, err = read_chunk(ctx);
-			if err != nil {
-				return img, err;
-			}
+			c = read_chunk(ctx) or_return;
 			seen_bkgd = true;
 			seen_bkgd = true;
 			if .return_metadata in options {
 			if .return_metadata in options {
 				append(&info.chunks, c);
 				append(&info.chunks, c);
@@ -604,10 +588,7 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a
 					img.background = [3]u16{u16(col[0]), u16(col[1]), u16(col[2])};
 					img.background = [3]u16{u16(col[0]), u16(col[1]), u16(col[2])};
 			}
 			}
 		case .tRNS:
 		case .tRNS:
-			c, err = read_chunk(ctx);
-			if err != nil {
-				return img, err;
-			}
+			c = read_chunk(ctx) or_return;
 
 
 			if .Alpha in info.header.color_type {
 			if .Alpha in info.header.color_type {
 				return img, E_PNG.TRNS_Encountered_Unexpectedly;
 				return img, E_PNG.TRNS_Encountered_Unexpectedly;
@@ -646,10 +627,8 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a
 			return img, E_PNG.PNG_Does_Not_Adhere_to_Spec;
 			return img, E_PNG.PNG_Does_Not_Adhere_to_Spec;
 		case:
 		case:
 			// Unhandled type
 			// Unhandled type
-			c, err = read_chunk(ctx);
-			if err != nil {
-				return img, err;
-			}
+			c = read_chunk(ctx) or_return;
+
 			if .return_metadata in options {
 			if .return_metadata in options {
 				// NOTE: Chunk cata is currently allocated on the temp allocator.
 				// NOTE: Chunk cata is currently allocated on the temp allocator.
 				append(&info.chunks, c);
 				append(&info.chunks, c);

+ 46 - 50
core/math/big/helpers.odin

@@ -42,7 +42,7 @@ int_set_from_integer :: proc(dest: ^Int, src: $T, minimize := false, allocator :
 		Check that `src` is usable and `dest` isn't immutable.
 		Check that `src` is usable and `dest` isn't immutable.
 	*/
 	*/
 	assert_if_nil(dest);
 	assert_if_nil(dest);
-	if err = #force_inline internal_error_if_immutable(dest); err != nil { return err; }
+	#force_inline internal_error_if_immutable(dest) or_return;
 
 
 	return #force_inline internal_int_set_from_integer(dest, src, minimize);
 	return #force_inline internal_int_set_from_integer(dest, src, minimize);
 }
 }
@@ -64,8 +64,8 @@ int_copy :: proc(dest, src: ^Int, minimize := false, allocator := context.alloca
 	assert_if_nil(dest, src);
 	assert_if_nil(dest, src);
 	context.allocator = allocator;
 	context.allocator = allocator;
 
 
-	if err = #force_inline internal_clear_if_uninitialized(src); err != nil { return err; }
-	if err = #force_inline internal_error_if_immutable(dest);    err != nil { return err; }
+	#force_inline internal_clear_if_uninitialized(src) or_return;
+	#force_inline internal_error_if_immutable(dest)    or_return;
 
 
 	return #force_inline internal_int_copy(dest, src, minimize);
 	return #force_inline internal_int_copy(dest, src, minimize);
 }
 }
@@ -92,8 +92,8 @@ int_abs :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error)
 	assert_if_nil(dest, src);
 	assert_if_nil(dest, src);
 	context.allocator = allocator;
 	context.allocator = allocator;
 
 
-	if err = #force_inline internal_clear_if_uninitialized(src); err != nil { return err; }
-	if err = #force_inline internal_error_if_immutable(dest);    err != nil { return err; }
+	#force_inline internal_clear_if_uninitialized(src) or_return;
+	#force_inline internal_error_if_immutable(dest)    or_return;
 
 
 	return #force_inline internal_int_abs(dest, src);
 	return #force_inline internal_int_abs(dest, src);
 }
 }
@@ -113,8 +113,8 @@ int_neg :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error)
 	assert_if_nil(dest, src);
 	assert_if_nil(dest, src);
 	context.allocator = allocator;
 	context.allocator = allocator;
 
 
-	if err = #force_inline internal_clear_if_uninitialized(src); err != nil { return err; }
-	if err = #force_inline internal_error_if_immutable(dest);    err != nil { return err; }
+	#force_inline internal_clear_if_uninitialized(src) or_return;
+	#force_inline internal_error_if_immutable(dest)    or_return;
 
 
 	return #force_inline internal_int_neg(dest, src);
 	return #force_inline internal_int_neg(dest, src);
 }
 }
@@ -134,8 +134,8 @@ int_bitfield_extract :: proc(a: ^Int, offset, count: int, allocator := context.a
 	assert_if_nil(a);
 	assert_if_nil(a);
 	context.allocator = allocator;
 	context.allocator = allocator;
 
 
-	if err = #force_inline internal_clear_if_uninitialized(a); err != nil { return {}, err; }
-	return #force_inline   internal_int_bitfield_extract(a, offset, count);
+	#force_inline internal_clear_if_uninitialized(a) or_return;
+	return #force_inline internal_int_bitfield_extract(a, offset, count);
 }
 }
 
 
 /*
 /*
@@ -148,8 +148,8 @@ shrink :: proc(a: ^Int, allocator := context.allocator) -> (err: Error) {
 	assert_if_nil(a);
 	assert_if_nil(a);
 	context.allocator = allocator;
 	context.allocator = allocator;
 
 
-	if err = #force_inline internal_clear_if_uninitialized(a); err != nil { return err; }
-	return #force_inline   internal_shrink(a);
+	#force_inline internal_clear_if_uninitialized(a) or_return;
+	return #force_inline internal_shrink(a);
 }
 }
 
 
 int_grow :: proc(a: ^Int, digits: int, allow_shrink := false, allocator := context.allocator) -> (err: Error) {
 int_grow :: proc(a: ^Int, digits: int, allow_shrink := false, allocator := context.allocator) -> (err: Error) {
@@ -305,8 +305,8 @@ int_get :: proc(a: ^Int, $T: typeid, allocator := context.allocator) -> (res: T,
 		Check that `a` is usable.
 		Check that `a` is usable.
 	*/
 	*/
 	assert_if_nil(a);
 	assert_if_nil(a);
-	if err = #force_inline internal_clear_if_uninitialized(a, allocator); err != nil { return T{}, err; }
-	return #force_inline   internal_int_get(a, T);
+	#force_inline internal_clear_if_uninitialized(a, allocator) or_return;
+	return #force_inline internal_int_get(a, T);
 }
 }
 get :: proc { int_get, };
 get :: proc { int_get, };
 
 
@@ -315,8 +315,8 @@ int_get_float :: proc(a: ^Int, allocator := context.allocator) -> (res: f64, err
 		Check that `a` is usable.
 		Check that `a` is usable.
 	*/
 	*/
 	assert_if_nil(a);
 	assert_if_nil(a);
-	if err = #force_inline internal_clear_if_uninitialized(a, allocator); err != nil { return 0, err; }
-	return #force_inline   internal_int_get_float(a);
+	#force_inline internal_clear_if_uninitialized(a, allocator) or_return;
+	return #force_inline internal_int_get_float(a);
 }
 }
 
 
 /*
 /*
@@ -327,8 +327,8 @@ count_bits :: proc(a: ^Int, allocator := context.allocator) -> (count: int, err:
 		Check that `a` is usable.
 		Check that `a` is usable.
 	*/
 	*/
 	assert_if_nil(a);
 	assert_if_nil(a);
-	if err = #force_inline internal_clear_if_uninitialized(a, allocator); err != nil { return 0, err; }
-	return #force_inline   internal_count_bits(a), nil;
+	#force_inline internal_clear_if_uninitialized(a, allocator) or_return;
+	return #force_inline internal_count_bits(a), nil;
 }
 }
 
 
 /*
 /*
@@ -340,8 +340,8 @@ int_count_lsb :: proc(a: ^Int, allocator := context.allocator) -> (count: int, e
 		Check that `a` is usable.
 		Check that `a` is usable.
 	*/
 	*/
 	assert_if_nil(a);
 	assert_if_nil(a);
-	if err = #force_inline internal_clear_if_uninitialized(a, allocator); err != nil { return 0, err; }
-	return #force_inline   internal_int_count_lsb(a);
+	#force_inline internal_clear_if_uninitialized(a, allocator) or_return;
+	return #force_inline internal_int_count_lsb(a);
 }
 }
 
 
 platform_count_lsb :: #force_inline proc(a: $T) -> (count: int)
 platform_count_lsb :: #force_inline proc(a: $T) -> (count: int)
@@ -398,7 +398,7 @@ clear_if_uninitialized_multi :: proc(args: ..^Int, allocator := context.allocato
 	assert_if_nil(..args);
 	assert_if_nil(..args);
 
 
 	for i in &args {
 	for i in &args {
-		if err = #force_inline internal_clear_if_uninitialized_single(i, allocator); err != nil { return nil; }
+		#force_inline internal_clear_if_uninitialized_single(i, allocator) or_return;
 	}
 	}
 	return err;
 	return err;
 }
 }
@@ -425,7 +425,7 @@ int_init_multi :: proc(integers: ..^Int, allocator := context.allocator) -> (err
 
 
 	integers := integers;
 	integers := integers;
 	for a in &integers {
 	for a in &integers {
-		if err = #force_inline internal_clear(a, true, allocator); err != nil { return err; }
+		#force_inline internal_clear(a, true, allocator) or_return;
 	}
 	}
 	return nil;
 	return nil;
 }
 }
@@ -440,7 +440,7 @@ copy_digits :: proc(dest, src: ^Int, digits: int, allocator := context.allocator
 		Check that `src` is usable and `dest` isn't immutable.
 		Check that `src` is usable and `dest` isn't immutable.
 	*/
 	*/
 	assert_if_nil(dest, src);
 	assert_if_nil(dest, src);
-	if err = #force_inline internal_clear_if_uninitialized(src); err != nil { return err; }
+	#force_inline internal_clear_if_uninitialized(src) or_return;
 
 
 	digits = min(digits, len(src.digit), len(dest.digit));
 	digits = min(digits, len(src.digit), len(dest.digit));
 	return #force_inline internal_copy_digits(dest, src, digits);
 	return #force_inline internal_copy_digits(dest, src, digits);
@@ -454,7 +454,7 @@ copy_digits :: proc(dest, src: ^Int, digits: int, allocator := context.allocator
 */
 */
 clamp :: proc(a: ^Int, allocator := context.allocator) -> (err: Error) {
 clamp :: proc(a: ^Int, allocator := context.allocator) -> (err: Error) {
 	assert_if_nil(a);
 	assert_if_nil(a);
-	if err = #force_inline internal_clear_if_uninitialized(a, allocator); err != nil { return err; }
+	#force_inline internal_clear_if_uninitialized(a, allocator) or_return;
 
 
 	for a.used > 0 && a.digit[a.used - 1] == 0 {
 	for a.used > 0 && a.digit[a.used - 1] == 0 {
 		a.used -= 1;
 		a.used -= 1;
@@ -472,7 +472,7 @@ clamp :: proc(a: ^Int, allocator := context.allocator) -> (err: Error) {
 */
 */
 int_to_bytes_size :: proc(a: ^Int, signed := false, allocator := context.allocator) -> (size_in_bytes: int, err: Error) {
 int_to_bytes_size :: proc(a: ^Int, signed := false, allocator := context.allocator) -> (size_in_bytes: int, err: Error) {
 	assert_if_nil(a);
 	assert_if_nil(a);
-	if err = #force_inline internal_clear_if_uninitialized(a, allocator); err != nil { return {}, err; }
+	#force_inline internal_clear_if_uninitialized(a, allocator) or_return;
 
 
 	size_in_bits := internal_count_bits(a);
 	size_in_bits := internal_count_bits(a);
 
 
@@ -488,9 +488,8 @@ int_to_bytes_size :: proc(a: ^Int, signed := false, allocator := context.allocat
 */
 */
 int_to_bytes_little :: proc(a: ^Int, buf: []u8, signed := false, allocator := context.allocator) -> (err: Error) {
 int_to_bytes_little :: proc(a: ^Int, buf: []u8, signed := false, allocator := context.allocator) -> (err: Error) {
 	assert_if_nil(a);
 	assert_if_nil(a);
-	size_in_bytes: int;
 
 
-	if size_in_bytes, err = int_to_bytes_size(a, signed, allocator); err != nil { return err; }
+	size_in_bytes := int_to_bytes_size(a, signed, allocator) or_return;
 	l := len(buf);
 	l := len(buf);
 	if size_in_bytes > l { return .Buffer_Overflow; }
 	if size_in_bytes > l { return .Buffer_Overflow; }
 
 
@@ -512,9 +511,8 @@ int_to_bytes_little :: proc(a: ^Int, buf: []u8, signed := false, allocator := co
 */
 */
 int_to_bytes_big :: proc(a: ^Int, buf: []u8, signed := false, allocator := context.allocator) -> (err: Error) {
 int_to_bytes_big :: proc(a: ^Int, buf: []u8, signed := false, allocator := context.allocator) -> (err: Error) {
 	assert_if_nil(a);
 	assert_if_nil(a);
-	size_in_bytes: int;
 
 
-	if size_in_bytes, err = int_to_bytes_size(a, signed, allocator); err != nil { return err; }
+	size_in_bytes := int_to_bytes_size(a, signed, allocator) or_return;
 	l := len(buf);
 	l := len(buf);
 	if size_in_bytes > l { return .Buffer_Overflow; }
 	if size_in_bytes > l { return .Buffer_Overflow; }
 
 
@@ -537,18 +535,17 @@ int_to_bytes_big :: proc(a: ^Int, buf: []u8, signed := false, allocator := conte
 */
 */
 int_to_bytes_little_python :: proc(a: ^Int, buf: []u8, signed := false, allocator := context.allocator) -> (err: Error) {
 int_to_bytes_little_python :: proc(a: ^Int, buf: []u8, signed := false, allocator := context.allocator) -> (err: Error) {
 	assert_if_nil(a);
 	assert_if_nil(a);
-	size_in_bytes: int;
 
 
 	if !signed && a.sign == .Negative { return .Invalid_Argument; }
 	if !signed && a.sign == .Negative { return .Invalid_Argument; }
 
 
 	l := len(buf);
 	l := len(buf);
-	if size_in_bytes, err = int_to_bytes_size(a, signed, allocator); err != nil { return err; }
-	if size_in_bytes > l              { return .Buffer_Overflow;  }
+	size_in_bytes := int_to_bytes_size(a, signed, allocator) or_return;
+	if size_in_bytes > l { return .Buffer_Overflow;  }
 
 
 	if a.sign == .Negative {
 	if a.sign == .Negative {
 		t := &Int{};
 		t := &Int{};
 		defer destroy(t);
 		defer destroy(t);
-		if err = internal_complement(t, a, allocator); err != nil { return err; }
+		internal_complement(t, a, allocator) or_return;
 
 
 		size_in_bits := internal_count_bits(t);
 		size_in_bits := internal_count_bits(t);
 		i := 0;
 		i := 0;
@@ -574,19 +571,18 @@ int_to_bytes_little_python :: proc(a: ^Int, buf: []u8, signed := false, allocato
 */
 */
 int_to_bytes_big_python :: proc(a: ^Int, buf: []u8, signed := false, allocator := context.allocator) -> (err: Error) {
 int_to_bytes_big_python :: proc(a: ^Int, buf: []u8, signed := false, allocator := context.allocator) -> (err: Error) {
 	assert_if_nil(a);
 	assert_if_nil(a);
-	size_in_bytes: int;
 
 
 	if !signed && a.sign == .Negative { return .Invalid_Argument; }
 	if !signed && a.sign == .Negative { return .Invalid_Argument; }
 	if a.sign == .Zero_or_Positive    { return int_to_bytes_big(a, buf, signed, allocator); }
 	if a.sign == .Zero_or_Positive    { return int_to_bytes_big(a, buf, signed, allocator); }
 
 
 	l := len(buf);
 	l := len(buf);
-	if size_in_bytes, err = int_to_bytes_size(a, signed, allocator); err != nil { return err; }
-	if size_in_bytes > l              { return .Buffer_Overflow;  }
+	size_in_bytes := int_to_bytes_size(a, signed, allocator) or_return;
+	if size_in_bytes > l { return .Buffer_Overflow;  }
 
 
 	t := &Int{};
 	t := &Int{};
 	defer destroy(t);
 	defer destroy(t);
 
 
-	if err = internal_complement(t, a, allocator); err != nil { return err; }
+	internal_complement(t, a, allocator) or_return;
 
 
 	size_in_bits := internal_count_bits(t);
 	size_in_bits := internal_count_bits(t);
 	i := l - 1;
 	i := l - 1;
@@ -619,8 +615,8 @@ int_from_bytes_big :: proc(a: ^Int, buf: []u8, signed := false, allocator := con
 	}
 	}
 	size_in_digits := (size_in_bits + _DIGIT_BITS - 1) / _DIGIT_BITS;
 	size_in_digits := (size_in_bits + _DIGIT_BITS - 1) / _DIGIT_BITS;
 	size_in_digits += 0 if size_in_bits % 8 == 0 else 1;
 	size_in_digits += 0 if size_in_bits % 8 == 0 else 1;
-	if err = internal_zero(a, false, allocator); err != nil { return err; }
-	if err = internal_grow(a, size_in_digits, false, allocator); err != nil { return err; }
+	internal_zero(a, false, allocator) or_return;
+	internal_grow(a, size_in_digits, false, allocator) or_return;
 
 
 	if signed {
 	if signed {
 		sign = .Zero_or_Positive if buf[0] == 0 else .Negative;
 		sign = .Zero_or_Positive if buf[0] == 0 else .Negative;
@@ -628,7 +624,7 @@ int_from_bytes_big :: proc(a: ^Int, buf: []u8, signed := false, allocator := con
 	}
 	}
 
 
 	for v in buf {
 	for v in buf {
-		if err = internal_shl(a, a, 8); err != nil { return err; }
+		internal_shl(a, a, 8) or_return;
 		a.digit[0] |= DIGIT(v);
 		a.digit[0] |= DIGIT(v);
 	}
 	}
 	a.sign = sign;
 	a.sign = sign;
@@ -656,8 +652,8 @@ int_from_bytes_big_python :: proc(a: ^Int, buf: []u8, signed := false, allocator
 	}
 	}
 	size_in_digits := (size_in_bits + _DIGIT_BITS - 1) / _DIGIT_BITS;
 	size_in_digits := (size_in_bits + _DIGIT_BITS - 1) / _DIGIT_BITS;
 	size_in_digits += 0 if size_in_bits % 8 == 0 else 1;
 	size_in_digits += 0 if size_in_bits % 8 == 0 else 1;
-	if err = internal_zero(a, false, allocator); err != nil { return err; }
-	if err = internal_grow(a, size_in_digits, false, allocator); err != nil { return err; }
+	internal_zero(a, false, allocator) or_return;
+	internal_grow(a, size_in_digits, false, allocator) or_return;
 
 
 	if signed {
 	if signed {
 		sign = .Zero_or_Positive if buf[0] == 0 else .Negative;
 		sign = .Zero_or_Positive if buf[0] == 0 else .Negative;
@@ -665,7 +661,7 @@ int_from_bytes_big_python :: proc(a: ^Int, buf: []u8, signed := false, allocator
 	}
 	}
 
 
 	for v in buf {
 	for v in buf {
-		if err = internal_shl(a, a, 8); err != nil { return err; }
+		internal_shl(a, a, 8) or_return;
 		if signed && sign == .Negative {
 		if signed && sign == .Negative {
 			a.digit[0] |= DIGIT(255 - v);	
 			a.digit[0] |= DIGIT(255 - v);	
 		} else {
 		} else {
@@ -674,7 +670,7 @@ int_from_bytes_big_python :: proc(a: ^Int, buf: []u8, signed := false, allocator
 	}
 	}
 	a.sign = sign;
 	a.sign = sign;
 	a.used = size_in_digits;
 	a.used = size_in_digits;
-	if err = internal_clamp(a); err != nil { return err; }
+	internal_clamp(a) or_return;
 
 
 	if signed && sign == .Negative {
 	if signed && sign == .Negative {
 		return internal_sub(a, a, 1);
 		return internal_sub(a, a, 1);
@@ -702,8 +698,8 @@ int_from_bytes_little :: proc(a: ^Int, buf: []u8, signed := false, allocator :=
 	}
 	}
 	size_in_digits := (size_in_bits + _DIGIT_BITS - 1) / _DIGIT_BITS;
 	size_in_digits := (size_in_bits + _DIGIT_BITS - 1) / _DIGIT_BITS;
 	size_in_digits += 0 if size_in_bits % 8 == 0 else 1;
 	size_in_digits += 0 if size_in_bits % 8 == 0 else 1;
-	if err = internal_zero(a, false, allocator); err != nil { return err; }
-	if err = internal_grow(a, size_in_digits, false, allocator); err != nil { return err; }
+	internal_zero(a, false, allocator) or_return;
+	internal_grow(a, size_in_digits, false, allocator) or_return;
 
 
 	if signed {
 	if signed {
 		sign = .Zero_or_Positive if buf[l-1] == 0 else .Negative;
 		sign = .Zero_or_Positive if buf[l-1] == 0 else .Negative;
@@ -712,7 +708,7 @@ int_from_bytes_little :: proc(a: ^Int, buf: []u8, signed := false, allocator :=
 	}
 	}
 
 
 	for _, i in buf {
 	for _, i in buf {
-		if err = internal_shl(a, a, 8); err != nil { return err; }
+		internal_shl(a, a, 8) or_return;
 		a.digit[0] |= DIGIT(buf[l-i-1]);
 		a.digit[0] |= DIGIT(buf[l-i-1]);
 	}
 	}
 	a.sign = sign;
 	a.sign = sign;
@@ -740,8 +736,8 @@ int_from_bytes_little_python :: proc(a: ^Int, buf: []u8, signed := false, alloca
 	}
 	}
 	size_in_digits := (size_in_bits + _DIGIT_BITS - 1) / _DIGIT_BITS;
 	size_in_digits := (size_in_bits + _DIGIT_BITS - 1) / _DIGIT_BITS;
 	size_in_digits += 0 if size_in_bits % 8 == 0 else 1;
 	size_in_digits += 0 if size_in_bits % 8 == 0 else 1;
-	if err = internal_zero(a, false, allocator); err != nil { return err; }
-	if err = internal_grow(a, size_in_digits, false, allocator); err != nil { return err; }
+	internal_zero(a, false, allocator) or_return;
+	internal_grow(a, size_in_digits, false, allocator) or_return;
 
 
 	if signed {
 	if signed {
 		sign = .Zero_or_Positive if buf[l-1] == 0 else .Negative;
 		sign = .Zero_or_Positive if buf[l-1] == 0 else .Negative;
@@ -750,7 +746,7 @@ int_from_bytes_little_python :: proc(a: ^Int, buf: []u8, signed := false, alloca
 	}
 	}
 
 
 	for _, i in buf {
 	for _, i in buf {
-		if err = internal_shl(a, a, 8); err != nil { return err; }
+		internal_shl(a, a, 8) or_return;
 		if signed && sign == .Negative {
 		if signed && sign == .Negative {
 			a.digit[0] |= DIGIT(255 - buf[l-i-1]);
 			a.digit[0] |= DIGIT(255 - buf[l-i-1]);
 		} else {
 		} else {
@@ -759,7 +755,7 @@ int_from_bytes_little_python :: proc(a: ^Int, buf: []u8, signed := false, alloca
 	}
 	}
 	a.sign = sign;
 	a.sign = sign;
 	a.used = size_in_digits;
 	a.used = size_in_digits;
-	if err = internal_clamp(a); err != nil { return err; }
+	internal_clamp(a) or_return;
 
 
 	if signed && sign == .Negative {
 	if signed && sign == .Negative {
 		return internal_sub(a, a, 1);
 		return internal_sub(a, a, 1);

+ 72 - 75
core/math/big/internal.odin

@@ -58,7 +58,7 @@ internal_int_add_unsigned :: proc(dest, a, b: ^Int, allocator := context.allocat
 	max_used = x.used;
 	max_used = x.used;
 	old_used = dest.used;
 	old_used = dest.used;
 
 
-	if err = internal_grow(dest, max(max_used + 1, _DEFAULT_DIGIT_COUNT)); err != nil { return err; }
+	internal_grow(dest, max(max_used + 1, _DEFAULT_DIGIT_COUNT)) or_return;
 	dest.used = max_used + 1;
 	dest.used = max_used + 1;
 	/*
 	/*
 		All parameters have been initialized.
 		All parameters have been initialized.
@@ -158,7 +158,7 @@ internal_add_signed :: proc { internal_int_add_signed, };
 internal_int_add_digit :: proc(dest, a: ^Int, digit: DIGIT, allocator := context.allocator) -> (err: Error) {
 internal_int_add_digit :: proc(dest, a: ^Int, digit: DIGIT, allocator := context.allocator) -> (err: Error) {
 	context.allocator = allocator;
 	context.allocator = allocator;
 
 
-	if err = internal_grow(dest, a.used + 1); err != nil { return err; }
+	internal_grow(dest, a.used + 1) or_return;
 	/*
 	/*
 		Fast paths for destination and input Int being the same.
 		Fast paths for destination and input Int being the same.
 	*/
 	*/
@@ -284,7 +284,7 @@ internal_int_sub_unsigned :: proc(dest, number, decrease: ^Int, allocator := con
 	max_used := x.used;
 	max_used := x.used;
 	i: int;
 	i: int;
 
 
-	if err = grow(dest, max(max_used, _DEFAULT_DIGIT_COUNT)); err != nil { return err; }
+	grow(dest, max(max_used, _DEFAULT_DIGIT_COUNT)) or_return;
 	dest.used = max_used;
 	dest.used = max_used;
 	/*
 	/*
 		All parameters have been initialized.
 		All parameters have been initialized.
@@ -389,7 +389,7 @@ internal_int_sub_signed :: proc(dest, number, decrease: ^Int, allocator := conte
 internal_int_sub_digit :: proc(dest, number: ^Int, digit: DIGIT, allocator := context.allocator) -> (err: Error) {
 internal_int_sub_digit :: proc(dest, number: ^Int, digit: DIGIT, allocator := context.allocator) -> (err: Error) {
 	context.allocator = allocator;
 	context.allocator = allocator;
 
 
-	if err = internal_grow(dest, number.used + 1); err != nil { return err; }
+	internal_grow(dest, number.used + 1) or_return;
 
 
 	dest := dest; digit := digit;
 	dest := dest; digit := digit;
 	/*
 	/*
@@ -520,12 +520,12 @@ internal_int_shr1 :: proc(dest, src: ^Int) -> (err: Error) {
 internal_int_shl1 :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error) {
 internal_int_shl1 :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error) {
 	context.allocator = allocator;
 	context.allocator = allocator;
 
 
-	if err = internal_copy(dest, src); err != nil { return err; }
+	internal_copy(dest, src) or_return;
 	/*
 	/*
 		Grow `dest` to accommodate the additional bits.
 		Grow `dest` to accommodate the additional bits.
 	*/
 	*/
 	digits_needed := dest.used + 1;
 	digits_needed := dest.used + 1;
-	if err = internal_grow(dest, digits_needed); err != nil { return err; }
+	internal_grow(dest, digits_needed) or_return;
 	dest.used = digits_needed;
 	dest.used = digits_needed;
 
 
 	mask  := (DIGIT(1) << uint(1)) - DIGIT(1);
 	mask  := (DIGIT(1) << uint(1)) - DIGIT(1);
@@ -568,15 +568,14 @@ internal_int_mul_digit :: proc(dest, src: ^Int, multiplier: DIGIT, allocator :=
 		return #force_inline internal_int_shl1(dest, src);
 		return #force_inline internal_int_shl1(dest, src);
 	}
 	}
 	if #force_inline platform_int_is_power_of_two(int(multiplier)) {
 	if #force_inline platform_int_is_power_of_two(int(multiplier)) {
-		ix: int;
-		if ix, err = internal_log(multiplier, 2); err != nil { return err; }
+		ix := internal_log(multiplier, 2) or_return;
 		return internal_shl(dest, src, ix);
 		return internal_shl(dest, src, ix);
 	}
 	}
 
 
 	/*
 	/*
 		Ensure `dest` is big enough to hold `src` * `multiplier`.
 		Ensure `dest` is big enough to hold `src` * `multiplier`.
 	*/
 	*/
-	if err = grow(dest, max(src.used + 1, _DEFAULT_DIGIT_COUNT)); err != nil { return err; }
+	grow(dest, max(src.used + 1, _DEFAULT_DIGIT_COUNT)) or_return;
 
 
 	/*
 	/*
 		Save the original used count.
 		Save the original used count.
@@ -722,7 +721,7 @@ internal_int_divmod :: proc(quotient, remainder, numerator, denominator: ^Int, a
 	*/
 	*/
 	if #force_inline internal_cmp_mag(numerator, denominator) == -1 {
 	if #force_inline internal_cmp_mag(numerator, denominator) == -1 {
 		if remainder != nil {
 		if remainder != nil {
-			if err = internal_copy(remainder, numerator); err != nil { return err; }
+			internal_copy(remainder, numerator) or_return;
 		}
 		}
 		if quotient != nil {
 		if quotient != nil {
 			internal_zero(quotient);
 			internal_zero(quotient);
@@ -809,7 +808,7 @@ internal_int_divmod_digit :: proc(quotient, numerator: ^Int, denominator: DIGIT,
 	*/
 	*/
 	q := &Int{};
 	q := &Int{};
 
 
-	if err = internal_grow(q, numerator.used); err != nil { return 0, err; }
+	internal_grow(q, numerator.used) or_return;
 
 
 	q.used = numerator.used;
 	q.used = numerator.used;
 	q.sign = numerator.sign;
 	q.sign = numerator.sign;
@@ -853,7 +852,7 @@ internal_div :: proc { internal_int_div, };
 	Asssumes quotient, numerator and denominator to have been initialized and not to be nil.
 	Asssumes quotient, numerator and denominator to have been initialized and not to be nil.
 */
 */
 internal_int_mod :: proc(remainder, numerator, denominator: ^Int, allocator := context.allocator) -> (err: Error) {
 internal_int_mod :: proc(remainder, numerator, denominator: ^Int, allocator := context.allocator) -> (err: Error) {
-	if err = #force_inline internal_int_divmod(nil, remainder, numerator, denominator, allocator); err != nil { return err; }
+	#force_inline internal_int_divmod(nil, remainder, numerator, denominator, allocator) or_return;
 
 
 	if remainder.used == 0 || denominator.sign == remainder.sign { return nil; }
 	if remainder.used == 0 || denominator.sign == remainder.sign { return nil; }
 
 
@@ -865,7 +864,7 @@ internal_mod :: proc{ internal_int_mod, };
 	remainder = (number + addend) % modulus.
 	remainder = (number + addend) % modulus.
 */
 */
 internal_int_addmod :: proc(remainder, number, addend, modulus: ^Int, allocator := context.allocator) -> (err: Error) {
 internal_int_addmod :: proc(remainder, number, addend, modulus: ^Int, allocator := context.allocator) -> (err: Error) {
-	if err = #force_inline internal_add(remainder, number, addend, allocator); err != nil { return err; }
+	#force_inline internal_add(remainder, number, addend, allocator) or_return;
 	return #force_inline internal_mod(remainder, remainder, modulus, allocator);
 	return #force_inline internal_mod(remainder, remainder, modulus, allocator);
 }
 }
 internal_addmod :: proc { internal_int_addmod, };
 internal_addmod :: proc { internal_int_addmod, };
@@ -874,7 +873,7 @@ internal_addmod :: proc { internal_int_addmod, };
 	remainder = (number - decrease) % modulus.
 	remainder = (number - decrease) % modulus.
 */
 */
 internal_int_submod :: proc(remainder, number, decrease, modulus: ^Int, allocator := context.allocator) -> (err: Error) {
 internal_int_submod :: proc(remainder, number, decrease, modulus: ^Int, allocator := context.allocator) -> (err: Error) {
-	if err = #force_inline internal_sub(remainder, number, decrease, allocator); err != nil { return err; }
+	#force_inline internal_sub(remainder, number, decrease, allocator) or_return;
 	return #force_inline internal_mod(remainder, remainder, modulus, allocator);
 	return #force_inline internal_mod(remainder, remainder, modulus, allocator);
 }
 }
 internal_submod :: proc { internal_int_submod, };
 internal_submod :: proc { internal_int_submod, };
@@ -883,7 +882,7 @@ internal_submod :: proc { internal_int_submod, };
 	remainder = (number * multiplicand) % modulus.
 	remainder = (number * multiplicand) % modulus.
 */
 */
 internal_int_mulmod :: proc(remainder, number, multiplicand, modulus: ^Int, allocator := context.allocator) -> (err: Error) {
 internal_int_mulmod :: proc(remainder, number, multiplicand, modulus: ^Int, allocator := context.allocator) -> (err: Error) {
-	if err = #force_inline internal_mul(remainder, number, multiplicand, allocator); err != nil { return err; }
+	#force_inline internal_mul(remainder, number, multiplicand, allocator) or_return;
 	return #force_inline internal_mod(remainder, remainder, modulus, allocator);
 	return #force_inline internal_mod(remainder, remainder, modulus, allocator);
 }
 }
 internal_mulmod :: proc { internal_int_mulmod, };
 internal_mulmod :: proc { internal_int_mulmod, };
@@ -892,7 +891,7 @@ internal_mulmod :: proc { internal_int_mulmod, };
 	remainder = (number * number) % modulus.
 	remainder = (number * number) % modulus.
 */
 */
 internal_int_sqrmod :: proc(remainder, number, modulus: ^Int, allocator := context.allocator) -> (err: Error) {
 internal_int_sqrmod :: proc(remainder, number, modulus: ^Int, allocator := context.allocator) -> (err: Error) {
-	if err = #force_inline internal_sqr(remainder, number, allocator); err != nil { return err; }
+	#force_inline internal_sqr(remainder, number, allocator) or_return;
 	return #force_inline internal_mod(remainder, remainder, modulus, allocator);
 	return #force_inline internal_mod(remainder, remainder, modulus, allocator);
 }
 }
 internal_sqrmod :: proc { internal_int_sqrmod, };
 internal_sqrmod :: proc { internal_int_sqrmod, };
@@ -915,9 +914,11 @@ internal_int_factorial :: proc(res: ^Int, n: int, allocator := context.allocator
 		return #force_inline internal_set(res, _factorial_table[n]);
 		return #force_inline internal_set(res, _factorial_table[n]);
 	}
 	}
 
 
-	if err = #force_inline internal_set(res, _factorial_table[i - 1]); err != nil { return err; }
+	#force_inline internal_set(res, _factorial_table[i - 1]) or_return;
 	for {
 	for {
-		if err = #force_inline internal_mul(res, res, DIGIT(i)); err != nil || i == n { return err; }
+		if err = #force_inline internal_mul(res, res, DIGIT(i)); err != nil || i == n {
+			return err;
+		}
 		i += 1;
 		i += 1;
 	}
 	}
 
 
@@ -950,8 +951,8 @@ internal_int_mod_bits :: proc(remainder, numerator: ^Int, bits: int, allocator :
 	/*
 	/*
 		If the modulus is larger than the value, return the value.
 		If the modulus is larger than the value, return the value.
 	*/
 	*/
-	err = internal_copy(remainder, numerator);
-	if bits >= (numerator.used * _DIGIT_BITS) || err != nil {
+	internal_copy(remainder, numerator) or_return;
+	if bits >= (numerator.used * _DIGIT_BITS) {
 		return;
 		return;
 	}
 	}
 
 
@@ -1264,7 +1265,7 @@ internal_int_pow :: proc(dest, base: ^Int, power: int, allocator := context.allo
 			A zero base is a special case.
 			A zero base is a special case.
 		*/
 		*/
 		if power  < 0 {
 		if power  < 0 {
-			if err = internal_zero(dest); err != nil { return err; }
+			internal_zero(dest) or_return;
 			return .Math_Domain_Error;
 			return .Math_Domain_Error;
 		}
 		}
 		if power == 0 { return  internal_one(dest); }
 		if power == 0 { return  internal_one(dest); }
@@ -1293,37 +1294,34 @@ internal_int_pow :: proc(dest, base: ^Int, power: int, allocator := context.allo
 	}
 	}
 
 
 	g := &Int{};
 	g := &Int{};
-	if err = internal_copy(g, base); err != nil { return err; }
+	internal_copy(g, base) or_return;
 
 
 	/*
 	/*
 		Set initial result.
 		Set initial result.
 	*/
 	*/
-	if err = internal_one(dest); err != nil { return err; }
+	internal_one(dest) or_return;
+
+	defer internal_destroy(g);
 
 
-	loop: for power > 0 {
+	for power > 0 {
 		/*
 		/*
 			If the bit is set, multiply.
 			If the bit is set, multiply.
 		*/
 		*/
 		if power & 1 != 0 {
 		if power & 1 != 0 {
-			if err = internal_mul(dest, g, dest); err != nil {
-				break loop;
-			}
+			internal_mul(dest, g, dest) or_return;
 		}
 		}
 		/*
 		/*
 			Square.
 			Square.
 		*/
 		*/
 		if power > 1 {
 		if power > 1 {
-			if err = #force_inline internal_sqr(g, g); err != nil {
-				break loop;
-			}
+			internal_sqr(g, g) or_return;
 		}
 		}
 
 
 		/* shift to next bit */
 		/* shift to next bit */
 		power >>= 1;
 		power >>= 1;
 	}
 	}
 
 
-	internal_destroy(g);
-	return err;
+	return;
 }
 }
 
 
 /*
 /*
@@ -1336,7 +1334,7 @@ internal_int_pow_int :: proc(dest: ^Int, base, power: int, allocator := context.
 	base_t := &Int{};
 	base_t := &Int{};
 	defer internal_destroy(base_t);
 	defer internal_destroy(base_t);
 
 
-	if err = internal_set(base_t, base); err != nil { return err; }
+	internal_set(base_t, base) or_return;
 
 
 	return #force_inline internal_int_pow(dest, base_t, power);
 	return #force_inline internal_int_pow(dest, base_t, power);
 }
 }
@@ -1387,15 +1385,15 @@ internal_int_sqrt :: proc(dest, src: ^Int, allocator := context.allocator) -> (e
 	count := #force_inline internal_count_bits(src);
 	count := #force_inline internal_count_bits(src);
 
 
 	a, b := count >> 1, count & 1;
 	a, b := count >> 1, count & 1;
-	if err = internal_int_power_of_two(x, a+b, allocator);   err != nil { return err; }
+	internal_int_power_of_two(x, a+b, allocator) or_return;
 
 
 	for {
 	for {
 		/*
 		/*
 			y = (x + n // x) // 2
 			y = (x + n // x) // 2
 		*/
 		*/
-		if err = internal_div(t1, src, x); err != nil { return err; }
-		if err = internal_add(t2, t1, x);  err != nil { return err; }
-		if err = internal_shr(y, t2, 1);   err != nil { return err; }
+		internal_div(t1, src, x) or_return;
+		internal_add(t2, t1, x)  or_return;
+		internal_shr(y, t2, 1)   or_return;
 
 
 		if c := internal_cmp(y, x); c == 0 || c == 1 {
 		if c := internal_cmp(y, x); c == 0 || c == 1 {
 			internal_swap(dest, x);
 			internal_swap(dest, x);
@@ -1480,33 +1478,33 @@ internal_int_root_n :: proc(dest, src: ^Int, n: int, allocator := context.alloca
 		Start value must be larger than root.
 		Start value must be larger than root.
 	*/
 	*/
 	ilog2 += 2;
 	ilog2 += 2;
-	if err = internal_int_power_of_two(t2, ilog2); err != nil { return err; }
+	internal_int_power_of_two(t2, ilog2) or_return;
 
 
 	c: int;
 	c: int;
 	iterations := 0;
 	iterations := 0;
 	for {
 	for {
 		/* t1 = t2 */
 		/* t1 = t2 */
-		if err = internal_copy(t1, t2); err != nil { return err; }
+		internal_copy(t1, t2) or_return;
 
 
 		/* t2 = t1 - ((t1**b - a) / (b * t1**(b-1))) */
 		/* t2 = t1 - ((t1**b - a) / (b * t1**(b-1))) */
 
 
 		/* t3 = t1**(b-1) */
 		/* t3 = t1**(b-1) */
-		if err = internal_pow(t3, t1, n-1); err != nil { return err; }
+		internal_pow(t3, t1, n-1) or_return;
 
 
 		/* numerator */
 		/* numerator */
 		/* t2 = t1**b */
 		/* t2 = t1**b */
-		if err = internal_mul(t2, t1, t3); err != nil { return err; }
+		internal_mul(t2, t1, t3) or_return;
 
 
 		/* t2 = t1**b - a */
 		/* t2 = t1**b - a */
-		if err = internal_sub(t2, t2, a); err != nil { return err; }
+		internal_sub(t2, t2, a) or_return;
 
 
 		/* denominator */
 		/* denominator */
 		/* t3 = t1**(b-1) * b  */
 		/* t3 = t1**(b-1) * b  */
-		if err = internal_mul(t3, t3, DIGIT(n)); err != nil { return err; }
+		internal_mul(t3, t3, DIGIT(n)) or_return;
 
 
 		/* t3 = (t1**b - a)/(b * t1**(b-1)) */
 		/* t3 = (t1**b - a)/(b * t1**(b-1)) */
-		if err = internal_div(t3, t2, t3); err != nil { return err; }
-		if err = internal_sub(t2, t1, t3); err != nil { return err; }
+		internal_div(t3, t2, t3) or_return;
+		internal_sub(t2, t1, t3) or_return;
 
 
 		/*
 		/*
 			 Number of rounds is at most log_2(root). If it is more it
 			 Number of rounds is at most log_2(root). If it is more it
@@ -1526,14 +1524,14 @@ internal_int_root_n :: proc(dest, src: ^Int, n: int, allocator := context.alloca
 
 
 	iterations = 0;
 	iterations = 0;
 	for {
 	for {
-		if err = internal_pow(t2, t1, n); err != nil { return err; }
+		internal_pow(t2, t1, n) or_return;
 
 
 		c = internal_cmp(t2, a);
 		c = internal_cmp(t2, a);
 		if c == 0 {
 		if c == 0 {
 			swap(dest, t1);
 			swap(dest, t1);
 			return nil;
 			return nil;
 		} else if c == -1 {
 		} else if c == -1 {
-			if err = internal_add(t1, t1, DIGIT(1)); err != nil { return err; }
+			internal_add(t1, t1, DIGIT(1)) or_return;
 		} else {
 		} else {
 			break;
 			break;
 		}
 		}
@@ -1549,11 +1547,11 @@ internal_int_root_n :: proc(dest, src: ^Int, n: int, allocator := context.alloca
 		Correct overshoot from above or from recurrence.
 		Correct overshoot from above or from recurrence.
 		*/
 		*/
 	for {
 	for {
-		if err = internal_pow(t2, t1, n); err != nil { return err; }
+		internal_pow(t2, t1, n) or_return;
 	
 	
 		if internal_cmp(t2, a) != 1 { break; }
 		if internal_cmp(t2, a) != 1 { break; }
 		
 		
-		if err = internal_sub(t1, t1, DIGIT(1)); err != nil { return err; }
+		internal_sub(t1, t1, DIGIT(1)) or_return;
 
 
 		iterations += 1;
 		iterations += 1;
 		if iterations == MAX_ITERATIONS_ROOT_N {
 		if iterations == MAX_ITERATIONS_ROOT_N {
@@ -1606,12 +1604,12 @@ internal_int_set_from_integer :: proc(dest: ^Int, src: $T, minimize := false, al
 
 
 	src := src;
 	src := src;
 
 
-	if err = internal_error_if_immutable(dest); err != nil { return err; }
+	internal_error_if_immutable(dest) or_return;
 	/*
 	/*
 		Most internal procs asssume an Int to have already been initialize,
 		Most internal procs asssume an Int to have already been initialize,
 		but as this is one of the procs that initializes, we have to check the following.
 		but as this is one of the procs that initializes, we have to check the following.
 	*/
 	*/
-	if err = internal_clear_if_uninitialized_single(dest); err != nil { return err; }
+	internal_clear_if_uninitialized_single(dest) or_return;
 
 
 	dest.flags = {}; // We're not -Inf, Inf, NaN or Immutable.
 	dest.flags = {}; // We're not -Inf, Inf, NaN or Immutable.
 
 
@@ -1631,7 +1629,7 @@ internal_int_set_from_integer :: proc(dest: ^Int, src: $T, minimize := false, al
 internal_set :: proc { internal_int_set_from_integer, internal_int_copy };
 internal_set :: proc { internal_int_set_from_integer, internal_int_copy };
 
 
 internal_copy_digits :: #force_inline proc(dest, src: ^Int, digits: int) -> (err: Error) {
 internal_copy_digits :: #force_inline proc(dest, src: ^Int, digits: int) -> (err: Error) {
-	if err = #force_inline internal_error_if_immutable(dest); err != nil { return err; }
+	#force_inline internal_error_if_immutable(dest) or_return;
 
 
 	/*
 	/*
 		If dest == src, do nothing
 		If dest == src, do nothing
@@ -1653,7 +1651,7 @@ internal_int_copy :: proc(dest, src: ^Int, minimize := false, allocator := conte
 	*/
 	*/
 	if (dest == src) { return nil; }
 	if (dest == src) { return nil; }
 
 
-	if err = internal_error_if_immutable(dest); err != nil { return err; }
+	internal_error_if_immutable(dest) or_return;
 
 
 	/*
 	/*
 		Grow `dest` to fit `src`.
 		Grow `dest` to fit `src`.
@@ -1661,7 +1659,7 @@ internal_int_copy :: proc(dest, src: ^Int, minimize := false, allocator := conte
 	*/
 	*/
 	needed := src.used if minimize else max(src.used, _DEFAULT_DIGIT_COUNT);
 	needed := src.used if minimize else max(src.used, _DEFAULT_DIGIT_COUNT);
 
 
-	if err = internal_grow(dest, needed, minimize); err != nil { return err; }
+	internal_grow(dest, needed, minimize) or_return;
 
 
 	/*
 	/*
 		Copy everything over and zero high digits.
 		Copy everything over and zero high digits.
@@ -1708,9 +1706,7 @@ internal_int_abs :: proc(dest, src: ^Int, allocator := context.allocator) -> (er
 	/*
 	/*
 		Copy `src` to `dest`
 		Copy `src` to `dest`
 	*/
 	*/
-	if err = internal_copy(dest, src); err != nil {
-		return err;
-	}
+	internal_copy(dest, src) or_return;
 
 
 	/*
 	/*
 		Fix sign.
 		Fix sign.
@@ -1744,7 +1740,7 @@ internal_int_neg :: proc(dest, src: ^Int, allocator := context.allocator) -> (er
 	/*
 	/*
 		Copy `src` to `dest`
 		Copy `src` to `dest`
 	*/
 	*/
-	if err = internal_copy(dest, src); err != nil { return err; }
+	internal_copy(dest, src) or_return;
 
 
 	/*
 	/*
 		Fix sign.
 		Fix sign.
@@ -1953,7 +1949,7 @@ internal_int_power_of_two :: proc(a: ^Int, power: int, allocator := context.allo
 		Grow to accomodate the single bit.
 		Grow to accomodate the single bit.
 	*/
 	*/
 	a.used = (power / _DIGIT_BITS) + 1;
 	a.used = (power / _DIGIT_BITS) + 1;
-	if err = internal_grow(a, a.used); err != nil { return err; }
+	internal_grow(a, a.used) or_return;
 	/*
 	/*
 		Zero the entirety.
 		Zero the entirety.
 	*/
 	*/
@@ -2061,7 +2057,7 @@ internal_int_and :: proc(dest, a, b: ^Int, allocator := context.allocator) -> (e
 	/*
 	/*
 		Grow the destination to accomodate the result.
 		Grow the destination to accomodate the result.
 	*/
 	*/
-	if err = internal_grow(dest, used); err != nil { return err; }
+	internal_grow(dest, used) or_return;
 
 
 	neg_a := #force_inline internal_is_negative(a);
 	neg_a := #force_inline internal_is_negative(a);
 	neg_b := #force_inline internal_is_negative(b);
 	neg_b := #force_inline internal_is_negative(b);
@@ -2122,7 +2118,7 @@ internal_int_or :: proc(dest, a, b: ^Int, allocator := context.allocator) -> (er
 	/*
 	/*
 		Grow the destination to accomodate the result.
 		Grow the destination to accomodate the result.
 	*/
 	*/
-	if err = internal_grow(dest, used); err != nil { return err; }
+	internal_grow(dest, used) or_return;
 
 
 	neg_a := #force_inline internal_is_negative(a);
 	neg_a := #force_inline internal_is_negative(a);
 	neg_b := #force_inline internal_is_negative(b);
 	neg_b := #force_inline internal_is_negative(b);
@@ -2183,7 +2179,7 @@ internal_int_xor :: proc(dest, a, b: ^Int, allocator := context.allocator) -> (e
 	/*
 	/*
 		Grow the destination to accomodate the result.
 		Grow the destination to accomodate the result.
 	*/
 	*/
-	if err = internal_grow(dest, used); err != nil { return err; }
+	internal_grow(dest, used) or_return;
 
 
 	neg_a := #force_inline internal_is_negative(a);
 	neg_a := #force_inline internal_is_negative(a);
 	neg_b := #force_inline internal_is_negative(b);
 	neg_b := #force_inline internal_is_negative(b);
@@ -2269,21 +2265,21 @@ internal_int_shrmod :: proc(quotient, remainder, numerator: ^Int, bits: int, all
 	bits := bits;
 	bits := bits;
 	if bits < 0 { return .Invalid_Argument; }
 	if bits < 0 { return .Invalid_Argument; }
 
 
-	if err = internal_copy(quotient, numerator); err != nil { return err; }
+	internal_copy(quotient, numerator) or_return;
 
 
 	/*
 	/*
 		Shift right by a certain bit count (store quotient and optional remainder.)
 		Shift right by a certain bit count (store quotient and optional remainder.)
 	   `numerator` should not be used after this.
 	   `numerator` should not be used after this.
 	*/
 	*/
 	if remainder != nil {
 	if remainder != nil {
-		if err = internal_int_mod_bits(remainder, numerator, bits); err != nil { return err; }
+		internal_int_mod_bits(remainder, numerator, bits) or_return;
 	}
 	}
 
 
 	/*
 	/*
 		Shift by as many digits in the bit count.
 		Shift by as many digits in the bit count.
 	*/
 	*/
 	if bits >= _DIGIT_BITS {
 	if bits >= _DIGIT_BITS {
-		if err = internal_shr_digit(quotient, bits / _DIGIT_BITS); err != nil { return err; }
+		internal_shr_digit(quotient, bits / _DIGIT_BITS) or_return;
 	}
 	}
 
 
 	/*
 	/*
@@ -2362,9 +2358,8 @@ internal_int_shr_signed :: proc(dest, src: ^Int, bits: int, allocator := context
 	if src.sign == .Zero_or_Positive {
 	if src.sign == .Zero_or_Positive {
 		return internal_shr(dest, src, bits);
 		return internal_shr(dest, src, bits);
 	}
 	}
-	if err = internal_int_add_digit(dest, src, DIGIT(1)); err != nil { return err; }
-
-	if err = internal_shr(dest, dest, bits);              err != nil { return err; }
+	internal_int_add_digit(dest, src, DIGIT(1)) or_return;
+	internal_shr(dest, dest, bits) or_return;
 	return internal_sub(dest, src, DIGIT(1));
 	return internal_sub(dest, src, DIGIT(1));
 }
 }
 
 
@@ -2380,19 +2375,19 @@ internal_int_shl :: proc(dest, src: ^Int, bits: int, allocator := context.alloca
 
 
 	if bits < 0 { return .Invalid_Argument; }
 	if bits < 0 { return .Invalid_Argument; }
 
 
-	if err = internal_copy(dest, src); err != nil { return err; }
+	internal_copy(dest, src) or_return;
 
 
 	/*
 	/*
 		Grow `dest` to accommodate the additional bits.
 		Grow `dest` to accommodate the additional bits.
 	*/
 	*/
 	digits_needed := dest.used + (bits / _DIGIT_BITS) + 1;
 	digits_needed := dest.used + (bits / _DIGIT_BITS) + 1;
-	if err = internal_grow(dest, digits_needed); err != nil { return err; }
+	internal_grow(dest, digits_needed) or_return;
 	dest.used = digits_needed;
 	dest.used = digits_needed;
 	/*
 	/*
 		Shift by as many digits in the bit count as we have.
 		Shift by as many digits in the bit count as we have.
 	*/
 	*/
 	if bits >= _DIGIT_BITS {
 	if bits >= _DIGIT_BITS {
-		if err = internal_shl_digit(dest, bits / _DIGIT_BITS); err != nil { return err; }
+		internal_shl_digit(dest, bits / _DIGIT_BITS) or_return;
 	}
 	}
 
 
 	/*
 	/*
@@ -2434,12 +2429,14 @@ internal_int_shl_digit :: proc(quotient: ^Int, digits: int, allocator := context
 	/*
 	/*
 		No need to shift a zero.
 		No need to shift a zero.
 	*/
 	*/
-	if #force_inline internal_is_zero(quotient) { return {}; }
+	if #force_inline internal_is_zero(quotient) {
+		return nil;
+	}
 
 
 	/*
 	/*
 		Resize `quotient` to accomodate extra digits.
 		Resize `quotient` to accomodate extra digits.
 	*/
 	*/
-	if err = #force_inline internal_grow(quotient, quotient.used + digits); err != nil { return err; }
+	#force_inline internal_grow(quotient, quotient.used + digits) or_return;
 
 
 	/*
 	/*
 		Increment the used by the shift amount then copy upwards.
 		Increment the used by the shift amount then copy upwards.
@@ -2537,7 +2534,7 @@ internal_int_rand :: proc(dest: ^Int, bits: int, r: ^rnd.Rand = nil, allocator :
 		digits += 1;
 		digits += 1;
 	}
 	}
 
 
-	if err = #force_inline internal_grow(dest, digits); err != nil { return err; }
+	#force_inline internal_grow(dest, digits) or_return;
 
 
 	for i := 0; i < digits; i += 1 {
 	for i := 0; i < digits; i += 1 {
 		dest.digit[i] = int_random_digit(r) & _MASK;
 		dest.digit[i] = int_random_digit(r) & _MASK;
@@ -2600,7 +2597,7 @@ internal_int_init_multi :: proc(integers: ..^Int, allocator := context.allocator
 
 
 	integers := integers;
 	integers := integers;
 	for a in &integers {
 	for a in &integers {
-		if err = internal_clear(a); err != nil { return err; }
+		internal_clear(a) or_return;
 	}
 	}
 	return nil;
 	return nil;
 }
 }

+ 8 - 8
core/math/big/logical.odin

@@ -25,7 +25,7 @@ int_and :: proc(dest, a, b: ^Int, allocator := context.allocator) -> (err: Error
 	assert_if_nil(dest, a, b);
 	assert_if_nil(dest, a, b);
 	context.allocator = allocator;
 	context.allocator = allocator;
 
 
-	if err = internal_clear_if_uninitialized(a, b); err != nil { return err; }
+	internal_clear_if_uninitialized(a, b) or_return;
 	return #force_inline internal_int_and(dest, a, b);
 	return #force_inline internal_int_and(dest, a, b);
 }
 }
 and :: proc { int_and, };
 and :: proc { int_and, };
@@ -37,7 +37,7 @@ int_or :: proc(dest, a, b: ^Int, allocator := context.allocator) -> (err: Error)
 	assert_if_nil(dest, a, b);
 	assert_if_nil(dest, a, b);
 	context.allocator = allocator;
 	context.allocator = allocator;
 
 
-	if err = internal_clear_if_uninitialized(a, b); err != nil { return err; }
+	internal_clear_if_uninitialized(a, b) or_return;
 	return #force_inline internal_int_or(dest, a, b);
 	return #force_inline internal_int_or(dest, a, b);
 }
 }
 or :: proc { int_or, };
 or :: proc { int_or, };
@@ -49,7 +49,7 @@ int_xor :: proc(dest, a, b: ^Int, allocator := context.allocator) -> (err: Error
 	assert_if_nil(dest, a, b);
 	assert_if_nil(dest, a, b);
 	context.allocator = allocator;
 	context.allocator = allocator;
 
 
-	if err = internal_clear_if_uninitialized(a, b); err != nil { return err; }
+	internal_clear_if_uninitialized(a, b) or_return;
 	return #force_inline internal_int_xor(dest, a, b);
 	return #force_inline internal_int_xor(dest, a, b);
 }
 }
 xor :: proc { int_xor, };
 xor :: proc { int_xor, };
@@ -64,7 +64,7 @@ int_complement :: proc(dest, src: ^Int, allocator := context.allocator) -> (err:
 	assert_if_nil(dest, src);
 	assert_if_nil(dest, src);
 	context.allocator = allocator;
 	context.allocator = allocator;
 
 
-	if err = internal_clear_if_uninitialized(dest, src); err != nil { return err; }
+	internal_clear_if_uninitialized(dest, src) or_return;
 	return #force_inline internal_int_complement(dest, src);
 	return #force_inline internal_int_complement(dest, src);
 }
 }
 complement :: proc { int_complement, };
 complement :: proc { int_complement, };
@@ -97,7 +97,7 @@ int_shr_digit :: proc(quotient: ^Int, digits: int, allocator := context.allocato
 	assert_if_nil(quotient);
 	assert_if_nil(quotient);
 	context.allocator = allocator;
 	context.allocator = allocator;
 
 
-	if err = internal_clear_if_uninitialized(quotient); err != nil { return err; }
+	internal_clear_if_uninitialized(quotient) or_return;
 	return #force_inline internal_int_shr_digit(quotient, digits);
 	return #force_inline internal_int_shr_digit(quotient, digits);
 }
 }
 shr_digit :: proc { int_shr_digit, };
 shr_digit :: proc { int_shr_digit, };
@@ -109,7 +109,7 @@ int_shr_signed :: proc(dest, src: ^Int, bits: int, allocator := context.allocato
 	assert_if_nil(dest, src);
 	assert_if_nil(dest, src);
 	context.allocator = allocator;
 	context.allocator = allocator;
 
 
-	if err = internal_clear_if_uninitialized(dest, src); err != nil { return err; }
+	internal_clear_if_uninitialized(dest, src) or_return;
 	return #force_inline internal_int_shr_signed(dest, src, bits);
 	return #force_inline internal_int_shr_signed(dest, src, bits);
 }
 }
 
 
@@ -122,7 +122,7 @@ int_shl :: proc(dest, src: ^Int, bits: int, allocator := context.allocator) -> (
 	assert_if_nil(dest, src);
 	assert_if_nil(dest, src);
 	context.allocator = allocator;
 	context.allocator = allocator;
 
 
-	if err = internal_clear_if_uninitialized(dest, src); err != nil { return err; }
+	internal_clear_if_uninitialized(dest, src) or_return;
 	return #force_inline internal_int_shl(dest, src, bits);
 	return #force_inline internal_int_shl(dest, src, bits);
 }
 }
 shl :: proc { int_shl, };
 shl :: proc { int_shl, };
@@ -138,7 +138,7 @@ int_shl_digit :: proc(quotient: ^Int, digits: int, allocator := context.allocato
 	assert_if_nil(quotient);
 	assert_if_nil(quotient);
 	context.allocator = allocator;
 	context.allocator = allocator;
 
 
-	if err = internal_clear_if_uninitialized(quotient); err != nil { return err; }
+	internal_clear_if_uninitialized(quotient) or_return;
 	return #force_inline internal_int_shl_digit(quotient, digits);
 	return #force_inline internal_int_shl_digit(quotient, digits);
 }
 }
 shl_digit :: proc { int_shl_digit, };
 shl_digit :: proc { int_shl_digit, };

+ 5 - 4
core/math/big/prime.odin

@@ -19,12 +19,13 @@ int_prime_is_divisible :: proc(a: ^Int, allocator := context.allocator) -> (res:
 	assert_if_nil(a);
 	assert_if_nil(a);
 	context.allocator = allocator;
 	context.allocator = allocator;
 
 
-	if err = internal_clear_if_uninitialized(a); err != nil { return {}, err; }
+	internal_clear_if_uninitialized(a) or_return;
 
 
-	rem: DIGIT;
 	for prime in _private_prime_table {
 	for prime in _private_prime_table {
-		if rem, err = #force_inline int_mod_digit(a, prime); err != nil { return false, err; }
-		if rem == 0 { return true, nil; }
+		rem := #force_inline int_mod_digit(a, prime) or_return;
+		if rem == 0 {
+			return true, nil;
+		}
 	}
 	}
 	/*
 	/*
 		Default to not divisible.
 		Default to not divisible.

File diff suppressed because it is too large
+ 224 - 195
core/math/big/private.odin


+ 45 - 46
core/math/big/public.odin

@@ -24,7 +24,7 @@ int_add :: proc(dest, a, b: ^Int, allocator := context.allocator) -> (err: Error
 	assert_if_nil(dest, a, b);
 	assert_if_nil(dest, a, b);
 	context.allocator = allocator;
 	context.allocator = allocator;
 
 
-	if err = internal_clear_if_uninitialized(dest, a, b); err != nil { return err; }
+	internal_clear_if_uninitialized(dest, a, b) or_return;
 	/*
 	/*
 		All parameters have been initialized.
 		All parameters have been initialized.
 	*/
 	*/
@@ -41,11 +41,11 @@ int_add_digit :: proc(dest, a: ^Int, digit: DIGIT, allocator := context.allocato
 	assert_if_nil(dest, a);
 	assert_if_nil(dest, a);
 	context.allocator = allocator;
 	context.allocator = allocator;
 
 
-	if err = internal_clear_if_uninitialized(a); err != nil { return err; }
+	internal_clear_if_uninitialized(a) or_return;
 	/*
 	/*
 		Grow destination as required.
 		Grow destination as required.
 	*/
 	*/
-	if err = grow(dest, a.used + 1); err != nil { return err; }
+	grow(dest, a.used + 1) or_return;
 
 
 	/*
 	/*
 		All parameters have been initialized.
 		All parameters have been initialized.
@@ -60,7 +60,7 @@ int_sub :: proc(dest, number, decrease: ^Int, allocator := context.allocator) ->
 	assert_if_nil(dest, number, decrease);
 	assert_if_nil(dest, number, decrease);
 	context.allocator = allocator;
 	context.allocator = allocator;
 
 
-	if err = internal_clear_if_uninitialized(dest, number, decrease); err != nil { return err; }
+	internal_clear_if_uninitialized(dest, number, decrease) or_return;
 	/*
 	/*
 		All parameters have been initialized.
 		All parameters have been initialized.
 	*/
 	*/
@@ -77,11 +77,11 @@ int_sub_digit :: proc(dest, a: ^Int, digit: DIGIT, allocator := context.allocato
 	assert_if_nil(dest, a);
 	assert_if_nil(dest, a);
 	context.allocator = allocator;
 	context.allocator = allocator;
 
 
-	if err = internal_clear_if_uninitialized(a); err != nil { return err; }
+	internal_clear_if_uninitialized(a) or_return;
 	/*
 	/*
 		Grow destination as required.
 		Grow destination as required.
 	*/
 	*/
-	if err = grow(dest, a.used + 1); err != nil { return err; }
+	grow(dest, a.used + 1) or_return;
 
 
 	/*
 	/*
 		All parameters have been initialized.
 		All parameters have been initialized.
@@ -97,11 +97,11 @@ int_halve :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Erro
 	assert_if_nil(dest, src);
 	assert_if_nil(dest, src);
 	context.allocator = allocator;
 	context.allocator = allocator;
 
 
-	if err = internal_clear_if_uninitialized(dest, src); err != nil { return err; }
+	internal_clear_if_uninitialized(dest, src) or_return;
 	/*
 	/*
 		Grow destination as required.
 		Grow destination as required.
 	*/
 	*/
-	if dest != src { if err = grow(dest, src.used + 1); err != nil { return err; } }
+	if dest != src { grow(dest, src.used + 1) or_return }
 
 
 	return #force_inline internal_int_shr1(dest, src);
 	return #force_inline internal_int_shr1(dest, src);
 }
 }
@@ -116,11 +116,11 @@ int_double :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Err
 	assert_if_nil(dest, src);
 	assert_if_nil(dest, src);
 	context.allocator = allocator;
 	context.allocator = allocator;
 
 
-	if err = internal_clear_if_uninitialized(dest, src); err != nil { return err; }
+	internal_clear_if_uninitialized(dest, src) or_return;
 	/*
 	/*
 		Grow destination as required.
 		Grow destination as required.
 	*/
 	*/
-	if dest != src { if err = grow(dest, src.used + 1); err != nil { return err; } }
+	if dest != src { grow(dest, src.used + 1) or_return; }
 
 
 	return #force_inline internal_int_shl1(dest, src);
 	return #force_inline internal_int_shl1(dest, src);
 }
 }
@@ -134,7 +134,7 @@ int_mul_digit :: proc(dest, src: ^Int, multiplier: DIGIT, allocator := context.a
 	assert_if_nil(dest, src);
 	assert_if_nil(dest, src);
 	context.allocator = allocator;
 	context.allocator = allocator;
 
 
-	if err = internal_clear_if_uninitialized(src, dest); err != nil { return err; }
+	internal_clear_if_uninitialized(src, dest) or_return;
 
 
 	return #force_inline internal_int_mul_digit(dest, src, multiplier);
 	return #force_inline internal_int_mul_digit(dest, src, multiplier);
 }
 }
@@ -146,7 +146,7 @@ int_mul :: proc(dest, src, multiplier: ^Int, allocator := context.allocator) ->
 	assert_if_nil(dest, src, multiplier);
 	assert_if_nil(dest, src, multiplier);
 	context.allocator = allocator;
 	context.allocator = allocator;
 
 
-	if err = internal_clear_if_uninitialized(dest, src, multiplier); err != nil { return err; }
+	internal_clear_if_uninitialized(dest, src, multiplier) or_return;
 
 
 	return #force_inline internal_int_mul(dest, src, multiplier);
 	return #force_inline internal_int_mul(dest, src, multiplier);
 }
 }
@@ -166,7 +166,7 @@ int_divmod :: proc(quotient, remainder, numerator, denominator: ^Int, allocator
 		Early out if neither of the results is wanted.
 		Early out if neither of the results is wanted.
 	*/
 	*/
 	if quotient == nil && remainder == nil { return nil; }
 	if quotient == nil && remainder == nil { return nil; }
-	if err = internal_clear_if_uninitialized(numerator, denominator); err != nil { return err; }
+	internal_clear_if_uninitialized(numerator, denominator) or_return;
 
 
 	return #force_inline internal_divmod(quotient, remainder, numerator, denominator);
 	return #force_inline internal_divmod(quotient, remainder, numerator, denominator);
 }
 }
@@ -175,7 +175,7 @@ int_divmod_digit :: proc(quotient, numerator: ^Int, denominator: DIGIT, allocato
 	assert_if_nil(quotient, numerator);
 	assert_if_nil(quotient, numerator);
 	context.allocator = allocator;
 	context.allocator = allocator;
 
 
-	if err = internal_clear_if_uninitialized(numerator); err != nil { return 0, err; }
+	internal_clear_if_uninitialized(numerator) or_return;
 
 
 	return #force_inline internal_divmod(quotient, numerator, denominator);
 	return #force_inline internal_divmod(quotient, numerator, denominator);
 }
 }
@@ -185,7 +185,7 @@ int_div :: proc(quotient, numerator, denominator: ^Int, allocator := context.all
 	assert_if_nil(quotient, numerator, denominator);
 	assert_if_nil(quotient, numerator, denominator);
 	context.allocator = allocator;
 	context.allocator = allocator;
 
 
-	if err = internal_clear_if_uninitialized(numerator, denominator); err != nil { return err; }
+	internal_clear_if_uninitialized(numerator, denominator) or_return;
 
 
 	return #force_inline internal_divmod(quotient, nil, numerator, denominator);
 	return #force_inline internal_divmod(quotient, nil, numerator, denominator);
 }
 }
@@ -194,11 +194,10 @@ int_div_digit :: proc(quotient, numerator: ^Int, denominator: DIGIT, allocator :
 	assert_if_nil(quotient, numerator);
 	assert_if_nil(quotient, numerator);
 	context.allocator = allocator;
 	context.allocator = allocator;
 
 
-	if err = internal_clear_if_uninitialized(numerator); err != nil { return err; }
+	internal_clear_if_uninitialized(numerator) or_return;
 
 
-	remainder: DIGIT;
-	remainder, err = #force_inline internal_divmod(quotient, numerator, denominator);
-	return err;
+	_ = #force_inline internal_divmod(quotient, numerator, denominator) or_return;
+	return;
 }
 }
 div :: proc { int_div, int_div_digit, };
 div :: proc { int_div, int_div_digit, };
 
 
@@ -211,7 +210,7 @@ int_mod :: proc(remainder, numerator, denominator: ^Int, allocator := context.al
 	assert_if_nil(remainder, numerator, denominator);
 	assert_if_nil(remainder, numerator, denominator);
 	context.allocator = allocator;
 	context.allocator = allocator;
 
 
-	if err = internal_clear_if_uninitialized(numerator, denominator); err != nil { return err; }
+	internal_clear_if_uninitialized(numerator, denominator) or_return;
 
 
 	return #force_inline internal_int_mod(remainder, numerator, denominator);
 	return #force_inline internal_int_mod(remainder, numerator, denominator);
 }
 }
@@ -229,7 +228,7 @@ int_addmod :: proc(remainder, number, addend, modulus: ^Int, allocator := contex
 	assert_if_nil(remainder, number, addend);
 	assert_if_nil(remainder, number, addend);
 	context.allocator = allocator;
 	context.allocator = allocator;
 
 
-	if err = internal_clear_if_uninitialized(number, addend, modulus); err != nil { return err; }
+	internal_clear_if_uninitialized(number, addend, modulus) or_return;
 
 
 	return #force_inline internal_addmod(remainder, number, addend, modulus);
 	return #force_inline internal_addmod(remainder, number, addend, modulus);
 }
 }
@@ -242,7 +241,7 @@ int_submod :: proc(remainder, number, decrease, modulus: ^Int, allocator := cont
 	assert_if_nil(remainder, number, decrease);
 	assert_if_nil(remainder, number, decrease);
 	context.allocator = allocator;
 	context.allocator = allocator;
 
 
-	if err = internal_clear_if_uninitialized(number, decrease, modulus); err != nil { return err; }
+	internal_clear_if_uninitialized(number, decrease, modulus) or_return;
 
 
 	return #force_inline internal_submod(remainder, number, decrease, modulus);
 	return #force_inline internal_submod(remainder, number, decrease, modulus);
 }
 }
@@ -255,7 +254,7 @@ int_mulmod :: proc(remainder, number, multiplicand, modulus: ^Int, allocator :=
 	assert_if_nil(remainder, number, multiplicand);
 	assert_if_nil(remainder, number, multiplicand);
 	context.allocator = allocator;
 	context.allocator = allocator;
 
 
-	if err = internal_clear_if_uninitialized(number, multiplicand, modulus); err != nil { return err; }
+	internal_clear_if_uninitialized(number, multiplicand, modulus) or_return;
 
 
 	return #force_inline internal_mulmod(remainder, number, multiplicand, modulus);
 	return #force_inline internal_mulmod(remainder, number, multiplicand, modulus);
 }
 }
@@ -268,7 +267,7 @@ int_sqrmod :: proc(remainder, number, modulus: ^Int, allocator := context.alloca
 	assert_if_nil(remainder, number, modulus);
 	assert_if_nil(remainder, number, modulus);
 	context.allocator = allocator;
 	context.allocator = allocator;
 
 
-	if err = internal_clear_if_uninitialized(number, modulus); err != nil { return err; }
+	internal_clear_if_uninitialized(number, modulus) or_return;
 
 
 	return #force_inline internal_sqrmod(remainder, number, modulus);
 	return #force_inline internal_sqrmod(remainder, number, modulus);
 }
 }
@@ -312,14 +311,14 @@ int_choose_digit :: proc(res: ^Int, n, k: int, allocator := context.allocator) -
 	n_fac, k_fac, n_minus_k_fac := &Int{}, &Int{}, &Int{};
 	n_fac, k_fac, n_minus_k_fac := &Int{}, &Int{}, &Int{};
 	defer internal_destroy(n_fac, k_fac, n_minus_k_fac);
 	defer internal_destroy(n_fac, k_fac, n_minus_k_fac);
 
 
-	if err = #force_inline internal_int_factorial(n_minus_k_fac, n - k);  err != nil { return err; }
-	if err = #force_inline internal_int_factorial(k_fac, k);              err != nil { return err; }
-	if err = #force_inline internal_mul(k_fac, k_fac, n_minus_k_fac);     err != nil { return err; }
+	#force_inline internal_int_factorial(n_minus_k_fac, n - k) or_return;
+	#force_inline internal_int_factorial(k_fac, k)             or_return;
+	#force_inline internal_mul(k_fac, k_fac, n_minus_k_fac)    or_return;
 
 
-	if err = #force_inline internal_int_factorial(n_fac, n);              err != nil { return err; }
-	if err = #force_inline internal_div(res, n_fac, k_fac);               err != nil { return err; }
+	#force_inline internal_int_factorial(n_fac, n)             or_return;
+	#force_inline internal_div(res, n_fac, k_fac)              or_return;
 
 
-	return err;	
+	return;
 }
 }
 choose :: proc { int_choose_digit, };
 choose :: proc { int_choose_digit, };
 
 
@@ -331,7 +330,7 @@ int_gcd_lcm :: proc(res_gcd, res_lcm, a, b: ^Int, allocator := context.allocator
 	assert_if_nil(a, b);
 	assert_if_nil(a, b);
 	context.allocator = allocator;
 	context.allocator = allocator;
 
 
-	if err = internal_clear_if_uninitialized(a, b); err != nil { return err; }
+	internal_clear_if_uninitialized(a, b) or_return;
 	return #force_inline internal_int_gcd_lcm(res_gcd, res_lcm, a, b);
 	return #force_inline internal_int_gcd_lcm(res_gcd, res_lcm, a, b);
 }
 }
 gcd_lcm :: proc { int_gcd_lcm, };
 gcd_lcm :: proc { int_gcd_lcm, };
@@ -359,8 +358,8 @@ int_mod_bits :: proc(remainder, numerator: ^Int, bits: int, allocator := context
 	assert_if_nil(remainder, numerator);
 	assert_if_nil(remainder, numerator);
 	context.allocator = allocator;
 	context.allocator = allocator;
 
 
-	if err = internal_clear_if_uninitialized(remainder, numerator); err != nil { return err; }
-	if bits  < 0 { return .Invalid_Argument; }
+	internal_clear_if_uninitialized(remainder, numerator) or_return;
+	if bits < 0 { return .Invalid_Argument; }
 
 
 	return #force_inline internal_int_mod_bits(remainder, numerator, bits);
 	return #force_inline internal_int_mod_bits(remainder, numerator, bits);
 }
 }
@@ -375,7 +374,7 @@ int_log :: proc(a: ^Int, base: DIGIT, allocator := context.allocator) -> (res: i
 	assert_if_nil(a);
 	assert_if_nil(a);
 	context.allocator = allocator;
 	context.allocator = allocator;
 
 
-	if err = internal_clear_if_uninitialized(a); err != nil { return 0, err; }
+	internal_clear_if_uninitialized(a) or_return;
 
 
 	return #force_inline internal_int_log(a, base);
 	return #force_inline internal_int_log(a, base);
 }
 }
@@ -392,7 +391,7 @@ int_pow :: proc(dest, base: ^Int, power: int, allocator := context.allocator) ->
 	assert_if_nil(dest, base);
 	assert_if_nil(dest, base);
 	context.allocator = allocator;
 	context.allocator = allocator;
 
 
-	if err = internal_clear_if_uninitialized(dest, base); err != nil { return err; }
+	internal_clear_if_uninitialized(dest, base) or_return;
 
 
 	return #force_inline internal_int_pow(dest, base, power);
 	return #force_inline internal_int_pow(dest, base, power);
 }
 }
@@ -420,7 +419,7 @@ int_sqrt :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error
 	assert_if_nil(dest, src);
 	assert_if_nil(dest, src);
 	context.allocator = allocator;
 	context.allocator = allocator;
 
 
-	if err = internal_clear_if_uninitialized(dest, src);	err != nil { return err; }
+	internal_clear_if_uninitialized(dest, src) or_return;
 
 
 	return #force_inline internal_int_sqrt(dest, src);
 	return #force_inline internal_int_sqrt(dest, src);
 }
 }
@@ -446,7 +445,7 @@ int_root_n :: proc(dest, src: ^Int, n: int, allocator := context.allocator) -> (
 	/*
 	/*
 		Initialize dest + src if needed.
 		Initialize dest + src if needed.
 	*/
 	*/
-	if err = internal_clear_if_uninitialized(dest, src);	err != nil { return err; }
+	internal_clear_if_uninitialized(dest, src) or_return;
 
 
 	return #force_inline internal_int_root_n(dest, src, n);
 	return #force_inline internal_int_root_n(dest, src, n);
 }
 }
@@ -466,7 +465,7 @@ int_is_zero :: proc(a: ^Int, allocator := context.allocator) -> (zero: bool, err
 	assert_if_nil(a);
 	assert_if_nil(a);
 	context.allocator = allocator;
 	context.allocator = allocator;
 
 
-	if err = internal_clear_if_uninitialized(a); err != nil { return false, err; }
+	internal_clear_if_uninitialized(a) or_return;
 
 
 	return #force_inline internal_is_zero(a), nil;
 	return #force_inline internal_is_zero(a), nil;
 }
 }
@@ -475,7 +474,7 @@ int_is_positive :: proc(a: ^Int, allocator := context.allocator) -> (positive: b
 	assert_if_nil(a);
 	assert_if_nil(a);
 	context.allocator = allocator;
 	context.allocator = allocator;
 
 
-	if err = internal_clear_if_uninitialized(a); err != nil { return false, err; }
+	internal_clear_if_uninitialized(a) or_return;
 
 
 	return #force_inline internal_is_positive(a), nil;
 	return #force_inline internal_is_positive(a), nil;
 }
 }
@@ -484,7 +483,7 @@ int_is_negative :: proc(a: ^Int, allocator := context.allocator) -> (negative: b
 	assert_if_nil(a);
 	assert_if_nil(a);
 	context.allocator = allocator;
 	context.allocator = allocator;
 
 
-	if err = internal_clear_if_uninitialized(a); err != nil { return false, err; }
+	internal_clear_if_uninitialized(a) or_return;
 
 
 	return #force_inline internal_is_negative(a), nil;
 	return #force_inline internal_is_negative(a), nil;
 }
 }
@@ -493,7 +492,7 @@ int_is_even :: proc(a: ^Int, allocator := context.allocator) -> (even: bool, err
 	assert_if_nil(a);
 	assert_if_nil(a);
 	context.allocator = allocator;
 	context.allocator = allocator;
 
 
-	if err = internal_clear_if_uninitialized(a); err != nil { return false, err; }
+	internal_clear_if_uninitialized(a) or_return;
 
 
 	return #force_inline internal_is_even(a), nil;
 	return #force_inline internal_is_even(a), nil;
 }
 }
@@ -502,7 +501,7 @@ int_is_odd :: proc(a: ^Int, allocator := context.allocator) -> (odd: bool, err:
 	assert_if_nil(a);
 	assert_if_nil(a);
 	context.allocator = allocator;
 	context.allocator = allocator;
 
 
-	if err = internal_clear_if_uninitialized(a); err != nil { return false, err; }
+	internal_clear_if_uninitialized(a) or_return;
 
 
 	return #force_inline internal_is_odd(a), nil;
 	return #force_inline internal_is_odd(a), nil;
 }
 }
@@ -515,7 +514,7 @@ int_is_power_of_two :: proc(a: ^Int, allocator := context.allocator) -> (res: bo
 	assert_if_nil(a);
 	assert_if_nil(a);
 	context.allocator = allocator;
 	context.allocator = allocator;
 
 
-	if err = internal_clear_if_uninitialized(a); err != nil { return false, err; }
+	internal_clear_if_uninitialized(a) or_return;
 
 
 	return #force_inline internal_is_power_of_two(a), nil;
 	return #force_inline internal_is_power_of_two(a), nil;
 }
 }
@@ -527,7 +526,7 @@ int_compare :: proc(a, b: ^Int, allocator := context.allocator) -> (comparison:
 	assert_if_nil(a, b);
 	assert_if_nil(a, b);
 	context.allocator = allocator;
 	context.allocator = allocator;
 
 
-	if err = internal_clear_if_uninitialized(a, b); err != nil {	return 0, err; }
+	internal_clear_if_uninitialized(a, b) or_return;
 
 
 	return #force_inline internal_cmp(a, b), nil;
 	return #force_inline internal_cmp(a, b), nil;
 }
 }
@@ -540,7 +539,7 @@ int_compare_digit :: proc(a: ^Int, b: DIGIT, allocator := context.allocator) ->
 	assert_if_nil(a);
 	assert_if_nil(a);
 	context.allocator = allocator;
 	context.allocator = allocator;
 
 
-	if err = internal_clear_if_uninitialized(a); err != nil { return 0, err; }
+	internal_clear_if_uninitialized(a) or_return;
 
 
 	return #force_inline internal_cmp_digit(a, b), nil;
 	return #force_inline internal_cmp_digit(a, b), nil;
 }
 }
@@ -553,7 +552,7 @@ int_compare_magnitude :: proc(a, b: ^Int, allocator := context.allocator) -> (re
 	assert_if_nil(a, b);
 	assert_if_nil(a, b);
 	context.allocator = allocator;
 	context.allocator = allocator;
 
 
-	if err = internal_clear_if_uninitialized(a, b); err != nil { return 0, err; }
+	internal_clear_if_uninitialized(a, b) or_return;
 
 
 	return #force_inline internal_cmp_mag(a, b), nil;
 	return #force_inline internal_cmp_mag(a, b), nil;
 }
 }

+ 19 - 24
core/math/big/radix.odin

@@ -26,7 +26,7 @@ int_itoa_string :: proc(a: ^Int, radix := i8(-1), zero_terminate := false, alloc
 	context.allocator = allocator;
 	context.allocator = allocator;
 
 
 	a := a; radix := radix;
 	a := a; radix := radix;
-	if err = clear_if_uninitialized(a); err != nil { return "", err; }
+	clear_if_uninitialized(a) or_return;
 	/*
 	/*
 		Radix defaults to 10.
 		Radix defaults to 10.
 	*/
 	*/
@@ -39,14 +39,9 @@ int_itoa_string :: proc(a: ^Int, radix := i8(-1), zero_terminate := false, alloc
 
 
 	/*
 	/*
 		Calculate the size of the buffer we need, and 
 		Calculate the size of the buffer we need, and 
-	*/
-	size: int;
-	/*
 		Exit if calculating the size returned an error.
 		Exit if calculating the size returned an error.
 	*/
 	*/
-	if size, err = radix_size(a, radix, zero_terminate); err != nil {
-		return "", err;
-	}
+	size := radix_size(a, radix, zero_terminate) or_return;
 
 
 	/*
 	/*
 		Allocate the buffer we need.
 		Allocate the buffer we need.
@@ -70,7 +65,7 @@ int_itoa_cstring :: proc(a: ^Int, radix := i8(-1), allocator := context.allocato
 	context.allocator = allocator;
 	context.allocator = allocator;
 
 
 	a := a; radix := radix;
 	a := a; radix := radix;
-	if err = clear_if_uninitialized(a); err != nil { return "", err; }
+	clear_if_uninitialized(a) or_return;
 	/*
 	/*
 		Radix defaults to 10.
 		Radix defaults to 10.
 	*/
 	*/
@@ -104,7 +99,7 @@ int_itoa_cstring :: proc(a: ^Int, radix := i8(-1), allocator := context.allocato
 int_itoa_raw :: proc(a: ^Int, radix: i8, buffer: []u8, size := int(-1), zero_terminate := false) -> (written: int, err: Error) {
 int_itoa_raw :: proc(a: ^Int, radix: i8, buffer: []u8, size := int(-1), zero_terminate := false) -> (written: int, err: Error) {
 	assert_if_nil(a);
 	assert_if_nil(a);
 	a := a; radix := radix; size := size;
 	a := a; radix := radix; size := size;
-	if err = clear_if_uninitialized(a); err != nil { return 0, err; }
+	clear_if_uninitialized(a) or_return;
 	/*
 	/*
 		Radix defaults to 10.
 		Radix defaults to 10.
 	*/
 	*/
@@ -117,9 +112,7 @@ int_itoa_raw :: proc(a: ^Int, radix: i8, buffer: []u8, size := int(-1), zero_ter
 		We weren't given a size. Let's compute it.
 		We weren't given a size. Let's compute it.
 	*/
 	*/
 	if size == -1 {
 	if size == -1 {
-		if size, err = radix_size(a, radix, zero_terminate); err != nil {
-			return 0, err;
-		}
+		size = radix_size(a, radix, zero_terminate) or_return;
 	}
 	}
 
 
 	/*
 	/*
@@ -256,12 +249,14 @@ int_atoi :: proc(res: ^Int, input: string, radix: i8, allocator := context.alloc
 	/*
 	/*
 		Set the integer to the default of zero.
 		Set the integer to the default of zero.
 	*/
 	*/
-	if err = internal_zero(res); err != nil { return err; }
+	internal_zero(res) or_return;
 
 
 	/*
 	/*
 		We'll interpret an empty string as zero.
 		We'll interpret an empty string as zero.
 	*/
 	*/
-	if len(input) == 0 { return nil; }
+	if len(input) == 0 {
+		return nil;
+	}
 
 
 	/*
 	/*
 		If the leading digit is a minus set the sign to negative.
 		If the leading digit is a minus set the sign to negative.
@@ -301,8 +296,8 @@ int_atoi :: proc(res: ^Int, input: string, radix: i8, allocator := context.alloc
 			break;
 			break;
 		}
 		}
 
 
-		if err = internal_mul(res, res, DIGIT(radix)); err != nil { return err; }
-		if err = internal_add(res, res, DIGIT(y));     err != nil { return err; }
+		internal_mul(res, res, DIGIT(radix)) or_return;
+		internal_add(res, res, DIGIT(y))     or_return;
 
 
 		input = input[1:];
 		input = input[1:];
 	}
 	}
@@ -333,7 +328,7 @@ radix_size :: proc(a: ^Int, radix: i8, zero_terminate := false, allocator := con
 	assert_if_nil(a);
 	assert_if_nil(a);
 
 
 	if radix < 2 || radix > 64                     { return -1, .Invalid_Argument; }
 	if radix < 2 || radix > 64                     { return -1, .Invalid_Argument; }
-	if err = clear_if_uninitialized(a); err != nil { return {}, err; }
+	clear_if_uninitialized(a) or_return;
 
 
 	if internal_is_zero(a) {
 	if internal_is_zero(a) {
 		if zero_terminate {
 		if zero_terminate {
@@ -352,22 +347,22 @@ radix_size :: proc(a: ^Int, radix: i8, zero_terminate := false, allocator := con
 			digit     = a.digit,
 			digit     = a.digit,
 		};
 		};
 
 
-		if size, err = internal_log(t, DIGIT(radix));   err != nil { return {}, err; }
+		size = internal_log(t, DIGIT(radix)) or_return;
 	} else {
 	} else {
 		la, k := &Int{}, &Int{};
 		la, k := &Int{}, &Int{};
 		defer internal_destroy(la, k);
 		defer internal_destroy(la, k);
 
 
 		/* la = floor(log_2(a)) + 1 */
 		/* la = floor(log_2(a)) + 1 */
 		bit_count := internal_count_bits(a);
 		bit_count := internal_count_bits(a);
-		if err = internal_set(la, bit_count);           err != nil { return {}, err; }
+		internal_set(la, bit_count) or_return;
 
 
 		/* k = floor(2^29/log_2(radix)) + 1 */
 		/* k = floor(2^29/log_2(radix)) + 1 */
 		lb := _log_bases;
 		lb := _log_bases;
-		if err = internal_set(k, lb[radix]);            err != nil { return {}, err; }
+		internal_set(k, lb[radix]) or_return;
 
 
 		/* n = floor((la *  k) / 2^29) + 1 */
 		/* n = floor((la *  k) / 2^29) + 1 */
-		if err = internal_mul(k, la, k);                err != nil { return 0, err; }
-		if err = internal_shr(k, k, _RADIX_SIZE_SCALE); err != nil { return {}, err; }
+		internal_mul(k, la, k) or_return;
+		internal_shr(k, k, _RADIX_SIZE_SCALE) or_return;
 
 
 		/* The "+1" here is the "+1" in "floor((la *  k) / 2^29) + 1" */
 		/* The "+1" here is the "+1" in "floor((la *  k) / 2^29) + 1" */
 		/* n = n + 1 + EOS + sign */
 		/* n = n + 1 + EOS + sign */
@@ -440,8 +435,8 @@ _itoa_raw_full :: proc(a: ^Int, radix: i8, buffer: []u8, zero_terminate := false
 
 
 	temp, denominator := &Int{}, &Int{};
 	temp, denominator := &Int{}, &Int{};
 
 
-	if err = internal_copy(temp, a);           err != nil { return 0, err; }
-	if err = internal_set(denominator, radix); err != nil { return 0, err; }
+	internal_copy(temp, a)           or_return;
+	internal_set(denominator, radix) or_return;
 
 
 	available := len(buffer);
 	available := len(buffer);
 	if zero_terminate {
 	if zero_terminate {

+ 14 - 14
core/math/big/test.odin

@@ -49,7 +49,7 @@ PyRes :: struct {
 	if bb.used == 1 {
 	if bb.used == 1 {
 		if err = #force_inline internal_add(sum, aa, bb.digit[0]); err != nil { return PyRes{res=":add:add(sum,a,b):", err=err}; }	
 		if err = #force_inline internal_add(sum, aa, bb.digit[0]); err != nil { return PyRes{res=":add:add(sum,a,b):", err=err}; }	
 	} else {
 	} else {
-		if err = #force_inline internal_add(sum, aa, bb);          err != nil { return PyRes{res=":add:add(sum,a,b):", err=err}; }
+		if err = #force_inline internal_add(sum, aa, bb); err != nil { return PyRes{res=":add:add(sum,a,b):", err=err}; }
 	}
 	}
 
 
 	r: cstring;
 	r: cstring;
@@ -70,7 +70,7 @@ PyRes :: struct {
 	if bb.used == 1 {
 	if bb.used == 1 {
 		if err = #force_inline internal_sub(sum, aa, bb.digit[0]); err != nil { return PyRes{res=":sub:sub(sum,a,b):", err=err}; }
 		if err = #force_inline internal_sub(sum, aa, bb.digit[0]); err != nil { return PyRes{res=":sub:sub(sum,a,b):", err=err}; }
 	} else {
 	} else {
-		if err = #force_inline internal_sub(sum, aa, bb);          err != nil { return PyRes{res=":sub:sub(sum,a,b):", err=err}; }
+		if err = #force_inline internal_sub(sum, aa, bb); err != nil { return PyRes{res=":sub:sub(sum,a,b):", err=err}; }
 	}
 	}
 
 
 	r: cstring;
 	r: cstring;
@@ -88,7 +88,7 @@ PyRes :: struct {
 
 
 	if err = atoi(aa, string(a), 16); err != nil { return PyRes{res=":mul:atoi(a):", err=err}; }
 	if err = atoi(aa, string(a), 16); err != nil { return PyRes{res=":mul:atoi(a):", err=err}; }
 	if err = atoi(bb, string(b), 16); err != nil { return PyRes{res=":mul:atoi(b):", err=err}; }
 	if err = atoi(bb, string(b), 16); err != nil { return PyRes{res=":mul:atoi(b):", err=err}; }
-	if err = #force_inline internal_mul(product, aa, bb);    err != nil { return PyRes{res=":mul:mul(product,a,b):", err=err}; }
+	if err = #force_inline internal_mul(product, aa, bb); err != nil { return PyRes{res=":mul:mul(product,a,b):", err=err}; }
 
 
 	r: cstring;
 	r: cstring;
 	r, err = int_itoa_cstring(product, 16, context.temp_allocator);
 	r, err = int_itoa_cstring(product, 16, context.temp_allocator);
@@ -104,7 +104,7 @@ PyRes :: struct {
 	defer internal_destroy(aa, square);
 	defer internal_destroy(aa, square);
 
 
 	if err = atoi(aa, string(a), 16); err != nil { return PyRes{res=":sqr:atoi(a):", err=err}; }
 	if err = atoi(aa, string(a), 16); err != nil { return PyRes{res=":sqr:atoi(a):", err=err}; }
-	if err = #force_inline internal_sqr(square, aa);        err != nil { return PyRes{res=":sqr:sqr(square,a):", err=err}; }
+	if err = #force_inline internal_sqr(square, aa); err != nil { return PyRes{res=":sqr:sqr(square,a):", err=err}; }
 
 
 	r: cstring;
 	r: cstring;
 	r, err = int_itoa_cstring(square, 16, context.temp_allocator);
 	r, err = int_itoa_cstring(square, 16, context.temp_allocator);
@@ -124,7 +124,7 @@ PyRes :: struct {
 
 
 	if err = atoi(aa, string(a), 16); err != nil { return PyRes{res=":div:atoi(a):", err=err}; }
 	if err = atoi(aa, string(a), 16); err != nil { return PyRes{res=":div:atoi(a):", err=err}; }
 	if err = atoi(bb, string(b), 16); err != nil { return PyRes{res=":div:atoi(b):", err=err}; }
 	if err = atoi(bb, string(b), 16); err != nil { return PyRes{res=":div:atoi(b):", err=err}; }
-	if err = #force_inline internal_div(quotient, aa, bb);   err != nil { return PyRes{res=":div:div(quotient,a,b):", err=err}; }
+	if err = #force_inline internal_div(quotient, aa, bb); err != nil { return PyRes{res=":div:div(quotient,a,b):", err=err}; }
 
 
 	r: cstring;
 	r: cstring;
 	r, err = int_itoa_cstring(quotient, 16, context.temp_allocator);
 	r, err = int_itoa_cstring(quotient, 16, context.temp_allocator);
@@ -145,7 +145,7 @@ PyRes :: struct {
 	defer internal_destroy(aa);
 	defer internal_destroy(aa);
 
 
 	if err = atoi(aa, string(a), 16); err != nil { return PyRes{res=":log:atoi(a):", err=err}; }
 	if err = atoi(aa, string(a), 16); err != nil { return PyRes{res=":log:atoi(a):", err=err}; }
-	if l, err = #force_inline internal_log(aa, base);        err != nil { return PyRes{res=":log:log(a, base):", err=err}; }
+	if l, err = #force_inline internal_log(aa, base); err != nil { return PyRes{res=":log:log(a, base):", err=err}; }
 
 
 	#force_inline internal_zero(aa);
 	#force_inline internal_zero(aa);
 	aa.digit[0] = DIGIT(l)  & _MASK;
 	aa.digit[0] = DIGIT(l)  & _MASK;
@@ -170,7 +170,7 @@ PyRes :: struct {
 	defer internal_destroy(dest, bb);
 	defer internal_destroy(dest, bb);
 
 
 	if err = atoi(bb, string(base), 16); err != nil { return PyRes{res=":pow:atoi(base):", err=err}; }
 	if err = atoi(bb, string(base), 16); err != nil { return PyRes{res=":pow:atoi(base):", err=err}; }
-	if err = #force_inline internal_pow(dest, bb, power);       err != nil { return PyRes{res=":pow:pow(dest, base, power):", err=err}; }
+	if err = #force_inline internal_pow(dest, bb, power); err != nil { return PyRes{res=":pow:pow(dest, base, power):", err=err}; }
 
 
 	r: cstring;
 	r: cstring;
 	r, err = int_itoa_cstring(dest, 16, context.temp_allocator);
 	r, err = int_itoa_cstring(dest, 16, context.temp_allocator);
@@ -189,7 +189,7 @@ PyRes :: struct {
 	defer internal_destroy(src);
 	defer internal_destroy(src);
 
 
 	if err = atoi(src, string(source), 16); err != nil { return PyRes{res=":sqrt:atoi(src):", err=err}; }
 	if err = atoi(src, string(source), 16); err != nil { return PyRes{res=":sqrt:atoi(src):", err=err}; }
-	if err = #force_inline internal_sqrt(src, src);                err != nil { return PyRes{res=":sqrt:sqrt(src):", err=err}; }
+	if err = #force_inline internal_sqrt(src, src); err != nil { return PyRes{res=":sqrt:sqrt(src):", err=err}; }
 
 
 	r: cstring;
 	r: cstring;
 	r, err = int_itoa_cstring(src, 16, context.temp_allocator);
 	r, err = int_itoa_cstring(src, 16, context.temp_allocator);
@@ -208,7 +208,7 @@ PyRes :: struct {
 	defer internal_destroy(src);
 	defer internal_destroy(src);
 
 
 	if err = atoi(src, string(source), 16); err != nil { return PyRes{res=":root_n:atoi(src):", err=err}; }
 	if err = atoi(src, string(source), 16); err != nil { return PyRes{res=":root_n:atoi(src):", err=err}; }
-	if err = #force_inline internal_root_n(src, src, power);       err != nil { return PyRes{res=":root_n:root_n(src):", err=err}; }
+	if err = #force_inline internal_root_n(src, src, power); err != nil { return PyRes{res=":root_n:root_n(src):", err=err}; }
 
 
 	r: cstring;
 	r: cstring;
 	r, err = int_itoa_cstring(src, 16, context.temp_allocator);
 	r, err = int_itoa_cstring(src, 16, context.temp_allocator);
@@ -227,7 +227,7 @@ PyRes :: struct {
 	defer internal_destroy(src);
 	defer internal_destroy(src);
 
 
 	if err = atoi(src, string(source), 16); err != nil { return PyRes{res=":shr_digit:atoi(src):", err=err}; }
 	if err = atoi(src, string(source), 16); err != nil { return PyRes{res=":shr_digit:atoi(src):", err=err}; }
-	if err = #force_inline internal_shr_digit(src, digits);        err != nil { return PyRes{res=":shr_digit:shr_digit(src):", err=err}; }
+	if err = #force_inline internal_shr_digit(src, digits); err != nil { return PyRes{res=":shr_digit:shr_digit(src):", err=err}; }
 
 
 	r: cstring;
 	r: cstring;
 	r, err = int_itoa_cstring(src, 16, context.temp_allocator);
 	r, err = int_itoa_cstring(src, 16, context.temp_allocator);
@@ -246,7 +246,7 @@ PyRes :: struct {
 	defer internal_destroy(src);
 	defer internal_destroy(src);
 
 
 	if err = atoi(src, string(source), 16); err != nil { return PyRes{res=":shl_digit:atoi(src):", err=err}; }
 	if err = atoi(src, string(source), 16); err != nil { return PyRes{res=":shl_digit:atoi(src):", err=err}; }
-	if err = #force_inline internal_shl_digit(src, digits);        err != nil { return PyRes{res=":shl_digit:shr_digit(src):", err=err}; }
+	if err = #force_inline internal_shl_digit(src, digits); err != nil { return PyRes{res=":shl_digit:shr_digit(src):", err=err}; }
 
 
 	r: cstring;
 	r: cstring;
 	r, err = int_itoa_cstring(src, 16, context.temp_allocator);
 	r, err = int_itoa_cstring(src, 16, context.temp_allocator);
@@ -265,7 +265,7 @@ PyRes :: struct {
 	defer internal_destroy(src);
 	defer internal_destroy(src);
 
 
 	if err = atoi(src, string(source), 16); err != nil { return PyRes{res=":shr:atoi(src):", err=err}; }
 	if err = atoi(src, string(source), 16); err != nil { return PyRes{res=":shr:atoi(src):", err=err}; }
-	if err = #force_inline internal_shr(src, src, bits);           err != nil { return PyRes{res=":shr:shr(src, bits):", err=err}; }
+	if err = #force_inline internal_shr(src, src, bits); err != nil { return PyRes{res=":shr:shr(src, bits):", err=err}; }
 
 
 	r: cstring;
 	r: cstring;
 	r, err = int_itoa_cstring(src, 16, context.temp_allocator);
 	r, err = int_itoa_cstring(src, 16, context.temp_allocator);
@@ -284,7 +284,7 @@ PyRes :: struct {
 	defer internal_destroy(src);
 	defer internal_destroy(src);
 
 
 	if err = atoi(src, string(source), 16); err != nil { return PyRes{res=":shr_signed:atoi(src):", err=err}; }
 	if err = atoi(src, string(source), 16); err != nil { return PyRes{res=":shr_signed:atoi(src):", err=err}; }
-	if err = #force_inline internal_shr_signed(src, src, bits);    err != nil { return PyRes{res=":shr_signed:shr_signed(src, bits):", err=err}; }
+	if err = #force_inline internal_shr_signed(src, src, bits); err != nil { return PyRes{res=":shr_signed:shr_signed(src, bits):", err=err}; }
 
 
 	r: cstring;
 	r: cstring;
 	r, err = int_itoa_cstring(src, 16, context.temp_allocator);
 	r, err = int_itoa_cstring(src, 16, context.temp_allocator);
@@ -303,7 +303,7 @@ PyRes :: struct {
 	defer internal_destroy(src);
 	defer internal_destroy(src);
 
 
 	if err = atoi(src, string(source), 16); err != nil { return PyRes{res=":shl:atoi(src):", err=err}; }
 	if err = atoi(src, string(source), 16); err != nil { return PyRes{res=":shl:atoi(src):", err=err}; }
-	if err = #force_inline internal_shl(src, src, bits);           err != nil { return PyRes{res=":shl:shl(src, bits):", err=err}; }
+	if err = #force_inline internal_shl(src, src, bits); err != nil { return PyRes{res=":shl:shl(src, bits):", err=err}; }
 
 
 	r: cstring;
 	r: cstring;
 	r, err = int_itoa_cstring(src, 16, context.temp_allocator);
 	r, err = int_itoa_cstring(src, 16, context.temp_allocator);

+ 15 - 11
core/odin/ast/ast.odin

@@ -241,15 +241,6 @@ Field_Value :: struct {
 	value: ^Expr,
 	value: ^Expr,
 }
 }
 
 
-Ternary_Expr :: struct {
-	using node: Expr,
-	cond: ^Expr,
-	op1:  tokenizer.Token,
-	x:    ^Expr,
-	op2:  tokenizer.Token,
-	y:    ^Expr,
-}
-
 Ternary_If_Expr :: struct {
 Ternary_If_Expr :: struct {
 	using node: Expr,
 	using node: Expr,
 	x:    ^Expr,
 	x:    ^Expr,
@@ -261,13 +252,26 @@ Ternary_If_Expr :: struct {
 
 
 Ternary_When_Expr :: struct {
 Ternary_When_Expr :: struct {
 	using node: Expr,
 	using node: Expr,
-	x: ^Expr,
+	x:    ^Expr,
 	op1:  tokenizer.Token,
 	op1:  tokenizer.Token,
 	cond: ^Expr,
 	cond: ^Expr,
 	op2:  tokenizer.Token,
 	op2:  tokenizer.Token,
 	y:    ^Expr,
 	y:    ^Expr,
 }
 }
 
 
+Or_Else_Expr :: struct {
+	using node: Expr,
+	x:     ^Expr,
+	token: tokenizer.Token,
+	y:     ^Expr,
+}
+
+Or_Return_Expr :: struct {
+	using node: Expr,
+	expr:  ^Expr,
+	token: tokenizer.Token,
+}
+
 Type_Assertion :: struct {
 Type_Assertion :: struct {
 	using node: Expr,
 	using node: Expr,
 	expr:  ^Expr,
 	expr:  ^Expr,
@@ -542,7 +546,7 @@ Field_Flag :: enum {
 	No_Alias,
 	No_Alias,
 	C_Vararg,
 	C_Vararg,
 	Auto_Cast,
 	Auto_Cast,
-	In,
+	Any_Int,
 
 
 	Results,
 	Results,
 	Tags,
 	Tags,

+ 5 - 4
core/odin/ast/clone.odin

@@ -129,10 +129,6 @@ clone_node :: proc(node: ^Node) -> ^Node {
 	case Field_Value:
 	case Field_Value:
 		r.field = clone(r.field);
 		r.field = clone(r.field);
 		r.value = clone(r.value);
 		r.value = clone(r.value);
-	case Ternary_Expr:
-		r.cond = clone(r.cond);
-		r.x    = clone(r.x);
-		r.y    = clone(r.y);
 	case Ternary_If_Expr:
 	case Ternary_If_Expr:
 		r.x    = clone(r.x);
 		r.x    = clone(r.x);
 		r.cond = clone(r.cond);
 		r.cond = clone(r.cond);
@@ -141,6 +137,11 @@ clone_node :: proc(node: ^Node) -> ^Node {
 		r.x    = clone(r.x);
 		r.x    = clone(r.x);
 		r.cond = clone(r.cond);
 		r.cond = clone(r.cond);
 		r.y    = clone(r.y);
 		r.y    = clone(r.y);
+	case Or_Else_Expr:
+		r.x    = clone(r.x);
+		r.y    = clone(r.y);
+	case Or_Return_Expr:
+		r.expr = clone(r.expr);
 	case Type_Assertion:
 	case Type_Assertion:
 		r.expr = clone(r.expr);
 		r.expr = clone(r.expr);
 		r.type = clone(r.type);
 		r.type = clone(r.type);

+ 5 - 4
core/odin/ast/walk.odin

@@ -126,10 +126,6 @@ walk :: proc(v: ^Visitor, node: ^Node) {
 	case Field_Value:
 	case Field_Value:
 		walk(v, n.field);
 		walk(v, n.field);
 		walk(v, n.value);
 		walk(v, n.value);
-	case Ternary_Expr:
-		walk(v, n.cond);
-		walk(v, n.x);
-		walk(v, n.y);
 	case Ternary_If_Expr:
 	case Ternary_If_Expr:
 		walk(v, n.x);
 		walk(v, n.x);
 		walk(v, n.cond);
 		walk(v, n.cond);
@@ -138,6 +134,11 @@ walk :: proc(v: ^Visitor, node: ^Node) {
 		walk(v, n.x);
 		walk(v, n.x);
 		walk(v, n.cond);
 		walk(v, n.cond);
 		walk(v, n.y);
 		walk(v, n.y);
+	case Or_Else_Expr:
+		walk(v, n.x);
+		walk(v, n.y);
+	case Or_Return_Expr:
+		walk(v, n.expr);
 	case Type_Assertion:
 	case Type_Assertion:
 		walk(v, n.expr);
 		walk(v, n.expr);
 		if n.type != nil {
 		if n.type != nil {

+ 64 - 47
core/odin/parser/parser.odin

@@ -374,11 +374,14 @@ expect_token_after :: proc(p: ^Parser, kind: tokenizer.Token_Kind, msg: string)
 
 
 expect_operator :: proc(p: ^Parser) -> tokenizer.Token {
 expect_operator :: proc(p: ^Parser) -> tokenizer.Token {
 	prev := p.curr_tok;
 	prev := p.curr_tok;
-	if prev.kind == .If || prev.kind == .When {
+	#partial switch prev.kind {
+	case .If, .When, .Or_Else, .Or_Return:
 		// okay
 		// okay
-	} else if !tokenizer.is_operator(prev.kind) {
-		g := tokenizer.token_to_string(prev);
-		error(p, prev.pos, "expected an operator, got '%s'", g);
+	case:
+		if !tokenizer.is_operator(prev.kind) {
+			g := tokenizer.token_to_string(prev);
+			error(p, prev.pos, "expected an operator, got '%s'", g);
+		}
 	}
 	}
 	advance_token(p);
 	advance_token(p);
 	return prev;
 	return prev;
@@ -1366,9 +1369,9 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
 			stmt := parse_stmt(p);
 			stmt := parse_stmt(p);
 			switch name {
 			switch name {
 			case "bounds_check":
 			case "bounds_check":
-				stmt.state_flags |= {.Bounds_Check};
+				stmt.state_flags += {.Bounds_Check};
 			case "no_bounds_check":
 			case "no_bounds_check":
-				stmt.state_flags |= {.No_Bounds_Check};
+				stmt.state_flags += {.No_Bounds_Check};
 			}
 			}
 			return stmt;
 			return stmt;
 		case "partial":
 		case "partial":
@@ -1449,7 +1452,7 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
 
 
 token_precedence :: proc(p: ^Parser, kind: tokenizer.Token_Kind) -> int {
 token_precedence :: proc(p: ^Parser, kind: tokenizer.Token_Kind) -> int {
 	#partial switch kind {
 	#partial switch kind {
-	case .Question, .If, .When:
+	case .Question, .If, .When, .Or_Else, .Or_Return:
 		return 1;
 		return 1;
 	case .Ellipsis, .Range_Half, .Range_Full:
 	case .Ellipsis, .Range_Half, .Range_Full:
 		if !p.allow_range {
 		if !p.allow_range {
@@ -1578,8 +1581,8 @@ Field_Prefix :: enum {
 	Using,
 	Using,
 	No_Alias,
 	No_Alias,
 	C_Vararg,
 	C_Vararg,
-	In,
 	Auto_Cast,
 	Auto_Cast,
+	Any_Int,
 }
 }
 
 
 Field_Prefixes :: distinct bit_set[Field_Prefix];
 Field_Prefixes :: distinct bit_set[Field_Prefix];
@@ -1626,19 +1629,15 @@ convert_to_ident_list :: proc(p: ^Parser, list: []Expr_And_Flags, ignore_flags,
 }
 }
 
 
 is_token_field_prefix :: proc(p: ^Parser) -> Field_Prefix {
 is_token_field_prefix :: proc(p: ^Parser) -> Field_Prefix {
-	using Field_Prefix;
 	#partial switch p.curr_tok.kind {
 	#partial switch p.curr_tok.kind {
 	case .EOF:
 	case .EOF:
-		return Invalid;
+		return .Invalid;
 	case .Using:
 	case .Using:
 		advance_token(p);
 		advance_token(p);
-		return Using;
-	case .In:
-		advance_token(p);
-		return In;
+		return .Using;
 	case .Auto_Cast:
 	case .Auto_Cast:
 		advance_token(p);
 		advance_token(p);
-		return Auto_Cast;
+		return .Auto_Cast;
 	case .Hash:
 	case .Hash:
 		advance_token(p);
 		advance_token(p);
 		defer advance_token(p);
 		defer advance_token(p);
@@ -1646,14 +1645,16 @@ is_token_field_prefix :: proc(p: ^Parser) -> Field_Prefix {
 		case .Ident:
 		case .Ident:
 			switch p.curr_tok.text {
 			switch p.curr_tok.text {
 			case "no_alias":
 			case "no_alias":
-				return No_Alias;
+				return .No_Alias;
 			case "c_vararg":
 			case "c_vararg":
-				return C_Vararg;
+				return .C_Vararg;
+			case "any_int":
+				return .Any_Int;
 			}
 			}
 		}
 		}
-		return Unknown;
+		return .Unknown;
 	}
 	}
-	return Invalid;
+	return .Invalid;
 }
 }
 
 
 parse_field_prefixes :: proc(p: ^Parser) -> ast.Field_Flags {
 parse_field_prefixes :: proc(p: ^Parser) -> ast.Field_Flags {
@@ -1677,24 +1678,23 @@ parse_field_prefixes :: proc(p: ^Parser) -> ast.Field_Flags {
 
 
 	for kind in Field_Prefix {
 	for kind in Field_Prefix {
 		count := counts[kind];
 		count := counts[kind];
-		using Field_Prefix;
 		switch kind {
 		switch kind {
-		case Invalid, Unknown: // Ignore
-		case Using:
+		case .Invalid, .Unknown: // Ignore
+		case .Using:
 			if count > 1 { error(p, p.curr_tok.pos, "multiple 'using' in this field list"); }
 			if count > 1 { error(p, p.curr_tok.pos, "multiple 'using' in this field list"); }
-			if count > 0 { flags |= {.Using}; }
-		case No_Alias:
+			if count > 0 { flags += {.Using}; }
+		case .No_Alias:
 			if count > 1 { error(p, p.curr_tok.pos, "multiple '#no_alias' in this field list"); }
 			if count > 1 { error(p, p.curr_tok.pos, "multiple '#no_alias' in this field list"); }
-			if count > 0 { flags |= {.No_Alias}; }
-		case C_Vararg:
+			if count > 0 { flags += {.No_Alias}; }
+		case .C_Vararg:
 			if count > 1 { error(p, p.curr_tok.pos, "multiple '#c_vararg' in this field list"); }
 			if count > 1 { error(p, p.curr_tok.pos, "multiple '#c_vararg' in this field list"); }
-			if count > 0 { flags |= {.C_Vararg}; }
-		case In:
-			if count > 1 { error(p, p.curr_tok.pos, "multiple 'in' in this field list"); }
-			if count > 0 { flags |= {.In}; }
-		case Auto_Cast:
+			if count > 0 { flags += {.C_Vararg}; }
+		case .Auto_Cast:
 			if count > 1 { error(p, p.curr_tok.pos, "multiple 'auto_cast' in this field list"); }
 			if count > 1 { error(p, p.curr_tok.pos, "multiple 'auto_cast' in this field list"); }
-			if count > 0 { flags |= {.Auto_Cast}; }
+			if count > 0 { flags += {.Auto_Cast}; }
+		case .Any_Int:
+			if count > 1 { error(p, p.curr_tok.pos, "multiple '#any_int' in this field list"); }
+			if count > 0 { flags += {.Any_Int}; }
 		}
 		}
 	}
 	}
 
 
@@ -1705,7 +1705,7 @@ check_field_flag_prefixes :: proc(p: ^Parser, name_count: int, allowed_flags, se
 	flags = set_flags;
 	flags = set_flags;
 	if name_count > 1 && .Using in flags {
 	if name_count > 1 && .Using in flags {
 		error(p, p.curr_tok.pos, "cannot apply 'using' to more than one of the same type");
 		error(p, p.curr_tok.pos, "cannot apply 'using' to more than one of the same type");
-		flags &~= {.Using};
+		flags -= {.Using};
 	}
 	}
 
 
 	for flag in ast.Field_Flag {
 	for flag in ast.Field_Flag {
@@ -1719,12 +1719,12 @@ check_field_flag_prefixes :: proc(p: ^Parser, name_count: int, allowed_flags, se
 				error(p, p.curr_tok.pos, "'#c_vararg' is not allowed within this field list");
 				error(p, p.curr_tok.pos, "'#c_vararg' is not allowed within this field list");
 			case .Auto_Cast:
 			case .Auto_Cast:
 				error(p, p.curr_tok.pos, "'auto_cast' is not allowed within this field list");
 				error(p, p.curr_tok.pos, "'auto_cast' is not allowed within this field list");
-			case .In:
-				error(p, p.curr_tok.pos, "'in' is not allowed within this field list");
+			case .Any_Int:
+				error(p, p.curr_tok.pos, "'#any_int' is not allowed within this field list");
 			case .Tags, .Ellipsis, .Results, .Default_Parameters, .Typeid_Token:
 			case .Tags, .Ellipsis, .Results, .Default_Parameters, .Typeid_Token:
 				panic("Impossible prefixes");
 				panic("Impossible prefixes");
 			}
 			}
-			flags &~= {flag};
+			flags -= {flag};
 		}
 		}
 	}
 	}
 
 
@@ -2062,10 +2062,10 @@ parse_proc_tags :: proc(p: ^Parser) -> (tags: ast.Proc_Tags) {
 		ident := expect_token(p, .Ident);
 		ident := expect_token(p, .Ident);
 
 
 		switch ident.text {
 		switch ident.text {
-		case "bounds_check":    tags |= {.Bounds_Check};
-		case "no_bounds_check": tags |= {.No_Bounds_Check};
-		case "optional_ok":     tags |= {.Optional_Ok};
-		case "optional_second": tags |= {.Optional_Second};
+		case "bounds_check":    tags += {.Bounds_Check};
+		case "no_bounds_check": tags += {.No_Bounds_Check};
+		case "optional_ok":     tags += {.Optional_Ok};
+		case "optional_second": tags += {.Optional_Second};
 		case:
 		case:
 		}
 		}
 	}
 	}
@@ -2267,12 +2267,12 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
 
 
 			switch name.text {
 			switch name.text {
 			case "bounds_check":
 			case "bounds_check":
-				operand.state_flags |= {.Bounds_Check};
+				operand.state_flags += {.Bounds_Check};
 				if .No_Bounds_Check in operand.state_flags {
 				if .No_Bounds_Check in operand.state_flags {
 					error(p, name.pos, "#bounds_check and #no_bounds_check cannot be applied together");
 					error(p, name.pos, "#bounds_check and #no_bounds_check cannot be applied together");
 				}
 				}
 			case "no_bounds_check":
 			case "no_bounds_check":
-				operand.state_flags |= {.No_Bounds_Check};
+				operand.state_flags += {.No_Bounds_Check};
 				if .Bounds_Check in operand.state_flags {
 				if .Bounds_Check in operand.state_flags {
 					error(p, name.pos, "#bounds_check and #no_bounds_check cannot be applied together");
 					error(p, name.pos, "#bounds_check and #no_bounds_check cannot be applied together");
 				}
 				}
@@ -3156,16 +3156,18 @@ parse_binary_expr :: proc(p: ^Parser, lhs: bool, prec_in: int) -> ^ast.Expr {
 	}
 	}
 
 
 	for prec := token_precedence(p, p.curr_tok.kind); prec >= prec_in; prec -= 1 {
 	for prec := token_precedence(p, p.curr_tok.kind); prec >= prec_in; prec -= 1 {
-		for {
+		loop: for {
 			op := p.curr_tok;
 			op := p.curr_tok;
 			op_prec := token_precedence(p, op.kind);
 			op_prec := token_precedence(p, op.kind);
 			if op_prec != prec {
 			if op_prec != prec {
-				break;
+				break loop;
 			}
 			}
-			if op.kind == .If || op.kind == .When {
+
+			#partial switch op.kind {
+			case .If, .When, .Or_Return, .Or_Else:
 				if p.prev_tok.pos.line < op.pos.line {
 				if p.prev_tok.pos.line < op.pos.line {
 					// NOTE(bill): Check to see if the `if` or `when` is on the same line of the `lhs` condition
 					// NOTE(bill): Check to see if the `if` or `when` is on the same line of the `lhs` condition
-					break;
+					break loop;
 				}
 				}
 			}
 			}
 
 
@@ -3178,7 +3180,7 @@ parse_binary_expr :: proc(p: ^Parser, lhs: bool, prec_in: int) -> ^ast.Expr {
 				x := parse_expr(p, lhs);
 				x := parse_expr(p, lhs);
 				colon := expect_token(p, .Colon);
 				colon := expect_token(p, .Colon);
 				y := parse_expr(p, lhs);
 				y := parse_expr(p, lhs);
-				te := ast.new(ast.Ternary_Expr, expr.pos, end_pos(p.prev_tok));
+				te := ast.new(ast.Ternary_If_Expr, expr.pos, end_pos(p.prev_tok));
 				te.cond = cond;
 				te.cond = cond;
 				te.op1  = op;
 				te.op1  = op;
 				te.x    = x;
 				te.x    = x;
@@ -3212,6 +3214,21 @@ parse_binary_expr :: proc(p: ^Parser, lhs: bool, prec_in: int) -> ^ast.Expr {
 				te.y    = y;
 				te.y    = y;
 
 
 				expr = te;
 				expr = te;
+			case .Or_Else:
+				x := expr;
+				y := parse_expr(p, lhs);
+				oe := ast.new(ast.Or_Else_Expr, expr.pos, end_pos(p.prev_tok));
+				oe.x     = x;
+				oe.token = op;
+				oe.y     = y;
+
+				expr = oe;
+			case .Or_Return:
+				oe := ast.new(ast.Or_Return_Expr, expr.pos, end_pos(p.prev_tok));
+				oe.expr  = expr;
+				oe.token = op;
+
+				expr = oe;
 			case:
 			case:
 				right := parse_binary_expr(p, false, prec+1);
 				right := parse_binary_expr(p, false, prec+1);
 				if right == nil {
 				if right == nil {

+ 7 - 6
core/odin/printer/visit.odin

@@ -944,12 +944,6 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) {
 	case Auto_Cast:
 	case Auto_Cast:
 		push_generic_token(p, v.op.kind, 1);
 		push_generic_token(p, v.op.kind, 1);
 		visit_expr(p, v.expr);
 		visit_expr(p, v.expr);
-	case Ternary_Expr:
-		visit_expr(p, v.cond);
-		push_generic_token(p, v.op1.kind, 1);
-		visit_expr(p, v.x);
-		push_generic_token(p, v.op2.kind, 1);
-		visit_expr(p, v.y);
 	case Ternary_If_Expr:
 	case Ternary_If_Expr:
 		visit_expr(p, v.x);
 		visit_expr(p, v.x);
 		push_generic_token(p, v.op1.kind, 1);
 		push_generic_token(p, v.op1.kind, 1);
@@ -962,6 +956,13 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) {
 		visit_expr(p, v.cond);
 		visit_expr(p, v.cond);
 		push_generic_token(p, v.op2.kind, 1);
 		push_generic_token(p, v.op2.kind, 1);
 		visit_expr(p, v.y);
 		visit_expr(p, v.y);
+	case Or_Else_Expr:
+		visit_expr(p, v.x);
+		push_generic_token(p, v.token.kind, 1);
+		visit_expr(p, v.y);
+	case Or_Return_Expr:
+		visit_expr(p, v.expr);
+		push_generic_token(p, v.token.kind, 1);
 	case Selector_Call_Expr:
 	case Selector_Call_Expr:
 		visit_expr(p, v.call.expr);
 		visit_expr(p, v.call.expr);
 		push_generic_token(p, .Open_Paren, 1);
 		push_generic_token(p, .Open_Paren, 1);

+ 8 - 4
core/odin/tokenizer/token.odin

@@ -144,10 +144,12 @@ Token_Kind :: enum u32 {
 		Transmute,   // transmute
 		Transmute,   // transmute
 		Distinct,    // distinct
 		Distinct,    // distinct
 		Using,       // using
 		Using,       // using
-		Inline,      // inline
-		No_Inline,   // no_inline
 		Context,     // context
 		Context,     // context
+		Or_Else,     // or_else
+		Or_Return,   // or_return
 		Asm,         // asm
 		Asm,         // asm
+		Inline,      // inline
+		No_Inline,   // no_inline
 	B_Keyword_End,
 	B_Keyword_End,
 
 
 	COUNT,
 	COUNT,
@@ -272,10 +274,12 @@ tokens := [Token_Kind.COUNT]string {
 	"transmute",
 	"transmute",
 	"distinct",
 	"distinct",
 	"using",
 	"using",
-	"inline",
-	"no_inline",
 	"context",
 	"context",
+	"or_else",
+	"or_return",
 	"asm",
 	"asm",
+	"inline",
+	"no_inline",
 	"",
 	"",
 };
 };
 
 

+ 1 - 1
core/odin/tokenizer/tokenizer.odin

@@ -724,7 +724,7 @@ scan :: proc(t: ^Tokenizer) -> Token {
 		case .Ident, .Context, .Typeid, .Break, .Continue, .Fallthrough, .Return,
 		case .Ident, .Context, .Typeid, .Break, .Continue, .Fallthrough, .Return,
 		     .Integer, .Float, .Imag, .Rune, .String, .Undef,
 		     .Integer, .Float, .Imag, .Rune, .String, .Undef,
 		     .Question, .Pointer, .Close_Paren, .Close_Bracket, .Close_Brace,
 		     .Question, .Pointer, .Close_Paren, .Close_Bracket, .Close_Brace,
-		     .Increment, .Decrement:
+		     .Increment, .Decrement, .Or_Return:
 			/*fallthrough*/
 			/*fallthrough*/
 			t.insert_semicolon = true;
 			t.insert_semicolon = true;
 		case:
 		case:

+ 1 - 1
core/os/os2/errors.odin

@@ -57,7 +57,7 @@ link_error_delete :: proc(lerr: Maybe(Link_Error)) {
 
 
 
 
 is_platform_error :: proc(ferr: Error) -> (err: i32, ok: bool) {
 is_platform_error :: proc(ferr: Error) -> (err: i32, ok: bool) {
-	v := or_else(ferr.(Platform_Error), {});
+	v := ferr.(Platform_Error) or_else {};
 	return v.err, v.err != 0;
 	return v.err, v.err != 0;
 }
 }
 
 

+ 1 - 1
core/os/os2/file_stream.odin

@@ -13,7 +13,7 @@ error_to_io_error :: proc(ferr: Error) -> io.Error {
 	if ferr == nil {
 	if ferr == nil {
 		return .None;
 		return .None;
 	}
 	}
-	return or_else(ferr.(io.Error), .Unknown);
+	return ferr.(io.Error) or_else .Unknown;
 }
 }
 
 
 
 

+ 1 - 4
core/path/filepath/match.odin

@@ -298,10 +298,7 @@ _glob :: proc(dir, pattern: string, matches: ^[dynamic]string) -> (m: [dynamic]s
 
 
 	for fi in fis {
 	for fi in fis {
 		n := fi.name;
 		n := fi.name;
-		matched, err := match(pattern, n);
-		if err != nil {
-			return m, err;
-		}
+		matched := match(pattern, n) or_return;
 		if matched {
 		if matched {
 			append(&m, join(dir, n));
 			append(&m, join(dir, n));
 		}
 		}

+ 1 - 1
core/sync/sync2/primitives_pthreads.odin

@@ -129,7 +129,7 @@ _Recursive_Mutex :: struct {
 }
 }
 
 
 _recursive_mutex_lock :: proc(m: ^Recursive_Mutex) {
 _recursive_mutex_lock :: proc(m: ^Recursive_Mutex) {
-	tid := runtime.current_thread_id();
+	tid := _current_thread_id();
 	if tid != m.impl.owner {
 	if tid != m.impl.owner {
 		mutex_lock(&m.impl.mutex);
 		mutex_lock(&m.impl.mutex);
 	}
 	}

+ 1 - 1
core/testing/runner_windows.odin

@@ -68,7 +68,7 @@ Thread_Os_Specific :: struct {
 thread_create :: proc(procedure: Thread_Proc) -> ^Thread {
 thread_create :: proc(procedure: Thread_Proc) -> ^Thread {
 	__windows_thread_entry_proc :: proc "stdcall" (t_: rawptr) -> win32.DWORD {
 	__windows_thread_entry_proc :: proc "stdcall" (t_: rawptr) -> win32.DWORD {
 		t := (^Thread)(t_);
 		t := (^Thread)(t_);
-		context = or_else(t.init_context.?, runtime.default_context());
+		context = t.init_context.? or_else runtime.default_context();
 
 
 		t.procedure(t);
 		t.procedure(t);
 
 

+ 1 - 1
core/thread/thread_unix.odin

@@ -46,7 +46,7 @@ _create :: proc(procedure: Thread_Proc, priority := Thread_Priority.Normal) -> ^
 		t.start_gate = {};
 		t.start_gate = {};
 		t.start_mutex = {};
 		t.start_mutex = {};
 
 
-		context = or_else(t.init_context.?, runtime.default_context());
+		context = t.init_context.? or_else runtime.default_context();
 
 
 		t.procedure(t);
 		t.procedure(t);
 
 

+ 1 - 1
core/thread/thread_windows.odin

@@ -23,7 +23,7 @@ _create :: proc(procedure: Thread_Proc, priority := Thread_Priority.Normal) -> ^
 
 
 	__windows_thread_entry_proc :: proc "stdcall" (t_: rawptr) -> win32.DWORD {
 	__windows_thread_entry_proc :: proc "stdcall" (t_: rawptr) -> win32.DWORD {
 		t := (^Thread)(t_);
 		t := (^Thread)(t_);
-		context = or_else(t.init_context.?, runtime.default_context());
+		context = t.init_context.? or_else runtime.default_context();
 
 
 		t.procedure(t);
 		t.procedure(t);
 
 

+ 50 - 50
examples/all/all_main.odin

@@ -3,57 +3,57 @@ package all
 // Imports every package
 // Imports every package
 // This is useful for knowing what exists and producing documentation with `odin doc`
 // This is useful for knowing what exists and producing documentation with `odin doc`
 
 
-import "core:bufio"
-import "core:bytes"
-import "core:c"
-import c_tokenizer "core:c/frontend/tokenizer"
+import bufio          "core:bufio"
+import bytes          "core:bytes"
+import c              "core:c"
+import c_tokenizer    "core:c/frontend/tokenizer"
 import c_preprocessor "core:c/frontend/preprocessor"
 import c_preprocessor "core:c/frontend/preprocessor"
-import "core:compress"
-import "core:compress/gzip"
-import "core:compress/zlib"
-import "core:container"
-import "core:dynlib"
-import "core:encoding"
-import "core:encoding/base32"
-import "core:encoding/base64"
-import "core:encoding/csv"
-import "core:encoding/hxa"
-import "core:encoding/json"
-import "core:fmt"
-import "core:hash"
-import "core:image"
-import "core:image/png"
-import "core:io"
-import "core:log"
-import "core:math"
-import "core:math/big"
-import "core:math/bits"
-import "core:math/fixed"
-import "core:math/linalg"
-import "core:math/rand"
-import "core:mem"
-import "core:odin/ast"
-import doc_format "core:odin/doc-format"
-import "core:odin/format"
-import "core:odin/parser"
-import "core:odin/printer"
+import compress       "core:compress"
+import gzip           "core:compress/gzip"
+import zlib           "core:compress/zlib"
+import container      "core:container"
+import dynlib         "core:dynlib"
+import encoding       "core:encoding"
+import base32         "core:encoding/base32"
+import base64         "core:encoding/base64"
+import csv            "core:encoding/csv"
+import hxa            "core:encoding/hxa"
+import json           "core:encoding/json"
+import fmt            "core:fmt"
+import hash           "core:hash"
+import image          "core:image"
+import png            "core:image/png"
+import io             "core:io"
+import log            "core:log"
+import math           "core:math"
+import big            "core:math/big"
+import bits           "core:math/bits"
+import fixed          "core:math/fixed"
+import linalg         "core:math/linalg"
+import rand           "core:math/rand"
+import mem            "core:mem"
+import ast            "core:odin/ast"
+import doc_format     "core:odin/doc-format"
+import odin_format    "core:odin/format"
+import odin_parser    "core:odin/parser"
+import odin_printer   "core:odin/printer"
 import odin_tokenizer "core:odin/tokenizer"
 import odin_tokenizer "core:odin/tokenizer"
-import "core:os"
-import "core:path"
-import "core:path/filepath"
-import "core:reflect"
-import "core:runtime"
-import "core:slice"
-import "core:sort"
-import "core:strconv"
-import "core:strings"
-import "core:sync"
-import "core:sync/sync2"
-import "core:text/scanner"
-import "core:thread"
-import "core:time"
-import "core:unicode"
-import "core:unicode/utf8"
-import "core:unicode/utf16"
+import os             "core:os"
+import path           "core:path"
+import filepath       "core:path/filepath"
+import reflect        "core:reflect"
+import runtime        "core:runtime"
+import slice          "core:slice"
+import sort           "core:sort"
+import strconv        "core:strconv"
+import strings        "core:strings"
+import sync           "core:sync"
+import sync2          "core:sync/sync2"
+import scanner        "core:text/scanner"
+import thread         "core:thread"
+import time           "core:time"
+import unicode        "core:unicode"
+import utf8           "core:unicode/utf8"
+import utf16          "core:unicode/utf16"
 
 
 main :: proc(){}
 main :: proc(){}

+ 109 - 8
examples/demo/demo.odin

@@ -1998,9 +1998,9 @@ relative_data_types :: proc() {
 	fmt.println(rel_slice[1]);
 	fmt.println(rel_slice[1]);
 }
 }
 
 
-or_else_procedure :: proc() {
+or_else_operator :: proc() {
 	fmt.println("\n#'or_else'");
 	fmt.println("\n#'or_else'");
-	// IMPORTANT NOTE: 'or_else' is experimental features and subject to change/removal
+	// IMPORTANT NOTE: 'or_else' is an experimental feature and subject to change/removal
 	{
 	{
 		m: map[string]int;
 		m: map[string]int;
 		i: int;
 		i: int;
@@ -2010,7 +2010,7 @@ or_else_procedure :: proc() {
 			i = 123;
 			i = 123;
 		}
 		}
 		// The above can be mapped to 'or_else'
 		// The above can be mapped to 'or_else'
-		i = or_else(m["hellope"], 123);
+		i = m["hellope"] or_else 123;
 
 
 		assert(i == 123);
 		assert(i == 123);
 	}
 	}
@@ -2019,16 +2019,117 @@ or_else_procedure :: proc() {
 		// have optional ok semantics
 		// have optional ok semantics
 		v: union{int, f64};
 		v: union{int, f64};
 		i: int;
 		i: int;
-		i = or_else(v.(int), 123);
-		i = or_else(v.?, 123); // Type inference magic
+		i = v.(int) or_else  123;
+		i = v.? or_else 123; // Type inference magic
 		assert(i == 123);
 		assert(i == 123);
 
 
 		m: Maybe(int);
 		m: Maybe(int);
-		i = or_else(m.?, 456);
+		i = m.? or_else 456;
 		assert(i == 456);
 		assert(i == 456);
 	}
 	}
 }
 }
 
 
+or_return_operator :: proc() {
+	fmt.println("\n#'or_return'");
+	// IMPORTANT NOTE: 'or_return' is an experimental feature and subject to change/removal
+	//
+	// The concept of 'or_return' will work by popping off the end value in a multiple
+	// valued expression and checking whether it was not 'nil' or 'false', and if so,
+	// set the end return value to value if possible. If the procedure only has one
+	// return value, it will do a simple return. If the procedure had multiple return
+	// values, 'or_return' will require that all parameters be named so that the end
+	// value could be assigned to by name and then an empty return could be called.
+
+	Error :: enum {
+		None,
+		Something_Bad,
+		Something_Worse,
+		The_Worst,
+		Your_Mum,
+	};
+
+	caller_1 :: proc() -> Error {
+		return .None;
+	}
+
+	caller_2 :: proc() -> (int, Error) {
+		return 123, .None;
+	}
+	caller_3 :: proc() -> (int, int, Error) {
+		return 123, 345, .None;
+	}
+
+	foo_1 :: proc() -> Error {
+		// This can be a common idiom in many code bases
+		n0, err := caller_2();
+		if err != nil {
+			return err;
+		}
+
+		// The above idiom can be transformed into the following
+		n1 := caller_2() or_return;
+
+
+		// And if the expression is 1-valued, it can be used like this
+		caller_1() or_return;
+		// which is functionally equivalent to
+		if err1 := caller_1(); err1 != nil {
+			return err1;
+		}
+
+		// Multiple return values still work with 'or_return' as it only
+		// pops off the end value in the multi-valued expression
+		n0, n1 = caller_3() or_return;
+
+		return .None;
+	}
+	foo_2 :: proc() -> (n: int, err: Error) {
+		// It is more common that your procedure turns multiple values
+		// If 'or_return' is used within a procedure multiple parameters (2+),
+		// then all the parameters must be named so that the remaining parameters
+		// so that a bare 'return' statement can be used
+
+		// This can be a common idiom in many code bases
+		x: int;
+		x, err = caller_2();
+		if err != nil {
+			return;
+		}
+
+		// The above idiom can be transformed into the following
+		y := caller_2() or_return;
+		_ = y;
+
+		// And if the expression is 1-valued, it can be used like this
+		caller_1() or_return;
+
+		// which is functionally equivalent to
+		if err1 := caller_1(); err1 != nil {
+			err = err1;
+			return;
+		}
+
+		// If using a non-bare 'return' statement is required, setting the return values
+		// using the normal idiom is a better choice and clearer to read.
+		if z, zerr := caller_2(); zerr != nil {
+			return -345 * z, zerr;
+		}
+
+		// If the other return values need to be set depending on what the end value is,
+		// the 'defer if' idiom is can be used
+		defer if err != nil {
+			n = -1;
+		}
+
+		n = 123;
+		return;
+	}
+
+	foo_1();
+	foo_2();
+}
+
+
 main :: proc() {
 main :: proc() {
 	when true {
 	when true {
 		the_basics();
 		the_basics();
@@ -2061,7 +2162,7 @@ main :: proc() {
 		union_maybe();
 		union_maybe();
 		explicit_context_definition();
 		explicit_context_definition();
 		relative_data_types();
 		relative_data_types();
-		or_else_procedure();
+		or_else_operator();
+		or_return_operator();
 	}
 	}
 }
 }
-//

+ 40 - 51
src/check_builtin.cpp

@@ -48,6 +48,17 @@ BuiltinTypeIsProc *builtin_type_is_procs[BuiltinProc__type_simple_boolean_end -
 };
 };
 
 
 
 
+void check_or_else_right_type(CheckerContext *c, Ast *expr, String const &name, Type *right_type) {
+	if (right_type == nullptr) {
+		return;
+	}
+	if (!is_type_boolean(right_type) && !type_has_nil(right_type)) {
+		gbString str = type_to_string(right_type);
+		error(expr, "'%.*s' expects an \"optional ok\" like value, or an n-valued expression where the last value is either a boolean or can be compared against 'nil', got %s", LIT(name), str);
+		gb_string_free(str);
+	}
+}
+
 void check_or_else_split_types(CheckerContext *c, Operand *x, String const &name, Type **left_type_, Type **right_type_) {
 void check_or_else_split_types(CheckerContext *c, Operand *x, String const &name, Type **left_type_, Type **right_type_) {
 	Type *left_type = nullptr;
 	Type *left_type = nullptr;
 	Type *right_type = nullptr;
 	Type *right_type = nullptr;
@@ -70,15 +81,11 @@ void check_or_else_split_types(CheckerContext *c, Operand *x, String const &name
 	if (left_type_)  *left_type_  = left_type;
 	if (left_type_)  *left_type_  = left_type;
 	if (right_type_) *right_type_ = right_type;
 	if (right_type_) *right_type_ = right_type;
 
 
-	if (!is_type_boolean(right_type)) {
-		gbString str = type_to_string(right_type);
-		error(x->expr, "'%.*s' expects an \"optional ok\" like value, got %s", LIT(name), str);
-		gb_string_free(str);
-	}
+	check_or_else_right_type(c, x->expr, name, right_type);
 }
 }
 
 
 
 
-void check_try_expr_no_value_error(CheckerContext *c, String const &name, Operand const &x, Type *type_hint) {
+void check_or_else_expr_no_value_error(CheckerContext *c, String const &name, Operand const &x, Type *type_hint) {
 	// TODO(bill): better error message
 	// TODO(bill): better error message
 	gbString t = type_to_string(x.type);
 	gbString t = type_to_string(x.type);
 	error(x.expr, "'%.*s' does not return a value, value is of type %s", LIT(name), t);
 	error(x.expr, "'%.*s' does not return a value, value is of type %s", LIT(name), t);
@@ -108,6 +115,33 @@ void check_try_expr_no_value_error(CheckerContext *c, String const &name, Operan
 }
 }
 
 
 
 
+void check_or_return_split_types(CheckerContext *c, Operand *x, String const &name, Type **left_type_, Type **right_type_) {
+	Type *left_type = nullptr;
+	Type *right_type = nullptr;
+	if (x->type->kind == Type_Tuple) {
+		auto const &vars = x->type->Tuple.variables;
+		auto lhs = array_slice(vars, 0, vars.count-1);
+		auto rhs = vars[vars.count-1];
+		if (lhs.count == 1) {
+			left_type = lhs[0]->type;
+		} else if (lhs.count != 0) {
+			left_type = alloc_type_tuple();
+			left_type->Tuple.variables = array_make_from_ptr(lhs.data, lhs.count, lhs.count);
+		}
+
+		right_type = rhs->type;
+	} else {
+		check_promote_optional_ok(c, x, &left_type, &right_type);
+	}
+
+	if (left_type_)  *left_type_  = left_type;
+	if (right_type_) *right_type_ = right_type;
+
+	check_or_else_right_type(c, x->expr, name, right_type);
+}
+
+
+
 bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 id, Type *type_hint) {
 bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 id, Type *type_hint) {
 	ast_node(ce, CallExpr, call);
 	ast_node(ce, CallExpr, call);
 	if (ce->inlining != ProcInlining_none) {
 	if (ce->inlining != ProcInlining_none) {
@@ -145,10 +179,6 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
 		// NOTE(bill): The first arg may be a Type, this will be checked case by case
 		// NOTE(bill): The first arg may be a Type, this will be checked case by case
 		break;
 		break;
 
 
-	case BuiltinProc_or_else:
-		// NOTE(bill): The arguments may be multi-expr
-		break;
-
 	case BuiltinProc_DIRECTIVE: {
 	case BuiltinProc_DIRECTIVE: {
 		ast_node(bd, BasicDirective, ce->proc);
 		ast_node(bd, BasicDirective, ce->proc);
 		String name = bd->name.string;
 		String name = bd->name.string;
@@ -1800,47 +1830,6 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
 		break;
 		break;
 	}
 	}
 
 
-	case BuiltinProc_or_else: {
-		GB_ASSERT(ce->args.count == 2);
-		Ast *arg = ce->args[0];
-		Ast *default_value = ce->args[1];
-
-		Operand x = {};
-		Operand y = {};
-		check_multi_expr_with_type_hint(c, &x, arg, type_hint);
-		if (x.mode == Addressing_Invalid) {
-			operand->mode = Addressing_Value;
-			operand->type = t_invalid;
-			return false;
-		}
-
-		check_multi_expr_with_type_hint(c, &y, default_value, x.type);
-		error_operand_no_value(&y);
-		if (y.mode == Addressing_Invalid) {
-			operand->mode = Addressing_Value;
-			operand->type = t_invalid;
-			return false;
-		}
-
-		Type *left_type = nullptr;
-		Type *right_type = nullptr;
-		check_or_else_split_types(c, &x, builtin_name, &left_type, &right_type);
-		add_type_and_value(&c->checker->info, arg, x.mode, x.type, x.value);
-
-		if (left_type != nullptr) {
-			check_assignment(c, &y, left_type, builtin_name);
-		} else {
-			check_try_expr_no_value_error(c, builtin_name, x, type_hint);
-		}
-
-		if (left_type == nullptr) {
-			left_type = t_invalid;
-		}
-		operand->mode = Addressing_Value;
-		operand->type = left_type;
-		return true;
-	}
-
 	case BuiltinProc_simd_vector: {
 	case BuiltinProc_simd_vector: {
 		Operand x = {};
 		Operand x = {};
 		Operand y = {};
 		Operand y = {};

+ 151 - 0
src/check_expr.cpp

@@ -114,6 +114,11 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
 
 
 void check_promote_optional_ok(CheckerContext *c, Operand *x, Type **val_type_, Type **ok_type_);
 void check_promote_optional_ok(CheckerContext *c, Operand *x, Type **val_type_, Type **ok_type_);
 
 
+void check_or_else_right_type(CheckerContext *c, Ast *expr, String const &name, Type *right_type);
+void check_or_else_split_types(CheckerContext *c, Operand *x, String const &name, Type **left_type_, Type **right_type_);
+void check_or_else_expr_no_value_error(CheckerContext *c, String const &name, Operand const &x, Type *type_hint);
+void check_or_return_split_types(CheckerContext *c, Operand *x, String const &name, Type **left_type_, Type **right_type_);
+
 Entity *entity_from_expr(Ast *expr) {
 Entity *entity_from_expr(Ast *expr) {
 	expr = unparen_expr(expr);
 	expr = unparen_expr(expr);
 	switch (expr->kind) {
 	switch (expr->kind) {
@@ -2960,6 +2965,25 @@ void update_untyped_expr_type(CheckerContext *c, Ast *e, Type *type, bool final)
 		update_untyped_expr_type(c, te->y, type, final);
 		update_untyped_expr_type(c, te->y, type, final);
 	case_end;
 	case_end;
 
 
+	case_ast_node(ore, OrReturnExpr, e);
+		if (old->value.kind != ExactValue_Invalid) {
+			// See above note in UnaryExpr case
+			break;
+		}
+
+		update_untyped_expr_type(c, ore->expr, type, final);
+	case_end;
+
+	case_ast_node(oee, OrElseExpr, e);
+		if (old->value.kind != ExactValue_Invalid) {
+			// See above note in UnaryExpr case
+			break;
+		}
+
+		update_untyped_expr_type(c, oee->x, type, final);
+		update_untyped_expr_type(c, oee->y, type, final);
+	case_end;
+
 	case_ast_node(pe, ParenExpr, e);
 	case_ast_node(pe, ParenExpr, e);
 		update_untyped_expr_type(c, pe->expr, type, final);
 		update_untyped_expr_type(c, pe->expr, type, final);
 	case_end;
 	case_end;
@@ -6602,6 +6626,123 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
 		}
 		}
 	case_end;
 	case_end;
 
 
+	case_ast_node(oe, OrElseExpr, node);
+		String name = oe->token.string;
+		Ast *arg = oe->x;
+		Ast *default_value = oe->y;
+
+		Operand x = {};
+		Operand y = {};
+		check_multi_expr_with_type_hint(c, &x, arg, type_hint);
+		if (x.mode == Addressing_Invalid) {
+			o->mode = Addressing_Value;
+			o->type = t_invalid;
+			o->expr = node;
+			return Expr_Expr;
+		}
+
+		check_multi_expr_with_type_hint(c, &y, default_value, x.type);
+		error_operand_no_value(&y);
+		if (y.mode == Addressing_Invalid) {
+			o->mode = Addressing_Value;
+			o->type = t_invalid;
+			o->expr = node;
+			return Expr_Expr;
+		}
+
+		Type *left_type = nullptr;
+		Type *right_type = nullptr;
+		check_or_else_split_types(c, &x, name, &left_type, &right_type);
+		add_type_and_value(&c->checker->info, arg, x.mode, x.type, x.value);
+
+		if (left_type != nullptr) {
+			check_assignment(c, &y, left_type, name);
+		} else {
+			check_or_else_expr_no_value_error(c, name, x, type_hint);
+		}
+
+		if (left_type == nullptr) {
+			left_type = t_invalid;
+		}
+		o->mode = Addressing_Value;
+		o->type = left_type;
+		o->expr = node;
+		return Expr_Expr;
+	case_end;
+
+	case_ast_node(re, OrReturnExpr, node);
+		String name = re->token.string;
+		Operand x = {};
+		check_multi_expr_with_type_hint(c, &x, re->expr, type_hint);
+		if (x.mode == Addressing_Invalid) {
+			o->mode = Addressing_Value;
+			o->type = t_invalid;
+			o->expr = node;
+			return Expr_Expr;
+		}
+
+		Type *left_type = nullptr;
+		Type *right_type = nullptr;
+		check_or_return_split_types(c, &x, name, &left_type, &right_type);
+		add_type_and_value(&c->checker->info, re->expr, x.mode, x.type, x.value);
+
+		if (right_type == nullptr) {
+			check_or_else_expr_no_value_error(c, name, x, type_hint);
+		} else {
+			Type *proc_type = base_type(c->curr_proc_sig);
+			GB_ASSERT(proc_type->kind == Type_Proc);
+			Type *result_type = proc_type->Proc.results;
+			if (result_type == nullptr) {
+				error(node, "'%.*s' requires the current procedure to have at least one return value", LIT(name));
+			} else {
+				GB_ASSERT(result_type->kind == Type_Tuple);
+
+				auto const &vars = result_type->Tuple.variables;
+				Type *end_type = vars[vars.count-1]->type;
+
+				if (vars.count > 1) {
+					if (!proc_type->Proc.has_named_results) {
+						error(node, "'%.*s' within a procedure with more than 1 return value requires that the return values are named, allowing for early return", LIT(name));
+					}
+				}
+
+				Operand rhs = {};
+				rhs.type = right_type;
+				rhs.mode = Addressing_Value;
+
+				// TODO(bill): better error message
+				if (!check_is_assignable_to(c, &rhs, end_type)) {
+					gbString a = type_to_string(right_type);
+					gbString b = type_to_string(end_type);
+					gbString ret_type = type_to_string(result_type);
+					error(node, "Cannot assign end value of type '%s' to '%s' in '%.*s'", a, b, LIT(name));
+					if (vars.count == 1) {
+						error_line("\tProcedure return value type: %s\n", ret_type);
+					} else {
+						error_line("\tProcedure return value types: (%s)\n", ret_type);
+					}
+					gb_string_free(ret_type);
+					gb_string_free(b);
+					gb_string_free(a);
+				}
+			}
+		}
+
+		o->expr = node;
+		o->type = left_type;
+		if (left_type != nullptr) {
+			o->mode = Addressing_Value;
+		} else {
+			o->mode = Addressing_NoValue;
+		}
+
+		if (c->curr_proc_sig == nullptr) {
+			error(node, "'%.*s' can only be used within a procedure", LIT(name));
+		}
+
+		return Expr_Expr;
+	case_end;
+
 	case_ast_node(cl, CompoundLit, node);
 	case_ast_node(cl, CompoundLit, node);
 		Type *type = type_hint;
 		Type *type = type_hint;
 		if (type != nullptr && is_type_untyped(type)) {
 		if (type != nullptr && is_type_untyped(type)) {
@@ -8565,6 +8706,16 @@ gbString write_expr_to_string(gbString str, Ast *node, bool shorthand) {
 		str = write_expr_to_string(str, te->y, shorthand);
 		str = write_expr_to_string(str, te->y, shorthand);
 	case_end;
 	case_end;
 
 
+	case_ast_node(oe, OrElseExpr, node);
+		str = write_expr_to_string(str, oe->x, shorthand);
+		str = gb_string_appendc(str, " or_else ");
+		str = write_expr_to_string(str, oe->y, shorthand);
+	case_end;
+
+	case_ast_node(oe, OrReturnExpr, node);
+		str = write_expr_to_string(str, oe->expr, shorthand);
+		str = gb_string_appendc(str, " or_return");
+	case_end;
 
 
 	case_ast_node(pe, ParenExpr, node);
 	case_ast_node(pe, ParenExpr, node);
 		str = gb_string_append_rune(str, '(');
 		str = gb_string_append_rune(str, '(');

+ 6 - 4
src/check_stmt.cpp

@@ -1480,8 +1480,10 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
 			if (kind == Expr_Stmt) {
 			if (kind == Expr_Stmt) {
 				return;
 				return;
 			}
 			}
-			if (operand.expr->kind == Ast_CallExpr) {
-				AstCallExpr *ce = &operand.expr->CallExpr;
+			Ast *expr = strip_or_return_expr(operand.expr);
+
+			if (expr->kind == Ast_CallExpr) {
+				AstCallExpr *ce = &expr->CallExpr;
 				Type *t = type_of_expr(ce->proc);
 				Type *t = type_of_expr(ce->proc);
 				if (is_type_proc(t)) {
 				if (is_type_proc(t)) {
 					if (t->Proc.require_results) {
 					if (t->Proc.require_results) {
@@ -1491,8 +1493,8 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
 					}
 					}
 				}
 				}
 				return;
 				return;
-			} else if (operand.expr->kind == Ast_SelectorCallExpr) {
-				AstSelectorCallExpr *se = &operand.expr->SelectorCallExpr;
+			} else if (expr->kind == Ast_SelectorCallExpr) {
+				AstSelectorCallExpr *se = &expr->SelectorCallExpr;
 				ast_node(ce, CallExpr, se->call);
 				ast_node(ce, CallExpr, se->call);
 				Type *t = type_of_expr(ce->proc);
 				Type *t = type_of_expr(ce->proc);
 				if (is_type_proc(t)) {
 				if (is_type_proc(t)) {

+ 0 - 4
src/checker_builtin_procs.hpp

@@ -33,8 +33,6 @@ enum BuiltinProcId {
 	BuiltinProc_soa_zip,
 	BuiltinProc_soa_zip,
 	BuiltinProc_soa_unzip,
 	BuiltinProc_soa_unzip,
 
 
-	BuiltinProc_or_else,
-
 	BuiltinProc_DIRECTIVE, // NOTE(bill): This is used for specialized hash-prefixed procedures
 	BuiltinProc_DIRECTIVE, // NOTE(bill): This is used for specialized hash-prefixed procedures
 
 
 	// "Intrinsics"
 	// "Intrinsics"
@@ -265,8 +263,6 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
 	{STR_LIT("soa_zip"),          1, true,  Expr_Expr, BuiltinProcPkg_builtin},
 	{STR_LIT("soa_zip"),          1, true,  Expr_Expr, BuiltinProcPkg_builtin},
 	{STR_LIT("soa_unzip"),        1, false, Expr_Expr, BuiltinProcPkg_builtin},
 	{STR_LIT("soa_unzip"),        1, false, Expr_Expr, BuiltinProcPkg_builtin},
 
 
-	{STR_LIT("or_else"),          2, false, Expr_Expr, BuiltinProcPkg_builtin},
-
 	{STR_LIT(""),                 0, true,  Expr_Expr, BuiltinProcPkg_builtin}, // DIRECTIVE
 	{STR_LIT(""),                 0, true,  Expr_Expr, BuiltinProcPkg_builtin}, // DIRECTIVE
 
 
 
 

+ 8 - 0
src/llvm_backend_expr.cpp

@@ -2305,6 +2305,14 @@ lbValue lb_build_expr(lbProcedure *p, Ast *expr) {
 		}
 		}
 	case_end;
 	case_end;
 
 
+	case_ast_node(oe, OrElseExpr, expr);
+		return lb_emit_or_else(p, oe->x, oe->y, tv);
+	case_end;
+
+	case_ast_node(oe, OrReturnExpr, expr);
+		return lb_emit_or_return(p, oe->expr, tv);
+	case_end;
+
 	case_ast_node(ta, TypeAssertion, expr);
 	case_ast_node(ta, TypeAssertion, expr);
 		TokenPos pos = ast_token(expr).pos;
 		TokenPos pos = ast_token(expr).pos;
 		Type *type = tv.type;
 		Type *type = tv.type;

+ 0 - 3
src/llvm_backend_proc.cpp

@@ -1252,9 +1252,6 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
 	case BuiltinProc_soa_unzip:
 	case BuiltinProc_soa_unzip:
 		return lb_soa_unzip(p, ce, tv);
 		return lb_soa_unzip(p, ce, tv);
 
 
-	case BuiltinProc_or_else:
-		return lb_emit_or_else(p, ce->args[0], ce->args[1], tv);
-
 	// "Intrinsics"
 	// "Intrinsics"
 
 
 	case BuiltinProc_alloca:
 	case BuiltinProc_alloca:

+ 42 - 0
src/llvm_backend_utility.cpp

@@ -364,6 +364,48 @@ lbValue lb_emit_or_else(lbProcedure *p, Ast *arg, Ast *else_expr, TypeAndValue c
 	return res;
 	return res;
 }
 }
 
 
+void lb_build_return_stmt(lbProcedure *p, Slice<Ast *> const &return_results);
+void lb_build_return_stmt_internal(lbProcedure *p, lbValue const &res);
+
+lbValue lb_emit_or_return(lbProcedure *p, Ast *arg, TypeAndValue const &tv) {
+	lbValue lhs = {};
+	lbValue rhs = {};
+	lb_emit_try_lhs_rhs(p, arg, tv, &lhs, &rhs);
+
+	lbBlock *return_block  = lb_create_block(p, "or_return.return");
+	lbBlock *continue_block  = lb_create_block(p, "or_return.continue");
+
+	lb_emit_if(p, lb_emit_try_has_value(p, rhs), continue_block, return_block);
+	lb_start_block(p, return_block);
+	{
+		Type *proc_type = base_type(p->type);
+		Type *results = proc_type->Proc.results;
+		GB_ASSERT(results != nullptr && results->kind == Type_Tuple);
+		TypeTuple *tuple = &results->Tuple;
+
+		GB_ASSERT(tuple->variables.count != 0);
+
+		Entity *end_entity = tuple->variables[tuple->variables.count-1];
+		rhs = lb_emit_conv(p, rhs, end_entity->type);
+		if (p->type->Proc.has_named_results) {
+			GB_ASSERT(end_entity->token.string.len != 0);
+
+			// NOTE(bill): store the named values before returning
+			lbValue found = map_must_get(&p->module->values, hash_entity(end_entity));
+			lb_emit_store(p, found, rhs);
+
+			lb_build_return_stmt(p, {});
+		} else {
+			GB_ASSERT(tuple->variables.count == 1);
+			lb_build_return_stmt_internal(p, rhs);
+		}
+	}
+	lb_start_block(p, continue_block);
+	if (tv.type != nullptr) {
+		return lb_emit_conv(p, lhs, tv.type);
+	}
+	return {};
+}
 
 
 
 
 void lb_emit_increment(lbProcedure *p, lbValue addr) {
 void lb_emit_increment(lbProcedure *p, lbValue addr) {

+ 57 - 5
src/parser.cpp

@@ -187,6 +187,13 @@ Ast *clone_ast(Ast *node) {
 		n->TernaryWhenExpr.cond = clone_ast(n->TernaryWhenExpr.cond);
 		n->TernaryWhenExpr.cond = clone_ast(n->TernaryWhenExpr.cond);
 		n->TernaryWhenExpr.y    = clone_ast(n->TernaryWhenExpr.y);
 		n->TernaryWhenExpr.y    = clone_ast(n->TernaryWhenExpr.y);
 		break;
 		break;
+	case Ast_OrElseExpr:
+		n->OrElseExpr.x = clone_ast(n->OrElseExpr.x);
+		n->OrElseExpr.y = clone_ast(n->OrElseExpr.y);
+		break;
+	case Ast_OrReturnExpr:
+		n->OrReturnExpr.expr = clone_ast(n->OrReturnExpr.expr);
+		break;
 	case Ast_TypeAssertion:
 	case Ast_TypeAssertion:
 		n->TypeAssertion.expr = clone_ast(n->TypeAssertion.expr);
 		n->TypeAssertion.expr = clone_ast(n->TypeAssertion.expr);
 		n->TypeAssertion.type = clone_ast(n->TypeAssertion.type);
 		n->TypeAssertion.type = clone_ast(n->TypeAssertion.type);
@@ -685,6 +692,21 @@ Ast *ast_ternary_when_expr(AstFile *f, Ast *x, Ast *cond, Ast *y) {
 	return result;
 	return result;
 }
 }
 
 
+Ast *ast_or_else_expr(AstFile *f, Ast *x, Token const &token, Ast *y) {
+	Ast *result = alloc_ast_node(f, Ast_OrElseExpr);
+	result->OrElseExpr.x = x;
+	result->OrElseExpr.token = token;
+	result->OrElseExpr.y = y;
+	return result;
+}
+
+Ast *ast_or_return_expr(AstFile *f, Ast *expr, Token const &token) {
+	Ast *result = alloc_ast_node(f, Ast_OrReturnExpr);
+	result->OrReturnExpr.expr = expr;
+	result->OrReturnExpr.token = token;
+	return result;
+}
+
 Ast *ast_type_assertion(AstFile *f, Ast *expr, Token dot, Ast *type) {
 Ast *ast_type_assertion(AstFile *f, Ast *expr, Token dot, Ast *type) {
 	Ast *result = alloc_ast_node(f, Ast_TypeAssertion);
 	Ast *result = alloc_ast_node(f, Ast_TypeAssertion);
 	result->TypeAssertion.expr = expr;
 	result->TypeAssertion.expr = expr;
@@ -1340,6 +1362,8 @@ Token expect_operator(AstFile *f) {
 		// okay
 		// okay
 	} else if (prev.kind == Token_if || prev.kind == Token_when) {
 	} else if (prev.kind == Token_if || prev.kind == Token_when) {
 		// okay
 		// okay
+	} else if (prev.kind == Token_or_else || prev.kind == Token_or_return) {
+		// okay
 	} else if (!gb_is_between(prev.kind, Token__OperatorBegin+1, Token__OperatorEnd-1)) {
 	} else if (!gb_is_between(prev.kind, Token__OperatorBegin+1, Token__OperatorEnd-1)) {
 		String p = token_to_string(prev);
 		String p = token_to_string(prev);
 		syntax_error(f->curr_token, "Expected an operator, got '%.*s'",
 		syntax_error(f->curr_token, "Expected an operator, got '%.*s'",
@@ -1674,6 +1698,22 @@ Ast *unselector_expr(Ast *node) {
 	return node;
 	return node;
 }
 }
 
 
+Ast *strip_or_return_expr(Ast *node) {
+	for (;;) {
+		if (node == nullptr) {
+			return node;
+		}
+		if (node->kind == Ast_OrReturnExpr) {
+			node = node->OrReturnExpr.expr;
+		} else if (node->kind == Ast_ParenExpr) {
+			node = node->ParenExpr.expr;
+		} else {
+			return node;
+		}
+	}
+}
+
+
 Ast *parse_value(AstFile *f);
 Ast *parse_value(AstFile *f);
 
 
 Array<Ast *> parse_element_list(AstFile *f) {
 Array<Ast *> parse_element_list(AstFile *f) {
@@ -1892,7 +1932,7 @@ bool ast_on_same_line(Ast *x, Ast *y) {
 
 
 Ast *parse_force_inlining_operand(AstFile *f, Token token) {
 Ast *parse_force_inlining_operand(AstFile *f, Token token) {
 	Ast *expr = parse_unary_expr(f, false);
 	Ast *expr = parse_unary_expr(f, false);
-	Ast *e = unparen_expr(expr);
+	Ast *e = strip_or_return_expr(expr);
 	if (e->kind != Ast_ProcLit && e->kind != Ast_CallExpr) {
 	if (e->kind != Ast_ProcLit && e->kind != Ast_CallExpr) {
 		syntax_error(expr, "%.*s must be followed by a procedure literal or call, got %.*s", LIT(token.string), LIT(ast_strings[expr->kind]));
 		syntax_error(expr, "%.*s must be followed by a procedure literal or call, got %.*s", LIT(token.string), LIT(ast_strings[expr->kind]));
 		return ast_bad_expr(f, token, f->curr_token);
 		return ast_bad_expr(f, token, f->curr_token);
@@ -2777,6 +2817,10 @@ Ast *parse_atom_expr(AstFile *f, Ast *operand, bool lhs) {
 			operand = ast_deref_expr(f, operand, expect_token(f, Token_Pointer));
 			operand = ast_deref_expr(f, operand, expect_token(f, Token_Pointer));
 			break;
 			break;
 
 
+		case Token_or_return:
+			operand = ast_or_return_expr(f, operand, expect_token(f, Token_or_return));
+			break;
+
 		case Token_OpenBrace:
 		case Token_OpenBrace:
 			if (!lhs && is_literal_type(operand) && f->expr_level >= 0) {
 			if (!lhs && is_literal_type(operand) && f->expr_level >= 0) {
 				operand = parse_literal_value(f, operand);
 				operand = parse_literal_value(f, operand);
@@ -2870,6 +2914,7 @@ i32 token_precedence(AstFile *f, TokenKind t) {
 	case Token_Question:
 	case Token_Question:
 	case Token_if:
 	case Token_if:
 	case Token_when:
 	case Token_when:
+	case Token_or_else:
 		return 1;
 		return 1;
 	case Token_Ellipsis:
 	case Token_Ellipsis:
 	case Token_RangeFull:
 	case Token_RangeFull:
@@ -2924,14 +2969,16 @@ Ast *parse_binary_expr(AstFile *f, bool lhs, i32 prec_in) {
 				// NOTE(bill): This will also catch operators that are not valid "binary" operators
 				// NOTE(bill): This will also catch operators that are not valid "binary" operators
 				break;
 				break;
 			}
 			}
-			if (op.kind == Token_if || op.kind == Token_when) {
-				Token prev = f->prev_token;
+			Token prev = f->prev_token;
+			switch (op.kind) {
+			case Token_if:
+			case Token_when:
 				if (prev.pos.line < op.pos.line) {
 				if (prev.pos.line < op.pos.line) {
 					// NOTE(bill): Check to see if the `if` or `when` is on the same line of the `lhs` condition
 					// NOTE(bill): Check to see if the `if` or `when` is on the same line of the `lhs` condition
-					break;
+					goto loop_end;
 				}
 				}
+				break;
 			}
 			}
-
 			expect_operator(f); // NOTE(bill): error checks too
 			expect_operator(f); // NOTE(bill): error checks too
 
 
 			if (op.kind == Token_Question) {
 			if (op.kind == Token_Question) {
@@ -2955,6 +3002,10 @@ Ast *parse_binary_expr(AstFile *f, bool lhs, i32 prec_in) {
 				Token tok_else = expect_token(f, Token_else);
 				Token tok_else = expect_token(f, Token_else);
 				Ast *y = parse_expr(f, lhs);
 				Ast *y = parse_expr(f, lhs);
 				expr = ast_ternary_when_expr(f, x, cond, y);
 				expr = ast_ternary_when_expr(f, x, cond, y);
+			} else if (op.kind == Token_or_else) {
+				Ast *x = expr;
+				Ast *y = parse_expr(f, lhs);
+				expr = ast_or_else_expr(f, x, op, y);
 			} else {
 			} else {
 				Ast *right = parse_binary_expr(f, false, prec+1);
 				Ast *right = parse_binary_expr(f, false, prec+1);
 				if (right == nullptr) {
 				if (right == nullptr) {
@@ -2965,6 +3016,7 @@ Ast *parse_binary_expr(AstFile *f, bool lhs, i32 prec_in) {
 
 
 			lhs = false;
 			lhs = false;
 		}
 		}
+		loop_end:;
 	}
 	}
 	return expr;
 	return expr;
 }
 }

+ 2 - 0
src/parser.hpp

@@ -385,6 +385,8 @@ AST_KIND(_ExprBegin,  "",  bool) \
 	AST_KIND(FieldValue,      "field value",              struct { Token eq; Ast *field, *value; }) \
 	AST_KIND(FieldValue,      "field value",              struct { Token eq; Ast *field, *value; }) \
 	AST_KIND(TernaryIfExpr,   "ternary if expression",    struct { Ast *x, *cond, *y; }) \
 	AST_KIND(TernaryIfExpr,   "ternary if expression",    struct { Ast *x, *cond, *y; }) \
 	AST_KIND(TernaryWhenExpr, "ternary when expression",  struct { Ast *x, *cond, *y; }) \
 	AST_KIND(TernaryWhenExpr, "ternary when expression",  struct { Ast *x, *cond, *y; }) \
+	AST_KIND(OrElseExpr,      "or_else expression",       struct { Ast *x; Token token; Ast *y; }) \
+	AST_KIND(OrReturnExpr,    "or_return expression",     struct { Ast *expr; Token token; }) \
 	AST_KIND(TypeAssertion, "type assertion", struct { \
 	AST_KIND(TypeAssertion, "type assertion", struct { \
 		Ast *expr; \
 		Ast *expr; \
 		Token dot; \
 		Token dot; \

+ 4 - 0
src/parser_pos.cpp

@@ -41,6 +41,8 @@ Token ast_token(Ast *node) {
 	case Ast_DerefExpr:          return node->DerefExpr.op;
 	case Ast_DerefExpr:          return node->DerefExpr.op;
 	case Ast_TernaryIfExpr:      return ast_token(node->TernaryIfExpr.x);
 	case Ast_TernaryIfExpr:      return ast_token(node->TernaryIfExpr.x);
 	case Ast_TernaryWhenExpr:    return ast_token(node->TernaryWhenExpr.x);
 	case Ast_TernaryWhenExpr:    return ast_token(node->TernaryWhenExpr.x);
+	case Ast_OrElseExpr:         return ast_token(node->OrElseExpr.x);
+	case Ast_OrReturnExpr:       return ast_token(node->OrReturnExpr.expr);
 	case Ast_TypeAssertion:      return ast_token(node->TypeAssertion.expr);
 	case Ast_TypeAssertion:      return ast_token(node->TypeAssertion.expr);
 	case Ast_TypeCast:           return node->TypeCast.token;
 	case Ast_TypeCast:           return node->TypeCast.token;
 	case Ast_AutoCast:           return node->AutoCast.token;
 	case Ast_AutoCast:           return node->AutoCast.token;
@@ -175,6 +177,8 @@ Token ast_end_token(Ast *node) {
 	case Ast_DerefExpr:          return node->DerefExpr.op;
 	case Ast_DerefExpr:          return node->DerefExpr.op;
 	case Ast_TernaryIfExpr:      return ast_end_token(node->TernaryIfExpr.y);
 	case Ast_TernaryIfExpr:      return ast_end_token(node->TernaryIfExpr.y);
 	case Ast_TernaryWhenExpr:    return ast_end_token(node->TernaryWhenExpr.y);
 	case Ast_TernaryWhenExpr:    return ast_end_token(node->TernaryWhenExpr.y);
+	case Ast_OrElseExpr:         return ast_end_token(node->OrElseExpr.y);
+	case Ast_OrReturnExpr:       return node->OrReturnExpr.token;
 	case Ast_TypeAssertion:      return ast_end_token(node->TypeAssertion.type);
 	case Ast_TypeAssertion:      return ast_end_token(node->TypeAssertion.type);
 	case Ast_TypeCast:           return ast_end_token(node->TypeCast.expr);
 	case Ast_TypeCast:           return ast_end_token(node->TypeCast.expr);
 	case Ast_AutoCast:           return ast_end_token(node->AutoCast.expr);
 	case Ast_AutoCast:           return ast_end_token(node->AutoCast.expr);

+ 5 - 2
src/tokenizer.cpp

@@ -113,10 +113,12 @@ TOKEN_KIND(Token__KeywordBegin, ""), \
 	TOKEN_KIND(Token_transmute,   "transmute"),   \
 	TOKEN_KIND(Token_transmute,   "transmute"),   \
 	TOKEN_KIND(Token_distinct,    "distinct"),    \
 	TOKEN_KIND(Token_distinct,    "distinct"),    \
 	TOKEN_KIND(Token_using,       "using"),       \
 	TOKEN_KIND(Token_using,       "using"),       \
-	TOKEN_KIND(Token_inline,      "inline"),      \
-	TOKEN_KIND(Token_no_inline,   "no_inline"),   \
 	TOKEN_KIND(Token_context,     "context"),     \
 	TOKEN_KIND(Token_context,     "context"),     \
+	TOKEN_KIND(Token_or_else,     "or_else"),     \
+	TOKEN_KIND(Token_or_return,   "or_return"),   \
 	TOKEN_KIND(Token_asm,         "asm"),         \
 	TOKEN_KIND(Token_asm,         "asm"),         \
+	TOKEN_KIND(Token_inline,      "inline"),      \
+	TOKEN_KIND(Token_no_inline,   "no_inline"),   \
 TOKEN_KIND(Token__KeywordEnd, ""), \
 TOKEN_KIND(Token__KeywordEnd, ""), \
 	TOKEN_KIND(Token_Count, "")
 	TOKEN_KIND(Token_Count, "")
 
 
@@ -1508,6 +1510,7 @@ semicolon_check:;
 		case Token_continue:
 		case Token_continue:
 		case Token_fallthrough:
 		case Token_fallthrough:
 		case Token_return:
 		case Token_return:
+		case Token_or_return:
 			/*fallthrough*/
 			/*fallthrough*/
 		case Token_Integer:
 		case Token_Integer:
 		case Token_Float:
 		case Token_Float:

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