/// <summary>
 /// Tries to return the literal obtained from constant folding the binary expression whose literal arguments are given
 /// by opnd1 and opnd2. If any of these are null, the result is null. If the binary expression cannot be constant folded
 /// the result is also null.
 /// </summary>
 /// <param name="opnd1">null or literal corresponding to binary expression's 1st constant folded argument</param>
 /// <param name="opnd2">null or literal corresponding to binary expression's 2nd constant folded argument</param>
 /// <param name="binaryExpression">the original binary expression</param>
 /// <returns>null, or constant folded literal</returns>
 public static Literal EvalBinaryExpression(Literal opnd1, Literal opnd2, BinaryExpression binaryExpression, TypeSystem typeSystem){
   if (binaryExpression == null) return null;
   if (opnd1 == null) return null;
   if (opnd2 == null) return null;
   IConvertible ic1 = opnd1.Value as IConvertible;
   IConvertible ic2 = opnd2.Value as IConvertible;
   TypeCode code1 = ic1 == null ? TypeCode.Object : ic1.GetTypeCode();
   TypeCode code2 = ic2 == null ? TypeCode.Object : ic2.GetTypeCode();
   TypeNode type = SystemTypes.Object;
   object val = null;
   switch (binaryExpression.NodeType){
     case NodeType.Add :
       if (typeSystem != null && typeSystem.checkOverflow) goto case NodeType.Add_Ovf;
       return PureEvaluator.DoAdd(ic1, ic2, code1, code2, binaryExpression);
     case NodeType.Add_Ovf : 
     case NodeType.Add_Ovf_Un : 
       return PureEvaluator.DoAddOvf(ic1, ic2, code1, code2, binaryExpression);
     case NodeType.AddEventHandler :
       return null;
     case NodeType.And : 
       return PureEvaluator.DoAnd(ic1, ic2, code1, code2, binaryExpression);
     case NodeType.As :
       return null;
     case NodeType.Box :
     case NodeType.Castclass : 
     case NodeType.ExplicitCoercion :
       type = (TypeNode)opnd2.Value;
       TypeNode t = type;
       EnumNode en = type as EnumNode;
       if (en != null) t = en.UnderlyingType;
       if (t == null || !t.IsPrimitive) return null;
       if (typeSystem != null && binaryExpression.NodeType == NodeType.ExplicitCoercion){
         ErrorHandler savedErrorHandler = typeSystem.ErrorHandler;
         typeSystem.ErrorHandler = null;
         Expression result;
         try {
           result = typeSystem.ExplicitLiteralCoercion(opnd1, opnd1.Type, t, null);
         }
         finally {
           typeSystem.ErrorHandler = savedErrorHandler;
         };
         return result as Literal;
       }
       Type rt = t.GetRuntimeType();
       if (rt != null)
         val = Convert.ChangeType(opnd1.Value, rt, null);
       else
         val = opnd1.Value;
       break;
     case NodeType.Ceq : 
     case NodeType.Cgt : 
     case NodeType.Cgt_Un : 
     case NodeType.Clt : 
     case NodeType.Clt_Un : 
       return null;
     case NodeType.Comma:
       return opnd2;
     case NodeType.Div : 
     case NodeType.Div_Un : 
       return PureEvaluator.DoDiv(ic1, ic2, code1, code2, binaryExpression);
     case NodeType.Eq : 
       return PureEvaluator.DoEq(ic1, ic2, code1, code2, binaryExpression);
     case NodeType.Ge : 
       return PureEvaluator.DoGe(ic1, ic2, code1, code2, binaryExpression);
     case NodeType.Gt : 
       return PureEvaluator.DoGt(ic1, ic2, code1, code2, binaryExpression);
     case NodeType.Is : 
     case NodeType.Isinst : 
     case NodeType.Ldvirtftn :
       return null;
     case NodeType.Le : 
       return PureEvaluator.DoLe(ic1, ic2, code1, code2, binaryExpression);
     case NodeType.LogicalAnd :
       return PureEvaluator.DoLogicalAnd(ic1, ic2, code1, code2, binaryExpression);
     case NodeType.LogicalOr :
       return PureEvaluator.DoLogicalOr(ic1, ic2, code1, code2, binaryExpression);
     case NodeType.Lt : 
       return PureEvaluator.DoLt(ic1, ic2, code1, code2, binaryExpression);
     case NodeType.Mkrefany :
       return null;
     case NodeType.Mul :
       if (typeSystem != null && typeSystem.checkOverflow) goto case NodeType.Mul_Ovf;
       return PureEvaluator.DoMul(ic1, ic2, code1, code2, binaryExpression);
     case NodeType.Mul_Ovf : 
     case NodeType.Mul_Ovf_Un : 
       return PureEvaluator.DoMulOvf(ic1, ic2, code1, code2, binaryExpression);
     case NodeType.Ne : 
       return PureEvaluator.DoNe(ic1, ic2, code1, code2, binaryExpression);
     case NodeType.Or : 
       return PureEvaluator.DoOr(ic1, ic2, code1, code2, binaryExpression);
     case NodeType.Refanyval :
       return null;
     case NodeType.Rem : 
     case NodeType.Rem_Un : 
       return PureEvaluator.DoRem(ic1, ic2, code1, code2, binaryExpression);
     case NodeType.RemoveEventHandler :
       return null;
     case NodeType.Shl : 
       return PureEvaluator.DoLeftShift(ic1, ic2, code1, code2, binaryExpression);
     case NodeType.Shr : 
     case NodeType.Shr_Un : 
       return PureEvaluator.DoRightShift(ic1, ic2, code1, code2, binaryExpression);
     case NodeType.Sub :
       if (typeSystem != null && typeSystem.checkOverflow) goto case NodeType.Sub_Ovf;
       return PureEvaluator.DoSub(ic1, ic2, code1, code2, binaryExpression);        
     case NodeType.Sub_Ovf : 
     case NodeType.Sub_Ovf_Un : 
       return PureEvaluator.DoSubOvf(ic1, ic2, code1, code2, binaryExpression);
     case NodeType.Unbox : 
     case NodeType.Xor :
     default:
       return null;
   }
   return new Literal(val, type, binaryExpression.SourceContext);
 }