示例#1
0
        /// <summary>
        /// 暗黙のキャストを探す。
        /// </summary>
        private DynamicMetaObject DefferentType(DynamicMetaObject left, DynamicMetaObject right)
        {
            var val = TryCalcNumeric(left, right);

            if (val != null)
            {
                return(val);
            }
            // 左辺のキャスト
            var mInfo = BinderHelper.GetImplicitCast(left.LimitType, right.LimitType);

            if (mInfo != null)
            {
                Expression expr = Expression.MakeBinary(this.Operation,
                                                        BinderHelper.Wrap(left.Expression, left.LimitType, right.LimitType),
                                                        Expression.Convert(right.Expression, right.LimitType));
                return(new DynamicMetaObject(
                           BinderHelper.Wrap(expr, this.ReturnType),
                           BinderHelper.GetTypeRestriction(left, right)));
            }
            // 右辺のキャスト
            mInfo = BinderHelper.GetImplicitCast(right.LimitType, left.LimitType);
            if (mInfo != null)
            {
                Expression expr = Expression.MakeBinary(this.Operation,
                                                        Expression.Convert(left.Expression, left.LimitType),
                                                        BinderHelper.Wrap(right.Expression, right.LimitType, left.LimitType));
                return(new DynamicMetaObject(
                           BinderHelper.Wrap(expr, this.ReturnType),
                           BinderHelper.GetTypeRestriction(left, right)));
            }
            return(BinderHelper.NoResult(_name, this.ReturnType, left, right));
        }
示例#2
0
        /// <summary>
        /// 整数と小数の比較
        /// </summary>
        private DynamicMetaObject TryCalcOnDefferentNumericType(DynamicMetaObject left, DynamicMetaObject right)
        {
            Expression leftExpr  = BinderHelper.LimitTypeConvert(left);
            Expression rightExpr = BinderHelper.LimitTypeConvert(right);
            Expression expr      = null;

            foreach (var pattern in BinderHelper.CastPatterns)
            {
                if (leftExpr.Type == pattern.Narrow && rightExpr.Type == pattern.Wide)
                {
                    var upperLeft = Expression.Convert(leftExpr, pattern.Wide);
                    expr = Expression.MakeBinary(this.Operation, upperLeft, rightExpr);
                    break;
                }
                if (leftExpr.Type == pattern.Wide && rightExpr.Type == pattern.Narrow)
                {
                    var upperRight = Expression.Convert(rightExpr, pattern.Wide);
                    expr = Expression.MakeBinary(this.Operation, leftExpr, upperRight);
                    break;
                }
            }
            if (expr == null)
            {
                return(null);
            }
            return(new DynamicMetaObject(
                       BinderHelper.Wrap(expr, this.ReturnType),
                       BinderHelper.GetTypeRestriction(left, right)));
        }
示例#3
0
        /// <summary>
        /// 暗黙の型変換が存在する場合,それを利用する。
        /// </summary>
        private DynamicMetaObject TryImplicitCast(DynamicMetaObject left, DynamicMetaObject right)
        {
            Expression cmpExpr = null;

            if (BinderHelper.GetImplicitCast(left.LimitType, right.LimitType) != null)
            {
                try {
                    cmpExpr = Expression.MakeBinary(this.Operation,
                                                    BinderHelper.Wrap(left.Expression, left.LimitType, right.LimitType),
                                                    BinderHelper.Wrap(right.Expression, right.LimitType));
                }
                catch (InvalidCastException) { }
            }
            if (BinderHelper.GetImplicitCast(right.LimitType, left.LimitType) != null)
            {
                try {
                    cmpExpr = Expression.MakeBinary(this.Operation,
                                                    BinderHelper.Wrap(left.Expression, left.LimitType),
                                                    BinderHelper.Wrap(right.Expression, right.LimitType, left.LimitType));
                }
                catch (InvalidCastException) { }
            }
            if (cmpExpr == null)
            {
                return(null);
            }
            var expr = BinderHelper.Wrap(cmpExpr, this.ReturnType);
            var rest = BinderHelper.GetTypeRestriction(left, right);

            return(new DynamicMetaObject(expr, rest));
        }
示例#4
0
        public override DynamicMetaObject FallbackBinaryOperation(DynamicMetaObject target, DynamicMetaObject arg, DynamicMetaObject errorSuggestion)
        {
            if (target.Value == null || arg.Value == null)
            {
                return(BinderHelper.NullErrorOnOperation(_name, this.ReturnType, target, arg));
            }

            try {
                if (target.LimitType == arg.LimitType)
                {
                    var type        = target.LimitType;
                    var leftExpr    = BinderHelper.Wrap(target.Expression, type);
                    var rightExpr   = BinderHelper.Wrap(arg.Expression, type);
                    var checkedExpr = OverflowCheckingCalc(leftExpr, rightExpr);
                    if (checkedExpr != null)
                    {
                        var bindings = BinderHelper.GetTypeRestriction(target, arg);
                        return(new DynamicMetaObject(checkedExpr, bindings));
                    }
                }
                Expression expr = Expression.MakeBinary(
                    this.Operation,
                    BinderHelper.Wrap(target.Expression, target.LimitType),
                    BinderHelper.Wrap(arg.Expression, arg.LimitType));
                return(new DynamicMetaObject(
                           BinderHelper.Wrap(expr, this.ReturnType),
                           BinderHelper.GetTypeRestriction(target, arg)));
            }
            catch (InvalidOperationException) {
                return(DefferentType(target, arg));
            }
        }
示例#5
0
        /// <summary>
        /// 整数と小数の演算を行う
        /// </summary>
        private DynamicMetaObject TryCalcNumeric(DynamicMetaObject left, DynamicMetaObject right)
        {
            Expression leftExpr  = BinderHelper.LimitTypeConvert(left);
            Expression rightExpr = BinderHelper.LimitTypeConvert(right);
            Expression expr      = null;

            foreach (var pattern in BinderHelper.CastPatterns)
            {
                if (leftExpr.Type == pattern.Narrow && rightExpr.Type == pattern.Wide)
                {
                    var upperLeft = Expression.Convert(leftExpr, pattern.Wide);
                    expr = OverflowCheckingCalc(upperLeft, rightExpr);
                    break;
                }
                if (leftExpr.Type == pattern.Wide && rightExpr.Type == pattern.Narrow)
                {
                    var upperRight = Expression.Convert(rightExpr, pattern.Wide);
                    expr = OverflowCheckingCalc(leftExpr, upperRight);
                    break;
                }
            }
            if (expr == null)
            {
                return(null);
            }
            var bindings = BinderHelper.GetTypeRestriction(left, right);

            return(new DynamicMetaObject(expr, bindings));
        }
示例#6
0
        /// <summary>
        /// 適切な計算方法が見つからなかった場合、RuntimeBinderExceptionを投げる。
        /// </summary>
        public static DynamicMetaObject NoResult(string name, Type type, DynamicMetaObject left, DynamicMetaObject right)
        {
            var ctorInfo = typeof(InvalidOperationException).GetConstructor(new[] { typeof(string) });
            var errorMsg = "{0}と{1}を" + name + "出来ません。";
            var mInfo    = typeof(String).GetMethod("Format", new[] { typeof(string), typeof(object), typeof(object) });
            var msgExpr  = Expression.Call(mInfo,
                                           Expression.Constant(errorMsg),
                                           Expression.Convert(left.Expression, typeof(object)),
                                           Expression.Convert(right.Expression, typeof(object)));
            var expr = Expression.Throw(Expression.New(ctorInfo, msgExpr), typeof(object));

            return(new DynamicMetaObject(expr, BinderHelper.GetTypeRestriction(left, right)));
        }
示例#7
0
        /// <summary>
        /// 左辺と右辺を参照比較する。
        /// </summary>
        private DynamicMetaObject TryReferenceEqual(DynamicMetaObject left, DynamicMetaObject right)
        {
            if (left.LimitType.IsValueType || right.LimitType.IsValueType)
            {
                return(null);
            }
            var        boolResult = Expression.Constant(this.Operation == ExpressionType.Equal);
            Expression expr       = ExpressionHelper.BetaReduction(
                (object objA, object objB, bool result) => (object)(Object.ReferenceEquals(objA, objB) == result),
                left.Expression, right.Expression, boolResult);

            expr = BinderHelper.Wrap(expr, this.ReturnType);
            var rest = BinderHelper.GetTypeRestriction(left, right);

            return(new DynamicMetaObject(expr, rest));
        }
示例#8
0
        /// <summary>
        /// 標準の比較を用いる。
        /// 失敗した場合,右辺と左辺は等しくないものとする。
        /// </summary>
        private DynamicMetaObject Default(DynamicMetaObject left, DynamicMetaObject right)
        {
            Expression eqExpr = null;

            try {
                eqExpr = Expression.MakeBinary(this.Operation,
                                               BinderHelper.Wrap(left.Expression, left.LimitType),
                                               BinderHelper.Wrap(right.Expression, right.LimitType));
            }
            catch (InvalidOperationException) {
                eqExpr = Expression.Constant(this.Operation != ExpressionType.Equal);
            }
            var expr = BinderHelper.Wrap(eqExpr, this.ReturnType);
            var rest = BinderHelper.GetTypeRestriction(left, right);

            return(new DynamicMetaObject(expr, rest));
        }
示例#9
0
        /// <summary>
        /// 左辺がIComparable<T>を実装している場合、CompareToメソッドを呼ぶことで比較する。
        /// </summary>
        private DynamicMetaObject TryUseIComparableT(DynamicMetaObject left, DynamicMetaObject right)
        {
            var types      = left.LimitType.GetInterfaces();
            var cmpType    = typeof(IComparable <>).MakeGenericType(right.LimitType);
            var hasGeneric = Array.IndexOf(types, cmpType) != -1;

            if (hasGeneric == false)
            {
                return(null);
            }
            var callExpr = Expression.Call(
                Expression.Convert(left.Expression, cmpType),
                cmpType.GetMethod("CompareTo", new[] { right.LimitType }),
                Expression.Convert(right.Expression, right.LimitType));
            var expr = BinderHelper.Wrap(ExpressionHelper.BetaReduction(_compareExpr, callExpr), this.ReturnType);
            var rest = BinderHelper.GetTypeRestriction(left, right);

            return(new DynamicMetaObject(expr, rest));
        }
示例#10
0
        /// <summary>
        /// 左辺がIEquatable<T>を継承している場合,それを利用する。
        /// </summary>
        private DynamicMetaObject TryUseIEquatableT(DynamicMetaObject left, DynamicMetaObject right)
        {
            var types      = left.LimitType.GetInterfaces();
            var cmpType    = typeof(IEquatable <>).MakeGenericType(right.LimitType);
            var hasGeneric = Array.IndexOf(types, cmpType) != -1;

            if (hasGeneric == false)
            {
                return(null);
            }
            var callExpr = Expression.Call(
                Expression.Convert(left.Expression, cmpType),
                cmpType.GetMethod("Equals", new[] { right.LimitType }),
                Expression.Convert(right.Expression, right.LimitType));
            var result = Expression.Constant(this.Operation == ExpressionType.Equal);
            var expr   = BinderHelper.Wrap(Expression.Equal(callExpr, result), this.ReturnType);
            var rest   = BinderHelper.GetTypeRestriction(left, right);

            return(new DynamicMetaObject(expr, rest));
        }
示例#11
0
 public override DynamicMetaObject FallbackBinaryOperation(DynamicMetaObject target, DynamicMetaObject arg, DynamicMetaObject errorSuggestion)
 {
     if (target.Value == null && arg.Value == null)
     {
         return(CompareBotheNull(target, arg));
     }
     if (target.Value == null || arg.Value == null)
     {
         return(CompareEatherNull(target, arg));
     }
     try {
         var expr = Expression.MakeBinary(
             this.Operation,
             BinderHelper.Wrap(target.Expression, target.LimitType),
             BinderHelper.Wrap(arg.Expression, arg.LimitType));
         return(new DynamicMetaObject(
                    BinderHelper.Wrap(expr, this.ReturnType),
                    BinderHelper.GetTypeRestriction(target, arg)));
     }
     catch (InvalidOperationException) {
         return(Search(target, arg));
     }
 }