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

  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 NumericBinary : BinaryOp
  24.     {
  25.         private object metaData = null;
  26.        
  27.         internal NumericBinary(Context context, AST operand1, AST operand2, JSToken operatorTok) : base(context, operand1, operand2, operatorTok)
  28.         {
  29.         }
  30.        
  31.         public NumericBinary(int operatorTok) : base(null, null, null, (JSToken)operatorTok)
  32.         {
  33.         }
  34.        
  35.         internal override object Evaluate()
  36.         {
  37.             return this.EvaluateNumericBinary(this.operand1.Evaluate(), this.operand2.Evaluate());
  38.         }
  39.        
  40.         #if !DEBUG
  41.         [DebuggerStepThroughAttribute()]
  42.         [DebuggerHiddenAttribute()]
  43.         #endif
  44.         public object EvaluateNumericBinary(object v1, object v2)
  45.         {
  46.             if (v1 is Int32 && v2 is Int32)
  47.                 return NumericBinary.DoOp((Int32)v1, (Int32)v2, this.operatorTok);
  48.             else if (v1 is double && v2 is double)
  49.                 return NumericBinary.DoOp((double)v1, (double)v2, this.operatorTok);
  50.             else
  51.                 return this.EvaluateNumericBinary(v1, v2, this.operatorTok);
  52.         }
  53.        
  54.         #if !DEBUG
  55.         [DebuggerStepThroughAttribute()]
  56.         [DebuggerHiddenAttribute()]
  57.         #endif
  58.         private object EvaluateNumericBinary(object v1, object v2, JSToken operatorTok)
  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 Double.NaN;
  67.                 case TypeCode.DBNull:
  68.                    
  69.                     return this.EvaluateNumericBinary(0, v2, operatorTok);
  70.                 case TypeCode.Char:
  71.                    
  72.                    
  73.                     {
  74.                         object result;
  75.                         int val = ic1.ToInt32(null);
  76.                         switch (t2) {
  77.                             case TypeCode.Empty:
  78.                                 return Double.NaN;
  79.                             case TypeCode.DBNull:
  80.                                 return NumericBinary.DoOp(val, 0, operatorTok);
  81.                             case TypeCode.Boolean:
  82.                             case TypeCode.Char:
  83.                             case TypeCode.SByte:
  84.                             case TypeCode.Byte:
  85.                             case TypeCode.Int16:
  86.                             case TypeCode.UInt16:
  87.                             case TypeCode.Int32:
  88.                                 result = NumericBinary.DoOp(val, ic2.ToInt32(null), operatorTok);
  89.                                 break;
  90.                             case TypeCode.UInt32:
  91.                             case TypeCode.Int64:
  92.                                 result = NumericBinary.DoOp((long)val, ic2.ToInt64(null), operatorTok);
  93.                                 break;
  94.                             case TypeCode.UInt64:
  95.                                 result = NumericBinary.DoOp((double)val, ic2.ToDouble(null), operatorTok);
  96.                                 break;
  97.                             case TypeCode.Single:
  98.                             case TypeCode.Double:
  99.                                 result = NumericBinary.DoOp((double)ic1.ToInt32(null), ic2.ToDouble(null), operatorTok);
  100.                                 break;
  101.                             case TypeCode.String:
  102.                                 result = NumericBinary.DoOp(val, Convert.ToNumber(v2, ic2), operatorTok);
  103.                                 break;
  104.                             case TypeCode.Object:
  105.                             case TypeCode.Decimal:
  106.                             case TypeCode.DateTime:
  107.                             default:
  108.                                
  109.                                 result = null;
  110.                                 break;
  111.                         }
  112.                         if (this.operatorTok == JSToken.Minus && result != null && t2 != TypeCode.Char) {
  113.                             return Convert.Coerce2(result, TypeCode.Char, false);
  114.                         }
  115.                         else if (result != null)
  116.                             return result;
  117.                         break;
  118.                     }
  119.                     break;
  120.                 case TypeCode.Boolean:
  121.                 case TypeCode.SByte:
  122.                 case TypeCode.Byte:
  123.                 case TypeCode.Int16:
  124.                 case TypeCode.UInt16:
  125.                 case TypeCode.Int32:
  126.                    
  127.                     {
  128.                         int val = ic1.ToInt32(null);
  129.                         switch (t2) {
  130.                             case TypeCode.Empty:
  131.                                 return Double.NaN;
  132.                             case TypeCode.DBNull:
  133.                                 return NumericBinary.DoOp(val, 0, operatorTok);
  134.                             case TypeCode.Boolean:
  135.                             case TypeCode.Char:
  136.                             case TypeCode.SByte:
  137.                             case TypeCode.Byte:
  138.                             case TypeCode.Int16:
  139.                             case TypeCode.UInt16:
  140.                             case TypeCode.Int32:
  141.                                 return NumericBinary.DoOp(val, ic2.ToInt32(null), operatorTok);
  142.                             case TypeCode.UInt32:
  143.                             case TypeCode.Int64:
  144.                                 return NumericBinary.DoOp((long)val, ic2.ToInt64(null), operatorTok);
  145.                             case TypeCode.UInt64:
  146.                                 if (val >= 0)
  147.                                     return NumericBinary.DoOp((ulong)val, ic2.ToUInt64(null), operatorTok);
  148.                                 else
  149.                                     return NumericBinary.DoOp((double)val, ic2.ToDouble(null), operatorTok);
  150.                                 break;
  151.                             case TypeCode.Single:
  152.                             case TypeCode.Double:
  153.                                 return NumericBinary.DoOp((double)val, ic2.ToDouble(null), operatorTok);
  154.                             case TypeCode.Object:
  155.                             case TypeCode.Decimal:
  156.                             case TypeCode.DateTime:
  157.                             case TypeCode.String:
  158.                                 break;
  159.                         }
  160.                         break;
  161.                     }
  162.                     break;
  163.                 case TypeCode.UInt32:
  164.                    
  165.                    
  166.                     {
  167.                         uint val = ic1.ToUInt32(null);
  168.                         switch (t2) {
  169.                             case TypeCode.Empty:
  170.                                 return Double.NaN;
  171.                             case TypeCode.DBNull:
  172.                                 return NumericBinary.DoOp(val, 0, operatorTok);
  173.                             case TypeCode.SByte:
  174.                             case TypeCode.Byte:
  175.                             case TypeCode.Int16:
  176.                             case TypeCode.Int32:
  177.                                 int val2 = ic2.ToInt32(null);
  178.                                 if (val2 >= 0)
  179.                                     return NumericBinary.DoOp(val, (uint)val2, operatorTok);
  180.                                 else
  181.                                     return NumericBinary.DoOp((long)val, (long)val2, operatorTok);
  182.                                 break;
  183.                             case TypeCode.Int64:
  184.                                 return NumericBinary.DoOp((long)val, ic2.ToInt64(null), operatorTok);
  185.                             case TypeCode.Boolean:
  186.                             case TypeCode.Char:
  187.                             case TypeCode.UInt16:
  188.                             case TypeCode.UInt32:
  189.                                 return NumericBinary.DoOp(val, ic2.ToUInt32(null), operatorTok);
  190.                             case TypeCode.UInt64:
  191.                                 return NumericBinary.DoOp((ulong)val, ic2.ToUInt64(null), operatorTok);
  192.                             case TypeCode.Single:
  193.                             case TypeCode.Double:
  194.                                 return NumericBinary.DoOp((double)val, ic2.ToDouble(null), operatorTok);
  195.                             case TypeCode.Object:
  196.                             case TypeCode.Decimal:
  197.                             case TypeCode.DateTime:
  198.                             case TypeCode.String:
  199.                                 break;
  200.                         }
  201.                         break;
  202.                     }
  203.                     break;
  204.                 case TypeCode.Int64:
  205.                    
  206.                    
  207.                     {
  208.                         long val = ic1.ToInt64(null);
  209.                         switch (t2) {
  210.                             case TypeCode.Empty:
  211.                                 return Double.NaN;
  212.                             case TypeCode.DBNull:
  213.                                 return NumericBinary.DoOp(val, 0, operatorTok);
  214.                             case TypeCode.Boolean:
  215.                             case TypeCode.Char:
  216.                             case TypeCode.SByte:
  217.                             case TypeCode.Byte:
  218.                             case TypeCode.Int16:
  219.                             case TypeCode.UInt16:
  220.                             case TypeCode.Int32:
  221.                             case TypeCode.UInt32:
  222.                             case TypeCode.Int64:
  223.                                 return NumericBinary.DoOp(val, ic2.ToInt64(null), operatorTok);
  224.                             case TypeCode.UInt64:
  225.                                 if (val >= 0)
  226.                                     return NumericBinary.DoOp((ulong)val, ic2.ToUInt64(null), operatorTok);
  227.                                 else
  228.                                     return NumericBinary.DoOp((double)val, ic2.ToDouble(null), operatorTok);
  229.                                 break;
  230.                             case TypeCode.Single:
  231.                             case TypeCode.Double:
  232.                                 return NumericBinary.DoOp((double)val, ic2.ToDouble(null), operatorTok);
  233.                             case TypeCode.Object:
  234.                             case TypeCode.Decimal:
  235.                             case TypeCode.DateTime:
  236.                             case TypeCode.String:
  237.                                 break;
  238.                         }
  239.                         break;
  240.                     }
  241.                     break;
  242.                 case TypeCode.UInt64:
  243.                    
  244.                    
  245.                    
  246.                     {
  247.                         ulong val = ic1.ToUInt64(null);
  248.                         switch (t2) {
  249.                             case TypeCode.Empty:
  250.                                 return Double.NaN;
  251.                             case TypeCode.DBNull:
  252.                                 return NumericBinary.DoOp(val, 0, operatorTok);
  253.                             case TypeCode.SByte:
  254.                             case TypeCode.Byte:
  255.                             case TypeCode.Int16:
  256.                             case TypeCode.Int32:
  257.                             case TypeCode.Int64:
  258.                                 long val2 = ic2.ToInt64(null);
  259.                                 if (val2 >= 0)
  260.                                     return NumericBinary.DoOp(val, (ulong)val2, operatorTok);
  261.                                 else
  262.                                     return NumericBinary.DoOp((double)val, (double)val2, operatorTok);
  263.                                 break;
  264.                             case TypeCode.Boolean:
  265.                             case TypeCode.Char:
  266.                             case TypeCode.UInt16:
  267.                             case TypeCode.UInt32:
  268.                             case TypeCode.UInt64:
  269.                                 return NumericBinary.DoOp(val, ic2.ToUInt64(null), operatorTok);
  270.                             case TypeCode.Single:
  271.                             case TypeCode.Double:
  272.                                 return NumericBinary.DoOp((double)val, ic2.ToDouble(null), operatorTok);
  273.                             case TypeCode.Object:
  274.                             case TypeCode.Decimal:
  275.                             case TypeCode.DateTime:
  276.                             case TypeCode.String:
  277.                                 break;
  278.                         }
  279.                         break;
  280.                     }
  281.                     break;
  282.                 case TypeCode.Single:
  283.                 case TypeCode.Double:
  284.                    
  285.                    
  286.                     {
  287.                         double d = ic1.ToDouble(null);
  288.                         switch (t2) {
  289.                             case TypeCode.Empty:
  290.                                 return Double.NaN;
  291.                             case TypeCode.DBNull:
  292.                                 return NumericBinary.DoOp(d, 0, operatorTok);
  293.                             case TypeCode.Boolean:
  294.                             case TypeCode.Char:
  295.                             case TypeCode.SByte:
  296.                             case TypeCode.Byte:
  297.                             case TypeCode.Int16:
  298.                             case TypeCode.UInt16:
  299.                             case TypeCode.Int32:
  300.                                 return NumericBinary.DoOp(d, (double)ic2.ToInt32(null), operatorTok);
  301.                             case TypeCode.UInt32:
  302.                             case TypeCode.Int64:
  303.                             case TypeCode.UInt64:
  304.                             case TypeCode.Single:
  305.                             case TypeCode.Double:
  306.                                 return NumericBinary.DoOp(d, ic2.ToDouble(null), operatorTok);
  307.                             case TypeCode.Object:
  308.                             case TypeCode.Decimal:
  309.                             case TypeCode.DateTime:
  310.                             case TypeCode.String:
  311.                                 break;
  312.                         }
  313.                         break;
  314.                     }
  315.                     break;
  316.                 case TypeCode.Object:
  317.                 case TypeCode.Decimal:
  318.                 case TypeCode.DateTime:
  319.                 case TypeCode.String:
  320.                    
  321.                     break;
  322.             }
  323.             if (v2 == null)
  324.                 return Double.NaN;
  325.             MethodInfo oper = this.GetOperator(v1.GetType(), v2.GetType());
  326.             if (oper != null)
  327.                 return oper.Invoke(null, (BindingFlags)0, JSBinder.ob, new object[] {v1, v2}, null);
  328.             else {
  329.                 return NumericBinary.DoOp(v1, v2, ic1, ic2, operatorTok);
  330.             }
  331.         }
  332.        
  333.         public static object DoOp(object v1, object v2, JSToken operatorTok)
  334.         {
  335.             return DoOp(v1, v2, Convert.GetIConvertible(v1), Convert.GetIConvertible(v2), operatorTok);
  336.         }
  337.        
  338.         private static object DoOp(object v1, object v2, IConvertible ic1, IConvertible ic2, JSToken operatorTok)
  339.         {
  340.             if (operatorTok == JSToken.Minus) {
  341.                 IConvertible ic1a = ic1;
  342.                 object p1 = Convert.ToPrimitive(v1, PreferredType.Either, ref ic1a);
  343.                 TypeCode t1 = Convert.GetTypeCode(p1, ic1a);
  344.                 if (t1 == TypeCode.Char) {
  345.                     IConvertible ic2a = ic2;
  346.                     object p2 = Convert.ToPrimitive(v2, PreferredType.Either, ref ic2a);
  347.                     TypeCode t2 = Convert.GetTypeCode(p2, ic2a);
  348.                     if (t2 == TypeCode.String) {
  349.                         string str2 = ic2a.ToString(null);
  350.                         if (str2.Length == 1) {
  351.                             t2 = TypeCode.Char;
  352.                             p2 = str2[0];
  353.                             ic2a = Convert.GetIConvertible(p2);
  354.                         }
  355.                     }
  356.                     object result = NumericBinary.DoOp(Convert.ToNumber(p1, ic1a), Convert.ToNumber(p2, ic2a), operatorTok);
  357.                     if (t2 != TypeCode.Char)
  358.                         result = Convert.Coerce2(result, TypeCode.Char, false);
  359.                     return result;
  360.                 }
  361.             }
  362.             return NumericBinary.DoOp(Convert.ToNumber(v1, ic1), Convert.ToNumber(v2, ic2), operatorTok);
  363.         }
  364.        
  365.         private static object DoOp(int x, int y, JSToken operatorTok)
  366.         {
  367.             switch (operatorTok) {
  368.                 case JSToken.Divide:
  369.                     return ((double)x) / (double)y;
  370.                 case JSToken.Minus:
  371.                     int r = x - y;
  372.                     if ((r < x) == (y > 0))
  373.                         // If the result is on the opposite side of x as y is to 0, no overflow occured.
  374.                         return r;
  375.                     return ((double)x) - (double)y;
  376.                 case JSToken.Modulo:
  377.                     if (x <= 0 || y <= 0)
  378.                         return ((double)x) % (double)y;
  379.                     //Need to result in a signed 0
  380.                     return x % y;
  381.                 case JSToken.Multiply:
  382.                     if (x == 0 || y == 0)
  383.                         return ((double)x) * (double)y;
  384.                     //Need to result in a signed 0
  385.                     try {
  386.                         checked {
  387.                             return x * y;
  388.                         }
  389.                     }
  390.                     catch (OverflowException) {
  391.                         return ((double)x) * (double)y;
  392.                     }
  393.                     break;
  394.                 default:
  395.                     throw new JScriptException(JSError.InternalError);
  396.                     break;
  397.             }
  398.         }
  399.        
  400.         private static object DoOp(uint x, uint y, JSToken operatorTok)
  401.         {
  402.             switch (operatorTok) {
  403.                 case JSToken.Divide:
  404.                     return ((double)x) / (double)y;
  405.                 case JSToken.Minus:
  406.                     uint r = x - y;
  407.                     if (r <= x)
  408.                         // Since y is 0 or positive, if the result left of x or at x, no overflow occured.
  409.                         return r;
  410.                     return ((double)x) - (double)y;
  411.                 case JSToken.Modulo:
  412.                     if (y == 0)
  413.                         return Double.NaN;
  414.                     return x % y;
  415.                 case JSToken.Multiply:
  416.                     try {
  417.                         checked {
  418.                             return x * y;
  419.                         }
  420.                     }
  421.                     catch (OverflowException) {
  422.                         return ((double)x) * (double)y;
  423.                     }
  424.                     break;
  425.                 default:
  426.                     throw new JScriptException(JSError.InternalError);
  427.                     break;
  428.             }
  429.         }
  430.        
  431.         private static object DoOp(long x, long y, JSToken operatorTok)
  432.         {
  433.             switch (operatorTok) {
  434.                 case JSToken.Divide:
  435.                     return ((double)x) / (double)y;
  436.                 case JSToken.Minus:
  437.                     long r = x - y;
  438.                     if ((r < x) == (y > 0))
  439.                         // If the result is on the opposite side of x as y is to 0, no overflow occured.
  440.                         return r;
  441.                     return ((double)x) - (double)y;
  442.                 case JSToken.Modulo:
  443.                     if (y == 0)
  444.                         return Double.NaN;
  445.                     long result = x % y;
  446.                     if (result == 0)
  447.                         if (x < 0)
  448.                             if (y < 0)
  449.                                 return 0;
  450.                             else
  451.                                 return 1.0 / Double.NegativeInfinity;
  452.                         else if (y < 0)
  453.                             return 1.0 / Double.NegativeInfinity;
  454.                         else
  455.                         //Need to result in a signed 0
  456.                             return 0;
  457.                     return result;
  458.                 case JSToken.Multiply:
  459.                     if (x == 0 || y == 0)
  460.                         return ((double)x) * (double)y;
  461.                     //Need to result in a signed 0
  462.                     try {
  463.                         checked {
  464.                             return x * y;
  465.                         }
  466.                     }
  467.                     catch (OverflowException) {
  468.                         return ((double)x) * (double)y;
  469.                     }
  470.                     break;
  471.                 default:
  472.                     throw new JScriptException(JSError.InternalError);
  473.                     break;
  474.             }
  475.         }
  476.        
  477.         private static object DoOp(ulong x, ulong y, JSToken operatorTok)
  478.         {
  479.             switch (operatorTok) {
  480.                 case JSToken.Divide:
  481.                     return ((double)x) / (double)y;
  482.                 case JSToken.Minus:
  483.                     ulong r = x - y;
  484.                     if (r <= x)
  485.                         // Since y is 0 or positive, if the result left of x or at x, no overflow occured.
  486.                         return r;
  487.                     return ((double)x) - (double)y;
  488.                 case JSToken.Modulo:
  489.                     if (y == 0)
  490.                         return Double.NaN;
  491.                     return x % y;
  492.                 case JSToken.Multiply:
  493.                     try {
  494.                         checked {
  495.                             return x * y;
  496.                         }
  497.                     }
  498.                     catch (OverflowException) {
  499.                         return ((double)x) * (double)y;
  500.                     }
  501.                     break;
  502.                 default:
  503.                     throw new JScriptException(JSError.InternalError);
  504.                     break;
  505.             }
  506.         }
  507.        
  508.         private static object DoOp(double x, double y, JSToken operatorTok)
  509.         {
  510.             switch (operatorTok) {
  511.                 case JSToken.Divide:
  512.                     return x / y;
  513.                 case JSToken.Minus:
  514.                     return x - y;
  515.                 case JSToken.Modulo:
  516.                     return x % y;
  517.                 case JSToken.Multiply:
  518.                     return x * y;
  519.                 default:
  520.                     throw new JScriptException(JSError.InternalError);
  521.                     break;
  522.             }
  523.         }
  524.        
  525.         internal override IReflect InferType(JSField inference_target)
  526.         {
  527.             Debug.Assert(Globals.TypeRefs.InReferenceContext(this.type1));
  528.             Debug.Assert(Globals.TypeRefs.InReferenceContext(this.type2));
  529.             MethodInfo oper;
  530.             if (this.type1 == null || inference_target != null) {
  531.                 oper = this.GetOperator(this.operand1.InferType(inference_target), this.operand2.InferType(inference_target));
  532.             }
  533.             else
  534.                 oper = this.GetOperator(this.type1, this.type2);
  535.             if (oper != null) {
  536.                 this.metaData = oper;
  537.                 return oper.ReturnType;
  538.             }
  539.             if (this.type1 == Typeob.Char && this.operatorTok == JSToken.Minus) {
  540.                 TypeCode t2 = Type.GetTypeCode(this.type2);
  541.                 if (Convert.IsPrimitiveNumericTypeCode(t2) || t2 == TypeCode.Boolean)
  542.                     return Typeob.Char;
  543.                 else if (t2 == TypeCode.Char)
  544.                     return Typeob.Int32;
  545.             }
  546.             if ((Convert.IsPrimitiveNumericTypeFitForDouble(this.type1) || Typeob.JSObject.IsAssignableFrom(this.type1)) && (Convert.IsPrimitiveNumericTypeFitForDouble(this.type2) || Typeob.JSObject.IsAssignableFrom(this.type2)))
  547.                 return Typeob.Double;
  548.             else
  549.                 return Typeob.Object;
  550.         }
  551.        
  552.         internal override void TranslateToIL(ILGenerator il, Type rtype)
  553.         {
  554.             if (this.metaData == null) {
  555.                 Type rt = Typeob.Double;
  556.                 if (Convert.IsPrimitiveNumericType(rtype) && Convert.IsPromotableTo(this.type1, rtype) && Convert.IsPromotableTo(this.type2, rtype))
  557.                     rt = rtype;
  558.                 if (this.operatorTok == JSToken.Divide)
  559.                     rt = Typeob.Double;
  560.                 else if (rt == Typeob.SByte || rt == Typeob.Int16)
  561.                     rt = Typeob.Int32;
  562.                 else if (rt == Typeob.Byte || rt == Typeob.UInt16 || rt == Typeob.Char)
  563.                     rt = Typeob.UInt32;
  564.                 this.operand1.TranslateToIL(il, rt);
  565.                 this.operand2.TranslateToIL(il, rt);
  566.                 if (rt == Typeob.Double || rt == Typeob.Single) {
  567.                     switch (this.operatorTok) {
  568.                         case JSToken.Divide:
  569.                             il.Emit(OpCodes.Div);
  570.                             break;
  571.                         case JSToken.Minus:
  572.                             il.Emit(OpCodes.Sub);
  573.                             break;
  574.                         case JSToken.Modulo:
  575.                             il.Emit(OpCodes.Rem);
  576.                             break;
  577.                         case JSToken.Multiply:
  578.                             il.Emit(OpCodes.Mul);
  579.                             break;
  580.                         default:
  581.                             throw new JScriptException(JSError.InternalError, this.context);
  582.                             break;
  583.                     }
  584.                 }
  585.                 else if (rt == Typeob.Int32 || rt == Typeob.Int64) {
  586.                     switch (this.operatorTok) {
  587.                         case JSToken.Divide:
  588.                             il.Emit(OpCodes.Div);
  589.                             break;
  590.                         case JSToken.Minus:
  591.                             il.Emit(OpCodes.Sub_Ovf);
  592.                             break;
  593.                         case JSToken.Modulo:
  594.                             il.Emit(OpCodes.Rem);
  595.                             break;
  596.                         case JSToken.Multiply:
  597.                             il.Emit(OpCodes.Mul_Ovf);
  598.                             break;
  599.                         default:
  600.                             throw new JScriptException(JSError.InternalError, this.context);
  601.                             break;
  602.                     }
  603.                 }
  604.                 else {
  605.                     switch (this.operatorTok) {
  606.                         case JSToken.Divide:
  607.                             il.Emit(OpCodes.Div);
  608.                             break;
  609.                         case JSToken.Minus:
  610.                             il.Emit(OpCodes.Sub_Ovf_Un);
  611.                             break;
  612.                         case JSToken.Modulo:
  613.                             il.Emit(OpCodes.Rem);
  614.                             break;
  615.                         case JSToken.Multiply:
  616.                             il.Emit(OpCodes.Mul_Ovf_Un);
  617.                             break;
  618.                         default:
  619.                             throw new JScriptException(JSError.InternalError, this.context);
  620.                             break;
  621.                     }
  622.                 }
  623.                 if (Convert.ToType(this.InferType(null)) == Typeob.Char) {
  624.                     Convert.Emit(this, il, rt, Typeob.Char);
  625.                     Convert.Emit(this, il, Typeob.Char, rtype);
  626.                 }
  627.                 else
  628.                     Convert.Emit(this, il, rt, rtype);
  629.                 return;
  630.             }
  631.             if (this.metaData is MethodInfo) {
  632.                 MethodInfo oper = (MethodInfo)this.metaData;
  633.                 ParameterInfo[] pars = oper.GetParameters();
  634.                 this.operand1.TranslateToIL(il, pars[0].ParameterType);
  635.                 this.operand2.TranslateToIL(il, pars[1].ParameterType);
  636.                 il.Emit(OpCodes.Call, oper);
  637.                 Convert.Emit(this, il, oper.ReturnType, rtype);
  638.                 return;
  639.             }
  640.             //Getting here is just too bad. We do not know until the code runs whether or not to call an overloaded operator method.
  641.             //Compile operands to objects and devolve the decision making to run time thunks
  642.             il.Emit(OpCodes.Ldloc, (LocalBuilder)this.metaData);
  643.             this.operand1.TranslateToIL(il, Typeob.Object);
  644.             this.operand2.TranslateToIL(il, Typeob.Object);
  645.             il.Emit(OpCodes.Call, CompilerGlobals.evaluateNumericBinaryMethod);
  646.             Convert.Emit(this, il, Typeob.Object, rtype);
  647.         }
  648.        
  649.         internal override void TranslateToILInitializer(ILGenerator il)
  650.         {
  651.             IReflect rtype = this.InferType(null);
  652.             this.operand1.TranslateToILInitializer(il);
  653.             this.operand2.TranslateToILInitializer(il);
  654.             if (rtype != Typeob.Object)
  655.                 return;
  656.             this.metaData = il.DeclareLocal(Typeob.NumericBinary);
  657.             ConstantWrapper.TranslateToILInt(il, (int)this.operatorTok);
  658.             il.Emit(OpCodes.Newobj, CompilerGlobals.numericBinaryConstructor);
  659.             il.Emit(OpCodes.Stloc, (LocalBuilder)this.metaData);
  660.         }
  661.     }
  662. }

Developer Fusion