// If a type is one of "unsigned" int types, returns next bigger signed type
 protected virtual Type GetSignedTypeForUnsigned(Type type)
 {
     if (!UnsignedTypes.Contains(type))
     {
         return(type);
     }
     if (type == typeof(byte) || type == typeof(ushort))
     {
         return(typeof(int));
     }
     if (type == typeof(uint))
     {
         return(typeof(long));
     }
     if (type == typeof(ulong))
     {
         return(typeof(long)); //let's remain in Int64
     }
     return(typeof(BigInteger));
 }
 /// <summary>
 /// Returns the "up-type" to use in operation instead of the type that caused overflow.
 /// </summary>
 /// <param name="type">The base type for operation that caused overflow.</param>
 /// <returns>The type to use for operation.</returns>
 /// <remarks>
 /// Can be overwritten in language implementation to implement different type-conversion policy.
 /// </remarks>
 protected virtual Type GetUpType(Type type)
 {
     // In fact we do not need to care about unsigned types - they are eliminated from common types for operations,
     //  so "type" parameter can never be unsigned type. But just in case...
     if (UnsignedTypes.Contains(type))
     {
         return(GetSignedTypeForUnsigned(type)); //it will return "upped" type in fact
     }
     if (type == typeof(byte) || type == typeof(sbyte) || type == typeof(ushort) || type == typeof(short))
     {
         return(typeof(int));
     }
     if (type == typeof(int))
     {
         return(typeof(long));
     }
     if (type == typeof(long))
     {
         return(typeof(BigInteger));
     }
     return(null);
 }