The Labs \ Source Viewer \ SSCLI \ Microsoft.JScript \ Plus

  1. // ==++==
  2. //
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. //
  14. // ==--==
  15. namespace Microsoft.JScript
  16. {
  17.    
  18.     using System;
  19.     using System.Reflection;
  20.     using System.Reflection.Emit;
  21.     using System.Diagnostics;
  22.    
  23.     public sealed class Plus : BinaryOp
  24.     {
  25.         private object metaData = null;
  26.        
  27.         internal Plus(Context context, AST operand1, AST operand2) : base(context, operand1, operand2, JSToken.Plus)
  28.         {
  29.         }
  30.        
  31.         public Plus() : base(null, null, null, JSToken.Plus)
  32.         {
  33.         }
  34.        
  35.         internal override object Evaluate()
  36.         {
  37.             return this.EvaluatePlus(this.operand1.Evaluate(), this.operand2.Evaluate());
  38.         }
  39.        
  40.         #if !DEBUG
  41.         [DebuggerStepThroughAttribute()]
  42.         [DebuggerHiddenAttribute()]
  43.         #endif
  44.         public object EvaluatePlus(object v1, object v2)
  45.         {
  46.             if (v1 is Int32 && v2 is Int32)
  47.                 return Plus.DoOp((Int32)v1, (Int32)v2);
  48.             else if (v1 is double && v2 is double)
  49.                 return Plus.DoOp((double)v1, (double)v2);
  50.             else
  51.                 return this.EvaluatePlus2(v1, v2);
  52.         }
  53.        
  54.         #if !DEBUG
  55.         [DebuggerStepThroughAttribute()]
  56.         [DebuggerHiddenAttribute()]
  57.         #endif
  58.         private object EvaluatePlus2(object v1, object v2)
  59.         {
  60.             IConvertible ic1 = Convert.GetIConvertible(v1);
  61.             IConvertible ic2 = Convert.GetIConvertible(v2);
  62.             TypeCode t1 = Convert.GetTypeCode(v1, ic1);
  63.             TypeCode t2 = Convert.GetTypeCode(v2, ic2);
  64.             switch (t1) {
  65.                 case TypeCode.Empty:
  66.                     return Plus.DoOp(v1, v2);
  67.                 case TypeCode.DBNull:
  68.                    
  69.                     switch (t2) {
  70.                         case TypeCode.Empty:
  71.                             return Double.NaN;
  72.                         case TypeCode.DBNull:
  73.                             return 0;
  74.                         case TypeCode.Boolean:
  75.                         case TypeCode.Char:
  76.                         case TypeCode.SByte:
  77.                         case TypeCode.Byte:
  78.                         case TypeCode.Int16:
  79.                         case TypeCode.UInt16:
  80.                         case TypeCode.Int32:
  81.                             return ic2.ToInt32(null);
  82.                         case TypeCode.UInt32:
  83.                             return ic2.ToUInt32(null);
  84.                         case TypeCode.Int64:
  85.                             return ic2.ToInt64(null);
  86.                         case TypeCode.UInt64:
  87.                             return ic2.ToUInt64(null);
  88.                         case TypeCode.Single:
  89.                         case TypeCode.Double:
  90.                             return ic2.ToDouble(null);
  91.                         case TypeCode.Object:
  92.                         case TypeCode.Decimal:
  93.                         case TypeCode.DateTime:
  94.                             break;
  95.                         case TypeCode.String:
  96.                             return "null" + ic2.ToString(null);
  97.                     }
  98.                     break;
  99.                 case TypeCode.Char:
  100.                    
  101.                    
  102.                     {
  103.                         int val = ic1.ToInt32(null);
  104.                         switch (t2) {
  105.                             case TypeCode.Empty:
  106.                                 return Double.NaN;
  107.                             case TypeCode.DBNull:
  108.                                 return val;
  109.                             case TypeCode.Boolean:
  110.                             case TypeCode.SByte:
  111.                             case TypeCode.Byte:
  112.                             case TypeCode.Int16:
  113.                             case TypeCode.UInt16:
  114.                             case TypeCode.Int32:
  115.                                 return ((IConvertible)Plus.DoOp(val, ic2.ToInt32(null))).ToChar(null);
  116.                             case TypeCode.UInt32:
  117.                             case TypeCode.Int64:
  118.                                 return ((IConvertible)Plus.DoOp((long)val, ic2.ToInt64(null))).ToChar(null);
  119.                             case TypeCode.UInt64:
  120.                                 return ((IConvertible)Plus.DoOp((ulong)val, ic2.ToUInt64(null))).ToChar(null);
  121.                             case TypeCode.Single:
  122.                             case TypeCode.Double:
  123.                                 checked {
  124.                                     return (char)(int)(Convert.CheckIfDoubleIsInteger((double)Plus.DoOp((double)val, ic2.ToDouble(null))));
  125.                                 }
  126.                                 break;
  127.                             case TypeCode.Object:
  128.                             case TypeCode.Decimal:
  129.                             case TypeCode.DateTime:
  130.                                 return Plus.DoOp(v1, v2);
  131.                             case TypeCode.Char:
  132.                             case TypeCode.String:
  133.                                 return ic1.ToString(null) + ic2.ToString(null);
  134.                         }
  135.                         break;
  136.                     }
  137.                     break;
  138.                 case TypeCode.Boolean:
  139.                 case TypeCode.SByte:
  140.                 case TypeCode.Byte:
  141.                 case TypeCode.Int16:
  142.                 case TypeCode.UInt16:
  143.                 case TypeCode.Int32:
  144.                    
  145.                    
  146.                     {
  147.                         int val = ic1.ToInt32(null);
  148.                         switch (t2) {
  149.                             case TypeCode.Empty:
  150.                                 return Double.NaN;
  151.                             case TypeCode.DBNull:
  152.                                 return val;
  153.                             case TypeCode.Char:
  154.                                 return ((IConvertible)Plus.DoOp(val, ic2.ToInt32(null))).ToChar(null);
  155.                             case TypeCode.Boolean:
  156.                             case TypeCode.SByte:
  157.                             case TypeCode.Byte:
  158.                             case TypeCode.Int16:
  159.                             case TypeCode.UInt16:
  160.                             case TypeCode.Int32:
  161.                                 return Plus.DoOp(val, ic2.ToInt32(null));
  162.                             case TypeCode.UInt32:
  163.                             case TypeCode.Int64:
  164.                                 return Plus.DoOp((long)val, ic2.ToInt64(null));
  165.                             case TypeCode.UInt64:
  166.                                 if (val >= 0)
  167.                                     return Plus.DoOp((ulong)val, ic2.ToUInt64(null));
  168.                                 else
  169.                                     return Plus.DoOp((double)val, ic2.ToDouble(null));
  170.                                 break;
  171.                             case TypeCode.Single:
  172.                             case TypeCode.Double:
  173.                                 return Plus.DoOp((double)val, ic2.ToDouble(null));
  174.                             case TypeCode.Object:
  175.                             case TypeCode.Decimal:
  176.                             case TypeCode.DateTime:
  177.                                 break;
  178.                             case TypeCode.String:
  179.                                 return Convert.ToString(v1) + ic2.ToString(null);
  180.                         }
  181.                         break;
  182.                     }
  183.                     break;
  184.                 case TypeCode.UInt32:
  185.                    
  186.                    
  187.                     {
  188.                         uint val = ic1.ToUInt32(null);
  189.                         switch (t2) {
  190.                             case TypeCode.Empty:
  191.                                 return Double.NaN;
  192.                             case TypeCode.DBNull:
  193.                                 return val;
  194.                             case TypeCode.SByte:
  195.                             case TypeCode.Byte:
  196.                             case TypeCode.Int16:
  197.                             case TypeCode.Int32:
  198.                                 int val2 = ic2.ToInt32(null);
  199.                                 if (val2 >= 0)
  200.                                     return Plus.DoOp(val, (uint)val2);
  201.                                 else
  202.                                     return Plus.DoOp((long)val, (long)val2);
  203.                                 break;
  204.                             case TypeCode.Int64:
  205.                                 return Plus.DoOp((long)val, ic2.ToInt64(null));
  206.                             case TypeCode.Char:
  207.                                 return ((IConvertible)Plus.DoOp(val, ic2.ToUInt32(null))).ToChar(null);
  208.                             case TypeCode.Boolean:
  209.                             case TypeCode.UInt16:
  210.                             case TypeCode.UInt32:
  211.                                 return Plus.DoOp(val, ic2.ToUInt32(null));
  212.                             case TypeCode.UInt64:
  213.                                 return Plus.DoOp((ulong)val, ic2.ToUInt64(null));
  214.                             case TypeCode.Single:
  215.                             case TypeCode.Double:
  216.                                 return Plus.DoOp((double)val, ic2.ToDouble(null));
  217.                             case TypeCode.Object:
  218.                             case TypeCode.Decimal:
  219.                             case TypeCode.DateTime:
  220.                                 break;
  221.                             case TypeCode.String:
  222.                                 return Convert.ToString(v1) + ic2.ToString(null);
  223.                         }
  224.                         break;
  225.                     }
  226.                     break;
  227.                 case TypeCode.Int64:
  228.                    
  229.                    
  230.                     {
  231.                         long val = ic1.ToInt64(null);
  232.                         switch (t2) {
  233.                             case TypeCode.Empty:
  234.                                 return Double.NaN;
  235.                             case TypeCode.DBNull:
  236.                                 return val;
  237.                             case TypeCode.Char:
  238.                                 return ((IConvertible)Plus.DoOp(val, ic2.ToInt64(null))).ToChar(null);
  239.                             case TypeCode.Boolean:
  240.                             case TypeCode.SByte:
  241.                             case TypeCode.Byte:
  242.                             case TypeCode.Int16:
  243.                             case TypeCode.UInt16:
  244.                             case TypeCode.Int32:
  245.                             case TypeCode.UInt32:
  246.                             case TypeCode.Int64:
  247.                                 return Plus.DoOp(val, ic2.ToInt64(null));
  248.                             case TypeCode.UInt64:
  249.                                 if (val >= 0)
  250.                                     return Plus.DoOp((ulong)val, ic2.ToUInt64(null));
  251.                                 else
  252.                                     return Plus.DoOp((double)val, ic2.ToDouble(null));
  253.                                 break;
  254.                             case TypeCode.Single:
  255.                             case TypeCode.Double:
  256.                                 return Plus.DoOp((double)val, ic2.ToDouble(null));
  257.                             case TypeCode.Object:
  258.                             case TypeCode.Decimal:
  259.                             case TypeCode.DateTime:
  260.                                 break;
  261.                             case TypeCode.String:
  262.                                 return Convert.ToString(v1) + ic2.ToString(null);
  263.                         }
  264.                         break;
  265.                     }
  266.                     break;
  267.                 case TypeCode.UInt64:
  268.                    
  269.                    
  270.                     {
  271.                         ulong val = ic1.ToUInt64(null);
  272.                         switch (t2) {
  273.                             case TypeCode.Empty:
  274.                                 return Double.NaN;
  275.                             case TypeCode.DBNull:
  276.                                 return val;
  277.                             case TypeCode.SByte:
  278.                             case TypeCode.Byte:
  279.                             case TypeCode.Int16:
  280.                             case TypeCode.Int32:
  281.                             case TypeCode.Int64:
  282.                                 long val2 = ic2.ToInt64(null);
  283.                                 if (val2 >= 0)
  284.                                     return Plus.DoOp(val, (ulong)val2);
  285.                                 else
  286.                                     return Plus.DoOp((double)val, (double)val2);
  287.                                 break;
  288.                             case TypeCode.Char:
  289.                                 return ((IConvertible)Plus.DoOp(val, ic2.ToUInt64(null))).ToChar(null);
  290.                             case TypeCode.UInt16:
  291.                             case TypeCode.Boolean:
  292.                             case TypeCode.UInt32:
  293.                             case TypeCode.UInt64:
  294.                                 return Plus.DoOp(val, ic2.ToUInt64(null));
  295.                             case TypeCode.Single:
  296.                             case TypeCode.Double:
  297.                                 return Plus.DoOp((double)val, ic2.ToDouble(null));
  298.                             case TypeCode.Object:
  299.                             case TypeCode.Decimal:
  300.                             case TypeCode.DateTime:
  301.                                 break;
  302.                             case TypeCode.String:
  303.                                 return Convert.ToString(v1) + ic2.ToString(null);
  304.                         }
  305.                         break;
  306.                     }
  307.                     break;
  308.                 case TypeCode.Single:
  309.                 case TypeCode.Double:
  310.                    
  311.                    
  312.                     {
  313.                         double d = ic1.ToDouble(null);
  314.                         switch (t2) {
  315.                             case TypeCode.Empty:
  316.                                 return Double.NaN;
  317.                             case TypeCode.DBNull:
  318.                                 return ic1.ToDouble(null);
  319.                             case TypeCode.Char:
  320.                                 return System.Convert.ToChar(System.Convert.ToInt32((d + (double)ic2.ToInt32(null))));
  321.                             case TypeCode.Boolean:
  322.                             case TypeCode.SByte:
  323.                             case TypeCode.Byte:
  324.                             case TypeCode.Int16:
  325.                             case TypeCode.UInt16:
  326.                             case TypeCode.Int32:
  327.                                 return d + (double)ic2.ToInt32(null);
  328.                             case TypeCode.UInt32:
  329.                             case TypeCode.Int64:
  330.                             case TypeCode.UInt64:
  331.                             case TypeCode.Single:
  332.                             case TypeCode.Double:
  333.                                 return d + ic2.ToDouble(null);
  334.                             case TypeCode.Object:
  335.                             case TypeCode.Decimal:
  336.                             case TypeCode.DateTime:
  337.                                 break;
  338.                             case TypeCode.String:
  339.                                 return new ConcatString(Convert.ToString(d), ic2.ToString(null));
  340.                         }
  341.                         break;
  342.                     }
  343.                     break;
  344.                 case TypeCode.Object:
  345.                 case TypeCode.Decimal:
  346.                 case TypeCode.DateTime:
  347.                    
  348.                     break;
  349.                 case TypeCode.String:
  350.                    
  351.                     switch (t2) {
  352.                         case TypeCode.Object:
  353.                             break;
  354.                         case TypeCode.String:
  355.                             if (v1 is ConcatString)
  356.                                 return new ConcatString((ConcatString)v1, ic2.ToString(null));
  357.                             else
  358.                                 return new ConcatString(ic1.ToString(null), ic2.ToString(null));
  359.                             break;
  360.                         default:
  361.                             if (v1 is ConcatString)
  362.                                 return new ConcatString((ConcatString)v1, Convert.ToString(v2));
  363.                             else
  364.                                 return new ConcatString(ic1.ToString(null), Convert.ToString(v2));
  365.                             break;
  366.                     }
  367.                     break;
  368.             }
  369.             MethodInfo oper = this.GetOperator(v1 == null ? Typeob.Empty : v1.GetType(), v2 == null ? Typeob.Empty : v2.GetType());
  370.             if (oper != null)
  371.                 return oper.Invoke(null, (BindingFlags)0, JSBinder.ob, new object[] {v1, v2}, null);
  372.             else
  373.                 return Plus.DoOp(v1, v2);
  374.         }
  375.        
  376.         private new MethodInfo GetOperator(IReflect ir1, IReflect ir2)
  377.         {
  378.             Type t1 = ir1 is Type ? (Type)ir1 : Typeob.Object;
  379.             Type t2 = ir2 is Type ? (Type)ir2 : Typeob.Object;
  380.             if (this.type1 == t1 && this.type2 == t2)
  381.                 return this.operatorMeth;
  382.             if (t1 == Typeob.String || t2 == Typeob.String || ((Convert.IsPrimitiveNumericType(t1) || Typeob.JSObject.IsAssignableFrom(t1)) && (Convert.IsPrimitiveNumericType(t2) || Typeob.JSObject.IsAssignableFrom(t2)))) {
  383.                 this.operatorMeth = null;
  384.                 this.type1 = t1;
  385.                 this.type2 = t2;
  386.                 return null;
  387.             }
  388.             return base.GetOperator(t1, t2);
  389.         }
  390.        
  391.         private static object DoOp(double x, double y)
  392.         {
  393.             return x + y;
  394.         }
  395.        
  396.         private static object DoOp(int x, int y)
  397.         {
  398.             int r = x + y;
  399.             // If the result is on the same side of x as y is to 0, no overflow occured.
  400.             if ((r < x) == (y < 0))
  401.                 return r;
  402.             return ((double)x) + (double)y;
  403.         }
  404.        
  405.         private static object DoOp(long x, long y)
  406.         {
  407.             // If the result is on the same side of x as y is to 0, no overflow occured.
  408.             long r = x + y;
  409.             if ((r < x) == (y < 0))
  410.                 return r;
  411.             return ((double)x) + (double)y;
  412.         }
  413.        
  414.         private static object DoOp(uint x, uint y)
  415.         {
  416.             uint r = x + y;
  417.             if (r >= x)
  418.                 // Since y >= 0, no overflow occured if r >= x.
  419.                 return r;
  420.             return ((double)x) + (double)y;
  421.         }
  422.        
  423.         private static object DoOp(ulong x, ulong y)
  424.         {
  425.             ulong r = x + y;
  426.             if (r >= x)
  427.                 // Since y >= 0, no overflow occured if r >= x.
  428.                 return r;
  429.             return ((double)x) + (double)y;
  430.         }
  431.        
  432.         public static object DoOp(object v1, object v2)
  433.         {
  434.             IConvertible ic1 = Convert.GetIConvertible(v1);
  435.             IConvertible ic2 = Convert.GetIConvertible(v2);
  436.             v1 = Convert.ToPrimitive(v1, PreferredType.Either, ref ic1);
  437.             v2 = Convert.ToPrimitive(v2, PreferredType.Either, ref ic2);
  438.             TypeCode t1 = Convert.GetTypeCode(v1, ic1);
  439.             TypeCode t2 = Convert.GetTypeCode(v2, ic2);
  440.             if (t1 == TypeCode.String)
  441.                 if (v1 is ConcatString)
  442.                     return new ConcatString((ConcatString)v1, Convert.ToString(v2, ic2));
  443.                 else
  444.                     return new ConcatString(ic1.ToString(null), Convert.ToString(v2, ic2));
  445.             else if (t2 == TypeCode.String)
  446.                 return Convert.ToString(v1, ic1) + ic2.ToString(null);
  447.             else if (t1 == TypeCode.Char && t2 == TypeCode.Char)
  448.                 return ic1.ToString(null) + ic2.ToString(null);
  449.             else if ((t1 == TypeCode.Char && (Convert.IsPrimitiveNumericTypeCode(t2) || t2 == TypeCode.Boolean)) || (t2 == TypeCode.Char && (Convert.IsPrimitiveNumericTypeCode(t1) || t1 == TypeCode.Boolean)))
  450.                 return (char)(int)Runtime.DoubleToInt64(Convert.ToNumber(v1, ic1) + Convert.ToNumber(v2, ic2));
  451.             else
  452.                 return Convert.ToNumber(v1, ic1) + Convert.ToNumber(v2, ic2);
  453.         }
  454.        
  455.         internal override IReflect InferType(JSField inference_target)
  456.         {
  457.             Debug.Assert(Globals.TypeRefs.InReferenceContext(this.type1));
  458.             Debug.Assert(Globals.TypeRefs.InReferenceContext(this.type2));
  459.             MethodInfo oper;
  460.             if (this.type1 == null || inference_target != null)
  461.                 oper = this.GetOperator(this.operand1.InferType(inference_target), this.operand2.InferType(inference_target));
  462.             else
  463.                 oper = this.GetOperator(this.type1, this.type2);
  464.             if (oper != null) {
  465.                 this.metaData = oper;
  466.                 return oper.ReturnType;
  467.             }
  468.             if (this.type1 == Typeob.String || this.type2 == Typeob.String)
  469.                 return Typeob.String;
  470.             else if (this.type1 == Typeob.Char && this.type2 == Typeob.Char)
  471.                 return Typeob.String;
  472.             else if (Convert.IsPrimitiveNumericTypeFitForDouble(this.type1)) {
  473.                 if (this.type2 == Typeob.Char)
  474.                     return Typeob.Char;
  475.                 else if (Convert.IsPrimitiveNumericTypeFitForDouble(this.type2))
  476.                     return Typeob.Double;
  477.                 else
  478.                     return Typeob.Object;
  479.             }
  480.             else if (Convert.IsPrimitiveNumericTypeFitForDouble(this.type2)) {
  481.                 if (this.type1 == Typeob.Char)
  482.                     return Typeob.Char;
  483.                 else if (Convert.IsPrimitiveNumericTypeFitForDouble(this.type1))
  484.                     return Typeob.Double;
  485.                 else
  486.                     return Typeob.Object;
  487.             }
  488.             else if (this.type1 == Typeob.Boolean && this.type2 == Typeob.Char)
  489.                 return Typeob.Char;
  490.             else if (this.type1 == Typeob.Char && this.type2 == Typeob.Boolean)
  491.                 return Typeob.Char;
  492.             else
  493.                 return Typeob.Object;
  494.         }
  495.        
  496.         internal override void TranslateToIL(ILGenerator il, Type rtype)
  497.         {
  498.             Type type = Convert.ToType(this.InferType(null));
  499.             if (this.metaData == null) {
  500.                 Type rt = Typeob.Object;
  501.                 if (rtype == Typeob.Double)
  502.                     rt = rtype;
  503.                 else if (this.type1 == Typeob.Char && this.type2 == Typeob.Char)
  504.                     rt = Typeob.String;
  505.                 else if (Convert.IsPrimitiveNumericType(rtype) && Convert.IsPromotableTo(this.type1, rtype) && Convert.IsPromotableTo(this.type2, rtype))
  506.                     rt = rtype;
  507.                 else if (this.type1 != Typeob.String && this.type2 != Typeob.String)
  508.                     rt = Typeob.Double;
  509.                 else
  510.                     //Both will be converted to numbers
  511.                     //Won't get here unless InferType returned Typeob.Double.
  512.                     rt = Typeob.String;
  513.                 if (rt == Typeob.SByte || rt == Typeob.Int16)
  514.                     rt = Typeob.Int32;
  515.                 else if (rt == Typeob.Byte || rt == Typeob.UInt16 || rt == Typeob.Char)
  516.                     rt = Typeob.UInt32;
  517.                 if (rt == Typeob.String) {
  518.                     if (this.operand1 is Plus && this.type1 == rt) {
  519.                         Plus op1 = (Plus)this.operand1;
  520.                         if (op1.operand1 is Plus && op1.type1 == rt) {
  521.                             Plus op11 = (Plus)op1.operand1;
  522.                             if (op11.operand1 is Plus && op11.type1 == rt) {
  523.                                 int len = op1.TranslateToILArrayOfStrings(il, 1);
  524.                                 il.Emit(OpCodes.Dup);
  525.                                 ConstantWrapper.TranslateToILInt(il, len - 1);
  526.                                 this.operand2.TranslateToIL(il, rt);
  527.                                 il.Emit(OpCodes.Stelem_Ref);
  528.                                 il.Emit(OpCodes.Call, CompilerGlobals.stringConcatArrMethod);
  529.                                 Convert.Emit(this, il, rt, rtype);
  530.                                 return;
  531.                             }
  532.                             Plus.TranslateToStringWithSpecialCaseForNull(il, op11.operand1);
  533.                             Plus.TranslateToStringWithSpecialCaseForNull(il, op11.operand2);
  534.                             Plus.TranslateToStringWithSpecialCaseForNull(il, op1.operand2);
  535.                             Plus.TranslateToStringWithSpecialCaseForNull(il, this.operand2);
  536.                             il.Emit(OpCodes.Call, CompilerGlobals.stringConcat4Method);
  537.                             Convert.Emit(this, il, rt, rtype);
  538.                             return;
  539.                         }
  540.                         Plus.TranslateToStringWithSpecialCaseForNull(il, op1.operand1);
  541.                         Plus.TranslateToStringWithSpecialCaseForNull(il, op1.operand2);
  542.                         Plus.TranslateToStringWithSpecialCaseForNull(il, this.operand2);
  543.                         il.Emit(OpCodes.Call, CompilerGlobals.stringConcat3Method);
  544.                         Convert.Emit(this, il, rt, rtype);
  545.                         return;
  546.                     }
  547.                     Plus.TranslateToStringWithSpecialCaseForNull(il, this.operand1);
  548.                     Plus.TranslateToStringWithSpecialCaseForNull(il, this.operand2);
  549.                     il.Emit(OpCodes.Call, CompilerGlobals.stringConcat2Method);
  550.                     Convert.Emit(this, il, rt, rtype);
  551.                     return;
  552.                 }
  553.                 this.operand1.TranslateToIL(il, rt);
  554.                 this.operand2.TranslateToIL(il, rt);
  555.                 if (rt == Typeob.Object) {
  556.                     il.Emit(OpCodes.Call, CompilerGlobals.plusDoOpMethod);
  557.                 }
  558.                 else if (rt == Typeob.Double || rt == Typeob.Single)
  559.                     il.Emit(OpCodes.Add);
  560.                 else if (rt == Typeob.Int32 || rt == Typeob.Int64)
  561.                     il.Emit(OpCodes.Add_Ovf);
  562.                 else
  563.                     il.Emit(OpCodes.Add_Ovf_Un);
  564.                
  565.                 if (type == Typeob.Char) {
  566.                     Convert.Emit(this, il, rt, Typeob.Char);
  567.                     Convert.Emit(this, il, Typeob.Char, rtype);
  568.                 }
  569.                 else
  570.                     Convert.Emit(this, il, rt, rtype);
  571.                 return;
  572.             }
  573.             if (this.metaData is MethodInfo) {
  574.                 MethodInfo oper = (MethodInfo)this.metaData;
  575.                 ParameterInfo[] pars = oper.GetParameters();
  576.                 this.operand1.TranslateToIL(il, pars[0].ParameterType);
  577.                 this.operand2.TranslateToIL(il, pars[1].ParameterType);
  578.                 il.Emit(OpCodes.Call, oper);
  579.                 Convert.Emit(this, il, oper.ReturnType, rtype);
  580.                 return;
  581.             }
  582.             //Getting here is just too bad. We do not know until the code runs whether or not to call an overloaded operator method.
  583.             //Compile operands to objects and devolve the decision making to run time thunks
  584.             //Also get here when dealing with Int64 and UInt64. These cannot always be converted to doubles. The late-bound code checks for this.
  585.             il.Emit(OpCodes.Ldloc, (LocalBuilder)this.metaData);
  586.             this.operand1.TranslateToIL(il, Typeob.Object);
  587.             this.operand2.TranslateToIL(il, Typeob.Object);
  588.             il.Emit(OpCodes.Callvirt, CompilerGlobals.evaluatePlusMethod);
  589.             Convert.Emit(this, il, Typeob.Object, rtype);
  590.         }
  591.        
  592.         private int TranslateToILArrayOfStrings(ILGenerator il, int n)
  593.         {
  594.             int len = n + 2;
  595.             if (this.operand1 is Plus && this.type1 == Typeob.String)
  596.                 len = ((Plus)this.operand1).TranslateToILArrayOfStrings(il, n + 1);
  597.             else {
  598.                 ConstantWrapper.TranslateToILInt(il, len);
  599.                 il.Emit(OpCodes.Newarr, Typeob.String);
  600.                 il.Emit(OpCodes.Dup);
  601.                 il.Emit(OpCodes.Ldc_I4_0);
  602.                 Plus.TranslateToStringWithSpecialCaseForNull(il, this.operand1);
  603.                 il.Emit(OpCodes.Stelem_Ref);
  604.             }
  605.             il.Emit(OpCodes.Dup);
  606.             ConstantWrapper.TranslateToILInt(il, len - 1 - n);
  607.             Plus.TranslateToStringWithSpecialCaseForNull(il, this.operand2);
  608.             il.Emit(OpCodes.Stelem_Ref);
  609.             return len;
  610.         }
  611.        
  612.         internal override void TranslateToILInitializer(ILGenerator il)
  613.         {
  614.             IReflect rtype = this.InferType(null);
  615.             this.operand1.TranslateToILInitializer(il);
  616.             this.operand2.TranslateToILInitializer(il);
  617.             if (rtype != Typeob.Object)
  618.                 return;
  619.             this.metaData = il.DeclareLocal(Typeob.Plus);
  620.             il.Emit(OpCodes.Newobj, CompilerGlobals.plusConstructor);
  621.             il.Emit(OpCodes.Stloc, (LocalBuilder)this.metaData);
  622.         }
  623.        
  624.         private static void TranslateToStringWithSpecialCaseForNull(ILGenerator il, AST operand)
  625.         {
  626.             ConstantWrapper cw = operand as ConstantWrapper;
  627.             if (cw != null) {
  628.                 if (cw.value is DBNull)
  629.                     il.Emit(OpCodes.Ldstr, "null");
  630.                 else if (cw.value == Empty.Value)
  631.                     il.Emit(OpCodes.Ldstr, "undefined");
  632.                 else
  633.                     cw.TranslateToIL(il, Typeob.String);
  634.             }
  635.             else
  636.                 operand.TranslateToIL(il, Typeob.String);
  637.         }
  638.     }
  639. }

Developer Fusion