public override ValueExpression Evaluate(IParserContext context)
        {
            ValueExpression[] values = new[] { Left.Evaluate(context), Right.Evaluate(context) };

            Type type1 = values[0].Type;
            Type type2 = values[1].Type;

            bool nullable1 = type1.IsGenericType && type1.GetGenericTypeDefinition() == typeof(Nullable <>);
            bool nullable2 = type2.IsGenericType && type2.GetGenericTypeDefinition() == typeof(Nullable <>);

            type1 = Nullable.GetUnderlyingType(type1) ?? type1;
            type2 = Nullable.GetUnderlyingType(type2) ?? type2;

            bool isNullable = (nullable1 || nullable2);

            OperatorMethod operatorMethod = FindOperatorMethod(type1, type2);

            if (operatorMethod == null)
            {
                Type promotionType = null;

                if (type1 == typeof(decimal) || type2 == typeof(decimal))
                {
                    promotionType = typeof(decimal);
                }
                else if (type1 == typeof(double) || type2 == typeof(double))
                {
                    promotionType = typeof(double);
                }
                else if (type1 == typeof(float) || type2 == typeof(float))
                {
                    promotionType = typeof(float);
                }
                else if (type1 == typeof(ulong) || type2 == typeof(ulong))
                {
                    promotionType = typeof(ulong);
                }
                else if (type1 == typeof(long) || type2 == typeof(long))
                {
                    promotionType = typeof(long);
                }
                else if (type1 == typeof(uint) || type2 == typeof(uint) && (type1 == typeof(sbyte) || type2 == typeof(sbyte) || type1 == typeof(short) || type2 == typeof(short) || type1 == typeof(int) || type2 == typeof(int)))
                {
                    promotionType = typeof(long);
                }
                else if (type1 == typeof(uint) || type2 == typeof(uint))
                {
                    promotionType = typeof(uint);
                }
                else if (type1.IsPrimitive && type2.IsPrimitive && type1 != typeof(bool) && type2 != typeof(bool))
                {
                    promotionType = typeof(int);
                }

                if (promotionType != null)
                {
                    type1 = promotionType;
                    type2 = promotionType;
                }

                operatorMethod = FindOperatorMethod(type1, type2);
            }

            if (operatorMethod == null)
            {
                MethodInfo customOperatorMethod = type1.GetMethod(_operatorOverloadNames[_operator], new[] { type1, type2 });

                if (customOperatorMethod != null)
                {
                    return(new ValueExpression(TokenPosition, customOperatorMethod.Invoke(null, new[] { values[0].Value, values[1].Value }), customOperatorMethod.ReturnType));
                }

                if (_operator == "==" || _operator == "!=")
                {
                    return(new ValueExpression(TokenPosition, BinaryExpressionHelper.CalcObject(_operator, values[0].Value, values[1].Value, context.StringComparison, this), typeof(bool)));
                }

                throw new IllegalOperandsException("Operator " + _operator + " is not supported on " + values[0] + " and " + values[1], this);
            }

            Type returnType = operatorMethod.ReturnType;

            if (isNullable)
            {
                returnType = typeof(Nullable <>).MakeGenericType(returnType);

                //TODO: check specs for bool? values

                if (values[0].Value == null || values[1].Value == null)
                {
                    return(new ValueExpression(TokenPosition, null, returnType));
                }
            }

            object value1 = Convert.ChangeType(values[0].Value, operatorMethod.Type1);
            object value2 = Convert.ChangeType(values[1].Value, operatorMethod.Type2);

            return(new ValueExpression(TokenPosition, operatorMethod.Function(_operator, value1, value2, context.StringComparison, this), returnType));
        }
        public override ValueExpression Evaluate(ITemplateContext context)
        {
            ValueExpression[] values = new ValueExpression[] { Left.Evaluate(context), Right.Evaluate(context) };
            Type type1 = values[0].Type;
            Type type2 = values[1].Type;

            bool nullable1 = type1.IsGenericType && type1.GetGenericTypeDefinition() == typeof(Nullable <>);
            bool nullable2 = type2.IsGenericType && type2.GetGenericTypeDefinition() == typeof(Nullable <>);

            type1 = Nullable.GetUnderlyingType(type1) ?? type1;
            type2 = Nullable.GetUnderlyingType(type2) ?? type2;

            bool           isNullable     = (nullable1 || nullable2);
            OperatorMethod operatorMethod = FindOperatorMethod(type1, type2);

            if (operatorMethod == null)
            {
                Type promotionType = null;

                if (type1 == typeof(decimal) || type2 == typeof(decimal))
                {
                    promotionType = typeof(decimal);
                }
                else if (type1 == typeof(double) || type2 == typeof(double))
                {
                    promotionType = typeof(double);
                }
                else if (type1 == typeof(float) || type2 == typeof(float))
                {
                    promotionType = typeof(float);
                }
                else if (type1 == typeof(ulong) || type2 == typeof(ulong))
                {
                    promotionType = typeof(ulong);
                }
                else if (type1 == typeof(long) || type2 == typeof(long))
                {
                    promotionType = typeof(long);
                }
                else if (type1 == typeof(uint) || type2 == typeof(uint) && (type1 == typeof(sbyte) || type2 == typeof(sbyte) || type1 == typeof(short) || type2 == typeof(short) || type1 == typeof(int) || type2 == typeof(int)))
                {
                    promotionType = typeof(long);
                }
                else if (type1 == typeof(uint) || type2 == typeof(uint))
                {
                    promotionType = typeof(uint);
                }
                else if (type1.IsPrimitive && type2.IsPrimitive && type1 != typeof(bool) && type2 != typeof(bool))
                {
                    promotionType = typeof(int);
                }

                if (promotionType != null)
                {
                    type1 = promotionType;
                    type2 = promotionType;
                }

                operatorMethod = FindOperatorMethod(type1, type2);
            }

            if (operatorMethod == null)
            {
                if (_operator == "==" || _operator == "!=")
                {
                    return(new ValueExpression(BEH.CalcObject(_operator, values[0].Value, values[1].Value), typeof(bool)));
                }

                throw new ArithmeticException();
            }

            Type returnType = operatorMethod.ReturnType;

            if (isNullable)
            {
                returnType = typeof(Nullable <>).MakeGenericType(returnType);

                //TODO: check specs for bool? values
                if (values[0].Value == null || values[1].Value == null)
                {
                    return(new ValueExpression(null, returnType));
                }
            }

            object value1 = Convert.ChangeType(values[0].Value, operatorMethod.Type1);
            object value2 = Convert.ChangeType(values[1].Value, operatorMethod.Type2);

            return(new ValueExpression(operatorMethod.Function(_operator, value1, value2), returnType));
        }