private Expr GenerateBuiltInBinaryOperator(ExprBinOp expr)
{
Debug.Assert(expr != null);
PREDEFMETH pdm;
switch (expr.Kind)
{
case ExpressionKind.LeftShirt: pdm = PREDEFMETH.PM_EXPRESSION_LEFTSHIFT; break;
case ExpressionKind.RightShift: pdm = PREDEFMETH.PM_EXPRESSION_RIGHTSHIFT; break;
case ExpressionKind.BitwiseExclusiveOr: pdm = PREDEFMETH.PM_EXPRESSION_EXCLUSIVEOR; break;
case ExpressionKind.BitwiseOr: pdm = PREDEFMETH.PM_EXPRESSION_OR; break;
case ExpressionKind.BitwiseAnd: pdm = PREDEFMETH.PM_EXPRESSION_AND; break;
case ExpressionKind.LogicalAnd: pdm = PREDEFMETH.PM_EXPRESSION_ANDALSO; break;
case ExpressionKind.LogicalOr: pdm = PREDEFMETH.PM_EXPRESSION_ORELSE; break;
case ExpressionKind.StringEq: pdm = PREDEFMETH.PM_EXPRESSION_EQUAL; break;
case ExpressionKind.Eq: pdm = PREDEFMETH.PM_EXPRESSION_EQUAL; break;
case ExpressionKind.StringNotEq: pdm = PREDEFMETH.PM_EXPRESSION_NOTEQUAL; break;
case ExpressionKind.NotEq: pdm = PREDEFMETH.PM_EXPRESSION_NOTEQUAL; break;
case ExpressionKind.GreaterThanOrEqual: pdm = PREDEFMETH.PM_EXPRESSION_GREATERTHANOREQUAL; break;
case ExpressionKind.LessThanOrEqual: pdm = PREDEFMETH.PM_EXPRESSION_LESSTHANOREQUAL; break;
case ExpressionKind.LessThan: pdm = PREDEFMETH.PM_EXPRESSION_LESSTHAN; break;
case ExpressionKind.GreaterThan: pdm = PREDEFMETH.PM_EXPRESSION_GREATERTHAN; break;
case ExpressionKind.Modulo: pdm = PREDEFMETH.PM_EXPRESSION_MODULO; break;
case ExpressionKind.Divide: pdm = PREDEFMETH.PM_EXPRESSION_DIVIDE; break;
case ExpressionKind.Multiply:
pdm = expr.isChecked() ? PREDEFMETH.PM_EXPRESSION_MULTIPLYCHECKED : PREDEFMETH.PM_EXPRESSION_MULTIPLY;
break;
case ExpressionKind.Subtract:
pdm = expr.isChecked() ? PREDEFMETH.PM_EXPRESSION_SUBTRACTCHECKED : PREDEFMETH.PM_EXPRESSION_SUBTRACT;
break;
case ExpressionKind.Add:
pdm = expr.isChecked() ? PREDEFMETH.PM_EXPRESSION_ADDCHECKED : PREDEFMETH.PM_EXPRESSION_ADD;
break;
default:
throw Error.InternalCompilerError();
}
Expr origL = expr.OptionalLeftChild;
Expr origR = expr.OptionalRightChild;
Debug.Assert(origL != null);
Debug.Assert(origR != null);
CType typeL = origL.Type;
CType typeR = origR.Type;
Expr newL = Visit(origL);
Expr newR = Visit(origR);
bool didEnumConversion = false;
CType convertL = null;
CType convertR = null;
if (typeL.isEnumType())
{
// We have already inserted casts if not lifted, so we should never see an enum.
Debug.Assert(expr.IsLifted);
convertL = GetSymbolLoader().GetTypeManager().GetNullable(typeL.underlyingEnumType());
typeL = convertL;
didEnumConversion = true;
}
else if (typeL is NullableType nubL && nubL.UnderlyingType.isEnumType())
{
Debug.Assert(expr.IsLifted);
convertL = GetSymbolLoader().GetTypeManager().GetNullable(nubL.UnderlyingType.underlyingEnumType());
typeL = convertL;
didEnumConversion = true;
}
if (typeR.isEnumType())
{
Debug.Assert(expr.IsLifted);
convertR = GetSymbolLoader().GetTypeManager().GetNullable(typeR.underlyingEnumType());
typeR = convertR;
didEnumConversion = true;
}
else if (typeR is NullableType nubR && nubR.UnderlyingType.isEnumType())
{
Debug.Assert(expr.IsLifted);
convertR = GetSymbolLoader().GetTypeManager().GetNullable(nubR.UnderlyingType.underlyingEnumType());
typeR = convertR;
didEnumConversion = true;
}
if (typeL is NullableType nubL2 && nubL2.UnderlyingType == typeR)
{
convertR = typeL;
}
if (typeR is NullableType nubR2 && nubR2.UnderlyingType == typeL)
{
convertL = typeR;
}
if (convertL != null)
{
newL = GenerateCall(PREDEFMETH.PM_EXPRESSION_CONVERT, newL, CreateTypeOf(convertL));
}
if (convertR != null)
{
newR = GenerateCall(PREDEFMETH.PM_EXPRESSION_CONVERT, newR, CreateTypeOf(convertR));
}
Expr call = GenerateCall(pdm, newL, newR);
if (didEnumConversion && expr.Type.StripNubs().isEnumType())
{
call = GenerateCall(PREDEFMETH.PM_EXPRESSION_CONVERT, call, CreateTypeOf(expr.Type));
}
return(call);
}