Browse Source

Remove `try`; Replace `try x else y` with `or_else(x, y)`

gingerBill 4 years ago
parent
commit
a98eee145d
9 changed files with 169 additions and 395 deletions
  1. 8 114
      examples/demo/demo.odin
  2. 110 0
      src/check_builtin.cpp
  3. 0 186
      src/check_expr.cpp
  4. 4 0
      src/checker_builtin_procs.hpp
  5. 47 52
      src/llvm_backend.cpp
  6. 0 36
      src/parser.cpp
  7. 0 2
      src/parser.hpp
  8. 0 4
      src/parser_pos.cpp
  9. 0 1
      src/tokenizer.cpp

+ 8 - 114
examples/demo/demo.odin

@@ -1999,115 +1999,9 @@ relative_data_types :: proc() {
 	fmt.println(rel_slice[1]);
 	fmt.println(rel_slice[1]);
 }
 }
 
 
-try_and_try_else :: proc() {
-	fmt.println("\n#'try ...'' and 'try ... else ...'");
-	// IMPORTANT NOTE: 'try' and 'try else' are experimental features and subject to change/removal
-
-	Foo :: struct {};
-	Error :: enum {
-		None,
-		Something,
-		Whatever,
-	};
-
-	bar :: proc(ok: bool) -> (f: Foo, err: Error) {
-		if !ok {
-			err = .Something;
-		}
-		return;
-	}
-
-
-	try_return_value :: proc() -> Error {
-		// This is a common idiom, where the end value of an expression
-		// may not be 'nil' or may be 'false'
-		f0, err := bar(true);
-		if err != nil {
-			return err;
-		}
-		_ = f0;
-
-		// 'try' is a lovely shorthand that does this check automatically
-		// and returns early if necessary
-		f1 := try bar(true);
-		fmt.println(#procedure);
-		fmt.println(f1);
-
-		f2 := try bar(false);
-		fmt.println(#procedure);
-		fmt.println(f2);
-		return .None;
-	}
-
-	try_return_value2 :: proc() -> (i: int, err: Error) {
-		// 'try' will work within procedures with multiple return values
-		// However, the return values must be named
-		// 'try' effectively pops off the last value and checks it
-		// And then returns the rest of the values, meaning it works
-		// for as many return values as possible
-		i = 0;
-		f0, f0_err := bar(true);
-		if f0_err != nil {
-			err = f0_err;
-			return;
-		}
-		fmt.println(#procedure);
-		fmt.println(f0);
-
-		// The above can be translated into 'try'
-		i = 1;
-		f1 := try bar(true);
-		fmt.println(#procedure);
-		fmt.println(f1);
-
-		i = 2;
-
-		f2 := try bar(false);
-		fmt.println(#procedure);
-		fmt.println(f2);
-
-		i = 3;
-
-		return i, .None;
-	}
-
-	try_return_value4 :: proc() -> (i: int, j: f64, k: bool, err: Error) {
-		f := try bar(false);
-		fmt.println(#procedure);
-		fmt.println(f);
-		return 123, 456, true, .None;
-	}
-
-
-	try_optional_ok :: proc() -> bool {
-		m: map[string]int;
-		/*
-		f1, ok := m["hellope"];
-		if !ok {
-			return false;
-		}
-		*/
-		// 'try' equivalent
-		f2 := try m["hellope"];
-		fmt.println(f2);
-		return true;
-	}
-
-	{
-		// 'try' examples
-		err := try_return_value();
-		fmt.println(err);
-
-		ok := try_optional_ok();
-		fmt.println(ok);
-
-		i, err2 := try_return_value2();
-		fmt.println(i);
-		fmt.println(err2);
-
-		a, b, c, err4 := try_return_value4();
-		assert(a == 0 && b == 0 && c == false && err4 == .Something);
-	}
+or_else_procedure :: proc() {
+	fmt.println("\n#'or_else'");
+	// IMPORTANT NOTE: 'or_else' is experimental features and subject to change/removal
 	{
 	{
 		// 'try else' does a similar value check as 'try' but instead of doing an
 		// 'try else' does a similar value check as 'try' but instead of doing an
 		// early return, it will give a default value to be used instead
 		// early return, it will give a default value to be used instead
@@ -2120,7 +2014,7 @@ try_and_try_else :: proc() {
 			i = 123;
 			i = 123;
 		}
 		}
 		// The above can be mapped to 'try else'
 		// The above can be mapped to 'try else'
-		i = try m["hellope"] else 123;
+		i = or_else(m["hellope"], 123);
 
 
 		assert(i == 123);
 		assert(i == 123);
 	}
 	}
@@ -2129,12 +2023,12 @@ try_and_try_else :: proc() {
 		// have optional ok semantics
 		// have optional ok semantics
 		v: union{int, f64};
 		v: union{int, f64};
 		i: int;
 		i: int;
-		i = try v.(int) else 123;
-		i = try v.? else 123; // Type inference magic
+		i = or_else(v.(int), 123);
+		i = or_else(v.?, 123); // Type inference magic
 		assert(i == 123);
 		assert(i == 123);
 
 
 		m: Maybe(int);
 		m: Maybe(int);
-		i = try m.? else 456;
+		i = or_else(m.?, 456);
 		assert(i == 456);
 		assert(i == 456);
 	}
 	}
 }
 }
@@ -2171,6 +2065,6 @@ main :: proc() {
 		union_maybe();
 		union_maybe();
 		explicit_context_definition();
 		explicit_context_definition();
 		relative_data_types();
 		relative_data_types();
-		try_and_try_else();
+		or_else_procedure();
 	}
 	}
 }
 }

+ 110 - 0
src/check_builtin.cpp

@@ -47,6 +47,72 @@ BuiltinTypeIsProc *builtin_type_is_procs[BuiltinProc__type_simple_boolean_end -
 	type_has_nil,
 	type_has_nil,
 };
 };
 
 
+
+void check_try_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;
+
+	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);
+	}
+	// if (!type_has_nil(right_type) && !is_type_boolean(right_type)) {
+	// 	gbString str = type_to_string(right_type);
+	// 	error(x->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_try_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);
+	if (is_type_union(type_deref(x.type))) {
+		Type *bsrc = base_type(type_deref(x.type));
+		gbString th = nullptr;
+		if (type_hint != nullptr) {
+			GB_ASSERT(bsrc->kind == Type_Union);
+			for_array(i, bsrc->Union.variants) {
+				Type *vt = bsrc->Union.variants[i];
+				if (are_types_identical(vt, type_hint)) {
+					th = type_to_string(type_hint);
+					break;
+				}
+			}
+		}
+		gbString expr_str = expr_to_string(x.expr);
+		if (th != nullptr) {
+			error_line("\tSuggestion: was a type assertion such as %s.(%s) or %s.? wanted?\n", expr_str, th, expr_str);
+		} else {
+			error_line("\tSuggestion: was a type assertion such as %s.(T) or %s.? wanted?\n", expr_str, expr_str);
+		}
+		gb_string_free(th);
+		gb_string_free(expr_str);
+	}
+	gb_string_free(t);
+}
+
+
 bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 id, Type *type_hint) {
 bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 id, Type *type_hint) {
 	ast_node(ce, CallExpr, call);
 	ast_node(ce, CallExpr, call);
 	if (ce->inlining != ProcInlining_none) {
 	if (ce->inlining != ProcInlining_none) {
@@ -84,6 +150,9 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
 		// NOTE(bill): The first arg may be a Type, this will be checked case by case
 		// NOTE(bill): The first arg may be a Type, this will be checked case by case
 		break;
 		break;
 
 
+	case BuiltinProc_or_else:
+		// NOTE(bill): The arguments may be multi-expr
+		break;
 
 
 	case BuiltinProc_DIRECTIVE: {
 	case BuiltinProc_DIRECTIVE: {
 		ast_node(bd, BasicDirective, ce->proc);
 		ast_node(bd, BasicDirective, ce->proc);
@@ -1712,6 +1781,47 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
 		break;
 		break;
 	}
 	}
 
 
+	case BuiltinProc_or_else: {
+		GB_ASSERT(ce->args.count == 2);
+		Ast *arg = ce->args[0];
+		Ast *default_value = ce->args[1];
+
+		Operand x = {};
+		Operand y = {};
+		check_multi_expr_with_type_hint(c, &x, arg, type_hint);
+		if (x.mode == Addressing_Invalid) {
+			operand->mode = Addressing_Value;
+			operand->type = t_invalid;
+			return false;
+		}
+
+		check_multi_expr_with_type_hint(c, &y, default_value, x.type);
+		error_operand_no_value(&y);
+		if (y.mode == Addressing_Invalid) {
+			operand->mode = Addressing_Value;
+			operand->type = t_invalid;
+			return false;
+		}
+
+		Type *left_type = nullptr;
+		Type *right_type = nullptr;
+		check_try_split_types(c, &x, builtin_name, &left_type, &right_type);
+		add_type_and_value(&c->checker->info, arg, x.mode, x.type, x.value);
+
+		if (left_type != nullptr) {
+			check_assignment(c, &y, left_type, builtin_name);
+		} else {
+			check_try_expr_no_value_error(c, builtin_name, x, type_hint);
+		}
+
+		if (left_type == nullptr) {
+			left_type = t_invalid;
+		}
+		operand->mode = Addressing_Value;
+		operand->type = left_type;
+		return true;
+	}
+
 	case BuiltinProc_simd_vector: {
 	case BuiltinProc_simd_vector: {
 		Operand x = {};
 		Operand x = {};
 		Operand y = {};
 		Operand y = {};

+ 0 - 186
src/check_expr.cpp

@@ -6233,184 +6233,6 @@ void check_promote_optional_ok(CheckerContext *c, Operand *x, Type **val_type_,
 	GB_ASSERT(is_type_tuple(type_of_expr(x->expr)));
 	GB_ASSERT(is_type_tuple(type_of_expr(x->expr)));
 }
 }
 
 
-void check_try_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;
-
-	if (!type_has_nil(right_type) && !is_type_boolean(right_type)) {
-		gbString str = type_to_string(right_type);
-		error(x->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_try_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);
-	if (is_type_union(type_deref(x.type))) {
-		Type *bsrc = base_type(type_deref(x.type));
-		gbString th = nullptr;
-		if (type_hint != nullptr) {
-			GB_ASSERT(bsrc->kind == Type_Union);
-			for_array(i, bsrc->Union.variants) {
-				Type *vt = bsrc->Union.variants[i];
-				if (are_types_identical(vt, type_hint)) {
-					th = type_to_string(type_hint);
-					break;
-				}
-			}
-		}
-		gbString expr_str = expr_to_string(x.expr);
-		if (th != nullptr) {
-			error_line("\tSuggestion: was a type assertion such as %s.(%s) or %s.? wanted?\n", expr_str, th, expr_str);
-		} else {
-			error_line("\tSuggestion: was a type assertion such as %s.(T) or %s.? wanted?\n", expr_str, expr_str);
-		}
-		gb_string_free(th);
-		gb_string_free(expr_str);
-	}
-	gb_string_free(t);
-}
-ExprKind check_try_expr(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) {
-	String name = str_lit("try");
-
-	ast_node(te, TryExpr, node);
-
-	Operand x = {};
-	check_multi_expr_with_type_hint(c, &x, te->expr, type_hint);
-	if (x.mode == Addressing_Invalid) {
-		o->mode = Addressing_Value;
-		o->type = t_invalid;
-		return Expr_Expr;
-	}
-
-	if (c->in_defer) {
-		error(node, "'%.*s' cannot be used within a defer statement", LIT(name));
-	}
-
-	Type *left_type = nullptr;
-	Type *right_type = nullptr;
-	check_try_split_types(c, &x, name, &left_type, &right_type);
-	add_type_and_value(&c->checker->info, te->expr, x.mode, x.type, x.value);
-
-	if (c->curr_proc_sig == nullptr) {
-		error(node, "'%.*s' can only be used within a procedure", LIT(name));
-	}
-
-	if (right_type == nullptr) {
-		check_try_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);
-			}
-		}
-	}
-
-	if (left_type != nullptr) {
-		o->mode = Addressing_Value;
-		o->type = left_type;
-	} else {
-		o->mode = Addressing_NoValue;
-		o->type = nullptr;
-	}
-
-	return Expr_Expr;
-}
-ExprKind check_try_else_expr(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) {
-	String name = str_lit("try else");
-
-	ast_node(te, TryElseExpr, node);
-
-	Operand x = {};
-	Operand y = {};
-	check_multi_expr_with_type_hint(c, &x, te->expr, type_hint);
-	if (x.mode == Addressing_Invalid) {
-		o->mode = Addressing_Value;
-		o->type = t_invalid;
-		return Expr_Expr;
-	}
-
-	check_multi_expr_with_type_hint(c, &y, te->else_expr, x.type);
-	error_operand_no_value(&y);
-	if (y.mode == Addressing_Invalid) {
-		o->mode = Addressing_Value;
-		o->type = t_invalid;
-		return Expr_Expr;
-	}
-
-	Type *left_type = nullptr;
-	Type *right_type = nullptr;
-	check_try_split_types(c, &x, name, &left_type, &right_type);
-	add_type_and_value(&c->checker->info, te->expr, x.mode, x.type, x.value);
-
-	if (left_type != nullptr) {
-		check_assignment(c, &y, left_type, name);
-	} else {
-		check_try_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;
-
-	return Expr_Expr;
-}
-
 
 
 ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) {
 ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) {
 	u32 prev_state_flags = c->state_flags;
 	u32 prev_state_flags = c->state_flags;
@@ -7781,14 +7603,6 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
 		}
 		}
 	case_end;
 	case_end;
 
 
-	case_ast_node(te, TryExpr, node);
-		return check_try_expr(c, o, node, type_hint);
-	case_end;
-
-	case_ast_node(te, TryElseExpr, node);
-		return check_try_else_expr(c, o, node, type_hint);
-	case_end;
-
 	case_ast_node(se, SelectorExpr, node);
 	case_ast_node(se, SelectorExpr, node);
 		check_selector(c, o, node, type_hint);
 		check_selector(c, o, node, type_hint);
 		node->viral_state_flags |= se->expr->viral_state_flags;
 		node->viral_state_flags |= se->expr->viral_state_flags;

+ 4 - 0
src/checker_builtin_procs.hpp

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

+ 47 - 52
src/llvm_backend.cpp

@@ -9590,50 +9590,50 @@ lbValue lb_emit_try_has_value(lbProcedure *p, lbValue rhs) {
 	GB_ASSERT(has_value.value != nullptr);
 	GB_ASSERT(has_value.value != nullptr);
 	return has_value;
 	return has_value;
 }
 }
-lbValue lb_emit_try(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, "try.return", false);
-	lbBlock *continue_block = lb_create_block(p, "try.continue", false);
-	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 {};
-}
-
-
-lbValue lb_emit_try_else(lbProcedure *p, Ast *arg, Ast *else_expr, TypeAndValue const &tv) {
+// lbValue lb_emit_try(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, "try.return", false);
+// 	lbBlock *continue_block = lb_create_block(p, "try.continue", false);
+// 	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 {};
+// }
+
+
+lbValue lb_emit_or_else(lbProcedure *p, Ast *arg, Ast *else_expr, TypeAndValue const &tv) {
 	lbValue lhs = {};
 	lbValue lhs = {};
 	lbValue rhs = {};
 	lbValue rhs = {};
 	lb_emit_try_lhs_rhs(p, arg, tv, &lhs, &rhs);
 	lb_emit_try_lhs_rhs(p, arg, tv, &lhs, &rhs);
@@ -10064,6 +10064,9 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
 	case BuiltinProc_soa_unzip:
 	case BuiltinProc_soa_unzip:
 		return lb_soa_unzip(p, ce, tv);
 		return lb_soa_unzip(p, ce, tv);
 
 
+	case BuiltinProc_or_else:
+		return lb_emit_or_else(p, ce->args[0], ce->args[1], tv);
+
 	// "Intrinsics"
 	// "Intrinsics"
 
 
 	case BuiltinProc_alloca:
 	case BuiltinProc_alloca:
@@ -12783,14 +12786,6 @@ lbValue lb_build_expr(lbProcedure *p, Ast *expr) {
 		return lb_build_binary_expr(p, expr);
 		return lb_build_binary_expr(p, expr);
 	case_end;
 	case_end;
 
 
-	case_ast_node(te, TryExpr, expr);
-		return lb_emit_try(p, te->expr, tv);
-	case_end;
-
-	case_ast_node(te, TryElseExpr, expr);
-		return lb_emit_try_else(p, te->expr, te->else_expr, tv);
-	case_end;
-
 	case_ast_node(pl, ProcLit, expr);
 	case_ast_node(pl, ProcLit, expr);
 		return lb_generate_anonymous_proc_lit(p->module, p->name, expr, p);
 		return lb_generate_anonymous_proc_lit(p->module, p->name, expr, p);
 	case_end;
 	case_end;

+ 0 - 36
src/parser.cpp

@@ -199,15 +199,6 @@ Ast *clone_ast(Ast *node) {
 		n->AutoCast.expr = clone_ast(n->AutoCast.expr);
 		n->AutoCast.expr = clone_ast(n->AutoCast.expr);
 		break;
 		break;
 
 
-	case Ast_TryExpr:
-		n->TryExpr.expr = clone_ast(n->TryExpr.expr);
-		break;
-
-	case Ast_TryElseExpr:
-		n->TryElseExpr.expr = clone_ast(n->TryElseExpr.expr);
-		n->TryElseExpr.else_expr = clone_ast(n->TryElseExpr.else_expr);
-		break;
-
 	case Ast_InlineAsmExpr:
 	case Ast_InlineAsmExpr:
 		n->InlineAsmExpr.param_types        = clone_ast_array(n->InlineAsmExpr.param_types);
 		n->InlineAsmExpr.param_types        = clone_ast_array(n->InlineAsmExpr.param_types);
 		n->InlineAsmExpr.return_type        = clone_ast(n->InlineAsmExpr.return_type);
 		n->InlineAsmExpr.return_type        = clone_ast(n->InlineAsmExpr.return_type);
@@ -689,21 +680,6 @@ Ast *ast_auto_cast(AstFile *f, Token token, Ast *expr) {
 	return result;
 	return result;
 }
 }
 
 
-Ast *ast_try_expr(AstFile *f, Token token, Ast *expr) {
-	Ast *result = alloc_ast_node(f, Ast_TryExpr);
-	result->TryExpr.token = token;
-	result->TryExpr.expr  = expr;
-	return result;
-}
-Ast *ast_try_else_expr(AstFile *f, Token try_token, Ast *expr, Token else_token, Ast *else_expr) {
-	Ast *result = alloc_ast_node(f, Ast_TryElseExpr);
-	result->TryElseExpr.try_token  = try_token;
-	result->TryElseExpr.expr       = expr;
-	result->TryElseExpr.else_token = else_token;
-	result->TryElseExpr.else_expr  = else_expr;
-	return result;
-}
-
 
 
 Ast *ast_inline_asm_expr(AstFile *f, Token token, Token open, Token close,
 Ast *ast_inline_asm_expr(AstFile *f, Token token, Token open, Token close,
                          Array<Ast *> const &param_types,
                          Array<Ast *> const &param_types,
@@ -2748,17 +2724,6 @@ Ast *parse_unary_expr(AstFile *f, bool lhs) {
 		return ast_auto_cast(f, token, expr);
 		return ast_auto_cast(f, token, expr);
 	}
 	}
 
 
-	case Token_try: {
-		Token try_token = advance_token(f);
-		Ast *expr = parse_unary_expr(f, lhs);
-		if (f->curr_token.kind == Token_else) {
-			Token else_token = advance_token(f);
-			Ast *else_expr = parse_expr(f, lhs);
-			return ast_try_else_expr(f, try_token, expr, else_token, else_expr);
-		}
-		return ast_try_expr(f, try_token, expr);
-	}
-
 	case Token_Add:
 	case Token_Add:
 	case Token_Sub:
 	case Token_Sub:
 	case Token_Xor:
 	case Token_Xor:
@@ -4385,7 +4350,6 @@ Ast *parse_stmt(AstFile *f) {
 	case Token_String:
 	case Token_String:
 	case Token_OpenParen:
 	case Token_OpenParen:
 	case Token_Pointer:
 	case Token_Pointer:
-	case Token_try:
 	case Token_asm: // Inline assembly
 	case Token_asm: // Inline assembly
 	// Unary Operators
 	// Unary Operators
 	case Token_Add:
 	case Token_Add:

+ 0 - 2
src/parser.hpp

@@ -370,8 +370,6 @@ AST_KIND(_ExprBegin,  "",  bool) \
 	}) \
 	}) \
 	AST_KIND(TypeCast,      "type cast",           struct { Token token; Ast *type, *expr; }) \
 	AST_KIND(TypeCast,      "type cast",           struct { Token token; Ast *type, *expr; }) \
 	AST_KIND(AutoCast,      "auto_cast",           struct { Token token; Ast *expr; }) \
 	AST_KIND(AutoCast,      "auto_cast",           struct { Token token; Ast *expr; }) \
-	AST_KIND(TryExpr,       "try expression",      struct { Token token; Ast *expr; }) \
-	AST_KIND(TryElseExpr,   "try else expression", struct { Token try_token; Ast *expr; Token else_token; Ast *else_expr; }) \
 	AST_KIND(InlineAsmExpr, "inline asm expression", struct { \
 	AST_KIND(InlineAsmExpr, "inline asm expression", struct { \
 		Token token; \
 		Token token; \
 		Token open, close; \
 		Token open, close; \

+ 0 - 4
src/parser_pos.cpp

@@ -44,8 +44,6 @@ Token ast_token(Ast *node) {
 	case Ast_TypeAssertion:      return ast_token(node->TypeAssertion.expr);
 	case Ast_TypeAssertion:      return ast_token(node->TypeAssertion.expr);
 	case Ast_TypeCast:           return node->TypeCast.token;
 	case Ast_TypeCast:           return node->TypeCast.token;
 	case Ast_AutoCast:           return node->AutoCast.token;
 	case Ast_AutoCast:           return node->AutoCast.token;
-	case Ast_TryExpr:            return node->TryExpr.token;
-	case Ast_TryElseExpr:        return node->TryElseExpr.try_token;
 	case Ast_InlineAsmExpr:      return node->InlineAsmExpr.token;
 	case Ast_InlineAsmExpr:      return node->InlineAsmExpr.token;
 
 
 	case Ast_BadStmt:            return node->BadStmt.begin;
 	case Ast_BadStmt:            return node->BadStmt.begin;
@@ -180,8 +178,6 @@ Token ast_end_token(Ast *node) {
 	case Ast_TypeAssertion:      return ast_end_token(node->TypeAssertion.type);
 	case Ast_TypeAssertion:      return ast_end_token(node->TypeAssertion.type);
 	case Ast_TypeCast:           return ast_end_token(node->TypeCast.expr);
 	case Ast_TypeCast:           return ast_end_token(node->TypeCast.expr);
 	case Ast_AutoCast:           return ast_end_token(node->AutoCast.expr);
 	case Ast_AutoCast:           return ast_end_token(node->AutoCast.expr);
-	case Ast_TryExpr:            return ast_end_token(node->TryExpr.expr);
-	case Ast_TryElseExpr:        return ast_end_token(node->TryElseExpr.else_expr);
 	case Ast_InlineAsmExpr:      return node->InlineAsmExpr.close;
 	case Ast_InlineAsmExpr:      return node->InlineAsmExpr.close;
 
 
 	case Ast_BadStmt:            return node->BadStmt.end;
 	case Ast_BadStmt:            return node->BadStmt.end;

+ 0 - 1
src/tokenizer.cpp

@@ -117,7 +117,6 @@ TOKEN_KIND(Token__KeywordBegin, ""), \
 	TOKEN_KIND(Token_no_inline,   "no_inline"),   \
 	TOKEN_KIND(Token_no_inline,   "no_inline"),   \
 	TOKEN_KIND(Token_context,     "context"),     \
 	TOKEN_KIND(Token_context,     "context"),     \
 	TOKEN_KIND(Token_asm,         "asm"),         \
 	TOKEN_KIND(Token_asm,         "asm"),         \
-	TOKEN_KIND(Token_try,         "try"),         \
 TOKEN_KIND(Token__KeywordEnd, ""), \
 TOKEN_KIND(Token__KeywordEnd, ""), \
 	TOKEN_KIND(Token_Count, "")
 	TOKEN_KIND(Token_Count, "")