Ejemplo n.º 1
0
        public DynamicMetaObject FallbackOperation(DynamicMetaObject target, DynamicMetaObject[] args, DynamicMetaObject errorSuggestion)
        {
            Expression convertedTarget = Expression.Convert(target.Expression, target.LimitType);

            Expression[] convertedArgs = args.Select(x => Expression.Convert(x.Expression, x.LimitType)).ToArray();
            Expression   exp           = null;
            var          restrictions  = target.Restrictions.Merge(GetTypeRestriction(target));
            int          usedArgs      = 0;

            switch (OperationKind)
            {
            // Unary
            case TjsOperationKind.CharCodeToChar:
                exp = Expression.Call(Context.Convert(convertedTarget, typeof(char)), "ToString", null);
                break;

            case TjsOperationKind.CharToCharCode:
                exp = Expression.Call(new Func <string, long>(TjsOperationHelper.CharToCharCode).Method, Context.Convert(convertedTarget, typeof(string)));
                break;

            case TjsOperationKind.Evaluate:
            case TjsOperationKind.Invalidate:
            case TjsOperationKind.IsValid:
                if (errorSuggestion == null)
                {
                    errorSuggestion = new DynamicMetaObject(Expression.Throw(Expression.Constant(new NotImplementedException())), BindingRestrictions.Empty);
                }
                break;

            case TjsOperationKind.TypeOf:
                if (target.RuntimeType == null)
                {
                    exp = Expression.Constant("Object");
                }
                else if (target.RuntimeType == typeof(IronTjs.Builtins.Void))
                {
                    exp = Expression.Constant("void");
                }
                else if (target.RuntimeType == typeof(string))
                {
                    exp = Expression.Constant("String");
                }
                else if (Binders.IsInteger(target.RuntimeType))
                {
                    exp = Expression.Constant("Integer");
                }
                else if (Binders.IsFloatingPoint(target.RuntimeType))
                {
                    exp = Expression.Constant("Real");
                }
                else
                {
                    exp = Expression.Constant("Object");
                }
                break;

            // Unary (Special)
            case TjsOperationKind.InvokePropertyHandler:
                if (target.LimitType == typeof(Property))
                {
                    if (args.Length == 0)
                    {
                        exp = Expression.Property(convertedTarget, (System.Reflection.PropertyInfo)Utils.GetMember <Property>(x => x.Value));
                    }
                    else if (args.Length == 1)
                    {
                        exp      = Expression.Assign(Expression.Property(convertedTarget, (System.Reflection.PropertyInfo)Utils.GetMember <Property>(x => x.Value)), args[0].Expression);
                        usedArgs = 1;
                    }
                    else
                    {
                        if (errorSuggestion == null)
                        {
                            errorSuggestion = new DynamicMetaObject(Expression.Throw(Expression.Constant(new InvalidOperationException("引数の数が * 演算子に適用できる許容範囲を超えています。"))), BindingRestrictions.Empty);
                        }
                    }
                }
                else if (target.LimitType == typeof(BoundMemberTracker))
                {
                    var tracker = (BoundMemberTracker)target.Value;
                    if (tracker.Instance == null)
                    {
                        tracker = new BoundMemberTracker(tracker.BoundTo, new DynamicMetaObject(Expression.Constant(tracker.ObjectInstance), BindingRestrictions.Empty, tracker.ObjectInstance));
                    }
                    var type = tracker.Instance.GetLimitType();
                    if (args.Length == 0)
                    {
                        var res = tracker.GetValue(new TjsOverloadResolverFactory(Context.Binder), Context.Binder, type);
                        if (res != null)
                        {
                            exp          = res.Expression;
                            restrictions = restrictions.Merge(res.Restrictions);
                        }
                        else
                        {
                            if (errorSuggestion == null)
                            {
                                errorSuggestion = new DynamicMetaObject(Expression.Throw(Expression.Constant(new InvalidOperationException("メンバの取得に失敗しました。"))), BindingRestrictions.Empty);
                            }
                        }
                    }
                    else if (args.Length == 1)
                    {
                        var res = tracker.SetValue(new TjsOverloadResolverFactory(Context.Binder), Context.Binder, type, args[0]);
                        if (res != null)
                        {
                            exp          = res.Expression;
                            restrictions = restrictions.Merge(res.Restrictions);
                            usedArgs     = 1;
                        }
                        else
                        {
                            if (errorSuggestion == null)
                            {
                                errorSuggestion = new DynamicMetaObject(Expression.Throw(Expression.Constant(new InvalidOperationException("メンバの設定に失敗しました。"))), BindingRestrictions.Empty);
                            }
                        }
                    }
                    else
                    {
                        if (errorSuggestion == null)
                        {
                            errorSuggestion = new DynamicMetaObject(Expression.Throw(Expression.Constant(new InvalidOperationException("引数の数が * 演算子に適用できる許容範囲を超えています。"))), BindingRestrictions.Empty);
                        }
                    }
                }
                else
                {
                    if (errorSuggestion == null)
                    {
                        errorSuggestion = new DynamicMetaObject(Expression.Throw(Expression.Constant(new InvalidOperationException("プロパティ以外に対して * 演算子が使用されました。"))), BindingRestrictions.Empty);
                    }
                }
                break;

            // Binary (Arithmetic & Logical)
            case TjsOperationKind.FloorDivide:
                exp      = Expression.Divide(Context.Convert(convertedTarget, typeof(long)), Context.Convert(convertedArgs[0], typeof(long)));
                usedArgs = 1;
                break;

            case TjsOperationKind.RightShiftLogical:
                exp      = Expression.Convert(Expression.RightShift(Context.Convert(convertedTarget, typeof(ulong)), Context.Convert(convertedArgs[0], typeof(int))), typeof(long));
                usedArgs = 1;
                break;

            // Binary (Comparison)
            case TjsOperationKind.DistinctEqual:
                if (convertedTarget.Type == convertedArgs[0].Type)
                {
                    exp = Expression.Condition(Expression.Equal(convertedTarget, convertedArgs[0]), Expression.Constant(1L), Expression.Constant(0L));
                }
                else
                {
                    exp = Expression.Constant(0L);
                }
                usedArgs = 1;
                break;

            case TjsOperationKind.DistinctNotEqual:
                if (convertedTarget.Type == convertedArgs[0].Type)
                {
                    exp = Expression.Condition(Expression.Equal(convertedTarget, convertedArgs[0]), Expression.Constant(0L), Expression.Constant(1L));
                }
                else
                {
                    exp = Expression.Constant(1L);
                }
                usedArgs = 1;
                break;

            // Binary (Special)
            case TjsOperationKind.InstanceOf:
                exp = Expression.Condition(Expression.Equal(Expression.Constant(convertedTarget.Type.Name), Context.Convert(convertedArgs[0], typeof(string))),
                                           Expression.Constant(1L),
                                           Expression.Constant(0L)
                                           );
                usedArgs = 1;
                break;

            case TjsOperationKind.InContextOf:
                if (target.Value is IContextChangeable)
                {
                    exp = Expression.Call(Expression.Convert(convertedTarget, typeof(IContextChangeable)), "ChangeContext", null, args[0].Expression);
                }
                else if (target.LimitType == typeof(BoundMemberTracker))
                {
                    exp = Expression.New((System.Reflection.ConstructorInfo)Utils.GetMember(() => new BoundMemberTracker(null, (object)null)), Expression.PropertyOrField(convertedTarget, "BoundTo"), args[0].Expression);
                }
                else
                {
                    if (errorSuggestion == null)
                    {
                        errorSuggestion = new DynamicMetaObject(Expression.Throw(Expression.Constant(new InvalidOperationException("incontextof 演算子は指定されたオブジェクトに適用できません。"))), BindingRestrictions.Empty);
                    }
                }
                usedArgs = 1;
                break;
            }
            for (int i = 0; i < usedArgs; i++)
            {
                restrictions = restrictions.Merge(args[i].Restrictions).Merge(GetTypeRestriction(args[i]));
            }
            if (exp == null)
            {
                return(new DynamicMetaObject(errorSuggestion.Expression, errorSuggestion.Restrictions.Merge(restrictions)));
            }
            if (exp.Type != typeof(object))
            {
                exp = Expression.Convert(exp, typeof(object));
            }
            return(new DynamicMetaObject(exp, restrictions));
        }
Ejemplo n.º 2
0
        internal static Expression TryConvertExpression(Expression expression, Type toType, ParameterExpression succeeded)
        {
            var nonNullable = Binders.GetNonNullableType(toType);

            if (toType == typeof(object))
            {
                return(InSuccess(Expression.Convert(expression, toType), succeeded));
            }
            else if (toType == expression.Type)
            {
                return(InSuccess(expression, succeeded));
            }
            else if (expression.Type == typeof(IronTjs.Builtins.Void))
            {
                if (toType == typeof(string))
                {
                    return(InSuccess(Expression.Constant(string.Empty), succeeded));
                }
                else
                {
                    return(InSuccess(Expression.Default(toType), succeeded));
                }
            }
            else if (Binders.IsNumber(nonNullable))
            {
                if (Binders.IsNumber(expression.Type))
                {
                    return(InSuccess(NewNullableOrThrough(Expression.Convert(expression, nonNullable), toType, nonNullable), succeeded));
                }
                else if (expression.Type == typeof(string))
                {
                    ParameterExpression v;
                    Expression          test;
                    if (Binders.IsInteger(nonNullable))
                    {
                        v    = Expression.Variable(typeof(long));
                        test = Expression.Call(typeof(Binders).GetMethod("TryConvertInt64"), expression, v);
                    }
                    else if (Binders.IsFloatingPoint(nonNullable))
                    {
                        v    = Expression.Variable(typeof(double));
                        test = Expression.Call(typeof(Binders).GetMethod("TryConvertDouble"), expression, v);
                    }
                    else
                    {
                        v    = Expression.Variable(nonNullable);
                        test = Expression.Call(nonNullable.GetMethod("TryParse", new[] { typeof(string), nonNullable.MakeByRefType() }), expression, v);
                    }
                    if (succeeded != null)
                    {
                        test = Expression.Assign(succeeded, test);
                    }
                    return(Expression.Block(new[] { v },
                                            Expression.Condition(test,
                                                                 NewNullableOrThrough(v, toType, nonNullable),
                                                                 Expression.Default(toType)
                                                                 )
                                            ));
                }
            }
            else if (toType == typeof(string))
            {
                if (expression.Type.IsValueType)
                {
                    return(InSuccess(Expression.Call(expression, expression.Type.GetMethod("ToString", Type.EmptyTypes)), succeeded));
                }
                var v = Expression.Variable(expression.Type);
                return(InSuccess(Expression.Block(new[] { v },
                                                  Expression.Condition(Expression.NotEqual(Expression.Assign(v, expression), Expression.Constant(null)),
                                                                       Expression.Call(v, expression.Type.GetMethod("ToString", Type.EmptyTypes)),
                                                                       Expression.Constant("null")
                                                                       )
                                                  ), succeeded));
            }
            else if (nonNullable == typeof(bool))
            {
                Expression exp;
                if (Binders.IsNumber(expression.Type))
                {
                    exp = Expression.NotEqual(expression, Expression.Default(expression.Type));
                }
                else if (expression.Type == typeof(string))
                {
                    var v = Expression.Variable(typeof(long));
                    exp = Expression.Block(new[] { v },
                                           Expression.AndAlso(
                                               Expression.Call(typeof(long).GetMethod("TryParse", new[] { typeof(string), typeof(long).MakeByRefType() }), expression, v),
                                               Expression.NotEqual(v, Expression.Constant(0L))
                                               )
                                           );
                }
                else if (!expression.Type.IsValueType)
                {
                    exp = Expression.NotEqual(expression, Expression.Constant(null));
                }
                else if (expression.Type.IsGenericType && expression.Type.GetGenericTypeDefinition() == typeof(Nullable <>))
                {
                    exp = Expression.Property(expression, "HasValue");
                }
                else
                {
                    return(InSuccess(nonNullable == toType ? Expression.Constant(true) : Expression.Constant(new Nullable <bool>(true)), succeeded));
                }
                return(InSuccess(NewNullableOrThrough(exp, toType, nonNullable), succeeded));
            }
            return(null);
        }
Ejemplo n.º 3
0
        public override DynamicMetaObject FallbackUnaryOperation(DynamicMetaObject target, DynamicMetaObject errorSuggestion)
        {
            var        arg          = Expression.Convert(target.Expression, target.LimitType);
            var        restrictions = BindingRestrictionsHelpers.GetRuntimeTypeRestriction(target);
            Expression res          = null;

            switch (Operation)
            {
            case ExpressionType.Decrement:
                if (Binders.IsFloatingPoint(target.LimitType))
                {
                    res = Expression.Decrement(_context.Convert(arg, typeof(double)));
                }
                else
                {
                    res = Expression.Decrement(_context.Convert(arg, typeof(long)));
                }
                break;

            case ExpressionType.Increment:
                if (Binders.IsFloatingPoint(target.LimitType))
                {
                    res = Expression.Increment(_context.Convert(arg, typeof(double)));
                }
                else
                {
                    res = Expression.Increment(_context.Convert(arg, typeof(long)));
                }
                break;

            case ExpressionType.Negate:
                if (Binders.IsFloatingPoint(target.LimitType))
                {
                    res = Expression.Negate(_context.Convert(arg, typeof(double)));
                }
                else
                {
                    res = Expression.Negate(_context.Convert(arg, typeof(long)));
                }
                break;

            case ExpressionType.Not:
                res = Expression.Condition(_context.Convert(arg, typeof(bool)), Expression.Constant(0L), Expression.Constant(1L));
                break;

            case ExpressionType.OnesComplement:
                res = Expression.OnesComplement(_context.Convert(arg, typeof(long)));
                break;

            case ExpressionType.UnaryPlus:
                if (Binders.IsFloatingPoint(target.LimitType))
                {
                    res = _context.Convert(arg, typeof(double));
                }
                else if (Binders.IsInteger(target.LimitType))
                {
                    res = _context.Convert(arg, typeof(long));
                }
                else if (target.LimitType == typeof(string))
                {
                    res = Expression.Call(new Func <string, object>(Binders.ConvertNumber).Method, arg);
                }
                break;
            }
            if (res != null)
            {
                if (res.Type != typeof(object))
                {
                    return(new DynamicMetaObject(Expression.Convert(res, typeof(object)), restrictions));
                }
                else
                {
                    return(new DynamicMetaObject(res, restrictions));
                }
            }
            else
            {
                return(errorSuggestion ?? new DynamicMetaObject(Expression.Throw(Expression.Constant(new InvalidOperationException("不正な単項演算です。")), typeof(object)), restrictions));
            }
        }