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

  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 class Relational : BinaryOp
  24.     {
  25.         private object metaData = null;
  26.        
  27.         internal Relational(Context context, AST operand1, AST operand2, JSToken operatorTok) : base(context, operand1, operand2, operatorTok)
  28.         {
  29.         }
  30.        
  31.         public Relational(int operatorTok) : base(null, null, null, (JSToken)operatorTok)
  32.         {
  33.         }
  34.        
  35.         internal override object Evaluate()
  36.         {
  37.             object v1 = this.operand1.Evaluate();
  38.             object v2 = this.operand2.Evaluate();
  39.             double result = this.EvaluateRelational(v1, v2);
  40.             switch (this.operatorTok) {
  41.                 case JSToken.GreaterThan:
  42.                     return result > 0;
  43.                 case JSToken.GreaterThanEqual:
  44.                     return result >= 0;
  45.                 case JSToken.LessThan:
  46.                     return result < 0;
  47.                 case JSToken.LessThanEqual:
  48.                     return result <= 0;
  49.                 default:
  50.                     throw new JScriptException(JSError.InternalError, this.context);
  51.                     break;
  52.             }
  53.         }
  54.        
  55.         #if !DEBUG
  56.         [DebuggerStepThroughAttribute()]
  57.         [DebuggerHiddenAttribute()]
  58.         #endif
  59.         public double EvaluateRelational(object v1, object v2)
  60.         {
  61.             if (v1 is Int32) {
  62.                 if (v2 is Int32)
  63.                     return ((double)(int)v1) - (double)(int)v2;
  64.                 else if (v2 is double)
  65.                     return ((Int32)v1) - (double)v2;
  66.             }
  67.             else if (v1 is double) {
  68.                 if (v2 is double) {
  69.                     double d1 = (double)v1;
  70.                     double d2 = (double)v2;
  71.                     if (d1 == d2)
  72.                         return 0;
  73.                     //d1 and d2 could be infinities
  74.                     return d1 - d2;
  75.                 }
  76.                 else if (v2 is Int32)
  77.                     return ((double)v1) - (Int32)v2;
  78.             }
  79.             IConvertible ic1 = Convert.GetIConvertible(v1);
  80.             IConvertible ic2 = Convert.GetIConvertible(v2);
  81.             TypeCode t1 = Convert.GetTypeCode(v1, ic1);
  82.             TypeCode t2 = Convert.GetTypeCode(v2, ic2);
  83.             if (t1 == TypeCode.Object && t2 == TypeCode.Object) {
  84.                 MethodInfo oper = this.GetOperator(v1.GetType(), v2.GetType());
  85.                 if (oper != null) {
  86.                     bool result = Convert.ToBoolean(oper.Invoke(null, (BindingFlags)0, JSBinder.ob, new object[] {v1, v2}, null));
  87.                     switch (this.operatorTok) {
  88.                         case JSToken.GreaterThan:
  89.                         case JSToken.GreaterThanEqual:
  90.                             return result ? 1 : -1;
  91.                         case JSToken.LessThan:
  92.                         case JSToken.LessThanEqual:
  93.                             return result ? -1 : 1;
  94.                         default:
  95.                             throw new JScriptException(JSError.InternalError, this.context);
  96.                             break;
  97.                     }
  98.                 }
  99.             }
  100.             return JScriptCompare2(v1, v2, ic1, ic2, t1, t2);
  101.         }
  102.        
  103.         internal override IReflect InferType(JSField inference_target)
  104.         {
  105.             return Typeob.Boolean;
  106.         }
  107.        
  108.         public static double JScriptCompare(object v1, object v2)
  109.         {
  110.             if (v1 is Int32) {
  111.                 if (v2 is Int32)
  112.                     return ((Int32)v1) - (Int32)v2;
  113.                 else if (v2 is double)
  114.                     return ((Int32)v1) - (double)v2;
  115.             }
  116.             else if (v1 is double) {
  117.                 if (v2 is double) {
  118.                     double d1 = (double)v1;
  119.                     double d2 = (double)v2;
  120.                     if (d1 == d2)
  121.                         return 0;
  122.                     //d1 and d2 could be infinities
  123.                     return d1 - d2;
  124.                 }
  125.                 else if (v2 is Int32)
  126.                     return ((double)v1) - (Int32)v2;
  127.             }
  128.             IConvertible ic1 = Convert.GetIConvertible(v1);
  129.             IConvertible ic2 = Convert.GetIConvertible(v2);
  130.             TypeCode t1 = Convert.GetTypeCode(v1, ic1);
  131.             TypeCode t2 = Convert.GetTypeCode(v2, ic2);
  132.             return JScriptCompare2(v1, v2, ic1, ic2, t1, t2);
  133.         }
  134.        
  135.         private static double JScriptCompare2(object v1, object v2, IConvertible ic1, IConvertible ic2, TypeCode t1, TypeCode t2)
  136.         {
  137.             if (t1 == TypeCode.Object) {
  138.                 v1 = Convert.ToPrimitive(v1, PreferredType.Number, ref ic1);
  139.                 t1 = Convert.GetTypeCode(v1, ic1);
  140.             }
  141.             if (t2 == TypeCode.Object) {
  142.                 v2 = Convert.ToPrimitive(v2, PreferredType.Number, ref ic2);
  143.                 t2 = Convert.GetTypeCode(v2, ic2);
  144.             }
  145.             switch (t1) {
  146.                 case TypeCode.Char:
  147.                     if (t2 == TypeCode.String)
  148.                         return String.CompareOrdinal(Convert.ToString(v1, ic1), ic2.ToString(null));
  149.                     goto case TypeCode.UInt16;
  150.                     break;
  151.                 case TypeCode.SByte:
  152.                 case TypeCode.Byte:
  153.                 case TypeCode.Int16:
  154.                 case TypeCode.UInt16:
  155.                 case TypeCode.Int32:
  156.                 case TypeCode.UInt32:
  157.                 case TypeCode.Int64:
  158.                    
  159.                     long l = ic1.ToInt64(null);
  160.                     switch (t2) {
  161.                         case TypeCode.SByte:
  162.                         case TypeCode.Byte:
  163.                         case TypeCode.Int16:
  164.                         case TypeCode.UInt16:
  165.                         case TypeCode.Int32:
  166.                         case TypeCode.UInt32:
  167.                         case TypeCode.Int64:
  168.                             return l - ic2.ToInt64(null);
  169.                         case TypeCode.UInt64:
  170.                             if (l < 0)
  171.                                 return -1;
  172.                             ulong ul2 = ic2.ToUInt64(null);
  173.                             if (((ulong)l) < ul2)
  174.                                 return -1;
  175.                             if (((ulong)l) == ul2)
  176.                                 return 0;
  177.                             return 1;
  178.                         case TypeCode.Single:
  179.                         case TypeCode.Double:
  180.                             return ((double)l) - ic2.ToDouble(null);
  181.                         case TypeCode.Decimal:
  182.                             return (double)(new decimal(l) - ic2.ToDecimal(null));
  183.                         default:
  184.                             object bd2 = Convert.ToNumber(v2, ic2);
  185.                             return JScriptCompare2(v1, bd2, ic1, Convert.GetIConvertible(bd2), t1, TypeCode.Double);
  186.                     }
  187.                     break;
  188.                 case TypeCode.UInt64:
  189.                    
  190.                     ulong ul = ic1.ToUInt64(null);
  191.                     switch (t2) {
  192.                         case TypeCode.SByte:
  193.                         case TypeCode.Byte:
  194.                         case TypeCode.Int16:
  195.                         case TypeCode.UInt16:
  196.                         case TypeCode.Int32:
  197.                         case TypeCode.UInt32:
  198.                         case TypeCode.Int64:
  199.                             long l2 = ic2.ToInt64(null);
  200.                             if (l2 < 0)
  201.                                 return 1;
  202.                             if (ul == (ulong)l2)
  203.                                 return 0;
  204.                             return -1;
  205.                         case TypeCode.UInt64:
  206.                             ulong ul2 = ic2.ToUInt64(null);
  207.                             if (ul < ul2)
  208.                                 return -1;
  209.                             if (ul == ul2)
  210.                                 return 0;
  211.                             return 1;
  212.                         case TypeCode.Single:
  213.                         case TypeCode.Double:
  214.                             return ((double)ul) - ic2.ToDouble(null);
  215.                         case TypeCode.Decimal:
  216.                             return (double)(new decimal(ul) - ic2.ToDecimal(null));
  217.                         default:
  218.                             object bd2 = Convert.ToNumber(v2, ic2);
  219.                             return JScriptCompare2(v1, bd2, ic1, Convert.GetIConvertible(bd2), t1, TypeCode.Double);
  220.                     }
  221.                     break;
  222.                 case TypeCode.Decimal:
  223.                    
  224.                     decimal dec1 = ic1.ToDecimal(null);
  225.                     switch (t2) {
  226.                         case TypeCode.SByte:
  227.                         case TypeCode.Byte:
  228.                         case TypeCode.Int16:
  229.                         case TypeCode.UInt16:
  230.                         case TypeCode.Int32:
  231.                         case TypeCode.UInt32:
  232.                         case TypeCode.Int64:
  233.                             return (double)(dec1 - new decimal(ic2.ToInt64(null)));
  234.                         case TypeCode.UInt64:
  235.                             return (double)(dec1 - new decimal(ic2.ToUInt64(null)));
  236.                         case TypeCode.Single:
  237.                         case TypeCode.Double:
  238.                             return (double)(dec1 - new decimal(ic2.ToDouble(null)));
  239.                         case TypeCode.Decimal:
  240.                             return (double)(dec1 - ic2.ToDecimal(null));
  241.                         default:
  242.                             return (double)(dec1 - new decimal(Convert.ToNumber(v2, ic2)));
  243.                     }
  244.                     break;
  245.                 case TypeCode.String:
  246.                    
  247.                     switch (t2) {
  248.                         case TypeCode.String:
  249.                             return String.CompareOrdinal(ic1.ToString(null), ic2.ToString(null));
  250.                         case TypeCode.Char:
  251.                             return String.CompareOrdinal(ic1.ToString(null), Convert.ToString(v2, ic2));
  252.                     }
  253.                     goto default;
  254.                     break;
  255.                 default:
  256.                    
  257.                     double d1 = Convert.ToNumber(v1, ic1);
  258.                     double d2 = Convert.ToNumber(v2, ic2);
  259.                     if (d1 == d2)
  260.                         return 0;
  261.                     //d1 and d2 could be infinities
  262.                     return d1 - d2;
  263.             }
  264.         }
  265.        
  266.         internal override void TranslateToConditionalBranch(ILGenerator il, bool branchIfTrue, Label label, bool shortForm)
  267.         {
  268.             Type t1 = this.type1;
  269.             Type t2 = this.type2;
  270.             Type t3 = Typeob.Object;
  271.             if (t1.IsPrimitive && t2.IsPrimitive) {
  272.                 t3 = Typeob.Double;
  273.                 if (Convert.IsPromotableTo(t1, t2))
  274.                     t3 = t2;
  275.                 else if (Convert.IsPromotableTo(t2, t1))
  276.                     t3 = t1;
  277.                 else if (t1 == Typeob.Int64 || t1 == Typeob.UInt64 || t2 == Typeob.Int64 || t2 == Typeob.UInt64)
  278.                     t3 = Typeob.Object;
  279.                 //Cannot convert these to double without loss of precision in some cases, so use the helper method
  280.             }
  281.             if (t3 == Typeob.SByte || t3 == Typeob.Int16)
  282.                 t3 = Typeob.Int32;
  283.             else if (t3 == Typeob.Byte || t3 == Typeob.UInt16)
  284.                 t3 = Typeob.UInt32;
  285.             if (this.metaData == null) {
  286.                 this.operand1.TranslateToIL(il, t3);
  287.                 this.operand2.TranslateToIL(il, t3);
  288.                 if (t3 == Typeob.Object) {
  289.                     il.Emit(OpCodes.Call, CompilerGlobals.jScriptCompareMethod);
  290.                     il.Emit(OpCodes.Ldc_I4_0);
  291.                     il.Emit(OpCodes.Conv_R8);
  292.                     t3 = Typeob.Double;
  293.                 }
  294.             }
  295.             else if (this.metaData is MethodInfo) {
  296.                 MethodInfo oper = (MethodInfo)this.metaData;
  297.                 ParameterInfo[] pars = oper.GetParameters();
  298.                 this.operand1.TranslateToIL(il, pars[0].ParameterType);
  299.                 this.operand2.TranslateToIL(il, pars[1].ParameterType);
  300.                 il.Emit(OpCodes.Call, oper);
  301.                 if (branchIfTrue)
  302.                     il.Emit(shortForm ? OpCodes.Brtrue_S : OpCodes.Brtrue, label);
  303.                 else
  304.                     il.Emit(shortForm ? OpCodes.Brfalse_S : OpCodes.Brfalse, label);
  305.                 return;
  306.             }
  307.             else {
  308.                 //Getting here is just too bad. We do not know until the code runs whether or not to call an overloaded operator method.
  309.                 //Compile operands to objects and devolve the decision making to run time thunks
  310.                 il.Emit(OpCodes.Ldloc, (LocalBuilder)this.metaData);
  311.                 this.operand1.TranslateToIL(il, Typeob.Object);
  312.                 this.operand2.TranslateToIL(il, Typeob.Object);
  313.                 il.Emit(OpCodes.Call, CompilerGlobals.evaluateRelationalMethod);
  314.                 il.Emit(OpCodes.Ldc_I4_0);
  315.                 il.Emit(OpCodes.Conv_R8);
  316.                 t3 = Typeob.Double;
  317.             }
  318.             if (branchIfTrue) {
  319.                 if (t3 == Typeob.UInt32 || t3 == Typeob.UInt64)
  320.                     switch (this.operatorTok) {
  321.                         case JSToken.GreaterThan:
  322.                             il.Emit(shortForm ? OpCodes.Bgt_Un_S : OpCodes.Bgt_Un, label);
  323.                             break;
  324.                         case JSToken.GreaterThanEqual:
  325.                             il.Emit(shortForm ? OpCodes.Bge_Un_S : OpCodes.Bge_Un, label);
  326.                             break;
  327.                         case JSToken.LessThan:
  328.                             il.Emit(shortForm ? OpCodes.Blt_Un_S : OpCodes.Blt_Un, label);
  329.                             break;
  330.                         case JSToken.LessThanEqual:
  331.                             il.Emit(shortForm ? OpCodes.Ble_Un_S : OpCodes.Ble_Un, label);
  332.                             break;
  333.                         default:
  334.                             throw new JScriptException(JSError.InternalError, this.context);
  335.                             break;
  336.                     }
  337.                 else
  338.                     switch (this.operatorTok) {
  339.                         case JSToken.GreaterThan:
  340.                             il.Emit(shortForm ? OpCodes.Bgt_S : OpCodes.Bgt, label);
  341.                             break;
  342.                         case JSToken.GreaterThanEqual:
  343.                             il.Emit(shortForm ? OpCodes.Bge_S : OpCodes.Bge, label);
  344.                             break;
  345.                         case JSToken.LessThan:
  346.                             il.Emit(shortForm ? OpCodes.Blt_S : OpCodes.Blt, label);
  347.                             break;
  348.                         case JSToken.LessThanEqual:
  349.                             il.Emit(shortForm ? OpCodes.Ble_S : OpCodes.Ble, label);
  350.                             break;
  351.                         default:
  352.                             throw new JScriptException(JSError.InternalError, this.context);
  353.                             break;
  354.                     }
  355.             }
  356.             else {
  357.                 if (t3 == Typeob.Int32 || t3 == Typeob.Int64)
  358.                     switch (this.operatorTok) {
  359.                         case JSToken.GreaterThan:
  360.                             il.Emit(shortForm ? OpCodes.Ble_S : OpCodes.Ble, label);
  361.                             break;
  362.                         case JSToken.GreaterThanEqual:
  363.                             il.Emit(shortForm ? OpCodes.Blt_S : OpCodes.Blt, label);
  364.                             break;
  365.                         case JSToken.LessThan:
  366.                             il.Emit(shortForm ? OpCodes.Bge_S : OpCodes.Bge, label);
  367.                             break;
  368.                         case JSToken.LessThanEqual:
  369.                             il.Emit(shortForm ? OpCodes.Bgt_S : OpCodes.Bgt, label);
  370.                             break;
  371.                         default:
  372.                             throw new JScriptException(JSError.InternalError, this.context);
  373.                             break;
  374.                     }
  375.                 else
  376.                     switch (this.operatorTok) {
  377.                         case JSToken.GreaterThan:
  378.                             il.Emit(shortForm ? OpCodes.Ble_Un_S : OpCodes.Ble_Un, label);
  379.                             break;
  380.                         case JSToken.GreaterThanEqual:
  381.                             il.Emit(shortForm ? OpCodes.Blt_Un_S : OpCodes.Blt_Un, label);
  382.                             break;
  383.                         case JSToken.LessThan:
  384.                             il.Emit(shortForm ? OpCodes.Bge_Un_S : OpCodes.Bge_Un, label);
  385.                             break;
  386.                         case JSToken.LessThanEqual:
  387.                             il.Emit(shortForm ? OpCodes.Bgt_Un_S : OpCodes.Bgt_Un, label);
  388.                             break;
  389.                         default:
  390.                             throw new JScriptException(JSError.InternalError, this.context);
  391.                             break;
  392.                     }
  393.             }
  394.         }
  395.        
  396.         internal override void TranslateToIL(ILGenerator il, Type rtype)
  397.         {
  398.             Label true_label = il.DefineLabel();
  399.             Label done_label = il.DefineLabel();
  400.             this.TranslateToConditionalBranch(il, true, true_label, true);
  401.             il.Emit(OpCodes.Ldc_I4_0);
  402.             il.Emit(OpCodes.Br_S, done_label);
  403.             il.MarkLabel(true_label);
  404.             il.Emit(OpCodes.Ldc_I4_1);
  405.             il.MarkLabel(done_label);
  406.             Convert.Emit(this, il, Typeob.Boolean, rtype);
  407.         }
  408.        
  409.         internal override void TranslateToILInitializer(ILGenerator il)
  410.         {
  411.             this.operand1.TranslateToILInitializer(il);
  412.             this.operand2.TranslateToILInitializer(il);
  413.             MethodInfo oper = this.GetOperator(this.operand1.InferType(null), this.operand2.InferType(null));
  414.             if (oper != null) {
  415.                 this.metaData = oper;
  416.                 return;
  417.             }
  418.             if ((this.type1.IsPrimitive || Typeob.JSObject.IsAssignableFrom(this.type1)) && (this.type2.IsPrimitive || Typeob.JSObject.IsAssignableFrom(this.type2)))
  419.                 return;
  420.             this.metaData = il.DeclareLocal(Typeob.Relational);
  421.             ConstantWrapper.TranslateToILInt(il, (int)this.operatorTok);
  422.             il.Emit(OpCodes.Newobj, CompilerGlobals.relationalConstructor);
  423.             il.Emit(OpCodes.Stloc, (LocalBuilder)this.metaData);
  424.         }
  425.     }
  426. }

Developer Fusion