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 {
 		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 {
 			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;
 		}
 
-		cinfo  := (cmf >> 4) & 0xf;
-		if cinfo > 7 {
+		if cinfo := (cmf >> 4) & 0xf; cinfo > 7 {
 			return E_ZLIB.Unsupported_Window_Size;
 		}
 		flg, _ := compress.read_u8(ctx);
 
-		fcheck  := flg & 0x1f;
+		fcheck := flg & 0x1f;
 		fcheck_computed := (cmf << 8 | flg) & 0x1f;
 		if fcheck != fcheck_computed {
 			return E_General.Checksum_Failed;
 		}
 
-		fdict   := (flg >> 5) & 1;
 		/*
 			We don't handle built-in dictionaries for now.
 			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;
 		}
 
@@ -473,10 +471,7 @@ inflate_from_context :: proc(using ctx: ^compress.Context_Memory_Input, raw := f
 	}
 
 	// 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 {
 		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_offset:      ^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_offset);
 	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);
 	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
 			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);
 
@@ -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);
 			if type == 1 {
 				// 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 {
 				lencodes: [286+32+137]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);
 					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;
 				c: u16;
 
 				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 {
 						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;
 				}
 
-				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 {
 			break;
@@ -698,9 +661,7 @@ inflate_from_byte_array :: proc(input: []u8, buf: ^bytes.Buffer, raw := false, e
 	ctx.input_data = input;
 	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) {
@@ -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);
 }
 
-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];
 
 		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 _, err := io.write_string(w.w, field); err != nil {
-				return err;
-			}
+			io.write_string(w.w, field) or_return;
 			continue;
 		}
 
-		if err := io.write_byte(w.w, '"'); err != nil {
-			return err;
-		}
+		io.write_byte(w.w, '"') or_return;
 
 		for len(field) > 0 {
 			i := strings.index_any(field, CHAR_SET);
@@ -86,40 +80,28 @@ write :: proc(w: ^Writer, record: []string) -> io.Error {
 				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:];
 
 			if len(field) > 0 {
 				switch field[0] {
 				case '\r':
 					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':
 					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 {
-						if err := io.write_byte(w.w, '\n'); err != nil {
-							return err;
-						}
+						io.write_byte(w.w, '\n') or_return;
 					}
 				case '"':
-					if _, err := io.write_string(w.w, `""`); err != nil {
-						return err;
-					}
+					io.write_string(w.w, `""`) or_return;
 				}
 				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 {
@@ -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 :: proc(w: ^Writer, records: [][]string) -> io.Error {
 	for record in records {
-		err := write(w, record);
-		if err != nil {
-			return err;
-		}
+		write(w, record) or_return;
 	}
 	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) {
-		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) {
@@ -85,10 +77,9 @@ read :: proc(data: []byte, filename := "<input>", print_error := false, allocato
 		count := 0;
 		defer meta_data = meta_data[:count];
 		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 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)));
@@ -96,22 +87,15 @@ read :: proc(data: []byte, filename := "<input>", print_error := false, allocato
 				err = .Invalid_Data;
 				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 {
-			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;
@@ -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) {
-		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;
 		layers = make(Layer_Stack, stack_count);
 		defer layers = layers[:layer_count];
 		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 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)));
@@ -140,10 +122,10 @@ read :: proc(data: []byte, filename := "<input>", print_error := false, allocato
 			data_len := int(layer.components) * int(capacity);
 
 			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;
 		}
@@ -177,8 +159,7 @@ read :: proc(data: []byte, filename := "<input>", print_error := false, allocato
 
 	for node_idx in 0..<header.internal_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 r.print_error {
 				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;
 
-		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 {
 		case .Meta_Only:
@@ -198,35 +177,35 @@ read :: proc(data: []byte, filename := "<input>", print_error := false, allocato
 		case .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 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;
 
 		case .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);
 			if img.type == .Image_Cube {
 				dimensions = 2;
 			}
 			img.resolution = {1, 1, 1};
 			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];
 			if img.type == .Image_Cube {
 				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;
 		}

+ 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) {
-	if err = expect_token(p, .Open_Bracket); err != .None {
-		return;
-	}
+	expect_token(p, .Open_Bracket) or_return;
 
 	array: Array;
 	array.allocator = p.allocator;
@@ -147,11 +145,7 @@ parse_array :: proc(p: ^Parser) -> (value: Value, err: Error) {
 	}
 
 	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);
 
 		// 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;
 	return;
 }
@@ -200,9 +191,7 @@ parse_object_key :: proc(p: ^Parser) -> (key: string, 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.allocator = p.allocator;
@@ -227,11 +216,7 @@ parse_object :: proc(p: ^Parser) -> (value: Value, err: Error) {
 			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 {
 			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;
 	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);
 
 	if ok {
-		img, err = load_from_slice(data, options, allocator);
-		return;
+		return load_from_slice(data, options, allocator);
 	} else {
 		img = new(Image);
 		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;
 
-			header, err = read_header(ctx);
-			if err != nil {
-				return img, err;
-			}
+			header = read_header(ctx) or_return;
 
 			if .Paletted in header.color_type {
 				// 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;
 			}
 
-			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 {
 				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;
 			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);
 				idat_length += c.header.length;
@@ -560,19 +550,13 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a
 			}
 			seen_idat = true;
 		case .IEND:
-			c, err = read_chunk(ctx);
-			if err != nil {
-				return img, err;
-			}
+			c = read_chunk(ctx) or_return;
 			seen_iend = true;
 		case .bKGD:
 
 			// 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;
 			if .return_metadata in options {
 				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])};
 			}
 		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 {
 				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;
 		case:
 			// Unhandled type
-			c, err = read_chunk(ctx);
-			if err != nil {
-				return img, err;
-			}
+			c = read_chunk(ctx) or_return;
+
 			if .return_metadata in options {
 				// NOTE: Chunk cata is currently allocated on the temp allocator.
 				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.
 	*/
 	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);
 }
@@ -64,8 +64,8 @@ int_copy :: proc(dest, src: ^Int, minimize := false, allocator := context.alloca
 	assert_if_nil(dest, src);
 	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);
 }
@@ -92,8 +92,8 @@ int_abs :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error)
 	assert_if_nil(dest, src);
 	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);
 }
@@ -113,8 +113,8 @@ int_neg :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error)
 	assert_if_nil(dest, src);
 	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);
 }
@@ -134,8 +134,8 @@ int_bitfield_extract :: proc(a: ^Int, offset, count: int, allocator := context.a
 	assert_if_nil(a);
 	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);
 	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) {
@@ -305,8 +305,8 @@ int_get :: proc(a: ^Int, $T: typeid, allocator := context.allocator) -> (res: T,
 		Check that `a` is usable.
 	*/
 	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, };
 
@@ -315,8 +315,8 @@ int_get_float :: proc(a: ^Int, allocator := context.allocator) -> (res: f64, err
 		Check that `a` is usable.
 	*/
 	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.
 	*/
 	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.
 	*/
 	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)
@@ -398,7 +398,7 @@ clear_if_uninitialized_multi :: proc(args: ..^Int, allocator := context.allocato
 	assert_if_nil(..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;
 }
@@ -425,7 +425,7 @@ int_init_multi :: proc(integers: ..^Int, allocator := context.allocator) -> (err
 
 	integers := 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;
 }
@@ -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.
 	*/
 	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));
 	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) {
 	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 {
 		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) {
 	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);
 
@@ -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) {
 	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);
 	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) {
 	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);
 	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) {
 	assert_if_nil(a);
-	size_in_bytes: int;
 
 	if !signed && a.sign == .Negative { return .Invalid_Argument; }
 
 	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 {
 		t := &Int{};
 		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);
 		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) {
 	assert_if_nil(a);
-	size_in_bytes: int;
 
 	if !signed && a.sign == .Negative { return .Invalid_Argument; }
 	if a.sign == .Zero_or_Positive    { return int_to_bytes_big(a, buf, signed, allocator); }
 
 	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{};
 	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);
 	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 += 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 {
 		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 {
-		if err = internal_shl(a, a, 8); err != nil { return err; }
+		internal_shl(a, a, 8) or_return;
 		a.digit[0] |= DIGIT(v);
 	}
 	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 += 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 {
 		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 {
-		if err = internal_shl(a, a, 8); err != nil { return err; }
+		internal_shl(a, a, 8) or_return;
 		if signed && sign == .Negative {
 			a.digit[0] |= DIGIT(255 - v);	
 		} else {
@@ -674,7 +670,7 @@ int_from_bytes_big_python :: proc(a: ^Int, buf: []u8, signed := false, allocator
 	}
 	a.sign = sign;
 	a.used = size_in_digits;
-	if err = internal_clamp(a); err != nil { return err; }
+	internal_clamp(a) or_return;
 
 	if signed && sign == .Negative {
 		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 += 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 {
 		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 {
-		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.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 += 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 {
 		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 {
-		if err = internal_shl(a, a, 8); err != nil { return err; }
+		internal_shl(a, a, 8) or_return;
 		if signed && sign == .Negative {
 			a.digit[0] |= DIGIT(255 - buf[l-i-1]);
 		} else {
@@ -759,7 +755,7 @@ int_from_bytes_little_python :: proc(a: ^Int, buf: []u8, signed := false, alloca
 	}
 	a.sign = sign;
 	a.used = size_in_digits;
-	if err = internal_clamp(a); err != nil { return err; }
+	internal_clamp(a) or_return;
 
 	if signed && sign == .Negative {
 		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;
 	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;
 	/*
 		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) {
 	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.
 	*/
@@ -284,7 +284,7 @@ internal_int_sub_unsigned :: proc(dest, number, decrease: ^Int, allocator := con
 	max_used := x.used;
 	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;
 	/*
 		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) {
 	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;
 	/*
@@ -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) {
 	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.
 	*/
 	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;
 
 	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);
 	}
 	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);
 	}
 
 	/*
 		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.
@@ -722,7 +721,7 @@ internal_int_divmod :: proc(quotient, remainder, numerator, denominator: ^Int, a
 	*/
 	if #force_inline internal_cmp_mag(numerator, denominator) == -1 {
 		if remainder != nil {
-			if err = internal_copy(remainder, numerator); err != nil { return err; }
+			internal_copy(remainder, numerator) or_return;
 		}
 		if quotient != nil {
 			internal_zero(quotient);
@@ -809,7 +808,7 @@ internal_int_divmod_digit :: proc(quotient, numerator: ^Int, denominator: DIGIT,
 	*/
 	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.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.
 */
 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; }
 
@@ -865,7 +864,7 @@ internal_mod :: proc{ internal_int_mod, };
 	remainder = (number + addend) % modulus.
 */
 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);
 }
 internal_addmod :: proc { internal_int_addmod, };
@@ -874,7 +873,7 @@ internal_addmod :: proc { internal_int_addmod, };
 	remainder = (number - decrease) % modulus.
 */
 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);
 }
 internal_submod :: proc { internal_int_submod, };
@@ -883,7 +882,7 @@ internal_submod :: proc { internal_int_submod, };
 	remainder = (number * multiplicand) % modulus.
 */
 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);
 }
 internal_mulmod :: proc { internal_int_mulmod, };
@@ -892,7 +891,7 @@ internal_mulmod :: proc { internal_int_mulmod, };
 	remainder = (number * number) % modulus.
 */
 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);
 }
 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]);
 	}
 
-	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 {
-		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;
 	}
 
@@ -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.
 	*/
-	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;
 	}
 
@@ -1264,7 +1265,7 @@ internal_int_pow :: proc(dest, base: ^Int, power: int, allocator := context.allo
 			A zero base is a special case.
 		*/
 		if power  < 0 {
-			if err = internal_zero(dest); err != nil { return err; }
+			internal_zero(dest) or_return;
 			return .Math_Domain_Error;
 		}
 		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{};
-	if err = internal_copy(g, base); err != nil { return err; }
+	internal_copy(g, base) or_return;
 
 	/*
 		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 power & 1 != 0 {
-			if err = internal_mul(dest, g, dest); err != nil {
-				break loop;
-			}
+			internal_mul(dest, g, dest) or_return;
 		}
 		/*
 			Square.
 		*/
 		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 */
 		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{};
 	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);
 }
@@ -1387,15 +1385,15 @@ internal_int_sqrt :: proc(dest, src: ^Int, allocator := context.allocator) -> (e
 	count := #force_inline internal_count_bits(src);
 
 	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 {
 		/*
 			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 {
 			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.
 	*/
 	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;
 	iterations := 0;
 	for {
 		/* 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))) */
 
 		/* 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 */
 		/* 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 */
-		if err = internal_sub(t2, t2, a); err != nil { return err; }
+		internal_sub(t2, t2, a) or_return;
 
 		/* denominator */
 		/* 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)) */
-		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
@@ -1526,14 +1524,14 @@ internal_int_root_n :: proc(dest, src: ^Int, n: int, allocator := context.alloca
 
 	iterations = 0;
 	for {
-		if err = internal_pow(t2, t1, n); err != nil { return err; }
+		internal_pow(t2, t1, n) or_return;
 
 		c = internal_cmp(t2, a);
 		if c == 0 {
 			swap(dest, t1);
 			return nil;
 		} 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 {
 			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.
 		*/
 	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 err = internal_sub(t1, t1, DIGIT(1)); err != nil { return err; }
+		internal_sub(t1, t1, DIGIT(1)) or_return;
 
 		iterations += 1;
 		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;
 
-	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,
 		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.
 
@@ -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_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
@@ -1653,7 +1651,7 @@ internal_int_copy :: proc(dest, src: ^Int, minimize := false, allocator := conte
 	*/
 	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`.
@@ -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);
 
-	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.
@@ -1708,9 +1706,7 @@ internal_int_abs :: proc(dest, src: ^Int, allocator := context.allocator) -> (er
 	/*
 		Copy `src` to `dest`
 	*/
-	if err = internal_copy(dest, src); err != nil {
-		return err;
-	}
+	internal_copy(dest, src) or_return;
 
 	/*
 		Fix sign.
@@ -1744,7 +1740,7 @@ internal_int_neg :: proc(dest, src: ^Int, allocator := context.allocator) -> (er
 	/*
 		Copy `src` to `dest`
 	*/
-	if err = internal_copy(dest, src); err != nil { return err; }
+	internal_copy(dest, src) or_return;
 
 	/*
 		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.
 	*/
 	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.
 	*/
@@ -2061,7 +2057,7 @@ internal_int_and :: proc(dest, a, b: ^Int, allocator := context.allocator) -> (e
 	/*
 		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_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.
 	*/
-	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_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.
 	*/
-	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_b := #force_inline internal_is_negative(b);
@@ -2269,21 +2265,21 @@ internal_int_shrmod :: proc(quotient, remainder, numerator: ^Int, bits: int, all
 	bits := bits;
 	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.)
 	   `numerator` should not be used after this.
 	*/
 	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.
 	*/
 	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 {
 		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));
 }
 
@@ -2380,19 +2375,19 @@ internal_int_shl :: proc(dest, src: ^Int, bits: int, allocator := context.alloca
 
 	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.
 	*/
 	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;
 	/*
 		Shift by as many digits in the bit count as we have.
 	*/
 	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.
 	*/
-	if #force_inline internal_is_zero(quotient) { return {}; }
+	if #force_inline internal_is_zero(quotient) {
+		return nil;
+	}
 
 	/*
 		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.
@@ -2537,7 +2534,7 @@ internal_int_rand :: proc(dest: ^Int, bits: int, r: ^rnd.Rand = nil, allocator :
 		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 {
 		dest.digit[i] = int_random_digit(r) & _MASK;
@@ -2600,7 +2597,7 @@ internal_int_init_multi :: proc(integers: ..^Int, allocator := context.allocator
 
 	integers := integers;
 	for a in &integers {
-		if err = internal_clear(a); err != nil { return err; }
+		internal_clear(a) or_return;
 	}
 	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);
 	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);
 }
 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);
 	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);
 }
 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);
 	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);
 }
 xor :: proc { int_xor, };
@@ -64,7 +64,7 @@ int_complement :: proc(dest, src: ^Int, allocator := context.allocator) -> (err:
 	assert_if_nil(dest, src);
 	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);
 }
 complement :: proc { int_complement, };
@@ -97,7 +97,7 @@ int_shr_digit :: proc(quotient: ^Int, digits: int, allocator := context.allocato
 	assert_if_nil(quotient);
 	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);
 }
 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);
 	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);
 }
 
@@ -122,7 +122,7 @@ int_shl :: proc(dest, src: ^Int, bits: int, allocator := context.allocator) -> (
 	assert_if_nil(dest, src);
 	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);
 }
 shl :: proc { int_shl, };
@@ -138,7 +138,7 @@ int_shl_digit :: proc(quotient: ^Int, digits: int, allocator := context.allocato
 	assert_if_nil(quotient);
 	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);
 }
 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);
 	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 {
-		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.

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);
 	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.
 	*/
@@ -41,11 +41,11 @@ int_add_digit :: proc(dest, a: ^Int, digit: DIGIT, allocator := context.allocato
 	assert_if_nil(dest, a);
 	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.
 	*/
-	if err = grow(dest, a.used + 1); err != nil { return err; }
+	grow(dest, a.used + 1) or_return;
 
 	/*
 		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);
 	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.
 	*/
@@ -77,11 +77,11 @@ int_sub_digit :: proc(dest, a: ^Int, digit: DIGIT, allocator := context.allocato
 	assert_if_nil(dest, a);
 	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.
 	*/
-	if err = grow(dest, a.used + 1); err != nil { return err; }
+	grow(dest, a.used + 1) or_return;
 
 	/*
 		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);
 	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.
 	*/
-	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);
 }
@@ -116,11 +116,11 @@ int_double :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Err
 	assert_if_nil(dest, src);
 	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.
 	*/
-	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);
 }
@@ -134,7 +134,7 @@ int_mul_digit :: proc(dest, src: ^Int, multiplier: DIGIT, allocator := context.a
 	assert_if_nil(dest, src);
 	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);
 }
@@ -146,7 +146,7 @@ int_mul :: proc(dest, src, multiplier: ^Int, allocator := context.allocator) ->
 	assert_if_nil(dest, src, multiplier);
 	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);
 }
@@ -166,7 +166,7 @@ int_divmod :: proc(quotient, remainder, numerator, denominator: ^Int, allocator
 		Early out if neither of the results is wanted.
 	*/
 	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);
 }
@@ -175,7 +175,7 @@ int_divmod_digit :: proc(quotient, numerator: ^Int, denominator: DIGIT, allocato
 	assert_if_nil(quotient, numerator);
 	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);
 }
@@ -185,7 +185,7 @@ int_div :: proc(quotient, numerator, denominator: ^Int, allocator := context.all
 	assert_if_nil(quotient, numerator, denominator);
 	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);
 }
@@ -194,11 +194,10 @@ int_div_digit :: proc(quotient, numerator: ^Int, denominator: DIGIT, allocator :
 	assert_if_nil(quotient, numerator);
 	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, };
 
@@ -211,7 +210,7 @@ int_mod :: proc(remainder, numerator, denominator: ^Int, allocator := context.al
 	assert_if_nil(remainder, numerator, denominator);
 	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);
 }
@@ -229,7 +228,7 @@ int_addmod :: proc(remainder, number, addend, modulus: ^Int, allocator := contex
 	assert_if_nil(remainder, number, addend);
 	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);
 }
@@ -242,7 +241,7 @@ int_submod :: proc(remainder, number, decrease, modulus: ^Int, allocator := cont
 	assert_if_nil(remainder, number, decrease);
 	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);
 }
@@ -255,7 +254,7 @@ int_mulmod :: proc(remainder, number, multiplicand, modulus: ^Int, allocator :=
 	assert_if_nil(remainder, number, multiplicand);
 	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);
 }
@@ -268,7 +267,7 @@ int_sqrmod :: proc(remainder, number, modulus: ^Int, allocator := context.alloca
 	assert_if_nil(remainder, number, modulus);
 	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);
 }
@@ -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{};
 	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, };
 
@@ -331,7 +330,7 @@ int_gcd_lcm :: proc(res_gcd, res_lcm, a, b: ^Int, allocator := context.allocator
 	assert_if_nil(a, b);
 	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);
 }
 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);
 	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);
 }
@@ -375,7 +374,7 @@ int_log :: proc(a: ^Int, base: DIGIT, allocator := context.allocator) -> (res: i
 	assert_if_nil(a);
 	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);
 }
@@ -392,7 +391,7 @@ int_pow :: proc(dest, base: ^Int, power: int, allocator := context.allocator) ->
 	assert_if_nil(dest, base);
 	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);
 }
@@ -420,7 +419,7 @@ int_sqrt :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error
 	assert_if_nil(dest, src);
 	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);
 }
@@ -446,7 +445,7 @@ int_root_n :: proc(dest, src: ^Int, n: int, allocator := context.allocator) -> (
 	/*
 		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);
 }
@@ -466,7 +465,7 @@ int_is_zero :: proc(a: ^Int, allocator := context.allocator) -> (zero: bool, err
 	assert_if_nil(a);
 	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;
 }
@@ -475,7 +474,7 @@ int_is_positive :: proc(a: ^Int, allocator := context.allocator) -> (positive: b
 	assert_if_nil(a);
 	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;
 }
@@ -484,7 +483,7 @@ int_is_negative :: proc(a: ^Int, allocator := context.allocator) -> (negative: b
 	assert_if_nil(a);
 	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;
 }
@@ -493,7 +492,7 @@ int_is_even :: proc(a: ^Int, allocator := context.allocator) -> (even: bool, err
 	assert_if_nil(a);
 	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;
 }
@@ -502,7 +501,7 @@ int_is_odd :: proc(a: ^Int, allocator := context.allocator) -> (odd: bool, err:
 	assert_if_nil(a);
 	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;
 }
@@ -515,7 +514,7 @@ int_is_power_of_two :: proc(a: ^Int, allocator := context.allocator) -> (res: bo
 	assert_if_nil(a);
 	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;
 }
@@ -527,7 +526,7 @@ int_compare :: proc(a, b: ^Int, allocator := context.allocator) -> (comparison:
 	assert_if_nil(a, b);
 	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;
 }
@@ -540,7 +539,7 @@ int_compare_digit :: proc(a: ^Int, b: DIGIT, allocator := context.allocator) ->
 	assert_if_nil(a);
 	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;
 }
@@ -553,7 +552,7 @@ int_compare_magnitude :: proc(a, b: ^Int, allocator := context.allocator) -> (re
 	assert_if_nil(a, b);
 	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;
 }

+ 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;
 
 	a := a; radix := radix;
-	if err = clear_if_uninitialized(a); err != nil { return "", err; }
+	clear_if_uninitialized(a) or_return;
 	/*
 		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 
-	*/
-	size: int;
-	/*
 		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.
@@ -70,7 +65,7 @@ int_itoa_cstring :: proc(a: ^Int, radix := i8(-1), allocator := context.allocato
 	context.allocator = allocator;
 
 	a := a; radix := radix;
-	if err = clear_if_uninitialized(a); err != nil { return "", err; }
+	clear_if_uninitialized(a) or_return;
 	/*
 		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) {
 	assert_if_nil(a);
 	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.
 	*/
@@ -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.
 	*/
 	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.
 	*/
-	if err = internal_zero(res); err != nil { return err; }
+	internal_zero(res) or_return;
 
 	/*
 		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.
@@ -301,8 +296,8 @@ int_atoi :: proc(res: ^Int, input: string, radix: i8, allocator := context.alloc
 			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:];
 	}
@@ -333,7 +328,7 @@ radix_size :: proc(a: ^Int, radix: i8, zero_terminate := false, allocator := con
 	assert_if_nil(a);
 
 	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 zero_terminate {
@@ -352,22 +347,22 @@ radix_size :: proc(a: ^Int, radix: i8, zero_terminate := false, allocator := con
 			digit     = a.digit,
 		};
 
-		if size, err = internal_log(t, DIGIT(radix));   err != nil { return {}, err; }
+		size = internal_log(t, DIGIT(radix)) or_return;
 	} else {
 		la, k := &Int{}, &Int{};
 		defer internal_destroy(la, k);
 
 		/* la = floor(log_2(a)) + 1 */
 		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 */
 		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 */
-		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" */
 		/* 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{};
 
-	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);
 	if zero_terminate {

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

@@ -49,7 +49,7 @@ PyRes :: struct {
 	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}; }	
 	} 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;
@@ -70,7 +70,7 @@ PyRes :: struct {
 	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}; }
 	} 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;
@@ -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(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, err = int_itoa_cstring(product, 16, context.temp_allocator);
@@ -104,7 +104,7 @@ PyRes :: struct {
 	defer internal_destroy(aa, square);
 
 	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, 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(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, err = int_itoa_cstring(quotient, 16, context.temp_allocator);
@@ -145,7 +145,7 @@ PyRes :: struct {
 	defer internal_destroy(aa);
 
 	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);
 	aa.digit[0] = DIGIT(l)  & _MASK;
@@ -170,7 +170,7 @@ PyRes :: struct {
 	defer internal_destroy(dest, bb);
 
 	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, err = int_itoa_cstring(dest, 16, context.temp_allocator);
@@ -189,7 +189,7 @@ PyRes :: struct {
 	defer internal_destroy(src);
 
 	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, err = int_itoa_cstring(src, 16, context.temp_allocator);
@@ -208,7 +208,7 @@ PyRes :: struct {
 	defer internal_destroy(src);
 
 	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, err = int_itoa_cstring(src, 16, context.temp_allocator);
@@ -227,7 +227,7 @@ PyRes :: struct {
 	defer internal_destroy(src);
 
 	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, err = int_itoa_cstring(src, 16, context.temp_allocator);
@@ -246,7 +246,7 @@ PyRes :: struct {
 	defer internal_destroy(src);
 
 	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, err = int_itoa_cstring(src, 16, context.temp_allocator);
@@ -265,7 +265,7 @@ PyRes :: struct {
 	defer internal_destroy(src);
 
 	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, err = int_itoa_cstring(src, 16, context.temp_allocator);
@@ -284,7 +284,7 @@ PyRes :: struct {
 	defer internal_destroy(src);
 
 	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, err = int_itoa_cstring(src, 16, context.temp_allocator);
@@ -303,7 +303,7 @@ PyRes :: struct {
 	defer internal_destroy(src);
 
 	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, 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,
 }
 
-Ternary_Expr :: struct {
-	using node: Expr,
-	cond: ^Expr,
-	op1:  tokenizer.Token,
-	x:    ^Expr,
-	op2:  tokenizer.Token,
-	y:    ^Expr,
-}
-
 Ternary_If_Expr :: struct {
 	using node: Expr,
 	x:    ^Expr,
@@ -261,13 +252,26 @@ Ternary_If_Expr :: struct {
 
 Ternary_When_Expr :: struct {
 	using node: Expr,
-	x: ^Expr,
+	x:    ^Expr,
 	op1:  tokenizer.Token,
 	cond: ^Expr,
 	op2:  tokenizer.Token,
 	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 {
 	using node: Expr,
 	expr:  ^Expr,
@@ -542,7 +546,7 @@ Field_Flag :: enum {
 	No_Alias,
 	C_Vararg,
 	Auto_Cast,
-	In,
+	Any_Int,
 
 	Results,
 	Tags,

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

@@ -129,10 +129,6 @@ clone_node :: proc(node: ^Node) -> ^Node {
 	case Field_Value:
 		r.field = clone(r.field);
 		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:
 		r.x    = clone(r.x);
 		r.cond = clone(r.cond);
@@ -141,6 +137,11 @@ clone_node :: proc(node: ^Node) -> ^Node {
 		r.x    = clone(r.x);
 		r.cond = clone(r.cond);
 		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:
 		r.expr = clone(r.expr);
 		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:
 		walk(v, n.field);
 		walk(v, n.value);
-	case Ternary_Expr:
-		walk(v, n.cond);
-		walk(v, n.x);
-		walk(v, n.y);
 	case Ternary_If_Expr:
 		walk(v, n.x);
 		walk(v, n.cond);
@@ -138,6 +134,11 @@ walk :: proc(v: ^Visitor, node: ^Node) {
 		walk(v, n.x);
 		walk(v, n.cond);
 		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:
 		walk(v, n.expr);
 		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 {
 	prev := p.curr_tok;
-	if prev.kind == .If || prev.kind == .When {
+	#partial switch prev.kind {
+	case .If, .When, .Or_Else, .Or_Return:
 		// 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);
 	return prev;
@@ -1366,9 +1369,9 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
 			stmt := parse_stmt(p);
 			switch name {
 			case "bounds_check":
-				stmt.state_flags |= {.Bounds_Check};
+				stmt.state_flags += {.Bounds_Check};
 			case "no_bounds_check":
-				stmt.state_flags |= {.No_Bounds_Check};
+				stmt.state_flags += {.No_Bounds_Check};
 			}
 			return stmt;
 		case "partial":
@@ -1449,7 +1452,7 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
 
 token_precedence :: proc(p: ^Parser, kind: tokenizer.Token_Kind) -> int {
 	#partial switch kind {
-	case .Question, .If, .When:
+	case .Question, .If, .When, .Or_Else, .Or_Return:
 		return 1;
 	case .Ellipsis, .Range_Half, .Range_Full:
 		if !p.allow_range {
@@ -1578,8 +1581,8 @@ Field_Prefix :: enum {
 	Using,
 	No_Alias,
 	C_Vararg,
-	In,
 	Auto_Cast,
+	Any_Int,
 }
 
 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 {
-	using Field_Prefix;
 	#partial switch p.curr_tok.kind {
 	case .EOF:
-		return Invalid;
+		return .Invalid;
 	case .Using:
 		advance_token(p);
-		return Using;
-	case .In:
-		advance_token(p);
-		return In;
+		return .Using;
 	case .Auto_Cast:
 		advance_token(p);
-		return Auto_Cast;
+		return .Auto_Cast;
 	case .Hash:
 		advance_token(p);
 		defer advance_token(p);
@@ -1646,14 +1645,16 @@ is_token_field_prefix :: proc(p: ^Parser) -> Field_Prefix {
 		case .Ident:
 			switch p.curr_tok.text {
 			case "no_alias":
-				return No_Alias;
+				return .No_Alias;
 			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 {
@@ -1677,24 +1678,23 @@ parse_field_prefixes :: proc(p: ^Parser) -> ast.Field_Flags {
 
 	for kind in Field_Prefix {
 		count := counts[kind];
-		using Field_Prefix;
 		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 > 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 > 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 > 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 > 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;
 	if name_count > 1 && .Using in flags {
 		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 {
@@ -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");
 			case .Auto_Cast:
 				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:
 				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);
 
 		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:
 		}
 	}
@@ -2267,12 +2267,12 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
 
 			switch name.text {
 			case "bounds_check":
-				operand.state_flags |= {.Bounds_Check};
+				operand.state_flags += {.Bounds_Check};
 				if .No_Bounds_Check in operand.state_flags {
 					error(p, name.pos, "#bounds_check and #no_bounds_check cannot be applied together");
 				}
 			case "no_bounds_check":
-				operand.state_flags |= {.No_Bounds_Check};
+				operand.state_flags += {.No_Bounds_Check};
 				if .Bounds_Check in operand.state_flags {
 					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 {
+		loop: for {
 			op := p.curr_tok;
 			op_prec := token_precedence(p, op.kind);
 			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 {
 					// 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);
 				colon := expect_token(p, .Colon);
 				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.op1  = op;
 				te.x    = x;
@@ -3212,6 +3214,21 @@ parse_binary_expr :: proc(p: ^Parser, lhs: bool, prec_in: int) -> ^ast.Expr {
 				te.y    = y;
 
 				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:
 				right := parse_binary_expr(p, false, prec+1);
 				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:
 		push_generic_token(p, v.op.kind, 1);
 		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:
 		visit_expr(p, v.x);
 		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);
 		push_generic_token(p, v.op2.kind, 1);
 		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:
 		visit_expr(p, v.call.expr);
 		push_generic_token(p, .Open_Paren, 1);

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

@@ -144,10 +144,12 @@ Token_Kind :: enum u32 {
 		Transmute,   // transmute
 		Distinct,    // distinct
 		Using,       // using
-		Inline,      // inline
-		No_Inline,   // no_inline
 		Context,     // context
+		Or_Else,     // or_else
+		Or_Return,   // or_return
 		Asm,         // asm
+		Inline,      // inline
+		No_Inline,   // no_inline
 	B_Keyword_End,
 
 	COUNT,
@@ -272,10 +274,12 @@ tokens := [Token_Kind.COUNT]string {
 	"transmute",
 	"distinct",
 	"using",
-	"inline",
-	"no_inline",
 	"context",
+	"or_else",
+	"or_return",
 	"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,
 		     .Integer, .Float, .Imag, .Rune, .String, .Undef,
 		     .Question, .Pointer, .Close_Paren, .Close_Bracket, .Close_Brace,
-		     .Increment, .Decrement:
+		     .Increment, .Decrement, .Or_Return:
 			/*fallthrough*/
 			t.insert_semicolon = true;
 		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) {
-	v := or_else(ferr.(Platform_Error), {});
+	v := ferr.(Platform_Error) or_else {};
 	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 {
 		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 {
 		n := fi.name;
-		matched, err := match(pattern, n);
-		if err != nil {
-			return m, err;
-		}
+		matched := match(pattern, n) or_return;
 		if matched {
 			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) {
-	tid := runtime.current_thread_id();
+	tid := _current_thread_id();
 	if tid != m.impl.owner {
 		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 {
 	__windows_thread_entry_proc :: proc "stdcall" (t_: rawptr) -> win32.DWORD {
 		t := (^Thread)(t_);
-		context = or_else(t.init_context.?, runtime.default_context());
+		context = t.init_context.? or_else runtime.default_context();
 
 		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_mutex = {};
 
-		context = or_else(t.init_context.?, runtime.default_context());
+		context = t.init_context.? or_else runtime.default_context();
 
 		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 {
 		t := (^Thread)(t_);
-		context = or_else(t.init_context.?, runtime.default_context());
+		context = t.init_context.? or_else runtime.default_context();
 
 		t.procedure(t);
 

+ 50 - 50
examples/all/all_main.odin

@@ -3,57 +3,57 @@ package all
 // Imports every package
 // 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 "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 "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(){}

+ 109 - 8
examples/demo/demo.odin

@@ -1998,9 +1998,9 @@ relative_data_types :: proc() {
 	fmt.println(rel_slice[1]);
 }
 
-or_else_procedure :: proc() {
+or_else_operator :: proc() {
 	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;
 		i: int;
@@ -2010,7 +2010,7 @@ or_else_procedure :: proc() {
 			i = 123;
 		}
 		// The above can be mapped to 'or_else'
-		i = or_else(m["hellope"], 123);
+		i = m["hellope"] or_else 123;
 
 		assert(i == 123);
 	}
@@ -2019,16 +2019,117 @@ or_else_procedure :: proc() {
 		// have optional ok semantics
 		v: union{int, f64};
 		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);
 
 		m: Maybe(int);
-		i = or_else(m.?, 456);
+		i = m.? or_else 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() {
 	when true {
 		the_basics();
@@ -2061,7 +2162,7 @@ main :: proc() {
 		union_maybe();
 		explicit_context_definition();
 		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_) {
 	Type *left_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 (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
 	gbString t = type_to_string(x.type);
 	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) {
 	ast_node(ce, CallExpr, call);
 	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
 		break;
 
-	case BuiltinProc_or_else:
-		// NOTE(bill): The arguments may be multi-expr
-		break;
-
 	case BuiltinProc_DIRECTIVE: {
 		ast_node(bd, BasicDirective, ce->proc);
 		String name = bd->name.string;
@@ -1800,47 +1830,6 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
 		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: {
 		Operand x = {};
 		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_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) {
 	expr = unparen_expr(expr);
 	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);
 	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);
 		update_untyped_expr_type(c, pe->expr, type, final);
 	case_end;
@@ -6602,6 +6626,123 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
 		}
 	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);
 		Type *type = type_hint;
 		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);
 	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);
 		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) {
 				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);
 				if (is_type_proc(t)) {
 					if (t->Proc.require_results) {
@@ -1491,8 +1493,8 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
 					}
 				}
 				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);
 				Type *t = type_of_expr(ce->proc);
 				if (is_type_proc(t)) {

+ 0 - 4
src/checker_builtin_procs.hpp

@@ -33,8 +33,6 @@ enum BuiltinProcId {
 	BuiltinProc_soa_zip,
 	BuiltinProc_soa_unzip,
 
-	BuiltinProc_or_else,
-
 	BuiltinProc_DIRECTIVE, // NOTE(bill): This is used for specialized hash-prefixed procedures
 
 	// "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_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
 
 

+ 8 - 0
src/llvm_backend_expr.cpp

@@ -2305,6 +2305,14 @@ lbValue lb_build_expr(lbProcedure *p, Ast *expr) {
 		}
 	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);
 		TokenPos pos = ast_token(expr).pos;
 		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:
 		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"
 
 	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;
 }
 
+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) {

+ 57 - 5
src/parser.cpp

@@ -187,6 +187,13 @@ Ast *clone_ast(Ast *node) {
 		n->TernaryWhenExpr.cond = clone_ast(n->TernaryWhenExpr.cond);
 		n->TernaryWhenExpr.y    = clone_ast(n->TernaryWhenExpr.y);
 		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:
 		n->TypeAssertion.expr = clone_ast(n->TypeAssertion.expr);
 		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;
 }
 
+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 *result = alloc_ast_node(f, Ast_TypeAssertion);
 	result->TypeAssertion.expr = expr;
@@ -1340,6 +1362,8 @@ Token expect_operator(AstFile *f) {
 		// okay
 	} else if (prev.kind == Token_if || prev.kind == Token_when) {
 		// 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)) {
 		String p = token_to_string(prev);
 		syntax_error(f->curr_token, "Expected an operator, got '%.*s'",
@@ -1674,6 +1698,22 @@ Ast *unselector_expr(Ast *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);
 
 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 *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) {
 		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);
@@ -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));
 			break;
 
+		case Token_or_return:
+			operand = ast_or_return_expr(f, operand, expect_token(f, Token_or_return));
+			break;
+
 		case Token_OpenBrace:
 			if (!lhs && is_literal_type(operand) && f->expr_level >= 0) {
 				operand = parse_literal_value(f, operand);
@@ -2870,6 +2914,7 @@ i32 token_precedence(AstFile *f, TokenKind t) {
 	case Token_Question:
 	case Token_if:
 	case Token_when:
+	case Token_or_else:
 		return 1;
 	case Token_Ellipsis:
 	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
 				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) {
 					// 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
 
 			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);
 				Ast *y = parse_expr(f, lhs);
 				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 {
 				Ast *right = parse_binary_expr(f, false, prec+1);
 				if (right == nullptr) {
@@ -2965,6 +3016,7 @@ Ast *parse_binary_expr(AstFile *f, bool lhs, i32 prec_in) {
 
 			lhs = false;
 		}
+		loop_end:;
 	}
 	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(TernaryIfExpr,   "ternary if 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 *expr; \
 		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_TernaryIfExpr:      return ast_token(node->TernaryIfExpr.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_TypeCast:           return node->TypeCast.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_TernaryIfExpr:      return ast_end_token(node->TernaryIfExpr.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_TypeCast:           return ast_end_token(node->TypeCast.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_distinct,    "distinct"),    \
 	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_or_else,     "or_else"),     \
+	TOKEN_KIND(Token_or_return,   "or_return"),   \
 	TOKEN_KIND(Token_asm,         "asm"),         \
+	TOKEN_KIND(Token_inline,      "inline"),      \
+	TOKEN_KIND(Token_no_inline,   "no_inline"),   \
 TOKEN_KIND(Token__KeywordEnd, ""), \
 	TOKEN_KIND(Token_Count, "")
 
@@ -1508,6 +1510,7 @@ semicolon_check:;
 		case Token_continue:
 		case Token_fallthrough:
 		case Token_return:
+		case Token_or_return:
 			/*fallthrough*/
 		case Token_Integer:
 		case Token_Float:

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