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); }
internal override void TranslateToIL(ILGenerator il, Type rtype) { Type type = Microsoft.JScript.Convert.ToType(this.InferType(null)); if (this.metaData == null) { Type type2 = Typeob.Object; if (rtype == Typeob.Double) { type2 = rtype; } else if ((base.type1 == Typeob.Char) && (base.type2 == Typeob.Char)) { type2 = Typeob.String; } else if ((Microsoft.JScript.Convert.IsPrimitiveNumericType(rtype) && Microsoft.JScript.Convert.IsPromotableTo((IReflect)base.type1, (IReflect)rtype)) && Microsoft.JScript.Convert.IsPromotableTo((IReflect)base.type2, (IReflect)rtype)) { type2 = rtype; } else if ((base.type1 != Typeob.String) && (base.type2 != Typeob.String)) { type2 = Typeob.Double; } else { type2 = Typeob.String; } if ((type2 == Typeob.SByte) || (type2 == Typeob.Int16)) { type2 = Typeob.Int32; } else if (((type2 == Typeob.Byte) || (type2 == Typeob.UInt16)) || (type2 == Typeob.Char)) { type2 = Typeob.UInt32; } if (type2 == Typeob.String) { if ((base.operand1 is Plus) && (base.type1 == type2)) { Plus plus = (Plus)base.operand1; if ((plus.operand1 is Plus) && (plus.type1 == type2)) { Plus plus2 = (Plus)plus.operand1; if ((plus2.operand1 is Plus) && (plus2.type1 == type2)) { int num = plus.TranslateToILArrayOfStrings(il, 1); il.Emit(OpCodes.Dup); ConstantWrapper.TranslateToILInt(il, num - 1); base.operand2.TranslateToIL(il, type2); il.Emit(OpCodes.Stelem_Ref); il.Emit(OpCodes.Call, CompilerGlobals.stringConcatArrMethod); Microsoft.JScript.Convert.Emit(this, il, type2, rtype); } else { TranslateToStringWithSpecialCaseForNull(il, plus2.operand1); TranslateToStringWithSpecialCaseForNull(il, plus2.operand2); TranslateToStringWithSpecialCaseForNull(il, plus.operand2); TranslateToStringWithSpecialCaseForNull(il, base.operand2); il.Emit(OpCodes.Call, CompilerGlobals.stringConcat4Method); Microsoft.JScript.Convert.Emit(this, il, type2, rtype); } } else { TranslateToStringWithSpecialCaseForNull(il, plus.operand1); TranslateToStringWithSpecialCaseForNull(il, plus.operand2); TranslateToStringWithSpecialCaseForNull(il, base.operand2); il.Emit(OpCodes.Call, CompilerGlobals.stringConcat3Method); Microsoft.JScript.Convert.Emit(this, il, type2, rtype); } } else { TranslateToStringWithSpecialCaseForNull(il, base.operand1); TranslateToStringWithSpecialCaseForNull(il, base.operand2); il.Emit(OpCodes.Call, CompilerGlobals.stringConcat2Method); Microsoft.JScript.Convert.Emit(this, il, type2, rtype); } } else { base.operand1.TranslateToIL(il, type2); base.operand2.TranslateToIL(il, type2); if (type2 == Typeob.Object) { il.Emit(OpCodes.Call, CompilerGlobals.plusDoOpMethod); } else if ((type2 == Typeob.Double) || (type2 == Typeob.Single)) { il.Emit(OpCodes.Add); } else if ((type2 == Typeob.Int32) || (type2 == Typeob.Int64)) { il.Emit(OpCodes.Add_Ovf); } else { il.Emit(OpCodes.Add_Ovf_Un); } if (type == Typeob.Char) { Microsoft.JScript.Convert.Emit(this, il, type2, Typeob.Char); Microsoft.JScript.Convert.Emit(this, il, Typeob.Char, rtype); } else { Microsoft.JScript.Convert.Emit(this, il, type2, rtype); } } } else if (this.metaData is MethodInfo) { MethodInfo metaData = (MethodInfo)this.metaData; ParameterInfo[] parameters = metaData.GetParameters(); base.operand1.TranslateToIL(il, parameters[0].ParameterType); base.operand2.TranslateToIL(il, parameters[1].ParameterType); il.Emit(OpCodes.Call, metaData); Microsoft.JScript.Convert.Emit(this, il, metaData.ReturnType, rtype); } else { il.Emit(OpCodes.Ldloc, (LocalBuilder)this.metaData); base.operand1.TranslateToIL(il, Typeob.Object); base.operand2.TranslateToIL(il, Typeob.Object); il.Emit(OpCodes.Callvirt, CompilerGlobals.evaluatePlusMethod); Microsoft.JScript.Convert.Emit(this, il, Typeob.Object, rtype); } }