internal override void TranslateToIL(ILGenerator il, Type rtype)
{
Type type = Convert.ToType(this.InferType(null));
if (this.metaData == null)
{
Type rt = Typeob.Object;
if (rtype == Typeob.Double)
{
rt = rtype;
}
else if (this.type1 == Typeob.Char && this.type2 == Typeob.Char)
{
rt = Typeob.String;
}
else if (Convert.IsPrimitiveNumericType(rtype) && Convert.IsPromotableTo(this.type1, rtype) && Convert.IsPromotableTo(this.type2, rtype))
{
rt = rtype;
}
else if (this.type1 != Typeob.String && this.type2 != Typeob.String) //Both will be converted to numbers
{
rt = Typeob.Double; //Won't get here unless InferType returned Typeob.Double.
}
else
{
rt = Typeob.String;
}
if (rt == Typeob.SByte || rt == Typeob.Int16)
{
rt = Typeob.Int32;
}
else if (rt == Typeob.Byte || rt == Typeob.UInt16 || rt == Typeob.Char)
{
rt = Typeob.UInt32;
}
if (rt == Typeob.String)
{
if (this.operand1 is Plus && this.type1 == rt)
{
Plus op1 = (Plus)this.operand1;
if (op1.operand1 is Plus && op1.type1 == rt)
{
Plus op11 = (Plus)op1.operand1;
if (op11.operand1 is Plus && op11.type1 == rt)
{
int len = op1.TranslateToILArrayOfStrings(il, 1);
il.Emit(OpCodes.Dup);
ConstantWrapper.TranslateToILInt(il, len - 1);
this.operand2.TranslateToIL(il, rt);
il.Emit(OpCodes.Stelem_Ref);
il.Emit(OpCodes.Call, CompilerGlobals.stringConcatArrMethod);
Convert.Emit(this, il, rt, rtype);
return;
}
Plus.TranslateToStringWithSpecialCaseForNull(il, op11.operand1);
Plus.TranslateToStringWithSpecialCaseForNull(il, op11.operand2);
Plus.TranslateToStringWithSpecialCaseForNull(il, op1.operand2);
Plus.TranslateToStringWithSpecialCaseForNull(il, this.operand2);
il.Emit(OpCodes.Call, CompilerGlobals.stringConcat4Method);
Convert.Emit(this, il, rt, rtype);
return;
}
Plus.TranslateToStringWithSpecialCaseForNull(il, op1.operand1);
Plus.TranslateToStringWithSpecialCaseForNull(il, op1.operand2);
Plus.TranslateToStringWithSpecialCaseForNull(il, this.operand2);
il.Emit(OpCodes.Call, CompilerGlobals.stringConcat3Method);
Convert.Emit(this, il, rt, rtype);
return;
}
Plus.TranslateToStringWithSpecialCaseForNull(il, this.operand1);
Plus.TranslateToStringWithSpecialCaseForNull(il, this.operand2);
il.Emit(OpCodes.Call, CompilerGlobals.stringConcat2Method);
Convert.Emit(this, il, rt, rtype);
return;
}
this.operand1.TranslateToIL(il, rt);
this.operand2.TranslateToIL(il, rt);
if (rt == Typeob.Object)
{
il.Emit(OpCodes.Call, CompilerGlobals.plusDoOpMethod);
}
else if (rt == Typeob.Double || rt == Typeob.Single)
{
il.Emit(OpCodes.Add);
}
else if (rt == Typeob.Int32 || rt == Typeob.Int64)
{
il.Emit(OpCodes.Add_Ovf);
}
else
{
il.Emit(OpCodes.Add_Ovf_Un);
}
if (type == Typeob.Char)
{
Convert.Emit(this, il, rt, Typeob.Char);
Convert.Emit(this, il, Typeob.Char, rtype);
}
else
{
Convert.Emit(this, il, rt, rtype);
}
return;
}
if (this.metaData is MethodInfo)
{
MethodInfo oper = (MethodInfo)this.metaData;
ParameterInfo[] pars = oper.GetParameters();
this.operand1.TranslateToIL(il, pars[0].ParameterType);
this.operand2.TranslateToIL(il, pars[1].ParameterType);
il.Emit(OpCodes.Call, oper);
Convert.Emit(this, il, oper.ReturnType, rtype);
return;
}
//Getting here is just too bad. We do not know until the code runs whether or not to call an overloaded operator method.
//Compile operands to objects and devolve the decision making to run time thunks
//Also get here when dealing with Int64 and UInt64. These cannot always be converted to doubles. The late-bound code checks for this.
il.Emit(OpCodes.Ldloc, (LocalBuilder)this.metaData);
this.operand1.TranslateToIL(il, Typeob.Object);
this.operand2.TranslateToIL(il, Typeob.Object);
il.Emit(OpCodes.Callvirt, CompilerGlobals.evaluatePlusMethod);
Convert.Emit(this, il, Typeob.Object, rtype);
}