Browse Source

Unify `AstTernaryExpr` with `AstTernaryIfExpr`

Allow for both syntaxes `x if cond else y` and `cond ? x : y`
Removes the confusing semantics behind `?:` which could be `if` or `when` depending on the context.
gingerBill 4 years ago
parent
commit
278de3a92f
6 changed files with 17 additions and 172 deletions
  1. 1 1
      core/runtime/udivmod128.odin
  2. 15 105
      src/check_expr.cpp
  3. 0 10
      src/check_type.cpp
  4. 0 41
      src/llvm_backend.cpp
  5. 1 14
      src/parser.cpp
  6. 0 1
      src/parser.hpp

+ 1 - 1
core/runtime/udivmod128.odin

@@ -11,7 +11,7 @@ udivmod128 :: proc "c" (a, b: u128, rem: ^u128) -> u128 {
 	q, r: [2]u64 = ---, ---;
 	sr: u32 = 0;
 
-	low  :: ODIN_ENDIAN == "big" ? 1 : 0;
+	low  :: 1 when ODIN_ENDIAN == "big" else 0;
 	high :: 1 - low;
 	U64_BITS :: 8*size_of(u64);
 	U128_BITS :: 8*size_of(u128);

+ 15 - 105
src/check_expr.cpp

@@ -2860,16 +2860,6 @@ void update_expr_type(CheckerContext *c, Ast *e, Type *type, bool final) {
 		}
 	case_end;
 
-	case_ast_node(te, TernaryExpr, e);
-		if (old.value.kind != ExactValue_Invalid) {
-			// See above note in UnaryExpr case
-			break;
-		}
-
-		update_expr_type(c, te->x, type, final);
-		update_expr_type(c, te->y, type, final);
-	case_end;
-
 	case_ast_node(te, TernaryIfExpr, e);
 		if (old.value.kind != ExactValue_Invalid) {
 			// See above note in UnaryExpr case
@@ -6104,88 +6094,6 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
 		o->type = type;
 	case_end;
 
-	case_ast_node(te, TernaryExpr, node);
-		Operand cond = {Addressing_Invalid};
-		check_expr(c, &cond, te->cond);
-		node->viral_state_flags |= te->cond->viral_state_flags;
-
-		if (cond.mode != Addressing_Invalid && !is_type_boolean(cond.type)) {
-			error(te->cond, "Non-boolean condition in if expression");
-		}
-
-		Operand x = {Addressing_Invalid};
-		Operand y = {Addressing_Invalid};
-		check_expr_or_type(c, &x, te->x, type_hint);
-		node->viral_state_flags |= te->x->viral_state_flags;
-
-		if (te->y != nullptr) {
-			check_expr_or_type(c, &y, te->y, type_hint);
-			node->viral_state_flags |= te->y->viral_state_flags;
-		} else {
-			error(node, "A ternary expression must have an else clause");
-			return kind;
-		}
-
-		if (x.type == nullptr || x.type == t_invalid ||
-		    y.type == nullptr || y.type == t_invalid) {
-			return kind;
-		}
-
-		if (x.mode == Addressing_Type && y.mode == Addressing_Type &&
-		    cond.mode == Addressing_Constant && is_type_boolean(cond.type)) {
-			o->mode = Addressing_Type;
-			if (cond.value.value_bool) {
-				o->type = x.type;
-				o->expr = x.expr;
-			} else {
-				o->type = y.type;
-				o->expr = y.expr;
-			}
-			return Expr_Expr;
-		}
-
-		convert_to_typed(c, &x, y.type);
-		if (x.mode == Addressing_Invalid) {
-			return kind;
-		}
-		convert_to_typed(c, &y, x.type);
-		if (y.mode == Addressing_Invalid) {
-			x.mode = Addressing_Invalid;
-			return kind;
-		}
-
-		if (!ternary_compare_types(x.type, y.type)) {
-			gbString its = type_to_string(x.type);
-			gbString ets = type_to_string(y.type);
-			error(node, "Mismatched types in ternary expression, %s vs %s", its, ets);
-			gb_string_free(ets);
-			gb_string_free(its);
-			return kind;
-		}
-
-		Type *type = x.type;
-		if (is_type_untyped_nil(type) || is_type_untyped_undef(type)) {
-			type = y.type;
-		}
-
-		o->type = type;
-		o->mode = Addressing_Value;
-
-		if (cond.mode == Addressing_Constant && is_type_boolean(cond.type) &&
-		    x.mode == Addressing_Constant &&
-		    y.mode == Addressing_Constant) {
-
-			o->mode = Addressing_Constant;
-
-			if (cond.value.value_bool) {
-				o->value = x.value;
-			} else {
-				o->value = y.value;
-			}
-		}
-
-	case_end;
-
 	case_ast_node(te, TernaryIfExpr, node);
 		Operand cond = {Addressing_Invalid};
 		check_expr(c, &cond, te->cond);
@@ -8265,20 +8173,22 @@ gbString write_expr_to_string(gbString str, Ast *node, bool shorthand) {
 		str = write_expr_to_string(str, be->right, shorthand);
 	case_end;
 
-	case_ast_node(te, TernaryExpr, node);
-		str = write_expr_to_string(str, te->cond, shorthand);
-		str = gb_string_appendc(str, " ? ");
-		str = write_expr_to_string(str, te->x, shorthand);
-		str = gb_string_appendc(str, " : ");
-		str = write_expr_to_string(str, te->y, shorthand);
-	case_end;
-
 	case_ast_node(te, TernaryIfExpr, node);
-		str = write_expr_to_string(str, te->x, shorthand);
-		str = gb_string_appendc(str, " if ");
-		str = write_expr_to_string(str, te->cond, shorthand);
-		str = gb_string_appendc(str, " else ");
-		str = write_expr_to_string(str, te->y, shorthand);
+		TokenPos x = ast_token(te->x).pos;
+		TokenPos cond = ast_token(te->cond).pos;
+		if (x < cond) {
+			str = write_expr_to_string(str, te->x, shorthand);
+			str = gb_string_appendc(str, " if ");
+			str = write_expr_to_string(str, te->cond, shorthand);
+			str = gb_string_appendc(str, " else ");
+			str = write_expr_to_string(str, te->y, shorthand);
+		} else {
+			str = write_expr_to_string(str, te->cond, shorthand);
+			str = gb_string_appendc(str, " ? ");
+			str = write_expr_to_string(str, te->x, shorthand);
+			str = gb_string_appendc(str, " : ");
+			str = write_expr_to_string(str, te->y, shorthand);
+		}
 	case_end;
 
 	case_ast_node(te, TernaryWhenExpr, node);

+ 0 - 10
src/check_type.cpp

@@ -2889,16 +2889,6 @@ bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, Type *named_t
 		}
 	case_end;
 
-	case_ast_node(te, TernaryExpr, e);
-		Operand o = {};
-		check_expr_or_type(ctx, &o, e);
-		if (o.mode == Addressing_Type) {
-			*type = o.type;
-			set_base_type(named_type, *type);
-			return true;
-		}
-	case_end;
-
 	case_ast_node(te, TernaryIfExpr, e);
 		Operand o = {};
 		check_expr_or_type(ctx, &o, e);

+ 0 - 41
src/llvm_backend.cpp

@@ -11351,47 +11351,6 @@ lbValue lb_build_expr(lbProcedure *p, Ast *expr) {
 		return lb_build_expr(p, se->call);
 	case_end;
 
-	case_ast_node(te, TernaryExpr, expr);
-		LLVMValueRef incoming_values[2] = {};
-		LLVMBasicBlockRef incoming_blocks[2] = {};
-
-		GB_ASSERT(te->y != nullptr);
-		lbBlock *then  = lb_create_block(p, "if.then");
-		lbBlock *done  = lb_create_block(p, "if.done"); // NOTE(bill): Append later
-		lbBlock *else_ = lb_create_block(p, "if.else");
-
-		lbValue cond = lb_build_cond(p, te->cond, then, else_);
-		lb_start_block(p, then);
-
-		Type *type = default_type(type_of_expr(expr));
-
-		lb_open_scope(p, nullptr);
-		incoming_values[0] = lb_emit_conv(p, lb_build_expr(p, te->x), type).value;
-		lb_close_scope(p, lbDeferExit_Default, nullptr);
-
-		lb_emit_jump(p, done);
-		lb_start_block(p, else_);
-
-		lb_open_scope(p, nullptr);
-		incoming_values[1] = lb_emit_conv(p, lb_build_expr(p, te->y), type).value;
-		lb_close_scope(p, lbDeferExit_Default, nullptr);
-
-		lb_emit_jump(p, done);
-		lb_start_block(p, done);
-
-		lbValue res = {};
-		res.value = LLVMBuildPhi(p->builder, lb_type(p->module, type), "");
-		res.type = type;
-
-		GB_ASSERT(p->curr_block->preds.count >= 2);
-		incoming_blocks[0] = p->curr_block->preds[0]->block;
-		incoming_blocks[1] = p->curr_block->preds[1]->block;
-
-		LLVMAddIncoming(res.value, incoming_values, incoming_blocks, 2);
-
-		return res;
-	case_end;
-
 	case_ast_node(te, TernaryIfExpr, expr);
 		LLVMValueRef incoming_values[2] = {};
 		LLVMBasicBlockRef incoming_blocks[2] = {};

+ 1 - 14
src/parser.cpp

@@ -39,7 +39,6 @@ Token ast_token(Ast *node) {
 	case Ast_Ellipsis:           return node->Ellipsis.token;
 	case Ast_FieldValue:         return node->FieldValue.eq;
 	case Ast_DerefExpr:          return node->DerefExpr.op;
-	case Ast_TernaryExpr:        return ast_token(node->TernaryExpr.cond);
 	case Ast_TernaryIfExpr:      return ast_token(node->TernaryIfExpr.x);
 	case Ast_TernaryWhenExpr:    return ast_token(node->TernaryWhenExpr.x);
 	case Ast_TypeAssertion:      return ast_token(node->TypeAssertion.expr);
@@ -241,11 +240,6 @@ Ast *clone_ast(Ast *node) {
 		n->FieldValue.value = clone_ast(n->FieldValue.value);
 		break;
 
-	case Ast_TernaryExpr:
-		n->TernaryExpr.cond = clone_ast(n->TernaryExpr.cond);
-		n->TernaryExpr.x    = clone_ast(n->TernaryExpr.x);
-		n->TernaryExpr.y    = clone_ast(n->TernaryExpr.y);
-		break;
 	case Ast_TernaryIfExpr:
 		n->TernaryIfExpr.x    = clone_ast(n->TernaryIfExpr.x);
 		n->TernaryIfExpr.cond = clone_ast(n->TernaryIfExpr.cond);
@@ -698,13 +692,6 @@ Ast *ast_compound_lit(AstFile *f, Ast *type, Array<Ast *> const &elems, Token op
 }
 
 
-Ast *ast_ternary_expr(AstFile *f, Ast *cond, Ast *x, Ast *y) {
-	Ast *result = alloc_ast_node(f, Ast_TernaryExpr);
-	result->TernaryExpr.cond = cond;
-	result->TernaryExpr.x = x;
-	result->TernaryExpr.y = y;
-	return result;
-}
 Ast *ast_ternary_if_expr(AstFile *f, Ast *x, Ast *cond, Ast *y) {
 	Ast *result = alloc_ast_node(f, Ast_TernaryIfExpr);
 	result->TernaryIfExpr.x = x;
@@ -2871,7 +2858,7 @@ Ast *parse_binary_expr(AstFile *f, bool lhs, i32 prec_in) {
 				Ast *x = parse_expr(f, lhs);
 				Token token_c = expect_token(f, Token_Colon);
 				Ast *y = parse_expr(f, lhs);
-				expr = ast_ternary_expr(f, cond, x, y);
+				expr = ast_ternary_if_expr(f, x, cond, y);
 			} else if (op.kind == Token_if) {
 				Ast *x = expr;
 				// Token_if

+ 0 - 1
src/parser.hpp

@@ -343,7 +343,6 @@ AST_KIND(_ExprBegin,  "",  bool) \
 		i32          builtin_id; \
 	}) \
 	AST_KIND(FieldValue,      "field value",              struct { Token eq; Ast *field, *value; }) \
-	AST_KIND(TernaryExpr,     "ternary expression",       struct { Ast *cond, *x, *y; }) \
 	AST_KIND(TernaryIfExpr,   "ternary if expression",    struct { Ast *x, *cond, *y; }) \
 	AST_KIND(TernaryWhenExpr, "ternary when expression",  struct { Ast *x, *cond, *y; }) \
 	AST_KIND(TypeAssertion, "type assertion",      struct { Ast *expr; Token dot; Ast *type; Type *type_hint; }) \