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

  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.    
  22.     public abstract class BinaryOp : AST
  23.     {
  24.         protected AST operand1;
  25.         protected AST operand2;
  26.         protected JSToken operatorTok;
  27.         protected Type type1;
  28.         protected Type type2;
  29.         protected MethodInfo operatorMeth;
  30.        
  31.         internal BinaryOp(Context context, AST operand1, AST operand2) : this(context, operand1, operand2, (JSToken)0)
  32.         {
  33.         }
  34.        
  35.         internal BinaryOp(Context context, AST operand1, AST operand2, JSToken operatorTok) : base(context)
  36.         {
  37.             this.operand1 = operand1;
  38.             this.operand2 = operand2;
  39.             this.operatorTok = operatorTok;
  40.             this.type1 = null;
  41.             this.type2 = null;
  42.             this.operatorMeth = null;
  43.         }
  44.        
  45.         internal override void CheckIfOKToUseInSuperConstructorCall()
  46.         {
  47.             this.operand1.CheckIfOKToUseInSuperConstructorCall();
  48.             this.operand2.CheckIfOKToUseInSuperConstructorCall();
  49.         }
  50.        
  51.         protected MethodInfo GetOperator(IReflect ir1, IReflect ir2)
  52.         {
  53.             if (ir1 is ClassScope)
  54.                 ir1 = ((ClassScope)ir1).GetUnderlyingTypeIfEnum();
  55.             if (ir2 is ClassScope)
  56.                 ir2 = ((ClassScope)ir2).GetUnderlyingTypeIfEnum();
  57.             Type t1 = ir1 is Type ? (Type)ir1 : Typeob.Object;
  58.             Type t2 = ir2 is Type ? (Type)ir2 : Typeob.Object;
  59.             if (this.type1 == t1 && this.type2 == t2)
  60.                 return this.operatorMeth;
  61.             this.type1 = t1;
  62.             this.type2 = t2;
  63.             this.operatorMeth = null;
  64.             if (t1 == Typeob.String || Convert.IsPrimitiveNumericType(ir1) || Typeob.JSObject.IsAssignableFrom(t1))
  65.                 t1 = null;
  66.             if (t2 == Typeob.String || Convert.IsPrimitiveNumericType(ir2) || Typeob.JSObject.IsAssignableFrom(t2))
  67.                 t2 = null;
  68.             if (t1 == null && t2 == null)
  69.                 return null;
  70.             //One of the operands is an object of a type that might have a user defined operator.
  71.             string name = "op_NoSuchOp";
  72.             switch (this.operatorTok) {
  73.                 case JSToken.BitwiseAnd:
  74.                     name = "op_BitwiseAnd";
  75.                     break;
  76.                 case JSToken.BitwiseOr:
  77.                     name = "op_BitwiseOr";
  78.                     break;
  79.                 case JSToken.BitwiseXor:
  80.                     name = "op_ExclusiveOr";
  81.                     break;
  82.                 case JSToken.Divide:
  83.                     name = "op_Division";
  84.                     break;
  85.                 case JSToken.Equal:
  86.                     name = "op_Equality";
  87.                     break;
  88.                 case JSToken.GreaterThan:
  89.                     name = "op_GreaterThan";
  90.                     break;
  91.                 case JSToken.GreaterThanEqual:
  92.                     name = "op_GreaterThanOrEqual";
  93.                     break;
  94.                 case JSToken.LeftShift:
  95.                     name = "op_LeftShift";
  96.                     break;
  97.                 case JSToken.LessThan:
  98.                     name = "op_LessThan";
  99.                     break;
  100.                 case JSToken.LessThanEqual:
  101.                     name = "op_LessThanOrEqual";
  102.                     break;
  103.                 case JSToken.Minus:
  104.                     name = "op_Subtraction";
  105.                     break;
  106.                 case JSToken.Modulo:
  107.                     name = "op_Modulus";
  108.                     break;
  109.                 case JSToken.Multiply:
  110.                     name = "op_Multiply";
  111.                     break;
  112.                 case JSToken.NotEqual:
  113.                     name = "op_Inequality";
  114.                     break;
  115.                 case JSToken.Plus:
  116.                     name = "op_Addition";
  117.                     break;
  118.                 case JSToken.RightShift:
  119.                     name = "op_RightShift";
  120.                     break;
  121.             }
  122.             Type[] types = new Type[] {this.type1, this.type2};
  123.             if (t1 == t2) {
  124.                 MethodInfo op = t1.GetMethod(name, BindingFlags.Public | BindingFlags.Static, JSBinder.ob, types, null);
  125.                 if (op != null && (op.Attributes & MethodAttributes.SpecialName) != 0 && op.GetParameters().Length == 2)
  126.                     this.operatorMeth = op;
  127.             }
  128.             else {
  129.                 //Search both operand types, but only if there is a possibility that they might have operators defined on them
  130.                 MethodInfo op1 = t1 == null ? null : t1.GetMethod(name, BindingFlags.Public | BindingFlags.Static, JSBinder.ob, types, null);
  131.                 MethodInfo op2 = t2 == null ? null : t2.GetMethod(name, BindingFlags.Public | BindingFlags.Static, JSBinder.ob, types, null);
  132.                 this.operatorMeth = JSBinder.SelectOperator(op1, op2, this.type1, this.type2);
  133.                 //Choose the better of the two
  134.             }
  135.             if (this.operatorMeth != null)
  136.                 this.operatorMeth = new JSMethodInfo(this.operatorMeth);
  137.             return this.operatorMeth;
  138.         }
  139.        
  140.         internal override AST PartiallyEvaluate()
  141.         {
  142.             this.operand1 = this.operand1.PartiallyEvaluate();
  143.             this.operand2 = this.operand2.PartiallyEvaluate();
  144.             try {
  145.                 if (this.operand1 is ConstantWrapper) {
  146.                     if (this.operand2 is ConstantWrapper)
  147.                         return new ConstantWrapper(this.Evaluate(), this.context);
  148.                     else {
  149.                         object val = ((ConstantWrapper)this.operand1).value;
  150.                         if (val is string && ((string)val).Length == 1 && this.operand2.InferType(null) == Typeob.Char)
  151.                             ((ConstantWrapper)this.operand1).value = (char)((string)val)[0];
  152.                     }
  153.                 }
  154.                 else if (this.operand2 is ConstantWrapper) {
  155.                     object val = ((ConstantWrapper)this.operand2).value;
  156.                     if (val is string && ((string)val).Length == 1 && this.operand1.InferType(null) == Typeob.Char)
  157.                         ((ConstantWrapper)this.operand2).value = (char)((string)val)[0];
  158.                 }
  159.             }
  160.             catch (JScriptException e) {
  161.                 this.context.HandleError((JSError)(e.ErrorNumber & 65535));
  162.             }
  163.             catch {
  164.                 this.context.HandleError(JSError.TypeMismatch);
  165.             }
  166.             return this;
  167.         }
  168.        
  169.         internal override void TranslateToILInitializer(ILGenerator il)
  170.         {
  171.             this.operand1.TranslateToILInitializer(il);
  172.             this.operand2.TranslateToILInitializer(il);
  173.         }
  174.     }
  175. }

Developer Fusion