public override ABT.Expr GetExpr(ABT.Env env) {
ABT.Expr cond = this.Cond.GetExpr(env);
if (!cond.Type.IsScalar) {
throw new InvalidOperationException("Expected a scalar condition in conditional expression.");
}
if (cond.Type.IsIntegral) {
cond = ABT.TypeCast.IntegralPromotion(cond).Item1;
}
ABT.Expr true_expr = this.TrueExpr.GetExpr(env);
ABT.Expr false_expr = this.FalseExpr.GetExpr(env);
// 1. if both true_expr and false_Expr have arithmetic types:
// perform usual arithmetic conversion
if (true_expr.Type.IsArith && false_expr.Type.IsArith) {
var r_cast = ABT.TypeCast.UsualArithmeticConversion(true_expr, false_expr);
true_expr = r_cast.Item1;
false_expr = r_cast.Item2;
return new ABT.ConditionalExpr(cond, true_expr, false_expr, true_expr.Type);
}
if (true_expr.Type.Kind != false_expr.Type.Kind) {
throw new InvalidOperationException("Operand types not match in conditional expression.");
}
switch (true_expr.Type.Kind) {
// 2. if both true_expr and false_expr have struct or union Type
// make sure they are compatible
case ABT.ExprTypeKind.STRUCT_OR_UNION:
if (!true_expr.Type.EqualType(false_expr.Type)) {
throw new InvalidOperationException("Expected compatible types in conditional expression.");
}
return new ABT.ConditionalExpr(cond, true_expr, false_expr, true_expr.Type);
// 3. if both true_expr and false_expr have void Type
// return void
case ABT.ExprTypeKind.VOID:
return new ABT.ConditionalExpr(cond, true_expr, false_expr, true_expr.Type);
// 4. if both true_expr and false_expr have pointer Type
case ABT.ExprTypeKind.POINTER:
// if either points to void, convert to void *
if (((ABT.PointerType)true_expr.Type).RefType.Kind == ABT.ExprTypeKind.VOID
|| ((ABT.PointerType)false_expr.Type).RefType.Kind == ABT.ExprTypeKind.VOID) {
return new ABT.ConditionalExpr(cond, true_expr, false_expr, new ABT.PointerType(new ABT.VoidType()));
}
throw new NotImplementedException("More comparisons here.");
default:
throw new InvalidOperationException("Expected compatible types in conditional expression.");
}
}
}